Skip to content

Commit

Permalink
remove fees, add order hash to swap
Browse files Browse the repository at this point in the history
  • Loading branch information
0xtrooper committed Mar 24, 2023
1 parent 1498574 commit af8b1a8
Show file tree
Hide file tree
Showing 9 changed files with 41 additions and 949 deletions.
73 changes: 12 additions & 61 deletions evm_contracts/contracts/ZigZagExchange.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,12 @@ interface IWETH9 {
contract ZigZagExchange is EIP712 {
event Swap(
address maker,
bytes32 makerOrderHash,
address indexed taker,
address indexed makerSellToken,
address indexed takerSellToken,
uint256 makerSellAmount,
uint256 takerSellAmount,
uint256 makerVolumeFee,
uint256 takerVolumeFee
uint256 takerSellAmount
);

event CancelOrder(bytes32 indexed orderHash);
Expand All @@ -35,20 +34,12 @@ contract ZigZagExchange is EIP712 {

mapping(bytes32 => bool) public cancelled;

// fees
address immutable FEE_ADDRESS;
address immutable WETH_ADDRESS;
address immutable EXCHANGE_ADDRESS;
address constant ETH_ADDRESS = address(0);

uint256 maker_fee_numerator = 0;
uint256 maker_fee_denominator = 10000;
uint256 taker_fee_numerator = 5;
uint256 taker_fee_denominator = 10000;

// initialize fee address
constructor(string memory name, string memory version, address fee_address, address weth_address) EIP712(name, version) {
FEE_ADDRESS = fee_address;
constructor(string memory name, string memory version, address weth_address) EIP712(name, version) {
WETH_ADDRESS = weth_address;
EXCHANGE_ADDRESS = address(this);
}
Expand Down Expand Up @@ -102,9 +93,6 @@ contract ZigZagExchange is EIP712 {
fillAvailable
);
}

// adjust the takerAmountOut by the tx fee paid by the taker
takerAmount = takerAmount - (takerAmount * taker_fee_numerator) / taker_fee_denominator;
}

_refundETH();
Expand Down Expand Up @@ -141,9 +129,6 @@ contract ZigZagExchange is EIP712 {
takerAmount,
fillAvailable
);

// adjust the takerAmountOut by the tx fee paid by the taker
takerAmount = takerAmount - (takerAmount * taker_fee_numerator) / taker_fee_denominator;
}

return true;
Expand Down Expand Up @@ -178,8 +163,6 @@ contract ZigZagExchange is EIP712 {
uint takerBuyAmount,
bool fillAvailable
) public payable returns (bool) {
// add the takerFee to the buy amount to recive the exact amount after fees
takerBuyAmount = (takerBuyAmount * taker_fee_denominator) / (taker_fee_denominator - taker_fee_numerator);
_fillOrderETH(makerOrder, makerSignature, msg.sender, msg.sender, takerBuyAmount, fillAvailable);
_refundETH();
return true;
Expand Down Expand Up @@ -239,8 +222,6 @@ contract ZigZagExchange is EIP712 {
uint takerBuyAmount,
bool fillAvailable
) public returns (bool) {
// add the takerFee to the buy amount to recive the exact amount after fees
takerBuyAmount = (takerBuyAmount * taker_fee_denominator) / (taker_fee_denominator - taker_fee_numerator);
_fillOrder(
makerOrder,
makerSignature,
Expand Down Expand Up @@ -283,12 +264,6 @@ contract ZigZagExchange is EIP712 {
uint makerOrderFilled = makerOrderInfo.orderSellFilledAmount + takerBuyAmountAdjusted;
filled[makerOrderInfo.orderHash] = makerOrderFilled;

// The fee gets subtracted from the buy amounts so they deduct from the total instead of adding on to it
// The maker fee comes out of the taker sell quantity, so the maker ends up with less
// The taker fee comes out of the maker sell quantity, so the taker ends up with less
// makerFee = (takerSellAmount * maker_fee_numerator) / maker_fee_denominator
// takerFee = (takerBuyAmountAdjusted * taker_fee_numerator) / taker_fee_denominator

_settleMatchedOrders(
makerOrder.user,
taker,
Expand All @@ -297,8 +272,7 @@ contract ZigZagExchange is EIP712 {
buyToken,
takerBuyAmountAdjusted,
takerSellAmount,
(takerSellAmount * maker_fee_numerator) / maker_fee_denominator,
(takerBuyAmountAdjusted * taker_fee_numerator) / taker_fee_denominator
makerOrderInfo.orderHash
);

emit OrderStatus(makerOrderInfo.orderHash, makerOrderFilled, makerOrder.sellAmount - makerOrderFilled);
Expand All @@ -312,8 +286,7 @@ contract ZigZagExchange is EIP712 {
address takerSellToken,
uint makerSellAmount,
uint takerSellAmount,
uint makerFee,
uint takerFee
bytes32 makerOrderHash
) internal {
if (takerSellToken == ETH_ADDRESS) {
require(msg.value >= takerSellAmount, 'msg value not high enough');
Expand All @@ -330,46 +303,24 @@ contract ZigZagExchange is EIP712 {
require(IERC20(makerSellToken).allowance(maker, EXCHANGE_ADDRESS) >= makerSellAmount, 'maker order not enough allowance');
}

// Taker fee -> fee recipient
// taker fee is collected in takerBuyToken
if (takerFee > 0) {
if (makerSellToken == ETH_ADDRESS) {
IERC20(WETH_ADDRESS).transferFrom(maker, FEE_ADDRESS, takerFee);
} else {
IERC20(makerSellToken).transferFrom(maker, FEE_ADDRESS, takerFee);
}
}

// Maker fee -> fee recipient
// Maker fee is collected in makerBuyToken
if (makerFee > 0) {
if (takerSellToken == ETH_ADDRESS) {
IWETH9(WETH_ADDRESS).depositTo{ value: makerFee }(FEE_ADDRESS);
} else if (taker == EXCHANGE_ADDRESS) {
IERC20(takerSellToken).transfer(FEE_ADDRESS, makerFee);
} else {
IERC20(takerSellToken).transferFrom(taker, FEE_ADDRESS, makerFee);
}
}

// taker -> maker
if (takerSellToken == ETH_ADDRESS) {
IWETH9(WETH_ADDRESS).depositTo{ value: takerSellAmount - makerFee }(maker);
IWETH9(WETH_ADDRESS).depositTo{ value: takerSellAmount }(maker);
} else if (taker == EXCHANGE_ADDRESS) {
IERC20(takerSellToken).transfer(maker, takerSellAmount - makerFee);
IERC20(takerSellToken).transfer(maker, takerSellAmount);
} else {
IERC20(takerSellToken).transferFrom(taker, maker, takerSellAmount - makerFee);
IERC20(takerSellToken).transferFrom(taker, maker, takerSellAmount);
}

// maker -> taker
if (makerSellToken == ETH_ADDRESS) {
IERC20(WETH_ADDRESS).transferFrom(maker, EXCHANGE_ADDRESS, makerSellAmount - takerFee);
IWETH9(WETH_ADDRESS).withdrawTo(takerReciver, makerSellAmount - takerFee);
IERC20(WETH_ADDRESS).transferFrom(maker, EXCHANGE_ADDRESS, makerSellAmount);
IWETH9(WETH_ADDRESS).withdrawTo(takerReciver, makerSellAmount);
} else {
IERC20(makerSellToken).transferFrom(maker, takerReciver, makerSellAmount - takerFee);
IERC20(makerSellToken).transferFrom(maker, takerReciver, makerSellAmount);
}

emit Swap(maker, taker, makerSellToken, takerSellToken, makerSellAmount, takerSellAmount, makerFee, takerFee);
emit Swap(maker, makerOrderHash, taker, makerSellToken, takerSellToken, makerSellAmount, takerSellAmount);
}

function getOpenOrder(LibOrder.Order calldata order) public view returns (LibOrder.OrderInfo memory orderInfo) {
Expand Down
3 changes: 1 addition & 2 deletions evm_contracts/scripts/deployExchange.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ const hre = require('hardhat')

async function main() {
const Exchange = await hre.ethers.getContractFactory('ZigZagExchange')
const fee_address = "0xF4BBA1e2a5024a2754225b981e9A0DB7d2c33EE9";
const weth_address = "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1";
const exchange = await Exchange.deploy("ZigZag", "2.1", fee_address, weth_address);
const exchange = await Exchange.deploy("ZigZag", "2.1", weth_address);

await exchange.deployed()

Expand Down
120 changes: 0 additions & 120 deletions evm_contracts/test/FillOrderExactInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ describe('fillOrderExactInput', () => {
let tokenA: Contract
let tokenB: Contract
const wallets: Wallet[] = []
let FEE_ADDRESS: string

beforeEach(async function () {
this.timeout(30000)
Expand All @@ -30,11 +29,9 @@ describe('fillOrderExactInput', () => {
})
}

FEE_ADDRESS = wallets[3].address
exchangeContract = await Exchange.deploy(
'ZigZag',
'2.1',
FEE_ADDRESS,
ethers.constants.AddressZero
)

Expand Down Expand Up @@ -275,117 +272,6 @@ describe('fillOrderExactInput', () => {
).to.be.revertedWith('order expired')
})

it('feeRecipient should take Maker Fee', async () => {

const makerOrder = {
user: wallets[0].address,
sellToken: tokenA.address,
buyToken: tokenB.address,
sellAmount: ethers.utils.parseEther('1000'),
buyAmount: ethers.utils.parseEther('100'),
expirationTimeSeconds: ethers.BigNumber.from(
String(Math.floor(Date.now() / 1000) + 3600)
)
}
const signedLeftMessage = await signOrder(
TESTRPC_PRIVATE_KEYS_STRINGS[0],
makerOrder,
exchangeContract.address
)

const fillAmount = ethers.utils.parseEther('30')
await exchangeContract
.connect(wallets[1])
.fillOrderExactInput(
Object.values(makerOrder),
signedLeftMessage,
fillAmount,
false
)

const balance1 = await tokenA.balanceOf(wallets[0].address)
const balance2 = await tokenA.balanceOf(wallets[1].address)
const balance3 = await tokenA.balanceOf(wallets[2].address)
const balance4 = await tokenB.balanceOf(wallets[0].address)
const balance5 = await tokenB.balanceOf(wallets[1].address)
const balance6 = await tokenB.balanceOf(wallets[2].address)
const balance7 = await tokenA.balanceOf(FEE_ADDRESS)
const balance8 = await tokenB.balanceOf(FEE_ADDRESS)
console.log(
ethers.utils.formatEther(balance1),
ethers.utils.formatEther(balance4)
)
console.log(
ethers.utils.formatEther(balance2),
ethers.utils.formatEther(balance5)
)
console.log(
ethers.utils.formatEther(balance3),
ethers.utils.formatEther(balance6)
)
console.log(
ethers.utils.formatEther(balance7),
ethers.utils.formatEther(balance8)
)

expect(balance8).to.equal(ethers.utils.parseEther('0.0'))
})

it('feeRecipient should take Taker Fee', async () => {
const makerOrder = {
user: wallets[0].address,
sellToken: tokenA.address,
buyToken: tokenB.address,
sellAmount: ethers.utils.parseEther('1000'),
buyAmount: ethers.utils.parseEther('100'),
expirationTimeSeconds: ethers.BigNumber.from(
String(Math.floor(Date.now() / 1000) + 3600)
)
}
const signedLeftMessage = await signOrder(
TESTRPC_PRIVATE_KEYS_STRINGS[0],
makerOrder,
exchangeContract.address
)

const fillAmount = ethers.utils.parseEther('30')
await exchangeContract
.connect(wallets[1])
.fillOrderExactInput(
Object.values(makerOrder),
signedLeftMessage,
fillAmount,
false
)

const balance1 = await tokenA.balanceOf(wallets[0].address)
const balance2 = await tokenA.balanceOf(wallets[1].address)
const balance3 = await tokenA.balanceOf(wallets[2].address)
const balance4 = await tokenB.balanceOf(wallets[0].address)
const balance5 = await tokenB.balanceOf(wallets[1].address)
const balance6 = await tokenB.balanceOf(wallets[2].address)
const balance7 = await tokenA.balanceOf(FEE_ADDRESS)
const balance8 = await tokenB.balanceOf(FEE_ADDRESS)
console.log(
ethers.utils.formatEther(balance1),
ethers.utils.formatEther(balance4)
)
console.log(
ethers.utils.formatEther(balance2),
ethers.utils.formatEther(balance5)
)
console.log(
ethers.utils.formatEther(balance3),
ethers.utils.formatEther(balance6)
)
console.log(
ethers.utils.formatEther(balance7),
ethers.utils.formatEther(balance8)
)

expect(balance7).to.equal(ethers.utils.parseEther('0.15'))
})

it('should fail when filled twice', async () => {
const makerOrder = {
user: wallets[0].address,
Expand Down Expand Up @@ -459,8 +345,6 @@ describe('fillOrderExactInput', () => {
const balance4 = await tokenB.balanceOf(wallets[0].address)
const balance5 = await tokenB.balanceOf(wallets[1].address)
const balance6 = await tokenB.balanceOf(wallets[2].address)
const balance7 = await tokenA.balanceOf(FEE_ADDRESS)
const balance8 = await tokenB.balanceOf(FEE_ADDRESS)
console.log(
ethers.utils.formatEther(balance1),
ethers.utils.formatEther(balance4)
Expand All @@ -473,10 +357,6 @@ describe('fillOrderExactInput', () => {
ethers.utils.formatEther(balance3),
ethers.utils.formatEther(balance6)
)
console.log(
ethers.utils.formatEther(balance7),
ethers.utils.formatEther(balance8)
)

expect(balance2).to.equal(ethers.utils.parseEther('199.9'))
expect(balance4).to.equal(ethers.utils.parseEther('100'))
Expand Down
Loading

0 comments on commit af8b1a8

Please sign in to comment.