/matchOrders.js Secret
Last active
June 17, 2022 15:03
Revisions
-
minhquanym revised this gist
Jun 17, 2022 . 1 changed file with 11 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1,14 @@ // buy order // nft: [1, 2, 3] // constraints[0] = 2 => minimum tokens want to buy // sell order // nft: [1, 2, 3] // constraints[0] = 2 => maximum tokens want to sell // should not able to match // because seller only want to sell maximum 2 tokens const { expect } = require('chai'); const { ethers, network } = require('hardhat'); const { deployContract, nowSeconds, NULL_ADDRESS } = require('../tasks/utils'); -
minhquanym created this gist
Jun 17, 2022 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,254 @@ const { expect } = require('chai'); const { ethers, network } = require('hardhat'); const { deployContract, nowSeconds, NULL_ADDRESS } = require('../tasks/utils'); const { prepareOBOrder, getCurrentSignedOrderPrice, approveERC20, getCurrentOrderPrice } = require('../helpers/orders'); const { erc721Abi } = require('../abi/erc721'); describe('check matchOrders construct', async () => { let signers, signer1, signer2, signer3, token, infinityExchange, mock721Contract1, mock721Contract2, mock721Contract3, obComplication; const buyOrders = []; const sellOrders = []; let signer1Balance = toBN(0); let signer2Balance = toBN(0); let totalProtocolFees = toBN(0); let orderNonce = 0; const FEE_BPS = 250; const UNIT = toBN(1e18); const INITIAL_SUPPLY = toBN(1_000_000).mul(UNIT); const numNFTsToTransfer = 50; function toBN(val) { return ethers.BigNumber.from(val.toString()); } before("setup", async () => { // signers signers = await ethers.getSigners(); signer1 = signers[0]; signer2 = signers[1]; signer3 = signers[2]; // token token = await deployContract('MockERC20', await ethers.getContractFactory('MockERC20'), signers[0]); // NFT contracts mock721Contract1 = await deployContract('MockERC721', await ethers.getContractFactory('MockERC721'), signer1, [ 'Mock NFT 1', 'MCKNFT1' ]); mock721Contract2 = await deployContract('MockERC721', await ethers.getContractFactory('MockERC721'), signer1, [ 'Mock NFT 2', 'MCKNFT2' ]); mock721Contract3 = await deployContract('MockERC721', await ethers.getContractFactory('MockERC721'), signer1, [ 'Mock NFT 3', 'MCKNFT3' ]); // Exchange infinityExchange = await deployContract( 'InfinityExchange', await ethers.getContractFactory('InfinityExchange'), signer1, [token.address, signer3.address] ); // OB complication obComplication = await deployContract( 'InfinityOrderBookComplication', await ethers.getContractFactory('InfinityOrderBookComplication'), signer1 ); // add currencies to registry await infinityExchange.addCurrency(token.address); await infinityExchange.addCurrency(NULL_ADDRESS); // add complications to registry await infinityExchange.addComplication(obComplication.address); // send assets await token.transfer(signer2.address, INITIAL_SUPPLY.div(2).toString()); for (let i = 0; i < numNFTsToTransfer; i++) { await mock721Contract1.transferFrom(signer1.address, signer2.address, i); await mock721Contract2.transferFrom(signer1.address, signer2.address, i); await mock721Contract3.transferFrom(signer1.address, signer2.address, i); } }); // buy order // nft: [1, 2, 3] // constraints[0] = 2 => minimum tokens want to buy it('create buy order', async () => { const user = { address: signer1.address }; const chainId = network.config.chainId ?? 31337; const nfts = [ { collection: mock721Contract1.address, tokens: [ { tokenId: 1, numTokens: 1 }, { tokenId: 2, numTokens: 1 }, { tokenId: 3, numTokens: 1 } ] } ]; const execParams = { complicationAddress: obComplication.address, currencyAddress: token.address }; const extraParams = {}; const nonce = ++orderNonce; const orderId = ethers.utils.solidityKeccak256(['address', 'uint256', 'uint256'], [user.address, nonce, chainId]); const order = { id: orderId, chainId, isSellOrder: false, signerAddress: user.address, numItems: toBN(2), startPrice: ethers.utils.parseEther('1'), endPrice: ethers.utils.parseEther('1'), startTime: nowSeconds(), endTime: nowSeconds().add(24 * 60 * 60), nonce, nfts, execParams, extraParams }; const signedOrder = await prepareOBOrder(user, chainId, signer1, order, infinityExchange); expect(signedOrder).to.not.be.undefined; buyOrders.push(signedOrder); }); // sell order // nft: [1, 2, 3] // constraints[0] = 2 => maximum tokens want to sell it('create sell order', async function () { const user = { address: signer2.address }; const chainId = network.config.chainId ?? 31337; const nfts = [ { collection: mock721Contract1.address, tokens: [ { tokenId: 1, numTokens: 1 }, { tokenId: 2, numTokens: 1 }, { tokenId: 3, numTokens: 1 } ] } ]; const execParams = { complicationAddress: obComplication.address, currencyAddress: token.address }; const extraParams = {}; const nonce = ++orderNonce; const orderId = ethers.utils.solidityKeccak256(['address', 'uint256', 'uint256'], [user.address, nonce, chainId]); const order = { id: orderId, chainId, isSellOrder: true, signerAddress: user.address, numItems: toBN(2), startPrice: ethers.utils.parseEther('1'), endPrice: ethers.utils.parseEther('1'), startTime: nowSeconds(), endTime: nowSeconds().add(24 * 60 * 60), nonce, nfts, execParams, extraParams }; // approve currency (required for automatic execution) const salePrice = getCurrentOrderPrice(order); await approveERC20(user.address, execParams.currencyAddress, salePrice, signer2, infinityExchange.address); const signedOrder = await prepareOBOrder(user, chainId, signer2, order, infinityExchange); expect(signedOrder).to.not.be.undefined; sellOrders.push(signedOrder); }); // should not able to match // because seller only want to sell maximum 2 tokens it('match orders', async function () { const buyOrder = buyOrders[0]; const sellOrder = sellOrders[0]; const constructedOrder = sellOrder; const nfts = constructedOrder.nfts; // owners before sale for (const item of nfts) { const collection = item.collection; const contract = new ethers.Contract(collection, erc721Abi, signer1); for (const token of item.tokens) { const tokenId = token.tokenId; expect(await contract.ownerOf(tokenId)).to.equal(signer2.address); } } // sale price const salePrice = getCurrentSignedOrderPrice(constructedOrder); // balance before sale expect(await token.balanceOf(signer1.address)).to.equal(INITIAL_SUPPLY.div(2)); expect(await token.balanceOf(signer2.address)).to.equal(INITIAL_SUPPLY.div(2)); // estimate gas const numTokens = constructedOrder.nfts.reduce((acc, nft) => { return ( acc + nft.tokens.reduce((acc, token) => { return acc + token.numTokens; }, 0) ); }, 0); console.log('total numTokens in order', numTokens); const gasEstimate = await infinityExchange .connect(signer3) .estimateGas.matchOrders([sellOrder], [buyOrder], [constructedOrder.nfts]); console.log('gasEstimate', gasEstimate.toNumber()); console.log('gasEstimate per token', gasEstimate / numTokens); // initiate exchange by 3rd party await infinityExchange.connect(signer3).matchOrders([sellOrder], [buyOrder], [constructedOrder.nfts]); // owners after sale for (const item of nfts) { const collection = item.collection; const contract = new ethers.Contract(collection, erc721Abi, signer1); for (const token of item.tokens) { const tokenId = token.tokenId; expect(await contract.ownerOf(tokenId)).to.equal(signer1.address); } } // balance after sale const fee = salePrice.mul(FEE_BPS).div(10000); signer1Balance = INITIAL_SUPPLY.div(2).sub(salePrice); signer2Balance = INITIAL_SUPPLY.div(2).add(salePrice.sub(fee)); expect(await token.balanceOf(signer2.address)).to.equal(signer2Balance); const signer1TokenBalance = await token.balanceOf(signer1.address); const gasRefund = signer1Balance.sub(signer1TokenBalance); totalProtocolFees = totalProtocolFees.add(fee).add(gasRefund); expect(await token.balanceOf(infinityExchange.address)).to.equal(totalProtocolFees); const buyerBalance1 = parseFloat(ethers.utils.formatEther(signer1TokenBalance)); const buyerBalance2 = parseFloat(ethers.utils.formatEther(signer1Balance)); expect(buyerBalance1).to.be.lessThan(buyerBalance2); // less than because of the gas refund // update signer1Balance = signer1TokenBalance; }); });