|
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('Exchange_Match_Multiple_Constructed', function () { |
|
let signers, |
|
signer1, |
|
signer2, |
|
signer3, |
|
token, |
|
infinityExchange, |
|
mock721Contract1, |
|
mock721Contract2, |
|
mock721Contract3, |
|
obComplication; |
|
|
|
const buyOrders = []; |
|
const sellOrders = []; |
|
|
|
let signer1Balance = toBN(0); |
|
let signer2Balance = toBN(0); |
|
let signer3Balance = 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 totalNFTSupply = 100; |
|
const numNFTsToTransfer = 50; |
|
const numNFTsLeft = totalNFTSupply - numNFTsToTransfer; |
|
|
|
function toBN(val) { |
|
return ethers.BigNumber.from(val.toString()); |
|
} |
|
|
|
before(async () => { |
|
// signers |
|
signers = await ethers.getSigners(); |
|
signer1 = signers[0]; |
|
signer2 = signers[1]; |
|
signer3 = signers[2]; |
|
evil = signers[3]; |
|
|
|
for (let i = 0; i < 4; i++) { |
|
console.log(`signer ${i} - ${signers[i].address}`) |
|
} |
|
|
|
// token |
|
token = await deployContract('MockERC20', await ethers.getContractFactory('MockERC20'), signers[0]); |
|
|
|
// NFT contracts |
|
mock721Contract1 = await deployContract('EvilMockERC721', await ethers.getContractFactory('EvilMockERC721'), 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); |
|
} |
|
|
|
}); |
|
|
|
describe('Setup', () => { |
|
it('Should init properly', async function () { |
|
expect(await token.decimals()).to.equal(18); |
|
expect(await token.totalSupply()).to.equal(INITIAL_SUPPLY); |
|
|
|
expect(await token.balanceOf(signer1.address)).to.equal(INITIAL_SUPPLY.div(2)); |
|
expect(await token.balanceOf(signer2.address)).to.equal(INITIAL_SUPPLY.div(2)); |
|
|
|
expect(await mock721Contract1.balanceOf(signer1.address)).to.equal(numNFTsLeft); |
|
expect(await mock721Contract1.balanceOf(signer2.address)).to.equal(numNFTsToTransfer); |
|
|
|
expect(await mock721Contract2.balanceOf(signer1.address)).to.equal(numNFTsLeft); |
|
expect(await mock721Contract2.balanceOf(signer2.address)).to.equal(numNFTsToTransfer); |
|
|
|
expect(await mock721Contract3.balanceOf(signer1.address)).to.equal(numNFTsLeft); |
|
expect(await mock721Contract3.balanceOf(signer2.address)).to.equal(numNFTsToTransfer); |
|
}); |
|
}); |
|
|
|
describe('MultipleCollectionsAnyOneTokenBuy3', () => { |
|
it('Signed order should be valid', async function () { |
|
const user = { |
|
address: signer1.address |
|
}; |
|
const chainId = network.config.chainId ?? 31337; |
|
const nfts = [ |
|
{ |
|
collection: mock721Contract1.address, |
|
tokens: [] |
|
}, |
|
]; |
|
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 numItems = 3; |
|
const order = { |
|
id: orderId, |
|
chainId, |
|
isSellOrder: false, |
|
signerAddress: user.address, |
|
numItems, |
|
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); |
|
}); |
|
}); |
|
|
|
describe('MultipleCollectionsAnyOneTokenSell_ETH3', () => { |
|
it('Signed order should be valid', async function () { |
|
const user = { |
|
address: signer2.address |
|
}; |
|
const chainId = network.config.chainId ?? 31337; |
|
const nfts = [ |
|
{ |
|
collection: mock721Contract1.address, |
|
tokens: [] |
|
}, |
|
]; |
|
const execParams = { complicationAddress: obComplication.address, currencyAddress: NULL_ADDRESS }; |
|
const extraParams = {}; |
|
const nonce = ++orderNonce; |
|
const orderId = ethers.utils.solidityKeccak256(['address', 'uint256', 'uint256'], [user.address, nonce, chainId]); |
|
const numItems = 3; |
|
const order = { |
|
id: orderId, |
|
chainId, |
|
isSellOrder: true, |
|
signerAddress: user.address, |
|
numItems, |
|
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, signer2, order, infinityExchange); |
|
expect(signedOrder).to.not.be.undefined; |
|
sellOrders.push(signedOrder); |
|
}); |
|
}); |
|
|
|
describe('Match_All', () => { |
|
it('Should match valid orders', async function () { |
|
// order 8 |
|
const buyOrder8 = buyOrders[0]; |
|
const sellOrder8 = sellOrders[0]; |
|
const constructedOrder8 = { ...buyOrder8 }; |
|
|
|
// form matching nfts |
|
const nfts8 = [ |
|
{ |
|
collection: buyOrder8.nfts[0].collection, |
|
tokens: [ |
|
{ |
|
tokenId: 0, |
|
numTokens: 1 |
|
} |
|
] |
|
}, |
|
{ |
|
collection: buyOrder8.nfts[0].collection, |
|
tokens: [ |
|
{ |
|
tokenId: 1, |
|
numTokens: 1 |
|
} |
|
] |
|
}, |
|
{ |
|
collection: buyOrder8.nfts[0].collection, |
|
tokens: [ |
|
{ |
|
tokenId: 2, |
|
numTokens: 1 |
|
} |
|
] |
|
} |
|
]; |
|
constructedOrder8.nfts = nfts8; |
|
// owners before sale |
|
for (const item of nfts8) { |
|
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); |
|
} |
|
} |
|
|
|
// 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)); |
|
|
|
let numTokens = constructedOrder8.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 sellOrdersToMatch = [ |
|
sellOrder8, |
|
]; |
|
|
|
const buyOrdersToMatch = [ |
|
buyOrder8, |
|
]; |
|
|
|
const constructedNftsToMatch = [ |
|
constructedOrder8.nfts, |
|
]; |
|
|
|
console.log(`======= BEFORE MATCH ========`) |
|
for (const item of nfts8) { |
|
const collection = item.collection; |
|
const contract = new ethers.Contract(collection, erc721Abi, signer1); |
|
for (const token of item.tokens) { |
|
const tokenId = token.tokenId; |
|
console.log(`Owner of ${collection} #${tokenId} - ${await contract.ownerOf(tokenId)}`) |
|
} |
|
} |
|
console.log(`balance of ${signer1.address} - ${await token.balanceOf(signer1.address)}`) |
|
console.log(`balance of ${signer2.address} - ${await token.balanceOf(signer2.address)}`) |
|
|
|
await infinityExchange.connect(signer3).matchOrders(sellOrdersToMatch, buyOrdersToMatch, constructedNftsToMatch); |
|
|
|
console.log(`======= AFTER MATCH ========`) |
|
|
|
for (const item of nfts8) { |
|
const collection = item.collection; |
|
const contract = new ethers.Contract(collection, erc721Abi, signer1); |
|
for (const token of item.tokens) { |
|
const tokenId = token.tokenId; |
|
console.log(`Owner of ${collection} #${tokenId} - ${await contract.ownerOf(tokenId)}`) |
|
} |
|
} |
|
|
|
console.log(`balance of ${signer1.address} - ${await token.balanceOf(signer1.address)}`) |
|
console.log(`balance of ${signer2.address} - ${await token.balanceOf(signer2.address)}`) |
|
console.log(`balance is transferred, but NFT owners remain the same`) |
|
}); |
|
}); |
|
}); |