From 7ae38906926dc09bc10670c361af0d2bf0050426 Mon Sep 17 00:00:00 2001 From: Hsuan Lee Date: Sat, 19 Jan 2019 18:42:04 +0800 Subject: Update dependency packages --- .../test/extensions/balance_threshold_filter.ts | 1644 -------------------- .../extensions/test/extensions/dutch_auction.ts | 378 ----- contracts/extensions/test/extensions/forwarder.ts | 1291 --------------- .../extensions/test/extensions/order_matcher.ts | 818 ---------- .../extensions/test/extensions/order_validator.ts | 609 -------- contracts/extensions/test/global_hooks.ts | 17 - .../test/utils/balance_threshold_wrapper.ts | 283 ---- .../test/utils/dutch_auction_test_wrapper.ts | 62 - .../extensions/test/utils/forwarder_wrapper.ts | 124 -- 9 files changed, 5226 deletions(-) delete mode 100644 contracts/extensions/test/extensions/balance_threshold_filter.ts delete mode 100644 contracts/extensions/test/extensions/dutch_auction.ts delete mode 100644 contracts/extensions/test/extensions/forwarder.ts delete mode 100644 contracts/extensions/test/extensions/order_matcher.ts delete mode 100644 contracts/extensions/test/extensions/order_validator.ts delete mode 100644 contracts/extensions/test/global_hooks.ts delete mode 100644 contracts/extensions/test/utils/balance_threshold_wrapper.ts delete mode 100644 contracts/extensions/test/utils/dutch_auction_test_wrapper.ts delete mode 100644 contracts/extensions/test/utils/forwarder_wrapper.ts (limited to 'contracts/extensions/test') diff --git a/contracts/extensions/test/extensions/balance_threshold_filter.ts b/contracts/extensions/test/extensions/balance_threshold_filter.ts deleted file mode 100644 index adeb7c422..000000000 --- a/contracts/extensions/test/extensions/balance_threshold_filter.ts +++ /dev/null @@ -1,1644 +0,0 @@ -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { assetDataUtils } from '@0x/order-utils'; -import { Order, RevertReason, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as chai from 'chai'; -import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { - artifacts as protocolArtifacts, - ERC20Wrapper, - ERC721Wrapper, - ExchangeContract, - ExchangeWrapper, -} from '@0x/contracts-protocol'; -import { - chaiSetup, - constants, - ContractName, - ERC20BalancesByOwner, - expectTransactionFailedAsync, - OrderFactory, - OrderStatus, - provider, - TransactionFactory, - txDefaults, - web3Wrapper, -} from '@0x/contracts-test-utils'; -import { DummyERC20TokenContract } from '@0x/contracts-tokens'; - -import { BalanceThresholdFilterContract } from '../../generated-wrappers/balance_threshold_filter'; -import { artifacts } from '../../src/artifacts'; -import { BalanceThresholdWrapper } from '../utils/balance_threshold_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); -const DECIMALS_DEFAULT = 18; - -interface ValidatedAddressesLog { - args: { addresses: string[] }; -} - -describe(ContractName.BalanceThresholdFilter, () => { - const takerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(500), DECIMALS_DEFAULT); - const makerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), DECIMALS_DEFAULT); - const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(250), DECIMALS_DEFAULT); - - let validMakerAddress: string; - let validMakerAddress2: string; - let owner: string; - let validTakerAddress: string; - let feeRecipientAddress: string; - let invalidAddress: string; - let defaultMakerAssetAddress: string; - let defaultTakerAssetAddress: string; - let zrxAssetData: string; - let zrxToken: DummyERC20TokenContract; - let exchangeInstance: ExchangeContract; - let exchangeWrapper: ExchangeWrapper; - - let orderFactory: OrderFactory; - let orderFactory2: OrderFactory; - let invalidOrderFactory: OrderFactory; - let erc20Wrapper: ERC20Wrapper; - let erc20Balances: ERC20BalancesByOwner; - let erc20TakerBalanceThresholdWrapper: BalanceThresholdWrapper; - let erc721TakerBalanceThresholdWrapper: BalanceThresholdWrapper; - let erc721MakerBalanceThresholdWrapper: BalanceThresholdWrapper; - let erc721NonValidBalanceThresholdWrapper: BalanceThresholdWrapper; - - let defaultOrderParams: Partial; - let validSignedOrder: SignedOrder; - let validSignedOrder2: SignedOrder; - - let erc721BalanceThresholdFilterInstance: BalanceThresholdFilterContract; - let erc20BalanceThresholdFilterInstance: BalanceThresholdFilterContract; - - const assertValidatedAddressesLog = async ( - txReceipt: TransactionReceiptWithDecodedLogs, - expectedValidatedAddresses: string[], - ) => { - expect(txReceipt.logs.length).to.be.gte(1); - const validatedAddressesLog = (txReceipt.logs[0] as any) as ValidatedAddressesLog; - const validatedAddresses = validatedAddressesLog.args.addresses; - // @HACK-hysz: Nested addresses are not translated to lower-case but this will change once - // the new ABI Encoder/Decoder is used by the contract templates. - const validatedAddressesNormalized: string[] = []; - _.each(validatedAddresses, address => { - const normalizedAddress = _.toLower(address); - validatedAddressesNormalized.push(normalizedAddress); - }); - expect(validatedAddressesNormalized).to.be.deep.equal(expectedValidatedAddresses); - }; - - before(async () => { - // Create accounts - await blockchainLifecycle.startAsync(); - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - const usedAddresses = ([ - owner, - validMakerAddress, - validMakerAddress2, - validTakerAddress, - feeRecipientAddress, - invalidAddress, - ] = accounts); - const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(validTakerAddress)]; - const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(validMakerAddress)]; - const secondMakerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(validMakerAddress2)]; - const invalidAddressPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(invalidAddress)]; - // Create wrappers - erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); - const validAddresses = _.cloneDeepWith(usedAddresses); - _.remove(validAddresses, (address: string) => { - return address === invalidAddress; - }); - const erc721Wrapper = new ERC721Wrapper(provider, validAddresses, owner); - // Deploy ERC20 tokens - const numDummyErc20ToDeploy = 4; - let erc20TokenA: DummyERC20TokenContract; - let erc20TokenB: DummyERC20TokenContract; - let erc20BalanceThresholdAsset: DummyERC20TokenContract; - [erc20TokenA, erc20TokenB, zrxToken, erc20BalanceThresholdAsset] = await erc20Wrapper.deployDummyTokensAsync( - numDummyErc20ToDeploy, - constants.DUMMY_TOKEN_DECIMALS, - ); - defaultMakerAssetAddress = erc20TokenA.address; - defaultTakerAssetAddress = erc20TokenB.address; - zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address); - // Create proxies - const erc20Proxy = await erc20Wrapper.deployProxyAsync(); - await erc20Wrapper.setBalancesAndAllowancesAsync(); - // Deploy Exchange contract - exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync( - protocolArtifacts.Exchange, - provider, - txDefaults, - zrxAssetData, - ); - exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider); - // Register proxies - await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); - await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, { - from: owner, - }); - // Deploy Balance Threshold Filters - // One uses an ERC721 token as its balance threshold asset; the other uses an ERC20 - const erc721alanceThreshold = new BigNumber(1); - await erc721Wrapper.deployProxyAsync(); - const [erc721BalanceThresholdAsset] = await erc721Wrapper.deployDummyTokensAsync(); - await erc721Wrapper.setBalancesAndAllowancesAsync(); - erc721BalanceThresholdFilterInstance = await BalanceThresholdFilterContract.deployFrom0xArtifactAsync( - artifacts.BalanceThresholdFilter, - provider, - txDefaults, - exchangeInstance.address, - erc721BalanceThresholdAsset.address, - erc721alanceThreshold, - ); - const erc20BalanceThreshold = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 10); - erc20BalanceThresholdFilterInstance = await BalanceThresholdFilterContract.deployFrom0xArtifactAsync( - artifacts.BalanceThresholdFilter, - provider, - txDefaults, - exchangeInstance.address, - erc20BalanceThresholdAsset.address, - erc20BalanceThreshold, - ); - // Default order parameters - defaultOrderParams = { - exchangeAddress: exchangeInstance.address, - feeRecipientAddress, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress), - makerAssetAmount, - takerAssetAmount, - makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), DECIMALS_DEFAULT), - takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(150), DECIMALS_DEFAULT), - senderAddress: erc721BalanceThresholdFilterInstance.address, - }; - // Create two order factories with valid makers (who meet the threshold balance), and - // one factory for an invalid address (that does not meet the threshold balance) - // Valid order factory #1 - const defaultOrderParams1 = { - makerAddress: validMakerAddress, - ...defaultOrderParams, - }; - orderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams1); - // Valid order factory #2 - const defaultOrderParams2 = { - makerAddress: validMakerAddress2, - ...defaultOrderParams, - }; - orderFactory2 = new OrderFactory(secondMakerPrivateKey, defaultOrderParams2); - // Invalid order factory - const defaultNonValidOrderParams = { - makerAddress: invalidAddress, - ...defaultOrderParams, - }; - invalidOrderFactory = new OrderFactory(invalidAddressPrivateKey, defaultNonValidOrderParams); - // Create Balance Thresold Wrappers - erc20TakerBalanceThresholdWrapper = new BalanceThresholdWrapper( - erc20BalanceThresholdFilterInstance, - exchangeInstance, - new TransactionFactory(takerPrivateKey, exchangeInstance.address), - provider, - ); - erc721TakerBalanceThresholdWrapper = new BalanceThresholdWrapper( - erc721BalanceThresholdFilterInstance, - exchangeInstance, - new TransactionFactory(takerPrivateKey, exchangeInstance.address), - provider, - ); - erc721MakerBalanceThresholdWrapper = new BalanceThresholdWrapper( - erc721BalanceThresholdFilterInstance, - exchangeInstance, - new TransactionFactory(makerPrivateKey, exchangeInstance.address), - provider, - ); - erc721NonValidBalanceThresholdWrapper = new BalanceThresholdWrapper( - erc721BalanceThresholdFilterInstance, - exchangeInstance, - new TransactionFactory(invalidAddressPrivateKey, exchangeInstance.address), - provider, - ); - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - - describe('General Sanity Checks', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - validSignedOrder = await orderFactory.newSignedOrderAsync(); - validSignedOrder2 = await orderFactory2.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both maker/taker when both maker and taker exceed the balance threshold of an ERC20 token', async () => { - const validSignedOrderERC20Sender = await orderFactory.newSignedOrderAsync({ - ...defaultOrderParams, - makerAddress: validMakerAddress, - senderAddress: erc20TakerBalanceThresholdWrapper.getBalanceThresholdAddress(), - }); - // Execute a valid fill - const txReceipt = await erc20TakerBalanceThresholdWrapper.fillOrderAsync( - validSignedOrderERC20Sender, - validTakerAddress, - { takerAssetFillAmount }, - ); - // Assert validated addresses - const expectedValidatedAddresseses = [validSignedOrder.makerAddress, validTakerAddress]; - await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const makerAssetFillAmount = takerAssetFillAmount - .times(validSignedOrder.makerAssetAmount) - .dividedToIntegerBy(validSignedOrder.takerAssetAmount); - const makerFeePaid = validSignedOrder.makerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(validSignedOrder.makerAssetAmount); - const takerFeePaid = validSignedOrder.takerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(validSignedOrder.makerAssetAmount); - expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(takerAssetFillAmount), - ); - expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid), - ); - expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount), - ); - expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount), - ); - expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFeePaid.plus(takerFeePaid)), - ); - }); - it('should revert if the Exchange transaction function is not supported', async () => { - // Create signed order without the fillOrder function selector - const salt = new BigNumber(0); - const badSelectorHex = '0x00000000'; - const signatureHex = '0x'; - // Call valid forwarder - return expectTransactionFailedAsync( - erc721BalanceThresholdFilterInstance.executeTransaction.sendTransactionAsync( - salt, - validTakerAddress, - badSelectorHex, - signatureHex, - ), - RevertReason.InvalidOrBlockedExchangeSelector, - ); - }); - it('should revert if senderAddress is not set to the valid forwarding contract', async () => { - // Create signed order with incorrect senderAddress - const notBalanceThresholdFilterAddress = zrxToken.address; - const signedOrderWithBadSenderAddress = await orderFactory.newSignedOrderAsync({ - senderAddress: notBalanceThresholdFilterAddress, - }); - // Call valid forwarder - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.fillOrderAsync(signedOrderWithBadSenderAddress, validTakerAddress, { - takerAssetFillAmount, - }), - RevertReason.FailedExecution, - ); - }); - }); - - describe('batchFillOrders', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - validSignedOrder = await orderFactory.newSignedOrderAsync(); - validSignedOrder2 = await orderFactory2.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both makers/taker when both maker and taker meet the balance threshold', async () => { - // Execute a valid fill - const orders = [validSignedOrder, validSignedOrder2]; - const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; - const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrdersAsync(orders, validTakerAddress, { - takerAssetFillAmounts, - }); - // Assert validated addresses - const expectedValidatedAddresseses = [ - validSignedOrder.makerAddress, - validSignedOrder2.makerAddress, - validTakerAddress, - ]; - await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2); - const makerAssetFillAmount = takerAssetFillAmount - .times(validSignedOrder.makerAssetAmount) - .dividedToIntegerBy(validSignedOrder.takerAssetAmount); - const makerFeePaid = validSignedOrder.makerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(validSignedOrder.makerAssetAmount); - const takerFeePaid = validSignedOrder.takerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(validSignedOrder.makerAssetAmount) - .times(2); - // Maker #1 - expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(takerAssetFillAmount), - ); - expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid), - ); - // Maker #2 - expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][defaultTakerAssetAddress].plus(takerAssetFillAmount), - ); - expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid), - ); - // Taker - expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), - ); - - expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount.times(2)), - ); - expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - // Fee recipient - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFeePaid.times(2).plus(takerFeePaid)), - ); - }); - it('should revert if one maker does not meet the balance threshold', async () => { - // Create order set with one non-valid maker address - const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - makerAddress: invalidAddress, - }); - const orders = [validSignedOrder, signedOrderWithBadMakerAddress]; - // Execute transaction - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.batchFillOrdersAsync(orders, validTakerAddress, { - takerAssetFillAmounts, - }), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - const orders = [validSignedOrder, validSignedOrder2]; - const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; - return expectTransactionFailedAsync( - erc721NonValidBalanceThresholdWrapper.batchFillOrdersAsync(orders, invalidAddress, { - takerAssetFillAmounts, - }), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - }); - - describe('batchFillOrdersNoThrow', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - validSignedOrder = await orderFactory.newSignedOrderAsync(); - validSignedOrder2 = await orderFactory2.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both makers/taker when both maker and taker meet the balance threshold', async () => { - // Execute a valid fill - const orders = [validSignedOrder, validSignedOrder2]; - const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; - const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrdersNoThrowAsync( - orders, - validTakerAddress, - { - takerAssetFillAmounts, - // HACK(albrow): We need to hardcode the gas estimate here because - // the Geth gas estimator doesn't work with the way we use - // delegatecall and swallow errors. - gas: 600000, - }, - ); - // Assert validated addresses - const expectedValidatedAddresseses = [ - validSignedOrder.makerAddress, - validSignedOrder2.makerAddress, - validTakerAddress, - ]; - await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2); - const makerAssetFillAmount = takerAssetFillAmount - .times(validSignedOrder.makerAssetAmount) - .dividedToIntegerBy(validSignedOrder.takerAssetAmount); - const makerFeePaid = validSignedOrder.makerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(validSignedOrder.makerAssetAmount); - const takerFeePaid = validSignedOrder.takerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(validSignedOrder.makerAssetAmount) - .times(2); - // Maker #1 - expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(takerAssetFillAmount), - ); - expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid), - ); - // Maker #2 - expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][defaultTakerAssetAddress].plus(takerAssetFillAmount), - ); - expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid), - ); - // Taker - expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), - ); - - expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount.times(2)), - ); - expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - // Fee recipient - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFeePaid.times(2).plus(takerFeePaid)), - ); - }); - it('should revert if one maker does not meet the balance threshold', async () => { - // Create order set with one non-valid maker address - const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - makerAddress: invalidAddress, - }); - const orders = [validSignedOrder, signedOrderWithBadMakerAddress]; - // Execute transaction - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(orders, validTakerAddress, { - takerAssetFillAmounts, - }), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - const orders = [validSignedOrder, validSignedOrder2]; - const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; - return expectTransactionFailedAsync( - erc721NonValidBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(orders, invalidAddress, { - takerAssetFillAmounts, - }), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - }); - - describe('batchFillOrKillOrders', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - validSignedOrder = await orderFactory.newSignedOrderAsync(); - validSignedOrder2 = await orderFactory2.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => { - // Execute a valid fill - const orders = [validSignedOrder, validSignedOrder2]; - const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; - const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync( - orders, - validTakerAddress, - { takerAssetFillAmounts }, - ); - // Assert validated addresses - const expectedValidatedAddresseses = [ - validSignedOrder.makerAddress, - validSignedOrder2.makerAddress, - validTakerAddress, - ]; - await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2); - const makerAssetFillAmount = takerAssetFillAmount - .times(validSignedOrder.makerAssetAmount) - .dividedToIntegerBy(validSignedOrder.takerAssetAmount); - const makerFeePaid = validSignedOrder.makerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(validSignedOrder.makerAssetAmount); - const takerFeePaid = validSignedOrder.takerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(validSignedOrder.makerAssetAmount) - .times(2); - // Maker #1 - expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(takerAssetFillAmount), - ); - expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid), - ); - // Maker #2 - expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][defaultTakerAssetAddress].plus(takerAssetFillAmount), - ); - expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid), - ); - // Taker - expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), - ); - - expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount.times(2)), - ); - expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - // Fee recipient - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFeePaid.times(2).plus(takerFeePaid)), - ); - }); - it('should revert if one maker does not meet the balance threshold', async () => { - // Create order set with one non-valid maker address - const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - makerAddress: invalidAddress, - }); - const orders = [validSignedOrder, signedOrderWithBadMakerAddress]; - // Execute transaction - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, validTakerAddress, { - takerAssetFillAmounts, - }), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - const orders = [validSignedOrder, validSignedOrder2]; - const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; - return expectTransactionFailedAsync( - erc721NonValidBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, invalidAddress, { - takerAssetFillAmounts, - }), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - it('should revert if one takerAssetFillAmount is not fully filled', async () => { - const tooBigTakerAssetFillAmount = validSignedOrder.takerAssetAmount.times(2); - const orders = [validSignedOrder, validSignedOrder2]; - const takerAssetFillAmounts = [takerAssetFillAmount, tooBigTakerAssetFillAmount]; - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, validTakerAddress, { - takerAssetFillAmounts, - }), - RevertReason.FailedExecution, - ); - }); - }); - - describe('fillOrder', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - validSignedOrder = await orderFactory.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => { - // Execute a valid fill - const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrderAsync( - validSignedOrder, - validTakerAddress, - { takerAssetFillAmount }, - ); - // Assert validated addresses - const expectedValidatedAddresseses = [validSignedOrder.makerAddress, validTakerAddress]; - await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const makerAssetFillAmount = takerAssetFillAmount - .times(validSignedOrder.makerAssetAmount) - .dividedToIntegerBy(validSignedOrder.takerAssetAmount); - const makerFeePaid = validSignedOrder.makerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(validSignedOrder.makerAssetAmount); - const takerFeePaid = validSignedOrder.takerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(validSignedOrder.makerAssetAmount); - expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(takerAssetFillAmount), - ); - expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid), - ); - expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount), - ); - expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount), - ); - expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFeePaid.plus(takerFeePaid)), - ); - }); - it('should revert if maker does not meet the balance threshold', async () => { - // Create signed order with non-valid maker address - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - senderAddress: erc721BalanceThresholdFilterInstance.address, - makerAddress: invalidAddress, - }); - // Execute transaction - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.fillOrderAsync(signedOrderWithBadMakerAddress, validTakerAddress, { - takerAssetFillAmount, - }), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - return expectTransactionFailedAsync( - erc721NonValidBalanceThresholdWrapper.fillOrderAsync(validSignedOrder, invalidAddress, { - takerAssetFillAmount, - }), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - }); - - describe('fillOrderNoThrow', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - validSignedOrder = await orderFactory.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => { - // Execute a valid fill - const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrderNoThrowAsync( - validSignedOrder, - validTakerAddress, - { - takerAssetFillAmount, - // HACK(albrow): We need to hardcode the gas estimate here because - // the Geth gas estimator doesn't work with the way we use - // delegatecall and swallow errors. - gas: 600000, - }, - ); - // Assert validated addresses - const expectedValidatedAddresseses = [validSignedOrder.makerAddress, validTakerAddress]; - await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const makerAssetFillAmount = takerAssetFillAmount - .times(validSignedOrder.makerAssetAmount) - .dividedToIntegerBy(validSignedOrder.takerAssetAmount); - const makerFeePaid = validSignedOrder.makerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(validSignedOrder.makerAssetAmount); - const takerFeePaid = validSignedOrder.takerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(validSignedOrder.makerAssetAmount); - expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(takerAssetFillAmount), - ); - expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid), - ); - expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount), - ); - expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount), - ); - expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFeePaid.plus(takerFeePaid)), - ); - }); - it('should revert if maker does not meet the balance threshold', async () => { - // Create signed order with non-valid maker address - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - senderAddress: erc721BalanceThresholdFilterInstance.address, - makerAddress: invalidAddress, - }); - // Execute transaction - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.fillOrderNoThrowAsync( - signedOrderWithBadMakerAddress, - validTakerAddress, - { takerAssetFillAmount }, - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - return expectTransactionFailedAsync( - erc721NonValidBalanceThresholdWrapper.fillOrderNoThrowAsync(validSignedOrder, invalidAddress, { - takerAssetFillAmount, - }), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - }); - - describe('fillOrKillOrder', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - validSignedOrder = await orderFactory.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => { - // Execute a valid fill - const takerAssetFillAmount_ = validSignedOrder.takerAssetAmount; - const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync( - validSignedOrder, - validTakerAddress, - { takerAssetFillAmount: takerAssetFillAmount_ }, - ); - // Assert validated addresses - const expectedValidatedAddresseses = [validSignedOrder.makerAddress, validTakerAddress]; - await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const makerAssetFillAmount = takerAssetFillAmount_ - .times(validSignedOrder.makerAssetAmount) - .dividedToIntegerBy(validSignedOrder.takerAssetAmount); - const makerFeePaid = validSignedOrder.makerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(validSignedOrder.makerAssetAmount); - const takerFeePaid = validSignedOrder.takerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(validSignedOrder.makerAssetAmount); - expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(takerAssetFillAmount_), - ); - expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid), - ); - expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount_), - ); - expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount), - ); - expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].plus(makerFeePaid.plus(takerFeePaid)), - ); - }); - it('should revert if maker does not meet the balance threshold', async () => { - // Create signed order with non-valid maker address - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - senderAddress: erc721BalanceThresholdFilterInstance.address, - makerAddress: invalidAddress, - }); - // Execute transaction - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync( - signedOrderWithBadMakerAddress, - validTakerAddress, - { takerAssetFillAmount }, - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - return expectTransactionFailedAsync( - erc721NonValidBalanceThresholdWrapper.fillOrKillOrderAsync(validSignedOrder, invalidAddress, { - takerAssetFillAmount, - }), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - it('should revert if takerAssetFillAmount is not fully filled', async () => { - const tooBigTakerAssetFillAmount = validSignedOrder.takerAssetAmount.times(2); - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync(validSignedOrder, validTakerAddress, { - takerAssetFillAmount: tooBigTakerAssetFillAmount, - }), - RevertReason.FailedExecution, - ); - }); - }); - - describe('marketSellOrders', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - validSignedOrder = await orderFactory.newSignedOrderAsync(); - validSignedOrder2 = await orderFactory2.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => { - // Execute a valid fill - const orders = [validSignedOrder, validSignedOrder2]; - const cumulativeTakerAssetFillAmount = validSignedOrder.takerAssetAmount.plus(takerAssetFillAmount); - const txReceipt = await erc721TakerBalanceThresholdWrapper.marketSellOrdersAsync( - orders, - validTakerAddress, - { takerAssetFillAmount: cumulativeTakerAssetFillAmount }, - ); - // Assert validated addresses - const expectedValidatedAddresseses = [ - validSignedOrder.makerAddress, - validSignedOrder2.makerAddress, - validTakerAddress, - ]; - await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const makerAssetFillAmount2 = takerAssetFillAmount - .times(validSignedOrder.makerAssetAmount) - .dividedToIntegerBy(validSignedOrder.takerAssetAmount); - const makerFeePaid2 = validSignedOrder2.makerFee - .times(makerAssetFillAmount2) - .dividedToIntegerBy(validSignedOrder2.makerAssetAmount); - const takerFeePaid2 = validSignedOrder2.takerFee - .times(makerAssetFillAmount2) - .dividedToIntegerBy(validSignedOrder2.makerAssetAmount); - const takerFeePaid = validSignedOrder.takerFee.plus(takerFeePaid2); - const cumulativeMakerAssetFillAmount = validSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2); - // Maker #1 - expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(validSignedOrder.makerAssetAmount), - ); - expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(validSignedOrder.takerAssetAmount), - ); - expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][zrxToken.address].minus(validSignedOrder.makerFee), - ); - // Maker #2 - expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2), - ); - expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][defaultTakerAssetAddress].plus(takerAssetFillAmount), - ); - expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid2), - ); - // Taker - expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), - ); - expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(cumulativeMakerAssetFillAmount), - ); - expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - // Fee recipient - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address] - .plus(validSignedOrder.makerFee) - .plus(makerFeePaid2) - .plus(takerFeePaid), - ); - }); - it('should revert if one maker does not meet the balance threshold', async () => { - // Create order set with one non-valid maker address - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - makerAddress: invalidAddress, - }); - const orders = [validSignedOrder, signedOrderWithBadMakerAddress]; - // Execute transaction - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.marketSellOrdersAsync(orders, validTakerAddress, { - takerAssetFillAmount, - }), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - const orders = [validSignedOrder, validSignedOrder2]; - return expectTransactionFailedAsync( - erc721NonValidBalanceThresholdWrapper.marketSellOrdersAsync(orders, invalidAddress, { - takerAssetFillAmount, - }), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - }); - - describe('marketSellOrdersNoThrow', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - validSignedOrder = await orderFactory.newSignedOrderAsync(); - validSignedOrder2 = await orderFactory2.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => { - // Execute a valid fill - const orders = [validSignedOrder, validSignedOrder2]; - const cumulativeTakerAssetFillAmount = validSignedOrder.takerAssetAmount.plus(takerAssetFillAmount); - const txReceipt = await erc721TakerBalanceThresholdWrapper.marketSellOrdersNoThrowAsync( - orders, - validTakerAddress, - { - takerAssetFillAmount: cumulativeTakerAssetFillAmount, - // HACK(albrow): We need to hardcode the gas estimate here because - // the Geth gas estimator doesn't work with the way we use - // delegatecall and swallow errors. - gas: 600000, - }, - ); - // Assert validated addresses - const expectedValidatedAddresseses = [ - validSignedOrder.makerAddress, - validSignedOrder2.makerAddress, - validTakerAddress, - ]; - await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const makerAssetFillAmount2 = takerAssetFillAmount - .times(validSignedOrder.makerAssetAmount) - .dividedToIntegerBy(validSignedOrder.takerAssetAmount); - const makerFeePaid2 = validSignedOrder2.makerFee - .times(makerAssetFillAmount2) - .dividedToIntegerBy(validSignedOrder2.makerAssetAmount); - const takerFeePaid2 = validSignedOrder2.takerFee - .times(makerAssetFillAmount2) - .dividedToIntegerBy(validSignedOrder2.makerAssetAmount); - const takerFeePaid = validSignedOrder.takerFee.plus(takerFeePaid2); - const cumulativeMakerAssetFillAmount = validSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2); - // Maker #1 - expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(validSignedOrder.makerAssetAmount), - ); - expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(validSignedOrder.takerAssetAmount), - ); - expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][zrxToken.address].minus(validSignedOrder.makerFee), - ); - // Maker #2 - expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2), - ); - expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][defaultTakerAssetAddress].plus(takerAssetFillAmount), - ); - expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid2), - ); - // Taker - expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), - ); - expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(cumulativeMakerAssetFillAmount), - ); - expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - // Fee recipient - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address] - .plus(validSignedOrder.makerFee) - .plus(makerFeePaid2) - .plus(takerFeePaid), - ); - }); - it('should revert if one maker does not meet the balance threshold', async () => { - // Create order set with one non-valid maker address - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - makerAddress: invalidAddress, - }); - const orders = [validSignedOrder, signedOrderWithBadMakerAddress]; - // Execute transaction - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(orders, validTakerAddress, { - takerAssetFillAmount, - }), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - const orders = [validSignedOrder, validSignedOrder2]; - return expectTransactionFailedAsync( - erc721NonValidBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(orders, invalidAddress, { - takerAssetFillAmount, - }), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - }); - - describe('marketBuyOrders', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - validSignedOrder = await orderFactory.newSignedOrderAsync(); - validSignedOrder2 = await orderFactory2.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => { - // Execute a valid fill - const orders = [validSignedOrder, validSignedOrder2]; - const cumulativeTakerAssetFillAmount = validSignedOrder.takerAssetAmount.plus(takerAssetFillAmount); - const makerAssetFillAmount2 = takerAssetFillAmount - .times(validSignedOrder.makerAssetAmount) - .dividedToIntegerBy(validSignedOrder.takerAssetAmount); - const cumulativeMakerAssetFillAmount = validSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2); - const txReceipt = await erc721TakerBalanceThresholdWrapper.marketBuyOrdersAsync(orders, validTakerAddress, { - makerAssetFillAmount: cumulativeMakerAssetFillAmount, - }); - // Assert validated addresses - const expectedValidatedAddresseses = [ - validSignedOrder.makerAddress, - validSignedOrder2.makerAddress, - validTakerAddress, - ]; - await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const makerFeePaid2 = validSignedOrder2.makerFee - .times(makerAssetFillAmount2) - .dividedToIntegerBy(validSignedOrder2.makerAssetAmount); - const takerFeePaid2 = validSignedOrder2.takerFee - .times(makerAssetFillAmount2) - .dividedToIntegerBy(validSignedOrder2.makerAssetAmount); - const takerFeePaid = validSignedOrder.takerFee.plus(takerFeePaid2); - // Maker #1 - expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(validSignedOrder.makerAssetAmount), - ); - expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(validSignedOrder.takerAssetAmount), - ); - expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][zrxToken.address].minus(validSignedOrder.makerFee), - ); - // Maker #2 - expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2), - ); - expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][defaultTakerAssetAddress].plus(takerAssetFillAmount), - ); - expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid2), - ); - // Taker - expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), - ); - expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(cumulativeMakerAssetFillAmount), - ); - expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - // Fee recipient - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address] - .plus(validSignedOrder.makerFee) - .plus(makerFeePaid2) - .plus(takerFeePaid), - ); - }); - it('should revert if one maker does not meet the balance threshold', async () => { - // Create order set with one non-valid maker address - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - makerAddress: invalidAddress, - }); - const orders = [validSignedOrder, signedOrderWithBadMakerAddress]; - // Execute transaction - const dummyMakerAssetFillAmount = new BigNumber(0); - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.marketBuyOrdersAsync(orders, validTakerAddress, { - makerAssetFillAmount: dummyMakerAssetFillAmount, - }), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - const orders = [validSignedOrder, validSignedOrder2]; - const dummyMakerAssetFillAmount = new BigNumber(0); - return expectTransactionFailedAsync( - erc721NonValidBalanceThresholdWrapper.marketBuyOrdersAsync(orders, invalidAddress, { - makerAssetFillAmount: dummyMakerAssetFillAmount, - }), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - }); - - describe('marketBuyOrdersNoThrowAsync', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - validSignedOrder = await orderFactory.newSignedOrderAsync(); - validSignedOrder2 = await orderFactory2.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => { - // Execute a valid fill - const orders = [validSignedOrder, validSignedOrder2]; - const cumulativeTakerAssetFillAmount = validSignedOrder.takerAssetAmount.plus(takerAssetFillAmount); - const makerAssetFillAmount2 = takerAssetFillAmount - .times(validSignedOrder.makerAssetAmount) - .dividedToIntegerBy(validSignedOrder.takerAssetAmount); - const cumulativeMakerAssetFillAmount = validSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2); - const txReceipt = await erc721TakerBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync( - orders, - validTakerAddress, - { - makerAssetFillAmount: cumulativeMakerAssetFillAmount, - // HACK(albrow): We need to hardcode the gas estimate here because - // the Geth gas estimator doesn't work with the way we use - // delegatecall and swallow errors. - gas: 600000, - }, - ); - // Assert validated addresses - const expectedValidatedAddresseses = [ - validSignedOrder.makerAddress, - validSignedOrder2.makerAddress, - validTakerAddress, - ]; - await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const makerFeePaid2 = validSignedOrder2.makerFee - .times(makerAssetFillAmount2) - .dividedToIntegerBy(validSignedOrder2.makerAssetAmount); - const takerFeePaid2 = validSignedOrder2.takerFee - .times(makerAssetFillAmount2) - .dividedToIntegerBy(validSignedOrder2.makerAssetAmount); - const takerFeePaid = validSignedOrder.takerFee.plus(takerFeePaid2); - // Maker #1 - expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(validSignedOrder.makerAssetAmount), - ); - expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][defaultTakerAssetAddress].plus(validSignedOrder.takerAssetAmount), - ); - expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validMakerAddress][zrxToken.address].minus(validSignedOrder.makerFee), - ); - // Maker #2 - expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2), - ); - expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][defaultTakerAssetAddress].plus(takerAssetFillAmount), - ); - expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid2), - ); - // Taker - expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), - ); - expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus(cumulativeMakerAssetFillAmount), - ); - expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - // Fee recipient - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address] - .plus(validSignedOrder.makerFee) - .plus(makerFeePaid2) - .plus(takerFeePaid), - ); - }); - it('should revert if one maker does not meet the balance threshold', async () => { - // Create order set with one non-valid maker address - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - makerAddress: invalidAddress, - }); - const orders = [validSignedOrder, signedOrderWithBadMakerAddress]; - // Execute transaction - const dummyMakerAssetFillAmount = new BigNumber(0); - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(orders, validTakerAddress, { - makerAssetFillAmount: dummyMakerAssetFillAmount, - }), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - const orders = [validSignedOrder, validSignedOrder2]; - const dummyMakerAssetFillAmount = new BigNumber(0); - return expectTransactionFailedAsync( - erc721NonValidBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(orders, invalidAddress, { - makerAssetFillAmount: dummyMakerAssetFillAmount, - }), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - }); - - describe('matchOrders', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - validSignedOrder = await orderFactory.newSignedOrderAsync(); - validSignedOrder2 = await orderFactory2.newSignedOrderAsync(); - }); - it('Should transfer correct amounts when both makers and taker meet the balance threshold', async () => { - // Test values/results taken from Match Orders test: - // 'Should transfer correct amounts when right order is fully filled and values pass isRoundingErrorFloor but fail isRoundingErrorCeil' - // Create orders to match - const signedOrderLeft = await orderFactory.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(17), 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(98), 0), - makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), - takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), - feeRecipientAddress, - }); - const signedOrderRight = await orderFactory2.newSignedOrderAsync({ - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0), - makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), - takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), - feeRecipientAddress, - }); - // Compute expected transfer amounts - const expectedTransferAmounts = { - // Left Maker - amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0), - amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0), - feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('76.4705882352941176'), 16), // 76.47% - // Right Maker - amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0), - amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0), - feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% - // Taker - amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 0), - feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber('76.5306122448979591'), 16), // 76.53% - feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% - }; - const txReceipt = await erc721TakerBalanceThresholdWrapper.matchOrdersAsync( - signedOrderLeft, - signedOrderRight, - validTakerAddress, - ); - // Assert validated addresses - const expectedValidatedAddresseses = [ - signedOrderLeft.makerAddress, - signedOrderRight.makerAddress, - validTakerAddress, - ]; - await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - expect( - newBalances[signedOrderLeft.makerAddress][defaultMakerAssetAddress], - 'Checking left maker egress ERC20 account balance', - ).to.be.bignumber.equal( - erc20Balances[signedOrderLeft.makerAddress][defaultMakerAssetAddress].minus( - expectedTransferAmounts.amountSoldByLeftMaker, - ), - ); - expect( - newBalances[signedOrderRight.makerAddress][defaultTakerAssetAddress], - 'Checking right maker ingress ERC20 account balance', - ).to.be.bignumber.equal( - erc20Balances[signedOrderRight.makerAddress][defaultTakerAssetAddress].minus( - expectedTransferAmounts.amountSoldByRightMaker, - ), - ); - expect( - newBalances[validTakerAddress][defaultMakerAssetAddress], - 'Checking taker ingress ERC20 account balance', - ).to.be.bignumber.equal( - erc20Balances[validTakerAddress][defaultMakerAssetAddress].plus( - expectedTransferAmounts.amountReceivedByTaker, - ), - ); - expect( - newBalances[signedOrderLeft.makerAddress][defaultTakerAssetAddress], - 'Checking left maker ingress ERC20 account balance', - ).to.be.bignumber.equal( - erc20Balances[signedOrderLeft.makerAddress][defaultTakerAssetAddress].plus( - expectedTransferAmounts.amountBoughtByLeftMaker, - ), - ); - expect( - newBalances[signedOrderRight.makerAddress][defaultMakerAssetAddress], - 'Checking right maker egress ERC20 account balance', - ).to.be.bignumber.equal( - erc20Balances[signedOrderRight.makerAddress][defaultMakerAssetAddress].plus( - expectedTransferAmounts.amountBoughtByRightMaker, - ), - ); - // Paid fees - expect( - newBalances[signedOrderLeft.makerAddress][zrxToken.address], - 'Checking left maker egress ERC20 account fees', - ).to.be.bignumber.equal( - erc20Balances[signedOrderLeft.makerAddress][zrxToken.address].minus( - expectedTransferAmounts.feePaidByLeftMaker, - ), - ); - expect( - newBalances[signedOrderRight.makerAddress][zrxToken.address], - 'Checking right maker egress ERC20 account fees', - ).to.be.bignumber.equal( - erc20Balances[signedOrderRight.makerAddress][zrxToken.address].minus( - expectedTransferAmounts.feePaidByRightMaker, - ), - ); - expect( - newBalances[validTakerAddress][zrxToken.address], - 'Checking taker egress ERC20 account fees', - ).to.be.bignumber.equal( - erc20Balances[validTakerAddress][zrxToken.address] - .minus(expectedTransferAmounts.feePaidByTakerLeft) - .minus(expectedTransferAmounts.feePaidByTakerRight), - ); - // Received fees - expect( - newBalances[signedOrderLeft.feeRecipientAddress][zrxToken.address], - 'Checking left fee recipient ingress ERC20 account fees', - ).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address] - .plus(expectedTransferAmounts.feePaidByLeftMaker) - .plus(expectedTransferAmounts.feePaidByRightMaker) - .plus(expectedTransferAmounts.feePaidByTakerLeft) - .plus(expectedTransferAmounts.feePaidByTakerRight), - ); - }); - it('should revert if left maker does not meet the balance threshold', async () => { - // Create signed order with non-valid maker address - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - senderAddress: erc721BalanceThresholdFilterInstance.address, - makerAddress: invalidAddress, - }); - // Execute transaction - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.matchOrdersAsync( - validSignedOrder, - signedOrderWithBadMakerAddress, - validTakerAddress, - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - it('should revert if right maker does not meet the balance threshold', async () => { - // Create signed order with non-valid maker address - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - senderAddress: erc721BalanceThresholdFilterInstance.address, - makerAddress: invalidAddress, - }); - // Execute transaction - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.matchOrdersAsync( - signedOrderWithBadMakerAddress, - validSignedOrder, - validTakerAddress, - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - return expectTransactionFailedAsync( - erc721NonValidBalanceThresholdWrapper.matchOrdersAsync( - validSignedOrder, - validSignedOrder, - invalidAddress, - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, - ); - }); - }); - - describe('cancelOrder', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - validSignedOrder = await orderFactory.newSignedOrderAsync(); - validSignedOrder2 = await orderFactory2.newSignedOrderAsync(); - }); - it('Should successfully cancel order if maker meets balance threshold', async () => { - // Verify order is not cancelled - const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync( - validSignedOrder, - ); - expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.Fillable); - // Cancel - const txReceipt = await erc721MakerBalanceThresholdWrapper.cancelOrderAsync( - validSignedOrder, - validSignedOrder.makerAddress, - ); - // Assert validated addresses - const expectedValidatedAddresseses: string[] = []; - await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check that order was cancelled - const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync( - validSignedOrder, - ); - expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.Cancelled); - }); - it('Should successfully cancel order if maker does not meet balance threshold', async () => { - // Create order where maker does not meet balance threshold - const signedOrderWithBadMakerAddress = await invalidOrderFactory.newSignedOrderAsync({}); - // Verify order is not cancelled - const orderInfoBeforeCancelling = await erc721NonValidBalanceThresholdWrapper.getOrderInfoAsync( - signedOrderWithBadMakerAddress, - ); - expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.Fillable); - // Cancel - const txReceipt = await erc721NonValidBalanceThresholdWrapper.cancelOrderAsync( - signedOrderWithBadMakerAddress, - signedOrderWithBadMakerAddress.makerAddress, - ); - // Assert validated addresses - const expectedValidatedAddresseses: string[] = []; - await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check that order was cancelled - const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync( - signedOrderWithBadMakerAddress, - ); - expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.Cancelled); - }); - }); - - describe('batchCancelOrders', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - }); - it('Should successfully batch cancel orders if maker meets balance threshold', async () => { - // Create orders to cancel - const validSignedOrders = [ - await orderFactory.newSignedOrderAsync(), - await orderFactory.newSignedOrderAsync(), - await orderFactory.newSignedOrderAsync(), - ]; - // Verify orders are not cancelled - _.each(validSignedOrders, async signedOrder => { - const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync( - signedOrder, - ); - return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.Fillable); - }); - // Cancel - const txReceipt = await erc721MakerBalanceThresholdWrapper.batchCancelOrdersAsync( - validSignedOrders, - validSignedOrders[0].makerAddress, - ); - // Assert validated addresses - const expectedValidatedAddresseses: string[] = []; - await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check that order was cancelled - _.each(validSignedOrders, async signedOrder => { - const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync( - signedOrder, - ); - return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.Cancelled); - }); - }); - it('Should successfully batch cancel order if maker does not meet balance threshold', async () => { - // Create orders to cancel - const invalidSignedOrders = [ - await invalidOrderFactory.newSignedOrderAsync(), - await invalidOrderFactory.newSignedOrderAsync(), - await invalidOrderFactory.newSignedOrderAsync(), - ]; - // Verify orders are not cancelled - _.each(invalidSignedOrders, async signedOrder => { - const orderInfoBeforeCancelling = await erc721NonValidBalanceThresholdWrapper.getOrderInfoAsync( - signedOrder, - ); - return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.Fillable); - }); - // Cancel - const txReceipt = await erc721NonValidBalanceThresholdWrapper.batchCancelOrdersAsync( - invalidSignedOrders, - invalidAddress, - ); - // Assert validated addresses - const expectedValidatedAddresseses: string[] = []; - await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check that order was cancelled - _.each(invalidSignedOrders, async signedOrder => { - const orderInfoAfterCancelling = await erc721NonValidBalanceThresholdWrapper.getOrderInfoAsync( - signedOrder, - ); - return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.Cancelled); - }); - }); - }); - - describe('cancelOrdersUpTo', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - }); - it('Should successfully batch cancel orders if maker meets balance threshold', async () => { - // Create orders to cancel - const validSignedOrders = [ - await orderFactory.newSignedOrderAsync({ salt: new BigNumber(0) }), - await orderFactory.newSignedOrderAsync({ salt: new BigNumber(1) }), - await orderFactory.newSignedOrderAsync({ salt: new BigNumber(2) }), - ]; - // Verify orders are not cancelled - _.each(validSignedOrders, async signedOrder => { - const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync( - signedOrder, - ); - return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.Fillable); - }); - // Cancel - const cancelOrdersUpToThisSalt = new BigNumber(1); - const txReceipt = await erc721MakerBalanceThresholdWrapper.cancelOrdersUpToAsync( - cancelOrdersUpToThisSalt, - validSignedOrders[0].makerAddress, - ); - // Assert validated addresses - const expectedValidatedAddresseses: string[] = []; - await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check that order was cancelled - _.each(validSignedOrders, async (signedOrder, salt: number) => { - const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync( - signedOrder, - ); - const saltAsBigNumber = new BigNumber(salt); - if (saltAsBigNumber.isLessThanOrEqualTo(cancelOrdersUpToThisSalt)) { - return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.Cancelled); - } else { - return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.Fillable); - } - }); - }); - it('Should successfully batch cancel order if maker does not meet balance threshold', async () => { - // Create orders to cancel - const invalidSignedOrders = [ - await invalidOrderFactory.newSignedOrderAsync({ salt: new BigNumber(0) }), - await invalidOrderFactory.newSignedOrderAsync({ salt: new BigNumber(1) }), - await invalidOrderFactory.newSignedOrderAsync({ salt: new BigNumber(2) }), - ]; - // Verify orders are not cancelled - _.each(invalidSignedOrders, async signedOrder => { - const orderInfoBeforeCancelling = await erc721NonValidBalanceThresholdWrapper.getOrderInfoAsync( - signedOrder, - ); - return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.Fillable); - }); - // Cancel - const cancelOrdersUpToThisSalt = new BigNumber(1); - const txReceipt = await erc721NonValidBalanceThresholdWrapper.cancelOrdersUpToAsync( - cancelOrdersUpToThisSalt, - invalidAddress, - ); - // Assert validated addresses - const expectedValidatedAddresseses: string[] = []; - await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check that order was cancelled - _.each(invalidSignedOrders, async (signedOrder, salt: number) => { - const orderInfoAfterCancelling = await erc721NonValidBalanceThresholdWrapper.getOrderInfoAsync( - signedOrder, - ); - const saltAsBigNumber = new BigNumber(salt); - if (saltAsBigNumber.isLessThanOrEqualTo(cancelOrdersUpToThisSalt)) { - return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.Cancelled); - } else { - return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.Fillable); - } - }); - }); - }); -}); -// tslint:disable:max-file-line-count -// tslint:enable:no-unnecessary-type-assertion diff --git a/contracts/extensions/test/extensions/dutch_auction.ts b/contracts/extensions/test/extensions/dutch_auction.ts deleted file mode 100644 index 22b3caa16..000000000 --- a/contracts/extensions/test/extensions/dutch_auction.ts +++ /dev/null @@ -1,378 +0,0 @@ -import { DutchAuctionWrapper } from '@0x/contract-wrappers'; -import { - artifacts as protocolArtifacts, - ERC20Wrapper, - ERC721Wrapper, - ExchangeContract, - ExchangeWrapper, -} from '@0x/contracts-protocol'; -import { - chaiSetup, - constants, - ContractName, - ERC20BalancesByOwner, - expectTransactionFailedAsync, - getLatestBlockTimestampAsync, - OrderFactory, - provider, - txDefaults, - web3Wrapper, -} from '@0x/contracts-test-utils'; -import { - artifacts as tokensArtifacts, - DummyERC20TokenContract, - DummyERC721TokenContract, - WETH9Contract, -} from '@0x/contracts-tokens'; -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils'; -import { RevertReason, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as chai from 'chai'; -import * as _ from 'lodash'; - -import { DutchAuctionContract } from '../../generated-wrappers/dutch_auction'; -import { artifacts } from '../../src/artifacts'; -import { DutchAuctionTestWrapper } from '../utils/dutch_auction_test_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); -const DECIMALS_DEFAULT = 18; - -describe(ContractName.DutchAuction, () => { - let makerAddress: string; - let owner: string; - let takerAddress: string; - let feeRecipientAddress: string; - let defaultMakerAssetAddress: string; - - let zrxToken: DummyERC20TokenContract; - let erc20TokenA: DummyERC20TokenContract; - let erc721Token: DummyERC721TokenContract; - let dutchAuctionContract: DutchAuctionContract; - let wethContract: WETH9Contract; - - let sellerOrderFactory: OrderFactory; - let buyerOrderFactory: OrderFactory; - let erc20Wrapper: ERC20Wrapper; - let erc20Balances: ERC20BalancesByOwner; - let currentBlockTimestamp: number; - let auctionBeginTimeSeconds: BigNumber; - let auctionEndTimeSeconds: BigNumber; - let auctionBeginAmount: BigNumber; - let auctionEndAmount: BigNumber; - let sellOrder: SignedOrder; - let buyOrder: SignedOrder; - let erc721MakerAssetIds: BigNumber[]; - const tenMinutesInSeconds = 10 * 60; - - let dutchAuctionTestWrapper: DutchAuctionTestWrapper; - let defaultERC20MakerAssetData: string; - - before(async () => { - await blockchainLifecycle.startAsync(); - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts); - - erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); - - const numDummyErc20ToDeploy = 2; - [erc20TokenA, zrxToken] = await erc20Wrapper.deployDummyTokensAsync( - numDummyErc20ToDeploy, - constants.DUMMY_TOKEN_DECIMALS, - ); - const erc20Proxy = await erc20Wrapper.deployProxyAsync(); - await erc20Wrapper.setBalancesAndAllowancesAsync(); - - const erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner); - [erc721Token] = await erc721Wrapper.deployDummyTokensAsync(); - const erc721Proxy = await erc721Wrapper.deployProxyAsync(); - await erc721Wrapper.setBalancesAndAllowancesAsync(); - const erc721Balances = await erc721Wrapper.getBalancesAsync(); - erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address]; - - wethContract = await WETH9Contract.deployFrom0xArtifactAsync(tokensArtifacts.WETH9, provider, txDefaults); - erc20Wrapper.addDummyTokenContract(wethContract as any); - - const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address); - const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync( - protocolArtifacts.Exchange, - provider, - txDefaults, - zrxAssetData, - ); - const exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider); - await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); - await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner); - - await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, { - from: owner, - }); - await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, { - from: owner, - }); - - const dutchAuctionInstance = await DutchAuctionContract.deployFrom0xArtifactAsync( - artifacts.DutchAuction, - provider, - txDefaults, - exchangeInstance.address, - ); - dutchAuctionContract = new DutchAuctionContract( - dutchAuctionInstance.abi, - dutchAuctionInstance.address, - provider, - ); - dutchAuctionTestWrapper = new DutchAuctionTestWrapper(dutchAuctionInstance, provider); - - defaultMakerAssetAddress = erc20TokenA.address; - const defaultTakerAssetAddress = wethContract.address; - - // Set up taker WETH balance and allowance - await web3Wrapper.awaitTransactionSuccessAsync( - await wethContract.deposit.sendTransactionAsync({ - from: takerAddress, - value: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), DECIMALS_DEFAULT), - }), - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await wethContract.approve.sendTransactionAsync( - erc20Proxy.address, - constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, - { from: takerAddress }, - ), - ); - web3Wrapper.abiDecoder.addABI(exchangeInstance.abi); - web3Wrapper.abiDecoder.addABI(zrxToken.abi); - erc20Wrapper.addTokenOwnerAddress(dutchAuctionContract.address); - - currentBlockTimestamp = await getLatestBlockTimestampAsync(); - // Default auction begins 10 minutes ago - auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp).minus(tenMinutesInSeconds); - // Default auction ends 10 from now - auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp).plus(tenMinutesInSeconds); - auctionBeginAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(10), DECIMALS_DEFAULT); - auctionEndAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT); - - // Default sell order and buy order are exact mirrors - const sellerDefaultOrderParams = { - salt: generatePseudoRandomSalt(), - exchangeAddress: exchangeInstance.address, - makerAddress, - feeRecipientAddress, - // taker address or sender address should be set to the ducth auction contract - takerAddress: dutchAuctionContract.address, - makerAssetData: DutchAuctionWrapper.encodeDutchAuctionAssetData( - assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), - auctionBeginTimeSeconds, - auctionBeginAmount, - ), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress), - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), DECIMALS_DEFAULT), - takerAssetAmount: auctionEndAmount, - expirationTimeSeconds: auctionEndTimeSeconds, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - }; - // Default buy order is for the auction begin price - const buyerDefaultOrderParams = { - ...sellerDefaultOrderParams, - makerAddress: takerAddress, - makerAssetData: sellerDefaultOrderParams.takerAssetData, - takerAssetData: sellerDefaultOrderParams.makerAssetData, - makerAssetAmount: auctionBeginAmount, - takerAssetAmount: sellerDefaultOrderParams.makerAssetAmount, - }; - const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)]; - const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)]; - sellerOrderFactory = new OrderFactory(makerPrivateKey, sellerDefaultOrderParams); - buyerOrderFactory = new OrderFactory(takerPrivateKey, buyerDefaultOrderParams); - defaultERC20MakerAssetData = assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - erc20Balances = await erc20Wrapper.getBalancesAsync(); - sellOrder = await sellerOrderFactory.newSignedOrderAsync(); - buyOrder = await buyerOrderFactory.newSignedOrderAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - describe('matchOrders', () => { - it('should be worth the begin price at the begining of the auction', async () => { - auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp + 2); - const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData( - defaultERC20MakerAssetData, - auctionBeginTimeSeconds, - auctionBeginAmount, - ); - sellOrder = await sellerOrderFactory.newSignedOrderAsync({ makerAssetData }); - const auctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder); - expect(auctionDetails.currentTimeSeconds).to.be.bignumber.lte(auctionBeginTimeSeconds); - expect(auctionDetails.currentAmount).to.be.bignumber.equal(auctionBeginAmount); - expect(auctionDetails.beginAmount).to.be.bignumber.equal(auctionBeginAmount); - }); - it('should be be worth the end price at the end of the auction', async () => { - auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds * 2); - auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds); - const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData( - defaultERC20MakerAssetData, - auctionBeginTimeSeconds, - auctionBeginAmount, - ); - sellOrder = await sellerOrderFactory.newSignedOrderAsync({ - makerAssetData, - expirationTimeSeconds: auctionEndTimeSeconds, - }); - const auctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder); - expect(auctionDetails.currentTimeSeconds).to.be.bignumber.gte(auctionEndTimeSeconds); - expect(auctionDetails.currentAmount).to.be.bignumber.equal(auctionEndAmount); - expect(auctionDetails.beginAmount).to.be.bignumber.equal(auctionBeginAmount); - }); - it('should match orders at current amount and send excess to buyer', async () => { - const beforeAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder); - buyOrder = await buyerOrderFactory.newSignedOrderAsync({ - makerAssetAmount: beforeAuctionDetails.currentAmount.times(2), - }); - await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress); - const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder); - const newBalances = await erc20Wrapper.getBalancesAsync(); - expect(newBalances[dutchAuctionContract.address][wethContract.address]).to.be.bignumber.equal( - constants.ZERO_AMOUNT, - ); - // HACK gte used here due to a bug in ganache where the timestamp can change - // between multiple calls to the same block. Which can move the amount in our case - // ref: https://github.com/trufflesuite/ganache-core/issues/111 - expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte( - erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount), - ); - expect(newBalances[takerAddress][wethContract.address]).to.be.bignumber.gte( - erc20Balances[takerAddress][wethContract.address].minus(beforeAuctionDetails.currentAmount), - ); - }); - it('maker fees on sellOrder are paid to the fee receipient', async () => { - sellOrder = await sellerOrderFactory.newSignedOrderAsync({ - makerFee: new BigNumber(1), - }); - await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress); - const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder); - const newBalances = await erc20Wrapper.getBalancesAsync(); - expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte( - erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount), - ); - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].plus(sellOrder.makerFee), - ); - }); - it('maker fees on buyOrder are paid to the fee receipient', async () => { - buyOrder = await buyerOrderFactory.newSignedOrderAsync({ - makerFee: new BigNumber(1), - }); - await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress); - const newBalances = await erc20Wrapper.getBalancesAsync(); - const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder); - expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte( - erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount), - ); - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].plus(buyOrder.makerFee), - ); - }); - it('should revert when auction expires', async () => { - auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds * 2); - auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds); - const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData( - defaultERC20MakerAssetData, - auctionBeginTimeSeconds, - auctionBeginAmount, - ); - sellOrder = await sellerOrderFactory.newSignedOrderAsync({ - expirationTimeSeconds: auctionEndTimeSeconds, - makerAssetData, - }); - return expectTransactionFailedAsync( - dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress), - RevertReason.AuctionExpired, - ); - }); - it('cannot be filled for less than the current price', async () => { - buyOrder = await buyerOrderFactory.newSignedOrderAsync({ - makerAssetAmount: sellOrder.takerAssetAmount, - }); - return expectTransactionFailedAsync( - dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress), - RevertReason.AuctionInvalidAmount, - ); - }); - it('auction begin amount must be higher than final amount ', async () => { - sellOrder = await sellerOrderFactory.newSignedOrderAsync({ - takerAssetAmount: auctionBeginAmount.plus(1), - }); - return expectTransactionFailedAsync( - dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress), - RevertReason.AuctionInvalidAmount, - ); - }); - it('begin time is less than end time', async () => { - auctionBeginTimeSeconds = new BigNumber(auctionEndTimeSeconds).plus(tenMinutesInSeconds); - const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData( - defaultERC20MakerAssetData, - auctionBeginTimeSeconds, - auctionBeginAmount, - ); - sellOrder = await sellerOrderFactory.newSignedOrderAsync({ - expirationTimeSeconds: auctionEndTimeSeconds, - makerAssetData, - }); - return expectTransactionFailedAsync( - dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress), - RevertReason.AuctionInvalidBeginTime, - ); - }); - it('asset data contains auction parameters', async () => { - sellOrder = await sellerOrderFactory.newSignedOrderAsync({ - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), - }); - return expectTransactionFailedAsync( - dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress), - RevertReason.InvalidAssetData, - ); - }); - - describe('ERC721', () => { - it('should match orders when ERC721', async () => { - const makerAssetId = erc721MakerAssetIds[0]; - const erc721MakerAssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId); - const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData( - erc721MakerAssetData, - auctionBeginTimeSeconds, - auctionBeginAmount, - ); - sellOrder = await sellerOrderFactory.newSignedOrderAsync({ - makerAssetAmount: new BigNumber(1), - makerAssetData, - }); - buyOrder = await buyerOrderFactory.newSignedOrderAsync({ - takerAssetAmount: new BigNumber(1), - takerAssetData: sellOrder.makerAssetData, - }); - await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress); - const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder); - const newBalances = await erc20Wrapper.getBalancesAsync(); - // HACK gte used here due to a bug in ganache where the timestamp can change - // between multiple calls to the same block. Which can move the amount in our case - // ref: https://github.com/trufflesuite/ganache-core/issues/111 - expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte( - erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount), - ); - const newOwner = await erc721Token.ownerOf.callAsync(makerAssetId); - expect(newOwner).to.be.bignumber.equal(takerAddress); - }); - }); - }); -}); diff --git a/contracts/extensions/test/extensions/forwarder.ts b/contracts/extensions/test/extensions/forwarder.ts deleted file mode 100644 index 69939ed04..000000000 --- a/contracts/extensions/test/extensions/forwarder.ts +++ /dev/null @@ -1,1291 +0,0 @@ -import { - artifacts as protocolArtifacts, - ERC20Wrapper, - ERC721Wrapper, - ExchangeContract, - ExchangeWrapper, -} from '@0x/contracts-protocol'; -import { - chaiSetup, - constants, - ContractName, - ERC20BalancesByOwner, - expectContractCreationFailedAsync, - expectTransactionFailedAsync, - OrderFactory, - provider, - sendTransactionResult, - txDefaults, - web3Wrapper, -} from '@0x/contracts-test-utils'; -import { - artifacts as tokenArtifacts, - DummyERC20TokenContract, - DummyERC721TokenContract, - WETH9Contract, -} from '@0x/contracts-tokens'; -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { assetDataUtils } from '@0x/order-utils'; -import { RevertReason, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as chai from 'chai'; -import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; - -import { ForwarderContract } from '../../generated-wrappers/forwarder'; -import { artifacts } from '../../src/artifacts'; - -import { ForwarderWrapper } from '../utils/forwarder_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); -const DECIMALS_DEFAULT = 18; -const MAX_WETH_FILL_PERCENTAGE = 95; - -describe(ContractName.Forwarder, () => { - let makerAddress: string; - let owner: string; - let takerAddress: string; - let feeRecipientAddress: string; - let defaultMakerAssetAddress: string; - let zrxAssetData: string; - let wethAssetData: string; - - let weth: DummyERC20TokenContract; - let zrxToken: DummyERC20TokenContract; - let erc20TokenA: DummyERC20TokenContract; - let erc721Token: DummyERC721TokenContract; - let forwarderContract: ForwarderContract; - let wethContract: WETH9Contract; - let forwarderWrapper: ForwarderWrapper; - let exchangeWrapper: ExchangeWrapper; - - let orderWithoutFee: SignedOrder; - let orderWithFee: SignedOrder; - let feeOrder: SignedOrder; - let orderFactory: OrderFactory; - let erc20Wrapper: ERC20Wrapper; - let erc20Balances: ERC20BalancesByOwner; - let tx: TransactionReceiptWithDecodedLogs; - - let erc721MakerAssetIds: BigNumber[]; - let takerEthBalanceBefore: BigNumber; - let feePercentage: BigNumber; - let gasPrice: BigNumber; - - before(async () => { - await blockchainLifecycle.startAsync(); - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts); - - const txHash = await web3Wrapper.sendTransactionAsync({ from: accounts[0], to: accounts[0], value: 0 }); - const transaction = await web3Wrapper.getTransactionByHashAsync(txHash); - gasPrice = new BigNumber(transaction.gasPrice); - - const erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner); - erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); - - const numDummyErc20ToDeploy = 3; - [erc20TokenA, zrxToken] = await erc20Wrapper.deployDummyTokensAsync( - numDummyErc20ToDeploy, - constants.DUMMY_TOKEN_DECIMALS, - ); - const erc20Proxy = await erc20Wrapper.deployProxyAsync(); - await erc20Wrapper.setBalancesAndAllowancesAsync(); - - [erc721Token] = await erc721Wrapper.deployDummyTokensAsync(); - const erc721Proxy = await erc721Wrapper.deployProxyAsync(); - await erc721Wrapper.setBalancesAndAllowancesAsync(); - const erc721Balances = await erc721Wrapper.getBalancesAsync(); - erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address]; - - wethContract = await WETH9Contract.deployFrom0xArtifactAsync(tokenArtifacts.WETH9, provider, txDefaults); - weth = new DummyERC20TokenContract(wethContract.abi, wethContract.address, provider); - erc20Wrapper.addDummyTokenContract(weth); - - wethAssetData = assetDataUtils.encodeERC20AssetData(wethContract.address); - zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address); - const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync( - protocolArtifacts.Exchange, - provider, - txDefaults, - zrxAssetData, - ); - exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider); - await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); - await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner); - - await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, { - from: owner, - }); - await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, { - from: owner, - }); - - defaultMakerAssetAddress = erc20TokenA.address; - const defaultTakerAssetAddress = wethContract.address; - const defaultOrderParams = { - exchangeAddress: exchangeInstance.address, - makerAddress, - feeRecipientAddress, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress), - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), DECIMALS_DEFAULT), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), DECIMALS_DEFAULT), - makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT), - takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), DECIMALS_DEFAULT), - }; - const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)]; - orderFactory = new OrderFactory(privateKey, defaultOrderParams); - - const forwarderInstance = await ForwarderContract.deployFrom0xArtifactAsync( - artifacts.Forwarder, - provider, - txDefaults, - exchangeInstance.address, - zrxAssetData, - wethAssetData, - ); - forwarderContract = new ForwarderContract(forwarderInstance.abi, forwarderInstance.address, provider); - forwarderWrapper = new ForwarderWrapper(forwarderContract, provider); - const zrxDepositAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 18); - await web3Wrapper.awaitTransactionSuccessAsync( - await zrxToken.transfer.sendTransactionAsync(forwarderContract.address, zrxDepositAmount), - ); - erc20Wrapper.addTokenOwnerAddress(forwarderInstance.address); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - erc20Balances = await erc20Wrapper.getBalancesAsync(); - takerEthBalanceBefore = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - orderWithoutFee = await orderFactory.newSignedOrderAsync(); - feeOrder = await orderFactory.newSignedOrderAsync({ - makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address), - takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT), - }); - orderWithFee = await orderFactory.newSignedOrderAsync({ - takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT), - }); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - - describe('constructor', () => { - it('should revert if assetProxy is unregistered', async () => { - const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync( - protocolArtifacts.Exchange, - provider, - txDefaults, - zrxAssetData, - ); - return expectContractCreationFailedAsync( - (ForwarderContract.deployFrom0xArtifactAsync( - artifacts.Forwarder, - provider, - txDefaults, - exchangeInstance.address, - zrxAssetData, - wethAssetData, - ) as any) as sendTransactionResult, - RevertReason.UnregisteredAssetProxy, - ); - }); - }); - describe('marketSellOrdersWithEth without extra fees', () => { - it('should fill a single order', async () => { - const ordersWithoutFee = [orderWithoutFee]; - const feeOrders: SignedOrder[] = []; - const ethValue = orderWithoutFee.takerAssetAmount.dividedToIntegerBy(2); - - tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithoutFee, feeOrders, { - value: ethValue, - from: takerAddress, - }); - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); - const newBalances = await erc20Wrapper.getBalancesAsync(); - - const primaryTakerAssetFillAmount = ForwarderWrapper.getPercentageOfValue( - ethValue, - MAX_WETH_FILL_PERCENTAGE, - ); - const makerAssetFillAmount = primaryTakerAssetFillAmount - .times(orderWithoutFee.makerAssetAmount) - .dividedToIntegerBy(orderWithoutFee.takerAssetAmount); - const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed)); - - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount), - ); - expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount), - ); - expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal( - constants.ZERO_AMOUNT, - ); - expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should fill multiple orders', async () => { - const secondOrderWithoutFee = await orderFactory.newSignedOrderAsync(); - const ordersWithoutFee = [orderWithoutFee, secondOrderWithoutFee]; - const feeOrders: SignedOrder[] = []; - const ethValue = ordersWithoutFee[0].takerAssetAmount.plus( - ordersWithoutFee[1].takerAssetAmount.dividedToIntegerBy(2), - ); - - tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithoutFee, feeOrders, { - value: ethValue, - from: takerAddress, - }); - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); - const newBalances = await erc20Wrapper.getBalancesAsync(); - - const primaryTakerAssetFillAmount = ForwarderWrapper.getPercentageOfValue( - ethValue, - MAX_WETH_FILL_PERCENTAGE, - ); - const firstTakerAssetFillAmount = ordersWithoutFee[0].takerAssetAmount; - const secondTakerAssetFillAmount = primaryTakerAssetFillAmount.minus(firstTakerAssetFillAmount); - - const makerAssetFillAmount = ordersWithoutFee[0].makerAssetAmount.plus( - ordersWithoutFee[1].makerAssetAmount - .times(secondTakerAssetFillAmount) - .dividedToIntegerBy(ordersWithoutFee[1].takerAssetAmount), - ); - const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed)); - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount), - ); - expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount), - ); - expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal( - constants.ZERO_AMOUNT, - ); - expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should fill the order and pay ZRX fees from a single feeOrder', async () => { - const ordersWithFee = [orderWithFee]; - const feeOrders = [feeOrder]; - const ethValue = orderWithFee.takerAssetAmount.dividedToIntegerBy(2); - - tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithFee, feeOrders, { - value: ethValue, - from: takerAddress, - }); - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); - const newBalances = await erc20Wrapper.getBalancesAsync(); - - const primaryTakerAssetFillAmount = ForwarderWrapper.getPercentageOfValue( - ethValue, - MAX_WETH_FILL_PERCENTAGE, - ); - const makerAssetFillAmount = primaryTakerAssetFillAmount - .times(orderWithoutFee.makerAssetAmount) - .dividedToIntegerBy(orderWithoutFee.takerAssetAmount); - const feeAmount = ForwarderWrapper.getPercentageOfValue( - orderWithFee.takerFee.dividedToIntegerBy(2), - MAX_WETH_FILL_PERCENTAGE, - ); - const wethSpentOnFeeOrders = ForwarderWrapper.getWethForFeeOrders(feeAmount, feeOrders); - const totalEthSpent = primaryTakerAssetFillAmount - .plus(wethSpentOnFeeOrders) - .plus(gasPrice.times(tx.gasUsed)); - - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount), - ); - expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount).plus(wethSpentOnFeeOrders), - ); - expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal( - constants.ZERO_AMOUNT, - ); - expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should fill the orders and pay ZRX from multiple feeOrders', async () => { - const ordersWithFee = [orderWithFee]; - const ethValue = orderWithFee.takerAssetAmount; - const makerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address); - const makerAssetAmount = orderWithFee.takerFee.dividedToIntegerBy(2); - const takerAssetAmount = feeOrder.takerAssetAmount - .times(makerAssetAmount) - .dividedToIntegerBy(feeOrder.makerAssetAmount); - - const firstFeeOrder = await orderFactory.newSignedOrderAsync({ - makerAssetData, - makerAssetAmount, - takerAssetAmount, - }); - const secondFeeOrder = await orderFactory.newSignedOrderAsync({ - makerAssetData, - makerAssetAmount, - takerAssetAmount, - }); - const feeOrders = [firstFeeOrder, secondFeeOrder]; - - tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithFee, feeOrders, { - value: ethValue, - from: takerAddress, - }); - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); - const newBalances = await erc20Wrapper.getBalancesAsync(); - - const primaryTakerAssetFillAmount = ForwarderWrapper.getPercentageOfValue( - ethValue, - MAX_WETH_FILL_PERCENTAGE, - ); - const makerAssetFillAmount = primaryTakerAssetFillAmount - .times(orderWithoutFee.makerAssetAmount) - .dividedToIntegerBy(orderWithoutFee.takerAssetAmount); - const feeAmount = ForwarderWrapper.getPercentageOfValue(orderWithFee.takerFee, MAX_WETH_FILL_PERCENTAGE); - const wethSpentOnFeeOrders = ForwarderWrapper.getWethForFeeOrders(feeAmount, feeOrders); - const totalEthSpent = primaryTakerAssetFillAmount - .plus(wethSpentOnFeeOrders) - .plus(gasPrice.times(tx.gasUsed)); - - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount), - ); - expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount).plus(wethSpentOnFeeOrders), - ); - expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal( - constants.ZERO_AMOUNT, - ); - expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should fill the order when token is ZRX with fees', async () => { - orderWithFee = await orderFactory.newSignedOrderAsync({ - makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address), - takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT), - }); - const ordersWithFee = [orderWithFee]; - const feeOrders: SignedOrder[] = []; - const ethValue = orderWithFee.takerAssetAmount.dividedToIntegerBy(2); - - tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithFee, feeOrders, { - value: ethValue, - from: takerAddress, - }); - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); - const newBalances = await erc20Wrapper.getBalancesAsync(); - - const makerAssetFillAmount = orderWithFee.makerAssetAmount.dividedToIntegerBy(2); - const totalEthSpent = ethValue.plus(gasPrice.times(tx.gasUsed)); - const takerFeePaid = orderWithFee.takerFee.dividedToIntegerBy(2); - const makerFeePaid = orderWithFee.makerFee.dividedToIntegerBy(2); - - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][zrxToken.address].minus(makerAssetFillAmount).minus(makerFeePaid), - ); - expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[takerAddress][zrxToken.address].plus(makerAssetFillAmount).minus(takerFeePaid), - ); - expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][weth.address].plus(ethValue), - ); - expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(newBalances[forwarderContract.address][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[forwarderContract.address][zrxToken.address], - ); - expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should refund remaining ETH if amount is greater than takerAssetAmount', async () => { - const ordersWithoutFee = [orderWithoutFee]; - const feeOrders: SignedOrder[] = []; - const ethValue = orderWithoutFee.takerAssetAmount.times(2); - - tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithoutFee, feeOrders, { - value: ethValue, - from: takerAddress, - }); - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const totalEthSpent = orderWithoutFee.takerAssetAmount.plus(gasPrice.times(tx.gasUsed)); - - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - }); - it('should revert if ZRX cannot be fully repurchased', async () => { - orderWithFee = await orderFactory.newSignedOrderAsync({ - takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), DECIMALS_DEFAULT), - }); - const ordersWithFee = [orderWithFee]; - feeOrder = await orderFactory.newSignedOrderAsync({ - makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address), - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT), - }); - const feeOrders = [feeOrder]; - const ethValue = orderWithFee.takerAssetAmount; - return expectTransactionFailedAsync( - forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithFee, feeOrders, { - value: ethValue, - from: takerAddress, - }), - RevertReason.CompleteFillFailed, - ); - }); - it('should not fill orders with different makerAssetData than the first order', async () => { - const makerAssetId = erc721MakerAssetIds[0]; - const erc721SignedOrder = await orderFactory.newSignedOrderAsync({ - makerAssetAmount: new BigNumber(1), - makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId), - }); - const erc20SignedOrder = await orderFactory.newSignedOrderAsync(); - const ordersWithoutFee = [erc20SignedOrder, erc721SignedOrder]; - const feeOrders: SignedOrder[] = []; - const ethValue = erc20SignedOrder.takerAssetAmount.plus(erc721SignedOrder.takerAssetAmount); - - tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithoutFee, feeOrders, { - value: ethValue, - from: takerAddress, - }); - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const totalEthSpent = erc20SignedOrder.takerAssetAmount.plus(gasPrice.times(tx.gasUsed)); - - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - }); - }); - describe('marketSellOrdersWithEth with extra fees', () => { - it('should fill the order and send fee to feeRecipient', async () => { - const ordersWithoutFee = [orderWithoutFee]; - const feeOrders: SignedOrder[] = []; - const ethValue = orderWithoutFee.takerAssetAmount.div(2); - - const baseFeePercentage = 2; - feePercentage = ForwarderWrapper.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, baseFeePercentage); - const feeRecipientEthBalanceBefore = await web3Wrapper.getBalanceInWeiAsync(feeRecipientAddress); - tx = await forwarderWrapper.marketSellOrdersWithEthAsync( - ordersWithoutFee, - feeOrders, - { - value: ethValue, - from: takerAddress, - }, - { feePercentage, feeRecipient: feeRecipientAddress }, - ); - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const feeRecipientEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(feeRecipientAddress); - const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); - const newBalances = await erc20Wrapper.getBalancesAsync(); - - const primaryTakerAssetFillAmount = ForwarderWrapper.getPercentageOfValue( - ethValue, - MAX_WETH_FILL_PERCENTAGE, - ); - const makerAssetFillAmount = primaryTakerAssetFillAmount - .times(orderWithoutFee.makerAssetAmount) - .dividedToIntegerBy(orderWithoutFee.takerAssetAmount); - const ethSpentOnFee = ForwarderWrapper.getPercentageOfValue(primaryTakerAssetFillAmount, baseFeePercentage); - const totalEthSpent = primaryTakerAssetFillAmount.plus(ethSpentOnFee).plus(gasPrice.times(tx.gasUsed)); - - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount), - ); - expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount), - ); - expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal( - constants.ZERO_AMOUNT, - ); - expect(feeRecipientEthBalanceAfter).to.be.bignumber.equal(feeRecipientEthBalanceBefore.plus(ethSpentOnFee)); - expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should fail if the fee is set too high', async () => { - const ethValue = orderWithoutFee.takerAssetAmount.div(2); - const baseFeePercentage = 6; - feePercentage = ForwarderWrapper.getPercentageOfValue(ethValue, baseFeePercentage); - const ordersWithoutFee = [orderWithoutFee]; - const feeOrders: SignedOrder[] = []; - await expectTransactionFailedAsync( - forwarderWrapper.marketSellOrdersWithEthAsync( - ordersWithoutFee, - feeOrders, - { from: takerAddress, value: ethValue, gasPrice }, - { feePercentage, feeRecipient: feeRecipientAddress }, - ), - RevertReason.FeePercentageTooLarge, - ); - }); - it('should fail if there is not enough ETH remaining to pay the fee', async () => { - const ethValue = orderWithoutFee.takerAssetAmount.div(2); - const baseFeePercentage = 5; - feePercentage = ForwarderWrapper.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, baseFeePercentage); - const ordersWithFee = [orderWithFee]; - const feeOrders = [feeOrder]; - await expectTransactionFailedAsync( - forwarderWrapper.marketSellOrdersWithEthAsync( - ordersWithFee, - feeOrders, - { from: takerAddress, value: ethValue, gasPrice }, - { feePercentage, feeRecipient: feeRecipientAddress }, - ), - RevertReason.InsufficientEthRemaining, - ); - }); - }); - describe('marketBuyOrdersWithEth without extra fees', () => { - it('should buy the exact amount of makerAsset in a single order', async () => { - const ordersWithoutFee = [orderWithoutFee]; - const feeOrders: SignedOrder[] = []; - const makerAssetFillAmount = orderWithoutFee.makerAssetAmount.dividedToIntegerBy(2); - const ethValue = orderWithoutFee.takerAssetAmount.dividedToIntegerBy(2); - - tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, { - value: ethValue, - from: takerAddress, - }); - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); - const newBalances = await erc20Wrapper.getBalancesAsync(); - - const primaryTakerAssetFillAmount = ethValue; - const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed)); - - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount), - ); - expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount), - ); - expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal( - constants.ZERO_AMOUNT, - ); - expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should buy the exact amount of makerAsset in multiple orders', async () => { - const secondOrderWithoutFee = await orderFactory.newSignedOrderAsync(); - const ordersWithoutFee = [orderWithoutFee, secondOrderWithoutFee]; - const feeOrders: SignedOrder[] = []; - const makerAssetFillAmount = ordersWithoutFee[0].makerAssetAmount.plus( - ordersWithoutFee[1].makerAssetAmount.dividedToIntegerBy(2), - ); - const ethValue = ordersWithoutFee[0].takerAssetAmount.plus( - ordersWithoutFee[1].takerAssetAmount.dividedToIntegerBy(2), - ); - - tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, { - value: ethValue, - from: takerAddress, - }); - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); - const newBalances = await erc20Wrapper.getBalancesAsync(); - - const primaryTakerAssetFillAmount = ethValue; - const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed)); - - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount), - ); - expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount), - ); - expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal( - constants.ZERO_AMOUNT, - ); - expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should buy the exact amount of makerAsset and return excess ETH', async () => { - const ordersWithoutFee = [orderWithoutFee]; - const feeOrders: SignedOrder[] = []; - const makerAssetFillAmount = orderWithoutFee.makerAssetAmount.dividedToIntegerBy(2); - const ethValue = orderWithoutFee.takerAssetAmount; - - tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, { - value: ethValue, - from: takerAddress, - }); - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); - const newBalances = await erc20Wrapper.getBalancesAsync(); - - const primaryTakerAssetFillAmount = ethValue.dividedToIntegerBy(2); - const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed)); - - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount), - ); - expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount), - ); - expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal( - constants.ZERO_AMOUNT, - ); - expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should buy the exact amount of makerAsset and pay ZRX from feeOrders', async () => { - const ordersWithFee = [orderWithFee]; - const feeOrders = [feeOrder]; - const makerAssetFillAmount = orderWithFee.makerAssetAmount.dividedToIntegerBy(2); - const ethValue = orderWithFee.takerAssetAmount; - - tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithFee, feeOrders, makerAssetFillAmount, { - value: ethValue, - from: takerAddress, - }); - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); - const newBalances = await erc20Wrapper.getBalancesAsync(); - - const primaryTakerAssetFillAmount = orderWithFee.takerAssetAmount.dividedToIntegerBy(2); - const feeAmount = orderWithFee.takerFee.dividedToIntegerBy(2); - const wethSpentOnFeeOrders = ForwarderWrapper.getWethForFeeOrders(feeAmount, feeOrders); - const totalEthSpent = primaryTakerAssetFillAmount - .plus(wethSpentOnFeeOrders) - .plus(gasPrice.times(tx.gasUsed)); - - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount), - ); - expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount).plus(wethSpentOnFeeOrders), - ); - expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal( - constants.ZERO_AMOUNT, - ); - expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should buy slightly greater than makerAssetAmount when buying ZRX', async () => { - orderWithFee = await orderFactory.newSignedOrderAsync({ - makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address), - takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT), - }); - const ordersWithFee = [orderWithFee]; - const feeOrders: SignedOrder[] = []; - const makerAssetFillAmount = orderWithFee.makerAssetAmount.dividedToIntegerBy(2); - const ethValue = orderWithFee.takerAssetAmount; - tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithFee, feeOrders, makerAssetFillAmount, { - value: ethValue, - from: takerAddress, - }); - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); - const newBalances = await erc20Wrapper.getBalancesAsync(); - - const primaryTakerAssetFillAmount = ForwarderWrapper.getWethForFeeOrders( - makerAssetFillAmount, - ordersWithFee, - ); - const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed)); - const makerAssetFilledAmount = orderWithFee.makerAssetAmount - .times(primaryTakerAssetFillAmount) - .dividedToIntegerBy(orderWithFee.takerAssetAmount); - const takerFeePaid = orderWithFee.takerFee - .times(primaryTakerAssetFillAmount) - .dividedToIntegerBy(orderWithFee.takerAssetAmount); - const makerFeePaid = orderWithFee.makerFee - .times(primaryTakerAssetFillAmount) - .dividedToIntegerBy(orderWithFee.takerAssetAmount); - const totalZrxPurchased = makerAssetFilledAmount.minus(takerFeePaid); - // Up to 1 wei worth of ZRX will be overbought per order - const maxOverboughtZrx = new BigNumber(1) - .times(orderWithFee.makerAssetAmount) - .dividedToIntegerBy(orderWithFee.takerAssetAmount); - - expect(totalZrxPurchased).to.be.bignumber.gte(makerAssetFillAmount); - expect(totalZrxPurchased).to.be.bignumber.lte(makerAssetFillAmount.plus(maxOverboughtZrx)); - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][zrxToken.address].minus(makerAssetFilledAmount).minus(makerFeePaid), - ); - expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[takerAddress][zrxToken.address].plus(totalZrxPurchased), - ); - expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount), - ); - expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(newBalances[forwarderContract.address][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[forwarderContract.address][zrxToken.address], - ); - expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should revert if the amount of ETH sent is too low to fill the makerAssetAmount', async () => { - const ordersWithoutFee = [orderWithoutFee]; - const feeOrders: SignedOrder[] = []; - const makerAssetFillAmount = orderWithoutFee.makerAssetAmount.dividedToIntegerBy(2); - const ethValue = orderWithoutFee.takerAssetAmount.dividedToIntegerBy(4); - return expectTransactionFailedAsync( - forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, { - value: ethValue, - from: takerAddress, - }), - RevertReason.CompleteFillFailed, - ); - }); - it('should buy an ERC721 asset from a single order', async () => { - const makerAssetId = erc721MakerAssetIds[0]; - orderWithoutFee = await orderFactory.newSignedOrderAsync({ - makerAssetAmount: new BigNumber(1), - makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId), - }); - const ordersWithoutFee = [orderWithoutFee]; - const feeOrders: SignedOrder[] = []; - const makerAssetFillAmount = new BigNumber(1); - const ethValue = orderWithFee.takerAssetAmount; - - tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, { - from: takerAddress, - value: ethValue, - }); - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); - const newOwner = await erc721Token.ownerOf.callAsync(makerAssetId); - const newBalances = await erc20Wrapper.getBalancesAsync(); - - const primaryTakerAssetFillAmount = ethValue; - const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed)); - expect(newOwner).to.be.bignumber.equal(takerAddress); - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount), - ); - expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal( - constants.ZERO_AMOUNT, - ); - expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should revert if buying an ERC721 asset when later orders contain different makerAssetData', async () => { - const makerAssetId = erc721MakerAssetIds[0]; - orderWithoutFee = await orderFactory.newSignedOrderAsync({ - makerAssetAmount: new BigNumber(1), - makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId), - }); - const differentMakerAssetDataOrder = await orderFactory.newSignedOrderAsync(); - const ordersWithoutFee = [orderWithoutFee, differentMakerAssetDataOrder]; - const feeOrders: SignedOrder[] = []; - const makerAssetFillAmount = new BigNumber(1).plus(differentMakerAssetDataOrder.makerAssetAmount); - const ethValue = orderWithFee.takerAssetAmount; - return expectTransactionFailedAsync( - forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, { - value: ethValue, - from: takerAddress, - }), - RevertReason.CompleteFillFailed, - ); - }); - it('should buy an ERC721 asset and pay ZRX fees from a single fee order', async () => { - const makerAssetId = erc721MakerAssetIds[0]; - orderWithFee = await orderFactory.newSignedOrderAsync({ - makerAssetAmount: new BigNumber(1), - makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId), - takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT), - }); - const ordersWithFee = [orderWithFee]; - const feeOrders = [feeOrder]; - const makerAssetFillAmount = orderWithFee.makerAssetAmount; - const primaryTakerAssetFillAmount = orderWithFee.takerAssetAmount; - const feeAmount = orderWithFee.takerFee; - const wethSpentOnFeeOrders = ForwarderWrapper.getWethForFeeOrders(feeAmount, feeOrders); - const ethValue = primaryTakerAssetFillAmount.plus(wethSpentOnFeeOrders); - - tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithFee, feeOrders, makerAssetFillAmount, { - value: ethValue, - from: takerAddress, - }); - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); - const newOwner = await erc721Token.ownerOf.callAsync(makerAssetId); - const newBalances = await erc20Wrapper.getBalancesAsync(); - - const totalEthSpent = ethValue.plus(gasPrice.times(tx.gasUsed)); - - expect(newOwner).to.be.bignumber.equal(takerAddress); - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount).plus(wethSpentOnFeeOrders), - ); - expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal( - constants.ZERO_AMOUNT, - ); - expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should buy an ERC721 asset and pay ZRX fees from multiple fee orders', async () => { - const makerAssetId = erc721MakerAssetIds[0]; - orderWithFee = await orderFactory.newSignedOrderAsync({ - makerAssetAmount: new BigNumber(1), - makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId), - takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT), - }); - const ordersWithFee = [orderWithFee]; - const makerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address); - const makerAssetAmount = orderWithFee.takerFee.dividedToIntegerBy(2); - const takerAssetAmount = feeOrder.takerAssetAmount - .times(makerAssetAmount) - .dividedToIntegerBy(feeOrder.makerAssetAmount); - - const firstFeeOrder = await orderFactory.newSignedOrderAsync({ - makerAssetData, - makerAssetAmount, - takerAssetAmount, - }); - const secondFeeOrder = await orderFactory.newSignedOrderAsync({ - makerAssetData, - makerAssetAmount, - takerAssetAmount, - }); - const feeOrders = [firstFeeOrder, secondFeeOrder]; - - const makerAssetFillAmount = orderWithFee.makerAssetAmount; - const primaryTakerAssetFillAmount = orderWithFee.takerAssetAmount; - const feeAmount = orderWithFee.takerFee; - const wethSpentOnFeeOrders = ForwarderWrapper.getWethForFeeOrders(feeAmount, feeOrders); - const ethValue = primaryTakerAssetFillAmount.plus(wethSpentOnFeeOrders); - - tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithFee, feeOrders, makerAssetFillAmount, { - value: ethValue, - from: takerAddress, - }); - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); - const newOwner = await erc721Token.ownerOf.callAsync(makerAssetId); - const newBalances = await erc20Wrapper.getBalancesAsync(); - - const totalEthSpent = ethValue.plus(gasPrice.times(tx.gasUsed)); - - expect(newOwner).to.be.bignumber.equal(takerAddress); - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount).plus(wethSpentOnFeeOrders), - ); - expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal( - constants.ZERO_AMOUNT, - ); - expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('Should buy slightly greater MakerAsset when exchange rate is rounded', async () => { - // The 0x Protocol contracts round the exchange rate in favor of the Maker. - // In this case, the taker must round up how much they're going to spend, which - // in turn increases the amount of MakerAsset being purchased. - // Example: - // The taker wants to buy 5 units of the MakerAsset at a rate of 3M/2T. - // For every 2 units of TakerAsset, the taker will receive 3 units of MakerAsset. - // To purchase 5 units, the taker must spend 10/3 = 3.33 units of TakerAssset. - // However, the Taker can only spend whole units. - // Spending floor(10/3) = 3 units will yield a profit of Floor(3*3/2) = Floor(4.5) = 4 units of MakerAsset. - // Spending ceil(10/3) = 4 units will yield a profit of Floor(4*3/2) = 6 units of MakerAsset. - // - // The forwarding contract will opt for the second option, which overbuys, to ensure the taker - // receives at least the amount of MakerAsset they requested. - // - // Construct test case using values from example above - orderWithoutFee = await orderFactory.newSignedOrderAsync({ - makerAssetAmount: new BigNumber('30'), - takerAssetAmount: new BigNumber('20'), - makerAssetData: assetDataUtils.encodeERC20AssetData(erc20TokenA.address), - takerAssetData: assetDataUtils.encodeERC20AssetData(weth.address), - makerFee: new BigNumber(0), - takerFee: new BigNumber(0), - }); - const ordersWithoutFee = [orderWithoutFee]; - const feeOrders: SignedOrder[] = []; - const desiredMakerAssetFillAmount = new BigNumber('5'); - const makerAssetFillAmount = new BigNumber('6'); - const ethValue = new BigNumber('4'); - // Execute test case - tx = await forwarderWrapper.marketBuyOrdersWithEthAsync( - ordersWithoutFee, - feeOrders, - desiredMakerAssetFillAmount, - { - value: ethValue, - from: takerAddress, - }, - ); - // Fetch end balances and construct expected outputs - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); - const newBalances = await erc20Wrapper.getBalancesAsync(); - const primaryTakerAssetFillAmount = ethValue; - const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed)); - // Validate test case - expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount); - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount), - ); - expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount), - ); - expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal( - constants.ZERO_AMOUNT, - ); - expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('Should buy slightly greater MakerAsset when exchange rate is rounded, and MakerAsset is ZRX', async () => { - // See the test case above for a detailed description of this case. - // The difference here is that the MakerAsset is ZRX. We expect the same result as above, - // but this tests a different code path. - // - // Construct test case using values from example above - orderWithoutFee = await orderFactory.newSignedOrderAsync({ - makerAssetAmount: new BigNumber('30'), - takerAssetAmount: new BigNumber('20'), - makerAssetData: zrxAssetData, - takerAssetData: assetDataUtils.encodeERC20AssetData(weth.address), - makerFee: new BigNumber(0), - takerFee: new BigNumber(0), - }); - const ordersWithoutFee = [orderWithoutFee]; - const feeOrders: SignedOrder[] = []; - const desiredMakerAssetFillAmount = new BigNumber('5'); - const makerAssetFillAmount = new BigNumber('6'); - const ethValue = new BigNumber('4'); - // Execute test case - tx = await forwarderWrapper.marketBuyOrdersWithEthAsync( - ordersWithoutFee, - feeOrders, - desiredMakerAssetFillAmount, - { - value: ethValue, - from: takerAddress, - }, - ); - // Fetch end balances and construct expected outputs - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); - const newBalances = await erc20Wrapper.getBalancesAsync(); - const primaryTakerAssetFillAmount = ethValue; - const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed)); - // Validate test case - expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount); - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][zrxToken.address].minus(makerAssetFillAmount), - ); - expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[takerAddress][zrxToken.address].plus(makerAssetFillAmount), - ); - expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount), - ); - expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('Should buy slightly greater MakerAsset when exchange rate is rounded (Regression Test)', async () => { - // Order taken from a transaction on mainnet that failed due to a rounding error. - orderWithoutFee = await orderFactory.newSignedOrderAsync({ - makerAssetAmount: new BigNumber('268166666666666666666'), - takerAssetAmount: new BigNumber('219090625878836371'), - makerAssetData: assetDataUtils.encodeERC20AssetData(erc20TokenA.address), - takerAssetData: assetDataUtils.encodeERC20AssetData(weth.address), - makerFee: new BigNumber(0), - takerFee: new BigNumber(0), - }); - const ordersWithoutFee = [orderWithoutFee]; - const feeOrders: SignedOrder[] = []; - // The taker will receive more than the desired amount of makerAsset due to rounding - const desiredMakerAssetFillAmount = new BigNumber('5000000000000000000'); - const ethValue = new BigNumber('4084971271824171'); - const makerAssetFillAmount = ethValue - .times(orderWithoutFee.makerAssetAmount) - .dividedToIntegerBy(orderWithoutFee.takerAssetAmount); - // Execute test case - tx = await forwarderWrapper.marketBuyOrdersWithEthAsync( - ordersWithoutFee, - feeOrders, - desiredMakerAssetFillAmount, - { - value: ethValue, - from: takerAddress, - }, - ); - // Fetch end balances and construct expected outputs - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); - const newBalances = await erc20Wrapper.getBalancesAsync(); - const primaryTakerAssetFillAmount = ethValue; - const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed)); - // Validate test case - expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount); - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount), - ); - expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount), - ); - expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal( - constants.ZERO_AMOUNT, - ); - expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('Should buy slightly greater MakerAsset when exchange rate is rounded, and MakerAsset is ZRX (Regression Test)', async () => { - // Order taken from a transaction on mainnet that failed due to a rounding error. - orderWithoutFee = await orderFactory.newSignedOrderAsync({ - makerAssetAmount: new BigNumber('268166666666666666666'), - takerAssetAmount: new BigNumber('219090625878836371'), - makerAssetData: zrxAssetData, - takerAssetData: assetDataUtils.encodeERC20AssetData(weth.address), - makerFee: new BigNumber(0), - takerFee: new BigNumber(0), - }); - const ordersWithoutFee = [orderWithoutFee]; - const feeOrders: SignedOrder[] = []; - // The taker will receive more than the desired amount of makerAsset due to rounding - const desiredMakerAssetFillAmount = new BigNumber('5000000000000000000'); - const ethValue = new BigNumber('4084971271824171'); - const makerAssetFillAmount = ethValue - .times(orderWithoutFee.makerAssetAmount) - .dividedToIntegerBy(orderWithoutFee.takerAssetAmount); - // Execute test case - tx = await forwarderWrapper.marketBuyOrdersWithEthAsync( - ordersWithoutFee, - feeOrders, - desiredMakerAssetFillAmount, - { - value: ethValue, - from: takerAddress, - }, - ); - // Fetch end balances and construct expected outputs - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); - const newBalances = await erc20Wrapper.getBalancesAsync(); - const primaryTakerAssetFillAmount = ethValue; - const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed)); - // Validate test case - expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount); - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][zrxToken.address].minus(makerAssetFillAmount), - ); - expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[takerAddress][zrxToken.address].plus(makerAssetFillAmount), - ); - expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount), - ); - expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('Should buy correct MakerAsset when exchange rate is NOT rounded, and MakerAsset is ZRX (Regression Test)', async () => { - // An extra unit of TakerAsset was sent to the exchange contract to account for rounding errors, in Forwarder v1. - // Specifically, the takerFillAmount was calculated using Floor(desiredMakerAmount * exchangeRate) + 1 - // We have since changed this to be Ceil(desiredMakerAmount * exchangeRate) - // These calculations produce different results when `desiredMakerAmount * exchangeRate` is an integer. - // - // This test verifies that `ceil` is sufficient: - // Let TakerAssetAmount = MakerAssetAmount * 2 - // -> exchangeRate = TakerAssetAmount / MakerAssetAmount = (2*MakerAssetAmount)/MakerAssetAmount = 2 - // .: desiredMakerAmount * exchangeRate is an integer. - // - // Construct test case using values from example above - orderWithoutFee = await orderFactory.newSignedOrderAsync({ - makerAssetAmount: new BigNumber('30'), - takerAssetAmount: new BigNumber('60'), - makerAssetData: zrxAssetData, - takerAssetData: assetDataUtils.encodeERC20AssetData(weth.address), - makerFee: new BigNumber(0), - takerFee: new BigNumber(0), - }); - const ordersWithoutFee = [orderWithoutFee]; - const feeOrders: SignedOrder[] = []; - const makerAssetFillAmount = new BigNumber('5'); - const ethValue = new BigNumber('10'); - // Execute test case - tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, { - value: ethValue, - from: takerAddress, - }); - // Fetch end balances and construct expected outputs - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); - const newBalances = await erc20Wrapper.getBalancesAsync(); - const primaryTakerAssetFillAmount = ethValue; - const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed)); - // Validate test case - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][zrxToken.address].minus(makerAssetFillAmount), - ); - expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[takerAddress][zrxToken.address].plus(makerAssetFillAmount), - ); - expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount), - ); - expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - }); - describe('marketBuyOrdersWithEth with extra fees', () => { - it('should buy an asset and send fee to feeRecipient', async () => { - const ordersWithoutFee = [orderWithoutFee]; - const feeOrders: SignedOrder[] = []; - const makerAssetFillAmount = orderWithoutFee.makerAssetAmount.dividedToIntegerBy(2); - const ethValue = orderWithoutFee.takerAssetAmount; - - const baseFeePercentage = 2; - feePercentage = ForwarderWrapper.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, baseFeePercentage); - const feeRecipientEthBalanceBefore = await web3Wrapper.getBalanceInWeiAsync(feeRecipientAddress); - tx = await forwarderWrapper.marketBuyOrdersWithEthAsync( - ordersWithoutFee, - feeOrders, - makerAssetFillAmount, - { - value: ethValue, - from: takerAddress, - }, - { feePercentage, feeRecipient: feeRecipientAddress }, - ); - const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); - const feeRecipientEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(feeRecipientAddress); - const newBalances = await erc20Wrapper.getBalancesAsync(); - - const primaryTakerAssetFillAmount = orderWithoutFee.takerAssetAmount.dividedToIntegerBy(2); - const ethSpentOnFee = ForwarderWrapper.getPercentageOfValue(primaryTakerAssetFillAmount, baseFeePercentage); - const totalEthSpent = primaryTakerAssetFillAmount.plus(ethSpentOnFee).plus(gasPrice.times(tx.gasUsed)); - - expect(feeRecipientEthBalanceAfter).to.be.bignumber.equal(feeRecipientEthBalanceBefore.plus(ethSpentOnFee)); - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount), - ); - expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount), - ); - expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal( - constants.ZERO_AMOUNT, - ); - expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should fail if the fee is set too high', async () => { - const ordersWithoutFee = [orderWithoutFee]; - const feeOrders: SignedOrder[] = []; - const makerAssetFillAmount = orderWithoutFee.makerAssetAmount.dividedToIntegerBy(2); - const ethValue = orderWithoutFee.takerAssetAmount; - - const baseFeePercentage = 6; - feePercentage = ForwarderWrapper.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, baseFeePercentage); - await expectTransactionFailedAsync( - forwarderWrapper.marketBuyOrdersWithEthAsync( - ordersWithoutFee, - feeOrders, - makerAssetFillAmount, - { - value: ethValue, - from: takerAddress, - }, - { feePercentage, feeRecipient: feeRecipientAddress }, - ), - RevertReason.FeePercentageTooLarge, - ); - }); - it('should fail if there is not enough ETH remaining to pay the fee', async () => { - const ordersWithoutFee = [orderWithoutFee]; - const feeOrders: SignedOrder[] = []; - const makerAssetFillAmount = orderWithoutFee.makerAssetAmount.dividedToIntegerBy(2); - const ethValue = orderWithoutFee.takerAssetAmount.dividedToIntegerBy(2); - - const baseFeePercentage = 2; - feePercentage = ForwarderWrapper.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, baseFeePercentage); - await expectTransactionFailedAsync( - forwarderWrapper.marketBuyOrdersWithEthAsync( - ordersWithoutFee, - feeOrders, - makerAssetFillAmount, - { - value: ethValue, - from: takerAddress, - }, - { feePercentage, feeRecipient: feeRecipientAddress }, - ), - RevertReason.InsufficientEthRemaining, - ); - }); - }); - describe('withdrawAsset', () => { - it('should allow owner to withdraw ERC20 tokens', async () => { - const zrxWithdrawAmount = erc20Balances[forwarderContract.address][zrxToken.address]; - await forwarderWrapper.withdrawAssetAsync(zrxAssetData, zrxWithdrawAmount, { from: owner }); - const newBalances = await erc20Wrapper.getBalancesAsync(); - expect(newBalances[owner][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[owner][zrxToken.address].plus(zrxWithdrawAmount), - ); - expect(newBalances[forwarderContract.address][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[forwarderContract.address][zrxToken.address].minus(zrxWithdrawAmount), - ); - }); - it('should revert if not called by owner', async () => { - const zrxWithdrawAmount = erc20Balances[forwarderContract.address][zrxToken.address]; - await expectTransactionFailedAsync( - forwarderWrapper.withdrawAssetAsync(zrxAssetData, zrxWithdrawAmount, { from: makerAddress }), - RevertReason.OnlyContractOwner, - ); - }); - }); -}); -// tslint:disable:max-file-line-count -// tslint:enable:no-unnecessary-type-assertion diff --git a/contracts/extensions/test/extensions/order_matcher.ts b/contracts/extensions/test/extensions/order_matcher.ts deleted file mode 100644 index acb46ced4..000000000 --- a/contracts/extensions/test/extensions/order_matcher.ts +++ /dev/null @@ -1,818 +0,0 @@ -import { - artifacts as protocolArtifacts, - ERC20ProxyContract, - ERC20Wrapper, - ERC721ProxyContract, - ExchangeContract, - ExchangeFillEventArgs, - ExchangeWrapper, -} from '@0x/contracts-protocol'; -import { - chaiSetup, - constants, - ERC20BalancesByOwner, - expectContractCreationFailedAsync, - expectTransactionFailedAsync, - LogDecoder, - OrderFactory, - provider, - sendTransactionResult, - txDefaults, - web3Wrapper, -} from '@0x/contracts-test-utils'; -import { artifacts as tokenArtifacts, DummyERC20TokenContract, DummyERC721TokenContract } from '@0x/contracts-tokens'; -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { assetDataUtils } from '@0x/order-utils'; -import { RevertReason } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as chai from 'chai'; -import { LogWithDecodedArgs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { OrderMatcherContract } from '../../generated-wrappers/order_matcher'; -import { artifacts } from '../../src/artifacts'; - -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); -chaiSetup.configure(); -const expect = chai.expect; -// tslint:disable:no-unnecessary-type-assertion -describe('OrderMatcher', () => { - let makerAddressLeft: string; - let makerAddressRight: string; - let owner: string; - let takerAddress: string; - let feeRecipientAddressLeft: string; - let feeRecipientAddressRight: string; - - let erc20TokenA: DummyERC20TokenContract; - let erc20TokenB: DummyERC20TokenContract; - let zrxToken: DummyERC20TokenContract; - let exchange: ExchangeContract; - let erc20Proxy: ERC20ProxyContract; - let erc721Proxy: ERC721ProxyContract; - let orderMatcher: OrderMatcherContract; - - let erc20BalancesByOwner: ERC20BalancesByOwner; - let exchangeWrapper: ExchangeWrapper; - let erc20Wrapper: ERC20Wrapper; - let orderFactoryLeft: OrderFactory; - let orderFactoryRight: OrderFactory; - - let leftMakerAssetData: string; - let leftTakerAssetData: string; - let defaultERC20MakerAssetAddress: string; - let defaultERC20TakerAssetAddress: string; - - before(async () => { - await blockchainLifecycle.startAsync(); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - before(async () => { - // Create accounts - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - // Hack(albrow): Both Prettier and TSLint insert a trailing comma below - // but that is invalid syntax as of TypeScript version >= 2.8. We don't - // have the right fine-grained configuration options in TSLint, - // Prettier, or TypeScript, to reconcile this, so we will just have to - // wait for them to sort it out. We disable TSLint and Prettier for - // this part of the code for now. This occurs several times in this - // file. See https://github.com/prettier/prettier/issues/4624. - // prettier-ignore - const usedAddresses = ([ - owner, - makerAddressLeft, - makerAddressRight, - takerAddress, - feeRecipientAddressLeft, - // tslint:disable-next-line:trailing-comma - feeRecipientAddressRight - ] = _.slice(accounts, 0, 6)); - // Create wrappers - erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); - // Deploy ERC20 token & ERC20 proxy - const numDummyErc20ToDeploy = 3; - [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync( - numDummyErc20ToDeploy, - constants.DUMMY_TOKEN_DECIMALS, - ); - erc20Proxy = await erc20Wrapper.deployProxyAsync(); - await erc20Wrapper.setBalancesAndAllowancesAsync(); - // Deploy ERC721 proxy - erc721Proxy = await ERC721ProxyContract.deployFrom0xArtifactAsync( - protocolArtifacts.ERC721Proxy, - provider, - txDefaults, - ); - // Depoy exchange - exchange = await ExchangeContract.deployFrom0xArtifactAsync( - protocolArtifacts.Exchange, - provider, - txDefaults, - assetDataUtils.encodeERC20AssetData(zrxToken.address), - ); - exchangeWrapper = new ExchangeWrapper(exchange, provider); - await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); - await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner); - // Authorize ERC20 trades by exchange - await web3Wrapper.awaitTransactionSuccessAsync( - await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { - from: owner, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // Deploy OrderMatcher - orderMatcher = await OrderMatcherContract.deployFrom0xArtifactAsync( - artifacts.OrderMatcher, - provider, - txDefaults, - exchange.address, - ); - // Set default addresses - defaultERC20MakerAssetAddress = erc20TokenA.address; - defaultERC20TakerAssetAddress = erc20TokenB.address; - leftMakerAssetData = assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress); - leftTakerAssetData = assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress); - // Set OrderMatcher balances and allowances - await web3Wrapper.awaitTransactionSuccessAsync( - await erc20TokenA.setBalance.sendTransactionAsync(orderMatcher.address, constants.INITIAL_ERC20_BALANCE, { - from: owner, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc20TokenB.setBalance.sendTransactionAsync(orderMatcher.address, constants.INITIAL_ERC20_BALANCE, { - from: owner, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await orderMatcher.approveAssetProxy.sendTransactionAsync( - leftMakerAssetData, - constants.INITIAL_ERC20_ALLOWANCE, - ), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await orderMatcher.approveAssetProxy.sendTransactionAsync( - leftTakerAssetData, - constants.INITIAL_ERC20_ALLOWANCE, - ), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // Create default order parameters - const defaultOrderParamsLeft = { - ...constants.STATIC_ORDER_PARAMS, - makerAddress: makerAddressLeft, - exchangeAddress: exchange.address, - makerAssetData: leftMakerAssetData, - takerAssetData: leftTakerAssetData, - feeRecipientAddress: feeRecipientAddressLeft, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - }; - const defaultOrderParamsRight = { - ...constants.STATIC_ORDER_PARAMS, - makerAddress: makerAddressRight, - exchangeAddress: exchange.address, - makerAssetData: leftTakerAssetData, - takerAssetData: leftMakerAssetData, - feeRecipientAddress: feeRecipientAddressRight, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - }; - const privateKeyLeft = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressLeft)]; - orderFactoryLeft = new OrderFactory(privateKeyLeft, defaultOrderParamsLeft); - const privateKeyRight = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressRight)]; - orderFactoryRight = new OrderFactory(privateKeyRight, defaultOrderParamsRight); - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - describe('constructor', () => { - it('should revert if assetProxy is unregistered', async () => { - const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync( - protocolArtifacts.Exchange, - provider, - txDefaults, - constants.NULL_BYTES, - ); - return expectContractCreationFailedAsync( - (OrderMatcherContract.deployFrom0xArtifactAsync( - artifacts.OrderMatcher, - provider, - txDefaults, - exchangeInstance.address, - ) as any) as sendTransactionResult, - RevertReason.UnregisteredAssetProxy, - ); - }); - }); - describe('matchOrders', () => { - beforeEach(async () => { - erc20BalancesByOwner = await erc20Wrapper.getBalancesAsync(); - }); - it('should revert if not called by owner', async () => { - // Create orders to match - const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - }); - const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), - }); - const data = exchange.matchOrders.getABIEncodedTransactionData( - signedOrderLeft, - signedOrderRight, - signedOrderLeft.signature, - signedOrderRight.signature, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - data, - to: orderMatcher.address, - from: takerAddress, - gas: constants.MAX_MATCH_ORDERS_GAS, - }), - RevertReason.OnlyContractOwner, - ); - }); - it('should transfer the correct amounts when orders completely fill each other', async () => { - // Create orders to match - const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - }); - const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), - }); - // Match signedOrderLeft with signedOrderRight - const expectedTransferAmounts = { - // Left Maker - amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount, - amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount, - // Right Maker - amountSoldByRightMaker: signedOrderRight.makerAssetAmount, - amountBoughtByRightMaker: signedOrderRight.takerAssetAmount, - // Taker - leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount), - }; - const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); - const data = exchange.matchOrders.getABIEncodedTransactionData( - signedOrderLeft, - signedOrderRight, - signedOrderLeft.signature, - signedOrderRight.signature, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - data, - to: orderMatcher.address, - from: owner, - gas: constants.MAX_MATCH_ORDERS_GAS, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); - const newErc20Balances = await erc20Wrapper.getBalancesAsync(); - expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal( - erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus( - expectedTransferAmounts.amountSoldByLeftMaker, - ), - ); - expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal( - erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus( - expectedTransferAmounts.amountSoldByRightMaker, - ), - ); - expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal( - erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus( - expectedTransferAmounts.amountBoughtByLeftMaker, - ), - ); - expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal( - erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus( - expectedTransferAmounts.amountBoughtByRightMaker, - ), - ); - expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal( - initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount), - ); - }); - it('should transfer the correct amounts when orders completely fill each other and taker doesnt take a profit', async () => { - // Create orders to match - const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - }); - const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), - }); - // Match signedOrderLeft with signedOrderRight - const expectedTransferAmounts = { - // Left Maker - amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount, - amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount, - // Right Maker - amountSoldByRightMaker: signedOrderRight.makerAssetAmount, - amountBoughtByRightMaker: signedOrderRight.takerAssetAmount, - }; - const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); - const data = exchange.matchOrders.getABIEncodedTransactionData( - signedOrderLeft, - signedOrderRight, - signedOrderLeft.signature, - signedOrderRight.signature, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - data, - to: orderMatcher.address, - from: owner, - gas: constants.MAX_MATCH_ORDERS_GAS, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); - const newErc20Balances = await erc20Wrapper.getBalancesAsync(); - expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal( - erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus( - expectedTransferAmounts.amountSoldByLeftMaker, - ), - ); - expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal( - erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus( - expectedTransferAmounts.amountSoldByRightMaker, - ), - ); - expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal( - erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus( - expectedTransferAmounts.amountBoughtByLeftMaker, - ), - ); - expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal( - erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus( - expectedTransferAmounts.amountBoughtByRightMaker, - ), - ); - expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(initialLeftMakerAssetTakerBalance); - }); - it('should transfer the correct amounts when left order is completely filled and right order would be partially filled', async () => { - // Create orders to match - const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - }); - const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18), - }); - // Match signedOrderLeft with signedOrderRight - const expectedTransferAmounts = { - // Left Maker - amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount, - amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount, - // Right Maker - amountSoldByRightMaker: signedOrderRight.makerAssetAmount, - amountBoughtByRightMaker: signedOrderRight.takerAssetAmount, - // Taker - leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount), - leftTakerAssetSpreadAmount: signedOrderRight.makerAssetAmount.minus(signedOrderLeft.takerAssetAmount), - }; - const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); - const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address); - // Match signedOrderLeft with signedOrderRight - const data = exchange.matchOrders.getABIEncodedTransactionData( - signedOrderLeft, - signedOrderRight, - signedOrderLeft.signature, - signedOrderRight.signature, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - data, - to: orderMatcher.address, - from: owner, - gas: constants.MAX_MATCH_ORDERS_GAS, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); - const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address); - const newErc20Balances = await erc20Wrapper.getBalancesAsync(); - expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal( - erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus( - expectedTransferAmounts.amountSoldByLeftMaker, - ), - ); - expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal( - erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus( - expectedTransferAmounts.amountSoldByRightMaker, - ), - ); - expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal( - erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus( - expectedTransferAmounts.amountBoughtByLeftMaker, - ), - ); - expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal( - erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus( - expectedTransferAmounts.amountBoughtByRightMaker, - ), - ); - expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal( - initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount), - ); - expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal( - initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount), - ); - }); - it('should not call fillOrder when rightOrder is completely filled after matchOrders call and orders were never partially filled', async () => { - // Create orders to match - const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - }); - const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), - }); - const data = exchange.matchOrders.getABIEncodedTransactionData( - signedOrderLeft, - signedOrderRight, - signedOrderLeft.signature, - signedOrderRight.signature, - ); - const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokenArtifacts, ...protocolArtifacts }); - const txReceipt = await logDecoder.getTxWithDecodedLogsAsync( - await web3Wrapper.sendTransactionAsync({ - data, - to: orderMatcher.address, - from: owner, - gas: constants.MAX_MATCH_ORDERS_GAS, - }), - ); - const fillLogs = _.filter( - txReceipt.logs, - log => (log as LogWithDecodedArgs).event === 'Fill', - ); - // Only 2 Fill logs should exist for `matchOrders` call. `fillOrder` should not have been called and should not have emitted a Fill event. - expect(fillLogs.length).to.be.equal(2); - }); - it('should not call fillOrder when rightOrder is completely filled after matchOrders call and orders were initially partially filled', async () => { - // Create orders to match - const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - }); - const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), - }); - await exchangeWrapper.fillOrderAsync(signedOrderLeft, takerAddress, { - takerAssetFillAmount: signedOrderLeft.takerAssetAmount.dividedToIntegerBy(5), - }); - await exchangeWrapper.fillOrderAsync(signedOrderRight, takerAddress, { - takerAssetFillAmount: signedOrderRight.takerAssetAmount.dividedToIntegerBy(5), - }); - const data = exchange.matchOrders.getABIEncodedTransactionData( - signedOrderLeft, - signedOrderRight, - signedOrderLeft.signature, - signedOrderRight.signature, - ); - const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokenArtifacts, ...protocolArtifacts }); - const txReceipt = await logDecoder.getTxWithDecodedLogsAsync( - await web3Wrapper.sendTransactionAsync({ - data, - to: orderMatcher.address, - from: owner, - gas: constants.MAX_MATCH_ORDERS_GAS, - }), - ); - const fillLogs = _.filter( - txReceipt.logs, - log => (log as LogWithDecodedArgs).event === 'Fill', - ); - // Only 2 Fill logs should exist for `matchOrders` call. `fillOrder` should not have been called and should not have emitted a Fill event. - expect(fillLogs.length).to.be.equal(2); - }); - it('should only take a spread in rightMakerAsset if entire leftMakerAssetSpread amount can be used to fill rightOrder after matchOrders call', async () => { - // Create orders to match - const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(0.9), 18), - }); - const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(990), 18), - }); - const initialLeftMakerAssetSpreadAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1.09), 18); - const leftTakerAssetSpreadAmount = initialLeftMakerAssetSpreadAmount - .times(signedOrderRight.makerAssetAmount) - .dividedToIntegerBy(signedOrderRight.takerAssetAmount); - // Match signedOrderLeft with signedOrderRight - const expectedTransferAmounts = { - // Left Maker - amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount, - amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount, - // Right Maker - amountSoldByRightMaker: signedOrderLeft.takerAssetAmount.plus(leftTakerAssetSpreadAmount), - amountBoughtByRightMaker: signedOrderLeft.makerAssetAmount, - // Taker - leftMakerAssetSpreadAmount: constants.ZERO_AMOUNT, - leftTakerAssetSpreadAmount, - }; - const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); - const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address); - // Match signedOrderLeft with signedOrderRight - const data = exchange.matchOrders.getABIEncodedTransactionData( - signedOrderLeft, - signedOrderRight, - signedOrderLeft.signature, - signedOrderRight.signature, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - data, - to: orderMatcher.address, - from: owner, - gas: constants.MAX_MATCH_ORDERS_GAS, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); - const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address); - const newErc20Balances = await erc20Wrapper.getBalancesAsync(); - expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal( - erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus( - expectedTransferAmounts.amountSoldByLeftMaker, - ), - ); - expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal( - erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus( - expectedTransferAmounts.amountSoldByRightMaker, - ), - ); - expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal( - erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus( - expectedTransferAmounts.amountBoughtByLeftMaker, - ), - ); - expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal( - erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus( - expectedTransferAmounts.amountBoughtByRightMaker, - ), - ); - expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal( - initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount), - ); - expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal( - initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount), - ); - }); - it("should succeed if rightOrder's makerAssetData and takerAssetData are not provided", async () => { - // Create orders to match - const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - }); - const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18), - }); - // Match signedOrderLeft with signedOrderRight - const expectedTransferAmounts = { - // Left Maker - amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount, - amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount, - // Right Maker - amountSoldByRightMaker: signedOrderRight.makerAssetAmount, - amountBoughtByRightMaker: signedOrderRight.takerAssetAmount, - // Taker - leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount), - leftTakerAssetSpreadAmount: signedOrderRight.makerAssetAmount.minus(signedOrderLeft.takerAssetAmount), - }; - const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); - const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address); - // Match signedOrderLeft with signedOrderRight - signedOrderRight.makerAssetData = constants.NULL_BYTES; - signedOrderRight.takerAssetData = constants.NULL_BYTES; - const data = exchange.matchOrders.getABIEncodedTransactionData( - signedOrderLeft, - signedOrderRight, - signedOrderLeft.signature, - signedOrderRight.signature, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - data, - to: orderMatcher.address, - from: owner, - gas: constants.MAX_MATCH_ORDERS_GAS, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); - const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address); - const newErc20Balances = await erc20Wrapper.getBalancesAsync(); - expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal( - erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus( - expectedTransferAmounts.amountSoldByLeftMaker, - ), - ); - expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal( - erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus( - expectedTransferAmounts.amountSoldByRightMaker, - ), - ); - expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal( - erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus( - expectedTransferAmounts.amountBoughtByLeftMaker, - ), - ); - expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal( - erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus( - expectedTransferAmounts.amountBoughtByRightMaker, - ), - ); - expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal( - initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount), - ); - expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal( - initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount), - ); - }); - it('should revert with the correct reason if matchOrders call reverts', async () => { - // Create orders to match - const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - }); - const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), - }); - signedOrderRight.signature = `0xff${signedOrderRight.signature.slice(4)}`; - const data = exchange.matchOrders.getABIEncodedTransactionData( - signedOrderLeft, - signedOrderRight, - signedOrderLeft.signature, - signedOrderRight.signature, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - data, - to: orderMatcher.address, - from: owner, - gas: constants.MAX_MATCH_ORDERS_GAS, - }), - RevertReason.InvalidOrderSignature, - ); - }); - it('should revert with the correct reason if fillOrder call reverts', async () => { - // Create orders to match - const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - }); - const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18), - }); - // Matcher will not have enough allowance to fill rightOrder - await web3Wrapper.awaitTransactionSuccessAsync( - await orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, constants.ZERO_AMOUNT, { - from: owner, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const data = exchange.matchOrders.getABIEncodedTransactionData( - signedOrderLeft, - signedOrderRight, - signedOrderLeft.signature, - signedOrderRight.signature, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - data, - to: orderMatcher.address, - from: owner, - gas: constants.MAX_MATCH_ORDERS_GAS, - }), - RevertReason.TransferFailed, - ); - }); - }); - describe('withdrawAsset', () => { - it('should allow owner to withdraw ERC20 tokens', async () => { - const erc20AWithdrawAmount = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); - expect(erc20AWithdrawAmount).to.be.bignumber.gt(constants.ZERO_AMOUNT); - await web3Wrapper.awaitTransactionSuccessAsync( - await orderMatcher.withdrawAsset.sendTransactionAsync(leftMakerAssetData, erc20AWithdrawAmount, { - from: owner, - }), - ); - const newBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); - expect(newBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should allow owner to withdraw ERC721 tokens', async () => { - const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync( - tokenArtifacts.DummyERC721Token, - provider, - txDefaults, - constants.DUMMY_TOKEN_NAME, - constants.DUMMY_TOKEN_SYMBOL, - ); - const tokenId = new BigNumber(1); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc721Token.mint.sendTransactionAsync(orderMatcher.address, tokenId, { from: owner }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId); - const withdrawAmount = new BigNumber(1); - await web3Wrapper.awaitTransactionSuccessAsync( - await orderMatcher.withdrawAsset.sendTransactionAsync(assetData, withdrawAmount, { from: owner }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const erc721Owner = await erc721Token.ownerOf.callAsync(tokenId); - expect(erc721Owner).to.be.equal(owner); - }); - it('should revert if not called by owner', async () => { - const erc20AWithdrawAmount = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); - expect(erc20AWithdrawAmount).to.be.bignumber.gt(constants.ZERO_AMOUNT); - await expectTransactionFailedAsync( - orderMatcher.withdrawAsset.sendTransactionAsync(leftMakerAssetData, erc20AWithdrawAmount, { - from: takerAddress, - }), - RevertReason.OnlyContractOwner, - ); - }); - }); - describe('approveAssetProxy', () => { - it('should be able to set an allowance for ERC20 tokens', async () => { - const allowance = new BigNumber(55465465426546); - await web3Wrapper.awaitTransactionSuccessAsync( - await orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, allowance, { - from: owner, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const newAllowance = await erc20TokenA.allowance.callAsync(orderMatcher.address, erc20Proxy.address); - expect(newAllowance).to.be.bignumber.equal(allowance); - }); - it('should be able to approve an ERC721 token by passing in allowance = 1', async () => { - const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync( - tokenArtifacts.DummyERC721Token, - provider, - txDefaults, - constants.DUMMY_TOKEN_NAME, - constants.DUMMY_TOKEN_SYMBOL, - ); - const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, constants.ZERO_AMOUNT); - const allowance = new BigNumber(1); - await web3Wrapper.awaitTransactionSuccessAsync( - await orderMatcher.approveAssetProxy.sendTransactionAsync(assetData, allowance, { from: owner }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const isApproved = await erc721Token.isApprovedForAll.callAsync(orderMatcher.address, erc721Proxy.address); - expect(isApproved).to.be.equal(true); - }); - it('should be able to approve an ERC721 token by passing in allowance > 1', async () => { - const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync( - tokenArtifacts.DummyERC721Token, - provider, - txDefaults, - constants.DUMMY_TOKEN_NAME, - constants.DUMMY_TOKEN_SYMBOL, - ); - const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, constants.ZERO_AMOUNT); - const allowance = new BigNumber(2); - await web3Wrapper.awaitTransactionSuccessAsync( - await orderMatcher.approveAssetProxy.sendTransactionAsync(assetData, allowance, { from: owner }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const isApproved = await erc721Token.isApprovedForAll.callAsync(orderMatcher.address, erc721Proxy.address); - expect(isApproved).to.be.equal(true); - }); - it('should revert if not called by owner', async () => { - const approval = new BigNumber(1); - await expectTransactionFailedAsync( - orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, approval, { - from: takerAddress, - }), - RevertReason.OnlyContractOwner, - ); - }); - }); -}); -// tslint:disable:max-file-line-count -// tslint:enable:no-unnecessary-type-assertion diff --git a/contracts/extensions/test/extensions/order_validator.ts b/contracts/extensions/test/extensions/order_validator.ts deleted file mode 100644 index 7d8675f36..000000000 --- a/contracts/extensions/test/extensions/order_validator.ts +++ /dev/null @@ -1,609 +0,0 @@ -import { - artifacts as protocolArtifacts, - ERC20ProxyContract, - ERC20Wrapper, - ERC721ProxyContract, - ERC721Wrapper, - ExchangeContract, - ExchangeWrapper, -} from '@0x/contracts-protocol'; -import { - chaiSetup, - constants, - OrderFactory, - OrderStatus, - provider, - txDefaults, - web3Wrapper, -} from '@0x/contracts-test-utils'; -import { DummyERC20TokenContract, DummyERC721TokenContract } from '@0x/contracts-tokens'; -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as chai from 'chai'; -import * as _ from 'lodash'; - -import { OrderValidatorContract } from '../../generated-wrappers/order_validator'; -import { artifacts } from '../../src/artifacts/index'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -describe('OrderValidator', () => { - let makerAddress: string; - let owner: string; - let takerAddress: string; - let erc20AssetData: string; - let erc721AssetData: string; - - let erc20Token: DummyERC20TokenContract; - let zrxToken: DummyERC20TokenContract; - let erc721Token: DummyERC721TokenContract; - let exchange: ExchangeContract; - let orderValidator: OrderValidatorContract; - let erc20Proxy: ERC20ProxyContract; - let erc721Proxy: ERC721ProxyContract; - - let signedOrder: SignedOrder; - let signedOrder2: SignedOrder; - let orderFactory: OrderFactory; - - const tokenId = new BigNumber(123456789); - const tokenId2 = new BigNumber(987654321); - const ERC721_BALANCE = new BigNumber(1); - const ERC721_ALLOWANCE = new BigNumber(1); - - before(async () => { - await blockchainLifecycle.startAsync(); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - - before(async () => { - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - const usedAddresses = ([owner, makerAddress, takerAddress] = _.slice(accounts, 0, 3)); - - const erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); - const erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner); - - const numDummyErc20ToDeploy = 2; - [erc20Token, zrxToken] = await erc20Wrapper.deployDummyTokensAsync( - numDummyErc20ToDeploy, - constants.DUMMY_TOKEN_DECIMALS, - ); - erc20Proxy = await erc20Wrapper.deployProxyAsync(); - - [erc721Token] = await erc721Wrapper.deployDummyTokensAsync(); - erc721Proxy = await erc721Wrapper.deployProxyAsync(); - - const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address); - exchange = await ExchangeContract.deployFrom0xArtifactAsync( - protocolArtifacts.Exchange, - provider, - txDefaults, - zrxAssetData, - ); - const exchangeWrapper = new ExchangeWrapper(exchange, provider); - await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); - await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner); - - orderValidator = await OrderValidatorContract.deployFrom0xArtifactAsync( - artifacts.OrderValidator, - provider, - txDefaults, - exchange.address, - zrxAssetData, - ); - - erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address); - erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId); - const defaultOrderParams = { - ...constants.STATIC_ORDER_PARAMS, - exchangeAddress: exchange.address, - makerAddress, - feeRecipientAddress: constants.NULL_ADDRESS, - makerAssetData: erc20AssetData, - takerAssetData: erc721AssetData, - }; - const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)]; - orderFactory = new OrderFactory(privateKey, defaultOrderParams); - }); - - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - - describe('getBalanceAndAllowance', () => { - describe('getERC721TokenOwner', async () => { - it('should return the null address when tokenId is not owned', async () => { - const tokenOwner = await orderValidator.getERC721TokenOwner.callAsync(makerAddress, tokenId); - expect(tokenOwner).to.be.equal(constants.NULL_ADDRESS); - }); - it('should return the owner address when tokenId is owned', async () => { - await web3Wrapper.awaitTransactionSuccessAsync( - await erc721Token.mint.sendTransactionAsync(makerAddress, tokenId), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const tokenOwner = await orderValidator.getERC721TokenOwner.callAsync(erc721Token.address, tokenId); - expect(tokenOwner).to.be.equal(makerAddress); - }); - }); - describe('ERC20 assetData', () => { - it('should return the correct balances and allowances when both values are 0', async () => { - const [newBalance, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync( - makerAddress, - erc20AssetData, - ); - expect(constants.ZERO_AMOUNT).to.be.bignumber.equal(newBalance); - expect(constants.ZERO_AMOUNT).to.be.bignumber.equal(newAllowance); - }); - it('should return the correct balance and allowance when both values are non-zero', async () => { - const balance = new BigNumber(123); - const allowance = new BigNumber(456); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc20Token.setBalance.sendTransactionAsync(makerAddress, balance), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, allowance, { - from: makerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const [newBalance, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync( - makerAddress, - erc20AssetData, - ); - expect(balance).to.be.bignumber.equal(newBalance); - expect(allowance).to.be.bignumber.equal(newAllowance); - }); - }); - describe('ERC721 assetData', () => { - it('should return a balance of 0 when the tokenId is not owned by target', async () => { - const [newBalance] = await orderValidator.getBalanceAndAllowance.callAsync( - makerAddress, - erc721AssetData, - ); - expect(newBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should return an allowance of 0 when no approval is set', async () => { - const [, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync( - makerAddress, - erc721AssetData, - ); - expect(newAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should return a balance of 1 when the tokenId is owned by target', async () => { - await web3Wrapper.awaitTransactionSuccessAsync( - await erc721Token.mint.sendTransactionAsync(makerAddress, tokenId), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const [newBalance] = await orderValidator.getBalanceAndAllowance.callAsync( - makerAddress, - erc721AssetData, - ); - expect(newBalance).to.be.bignumber.equal(ERC721_BALANCE); - }); - it('should return an allowance of 1 when ERC721Proxy is approved for all', async () => { - const isApproved = true; - await web3Wrapper.awaitTransactionSuccessAsync( - await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, { - from: makerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const [, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync( - makerAddress, - erc721AssetData, - ); - expect(newAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE); - }); - it('should return an allowance of 0 when ERC721Proxy is approved for specific tokenId', async () => { - await web3Wrapper.awaitTransactionSuccessAsync( - await erc721Token.mint.sendTransactionAsync(makerAddress, tokenId), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc721Token.approve.sendTransactionAsync(erc721Proxy.address, tokenId, { - from: makerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const [, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync( - makerAddress, - erc721AssetData, - ); - expect(newAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - }); - }); - describe('getBalancesAndAllowances', () => { - it('should return the correct balances and allowances when all values are 0', async () => { - const [ - [erc20Balance, erc721Balance], - [erc20Allowance, erc721Allowance], - ] = await orderValidator.getBalancesAndAllowances.callAsync(makerAddress, [ - erc20AssetData, - erc721AssetData, - ]); - expect(erc20Balance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(erc721Balance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(erc20Allowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(erc721Allowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should return the correct balances and allowances when balances and allowances are non-zero', async () => { - const balance = new BigNumber(123); - const allowance = new BigNumber(456); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc20Token.setBalance.sendTransactionAsync(makerAddress, balance), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, allowance, { - from: makerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc721Token.mint.sendTransactionAsync(makerAddress, tokenId), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const isApproved = true; - await web3Wrapper.awaitTransactionSuccessAsync( - await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, { - from: makerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const [ - [erc20Balance, erc721Balance], - [erc20Allowance, erc721Allowance], - ] = await orderValidator.getBalancesAndAllowances.callAsync(makerAddress, [ - erc20AssetData, - erc721AssetData, - ]); - expect(erc20Balance).to.be.bignumber.equal(balance); - expect(erc721Balance).to.be.bignumber.equal(ERC721_BALANCE); - expect(erc20Allowance).to.be.bignumber.equal(allowance); - expect(erc721Allowance).to.be.bignumber.equal(ERC721_ALLOWANCE); - }); - }); - describe('getTraderInfo', () => { - beforeEach(async () => { - signedOrder = await orderFactory.newSignedOrderAsync(); - }); - it('should return the correct info when no balances or allowances are set', async () => { - const traderInfo = await orderValidator.getTraderInfo.callAsync(signedOrder, takerAddress); - expect(traderInfo.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should return the correct info when balances and allowances are set', async () => { - const makerBalance = new BigNumber(123); - const makerAllowance = new BigNumber(456); - const makerZrxBalance = new BigNumber(789); - const takerZrxAllowance = new BigNumber(987); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc20Token.setBalance.sendTransactionAsync(makerAddress, makerBalance), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, makerAllowance, { - from: makerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await zrxToken.setBalance.sendTransactionAsync(makerAddress, makerZrxBalance), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await zrxToken.approve.sendTransactionAsync(erc20Proxy.address, takerZrxAllowance, { - from: takerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc721Token.mint.sendTransactionAsync(takerAddress, tokenId), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const isApproved = true; - await web3Wrapper.awaitTransactionSuccessAsync( - await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, { - from: takerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const traderInfo = await orderValidator.getTraderInfo.callAsync(signedOrder, takerAddress); - expect(traderInfo.makerBalance).to.be.bignumber.equal(makerBalance); - expect(traderInfo.makerAllowance).to.be.bignumber.equal(makerAllowance); - expect(traderInfo.takerBalance).to.be.bignumber.equal(ERC721_BALANCE); - expect(traderInfo.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE); - expect(traderInfo.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance); - expect(traderInfo.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance); - }); - }); - describe('getTradersInfo', () => { - beforeEach(async () => { - signedOrder = await orderFactory.newSignedOrderAsync(); - signedOrder2 = await orderFactory.newSignedOrderAsync({ - takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId2), - }); - }); - it('should return the correct info when no balances or allowances have been set', async () => { - const orders = [signedOrder, signedOrder2]; - const takers = [takerAddress, takerAddress]; - const [traderInfo1, traderInfo2] = await orderValidator.getTradersInfo.callAsync(orders, takers); - expect(traderInfo1.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo2.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo2.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo2.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo2.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo2.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo2.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo2.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo2.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should return the correct info when balances and allowances are set', async () => { - const makerBalance = new BigNumber(123); - const makerAllowance = new BigNumber(456); - const makerZrxBalance = new BigNumber(789); - const takerZrxAllowance = new BigNumber(987); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc20Token.setBalance.sendTransactionAsync(makerAddress, makerBalance), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, makerAllowance, { - from: makerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await zrxToken.setBalance.sendTransactionAsync(makerAddress, makerZrxBalance), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await zrxToken.approve.sendTransactionAsync(erc20Proxy.address, takerZrxAllowance, { - from: takerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const isApproved = true; - await web3Wrapper.awaitTransactionSuccessAsync( - await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, { - from: takerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc721Token.mint.sendTransactionAsync(takerAddress, tokenId2), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const orders = [signedOrder, signedOrder2]; - const takers = [takerAddress, takerAddress]; - const [traderInfo1, traderInfo2] = await orderValidator.getTradersInfo.callAsync(orders, takers); - - expect(traderInfo1.makerBalance).to.be.bignumber.equal(makerBalance); - expect(traderInfo1.makerAllowance).to.be.bignumber.equal(makerAllowance); - expect(traderInfo1.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE); - expect(traderInfo1.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance); - expect(traderInfo1.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance); - expect(traderInfo2.makerBalance).to.be.bignumber.equal(makerBalance); - expect(traderInfo2.makerAllowance).to.be.bignumber.equal(makerAllowance); - expect(traderInfo2.takerBalance).to.be.bignumber.equal(ERC721_BALANCE); - expect(traderInfo2.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE); - expect(traderInfo2.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance); - expect(traderInfo2.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo2.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo2.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance); - }); - }); - describe('getOrderAndTraderInfo', () => { - beforeEach(async () => { - signedOrder = await orderFactory.newSignedOrderAsync(); - }); - it('should return the correct info when no balances or allowances are set', async () => { - const [orderInfo, traderInfo] = await orderValidator.getOrderAndTraderInfo.callAsync( - signedOrder, - takerAddress, - ); - const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder); - expect(orderInfo.orderStatus).to.be.equal(OrderStatus.Fillable); - expect(orderInfo.orderHash).to.be.equal(expectedOrderHash); - expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should return the correct info when balances and allowances are set', async () => { - const makerBalance = new BigNumber(123); - const makerAllowance = new BigNumber(456); - const makerZrxBalance = new BigNumber(789); - const takerZrxAllowance = new BigNumber(987); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc20Token.setBalance.sendTransactionAsync(makerAddress, makerBalance), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, makerAllowance, { - from: makerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await zrxToken.setBalance.sendTransactionAsync(makerAddress, makerZrxBalance), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await zrxToken.approve.sendTransactionAsync(erc20Proxy.address, takerZrxAllowance, { - from: takerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc721Token.mint.sendTransactionAsync(takerAddress, tokenId), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const isApproved = true; - await web3Wrapper.awaitTransactionSuccessAsync( - await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, { - from: takerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const [orderInfo, traderInfo] = await orderValidator.getOrderAndTraderInfo.callAsync( - signedOrder, - takerAddress, - ); - const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder); - expect(orderInfo.orderStatus).to.be.equal(OrderStatus.Fillable); - expect(orderInfo.orderHash).to.be.equal(expectedOrderHash); - expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo.makerBalance).to.be.bignumber.equal(makerBalance); - expect(traderInfo.makerAllowance).to.be.bignumber.equal(makerAllowance); - expect(traderInfo.takerBalance).to.be.bignumber.equal(ERC721_BALANCE); - expect(traderInfo.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE); - expect(traderInfo.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance); - expect(traderInfo.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance); - }); - }); - describe('getOrdersAndTradersInfo', () => { - beforeEach(async () => { - signedOrder = await orderFactory.newSignedOrderAsync(); - signedOrder2 = await orderFactory.newSignedOrderAsync({ - takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId2), - }); - }); - it('should return the correct info when no balances or allowances have been set', async () => { - const orders = [signedOrder, signedOrder2]; - const takers = [takerAddress, takerAddress]; - const [ - [orderInfo1, orderInfo2], - [traderInfo1, traderInfo2], - ] = await orderValidator.getOrdersAndTradersInfo.callAsync(orders, takers); - const expectedOrderHash1 = orderHashUtils.getOrderHashHex(signedOrder); - const expectedOrderHash2 = orderHashUtils.getOrderHashHex(signedOrder2); - expect(orderInfo1.orderStatus).to.be.equal(OrderStatus.Fillable); - expect(orderInfo1.orderHash).to.be.equal(expectedOrderHash1); - expect(orderInfo1.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(orderInfo2.orderStatus).to.be.equal(OrderStatus.Fillable); - expect(orderInfo2.orderHash).to.be.equal(expectedOrderHash2); - expect(orderInfo2.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo2.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo2.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo2.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo2.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo2.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo2.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo2.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo2.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should return the correct info when balances and allowances are set', async () => { - const makerBalance = new BigNumber(123); - const makerAllowance = new BigNumber(456); - const makerZrxBalance = new BigNumber(789); - const takerZrxAllowance = new BigNumber(987); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc20Token.setBalance.sendTransactionAsync(makerAddress, makerBalance), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, makerAllowance, { - from: makerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await zrxToken.setBalance.sendTransactionAsync(makerAddress, makerZrxBalance), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await zrxToken.approve.sendTransactionAsync(erc20Proxy.address, takerZrxAllowance, { - from: takerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const isApproved = true; - await web3Wrapper.awaitTransactionSuccessAsync( - await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, { - from: takerAddress, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc721Token.mint.sendTransactionAsync(takerAddress, tokenId2), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const orders = [signedOrder, signedOrder2]; - const takers = [takerAddress, takerAddress]; - const [ - [orderInfo1, orderInfo2], - [traderInfo1, traderInfo2], - ] = await orderValidator.getOrdersAndTradersInfo.callAsync(orders, takers); - const expectedOrderHash1 = orderHashUtils.getOrderHashHex(signedOrder); - const expectedOrderHash2 = orderHashUtils.getOrderHashHex(signedOrder2); - expect(orderInfo1.orderStatus).to.be.equal(OrderStatus.Fillable); - expect(orderInfo1.orderHash).to.be.equal(expectedOrderHash1); - expect(orderInfo1.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(orderInfo2.orderStatus).to.be.equal(OrderStatus.Fillable); - expect(orderInfo2.orderHash).to.be.equal(expectedOrderHash2); - expect(orderInfo2.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.makerBalance).to.be.bignumber.equal(makerBalance); - expect(traderInfo1.makerAllowance).to.be.bignumber.equal(makerAllowance); - expect(traderInfo1.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE); - expect(traderInfo1.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance); - expect(traderInfo1.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo1.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance); - expect(traderInfo2.makerBalance).to.be.bignumber.equal(makerBalance); - expect(traderInfo2.makerAllowance).to.be.bignumber.equal(makerAllowance); - expect(traderInfo2.takerBalance).to.be.bignumber.equal(ERC721_BALANCE); - expect(traderInfo2.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE); - expect(traderInfo2.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance); - expect(traderInfo2.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo2.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); - expect(traderInfo2.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance); - }); - }); -}); -// tslint:disable:max-file-line-count diff --git a/contracts/extensions/test/global_hooks.ts b/contracts/extensions/test/global_hooks.ts deleted file mode 100644 index f8ace376a..000000000 --- a/contracts/extensions/test/global_hooks.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { env, EnvVars } from '@0x/dev-utils'; - -import { coverage, profiler, provider } from '@0x/contracts-test-utils'; -before('start web3 provider', () => { - provider.start(); -}); -after('generate coverage report', async () => { - if (env.parseBoolean(EnvVars.SolidityCoverage)) { - const coverageSubprovider = coverage.getCoverageSubproviderSingleton(); - await coverageSubprovider.writeCoverageAsync(); - } - if (env.parseBoolean(EnvVars.SolidityProfiler)) { - const profilerSubprovider = profiler.getProfilerSubproviderSingleton(); - await profilerSubprovider.writeProfilerOutputAsync(); - } - provider.stop(); -}); diff --git a/contracts/extensions/test/utils/balance_threshold_wrapper.ts b/contracts/extensions/test/utils/balance_threshold_wrapper.ts deleted file mode 100644 index 28a4ef011..000000000 --- a/contracts/extensions/test/utils/balance_threshold_wrapper.ts +++ /dev/null @@ -1,283 +0,0 @@ -import { artifacts as protocolArtifacts, ExchangeContract } from '@0x/contracts-protocol'; -import { - FillResults, - formatters, - LogDecoder, - OrderInfo, - orderUtils, - TransactionFactory, -} from '@0x/contracts-test-utils'; -import { artifacts as tokensArtifacts } from '@0x/contracts-tokens'; -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { BalanceThresholdFilterContract } from '../../generated-wrappers/balance_threshold_filter'; -import { artifacts } from '../../src/artifacts'; - -export class BalanceThresholdWrapper { - private readonly _balanceThresholdFilter: BalanceThresholdFilterContract; - private readonly _signerTransactionFactory: TransactionFactory; - private readonly _exchange: ExchangeContract; - private readonly _web3Wrapper: Web3Wrapper; - private readonly _logDecoder: LogDecoder; - constructor( - balanceThresholdFilter: BalanceThresholdFilterContract, - exchangeContract: ExchangeContract, - signerTransactionFactory: TransactionFactory, - provider: Provider, - ) { - this._balanceThresholdFilter = balanceThresholdFilter; - this._exchange = exchangeContract; - this._signerTransactionFactory = signerTransactionFactory; - this._web3Wrapper = new Web3Wrapper(provider); - this._logDecoder = new LogDecoder(this._web3Wrapper, { - ...artifacts, - ...tokensArtifacts, - ...protocolArtifacts, - }); - } - public async fillOrderAsync( - signedOrder: SignedOrder, - from: string, - opts: { takerAssetFillAmount?: BigNumber } = {}, - ): Promise { - const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); - const data = this._exchange.fillOrder.getABIEncodedTransactionData( - params.order, - params.takerAssetFillAmount, - params.signature, - ); - const txReceipt = this._executeTransactionAsync(data, from); - return txReceipt; - } - public async fillOrKillOrderAsync( - signedOrder: SignedOrder, - from: string, - opts: { takerAssetFillAmount?: BigNumber } = {}, - ): Promise { - const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); - const data = this._exchange.fillOrKillOrder.getABIEncodedTransactionData( - params.order, - params.takerAssetFillAmount, - params.signature, - ); - const txReceipt = this._executeTransactionAsync(data, from); - return txReceipt; - } - public async fillOrderNoThrowAsync( - signedOrder: SignedOrder, - from: string, - opts: { takerAssetFillAmount?: BigNumber; gas?: number } = {}, - ): Promise { - const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); - const data = this._exchange.fillOrderNoThrow.getABIEncodedTransactionData( - params.order, - params.takerAssetFillAmount, - params.signature, - ); - const txReceipt = this._executeTransactionAsync(data, from, opts.gas); - return txReceipt; - } - public async batchFillOrdersAsync( - orders: SignedOrder[], - from: string, - opts: { takerAssetFillAmounts?: BigNumber[] } = {}, - ): Promise { - const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts); - const data = this._exchange.batchFillOrders.getABIEncodedTransactionData( - params.orders, - params.takerAssetFillAmounts, - params.signatures, - ); - const txReceipt = this._executeTransactionAsync(data, from); - return txReceipt; - } - public async batchFillOrKillOrdersAsync( - orders: SignedOrder[], - from: string, - opts: { takerAssetFillAmounts?: BigNumber[] } = {}, - ): Promise { - const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts); - const data = this._exchange.batchFillOrKillOrders.getABIEncodedTransactionData( - params.orders, - params.takerAssetFillAmounts, - params.signatures, - ); - const txReceipt = this._executeTransactionAsync(data, from); - return txReceipt; - } - public async batchFillOrdersNoThrowAsync( - orders: SignedOrder[], - from: string, - opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number } = {}, - ): Promise { - const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts); - const data = this._exchange.batchFillOrKillOrders.getABIEncodedTransactionData( - params.orders, - params.takerAssetFillAmounts, - params.signatures, - ); - const txReceipt = this._executeTransactionAsync(data, from, opts.gas); - return txReceipt; - } - public async marketSellOrdersAsync( - orders: SignedOrder[], - from: string, - opts: { takerAssetFillAmount: BigNumber }, - ): Promise { - const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount); - const data = this._exchange.marketSellOrders.getABIEncodedTransactionData( - params.orders, - params.takerAssetFillAmount, - params.signatures, - ); - const txReceipt = this._executeTransactionAsync(data, from); - return txReceipt; - } - public async marketSellOrdersNoThrowAsync( - orders: SignedOrder[], - from: string, - opts: { takerAssetFillAmount: BigNumber; gas?: number }, - ): Promise { - const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount); - const data = this._exchange.marketSellOrdersNoThrow.getABIEncodedTransactionData( - params.orders, - params.takerAssetFillAmount, - params.signatures, - ); - const txReceipt = this._executeTransactionAsync(data, from, opts.gas); - return txReceipt; - } - public async marketBuyOrdersAsync( - orders: SignedOrder[], - from: string, - opts: { makerAssetFillAmount: BigNumber }, - ): Promise { - const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount); - const data = this._exchange.marketBuyOrders.getABIEncodedTransactionData( - params.orders, - params.makerAssetFillAmount, - params.signatures, - ); - const txReceipt = this._executeTransactionAsync(data, from); - return txReceipt; - } - public async marketBuyOrdersNoThrowAsync( - orders: SignedOrder[], - from: string, - opts: { makerAssetFillAmount: BigNumber; gas?: number }, - ): Promise { - const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount); - const data = this._exchange.marketBuyOrdersNoThrow.getABIEncodedTransactionData( - params.orders, - params.makerAssetFillAmount, - params.signatures, - ); - const txReceipt = this._executeTransactionAsync(data, from, opts.gas); - return txReceipt; - } - public async cancelOrderAsync(signedOrder: SignedOrder, from: string): Promise { - const params = orderUtils.createCancel(signedOrder); - const data = this._exchange.cancelOrder.getABIEncodedTransactionData(params.order); - const txReceipt = this._executeTransactionAsync(data, from); - return txReceipt; - } - public async batchCancelOrdersAsync( - orders: SignedOrder[], - from: string, - ): Promise { - const params = formatters.createBatchCancel(orders); - const data = this._exchange.batchCancelOrders.getABIEncodedTransactionData(params.orders); - const txReceipt = this._executeTransactionAsync(data, from); - return txReceipt; - } - public async cancelOrdersUpToAsync(salt: BigNumber, from: string): Promise { - const data = this._exchange.cancelOrdersUpTo.getABIEncodedTransactionData(salt); - const txReceipt = this._executeTransactionAsync(data, from); - return txReceipt; - } - public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise { - const filledAmount = await this._exchange.filled.callAsync(orderHashHex); - return filledAmount; - } - public async isCancelledAsync(orderHashHex: string): Promise { - const isCancelled = await this._exchange.cancelled.callAsync(orderHashHex); - return isCancelled; - } - public async getOrderEpochAsync(makerAddress: string, senderAddress: string): Promise { - const orderEpoch = await this._exchange.orderEpoch.callAsync(makerAddress, senderAddress); - return orderEpoch; - } - public async getOrderInfoAsync(signedOrder: SignedOrder): Promise { - const orderInfo = await this._exchange.getOrderInfo.callAsync(signedOrder); - return orderInfo; - } - public async getOrdersInfoAsync(signedOrders: SignedOrder[]): Promise { - const ordersInfo = (await this._exchange.getOrdersInfo.callAsync(signedOrders)) as OrderInfo[]; - return ordersInfo; - } - public async matchOrdersAsync( - signedOrderLeft: SignedOrder, - signedOrderRight: SignedOrder, - from: string, - ): Promise { - const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight); - const data = await this._exchange.matchOrders.getABIEncodedTransactionData( - params.left, - params.right, - params.leftSignature, - params.rightSignature, - ); - const txReceipt = this._executeTransactionAsync(data, from); - return txReceipt; - } - public async getFillOrderResultsAsync( - signedOrder: SignedOrder, - from: string, - opts: { takerAssetFillAmount?: BigNumber } = {}, - ): Promise { - const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); - const fillResults = await this._exchange.fillOrder.callAsync( - params.order, - params.takerAssetFillAmount, - params.signature, - { from }, - ); - return fillResults; - } - public abiEncodeFillOrder(signedOrder: SignedOrder, opts: { takerAssetFillAmount?: BigNumber } = {}): string { - const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); - const data = this._exchange.fillOrder.getABIEncodedTransactionData( - params.order, - params.takerAssetFillAmount, - params.signature, - ); - return data; - } - public getBalanceThresholdAddress(): string { - return this._balanceThresholdFilter.address; - } - public getExchangeAddress(): string { - return this._exchange.address; - } - private async _executeTransactionAsync( - abiEncodedExchangeTxData: string, - from: string, - gas?: number, - ): Promise { - const signedExchangeTx = this._signerTransactionFactory.newSignedTransaction(abiEncodedExchangeTxData); - const txOpts = _.isUndefined(gas) ? { from } : { from, gas }; - const txHash = await this._balanceThresholdFilter.executeTransaction.sendTransactionAsync( - signedExchangeTx.salt, - signedExchangeTx.signerAddress, - signedExchangeTx.data, - signedExchangeTx.signature, - txOpts, - ); - const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return txReceipt; - } -} diff --git a/contracts/extensions/test/utils/dutch_auction_test_wrapper.ts b/contracts/extensions/test/utils/dutch_auction_test_wrapper.ts deleted file mode 100644 index c1e2f2070..000000000 --- a/contracts/extensions/test/utils/dutch_auction_test_wrapper.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { artifacts as protocolArtifacts } from '@0x/contracts-protocol'; -import { LogDecoder } from '@0x/contracts-test-utils'; -import { artifacts as tokensArtifacts } from '@0x/contracts-tokens'; -import { DutchAuctionDetails, SignedOrder } from '@0x/types'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { DutchAuctionContract } from '../../generated-wrappers/dutch_auction'; -import { artifacts } from '../../src/artifacts'; - -export class DutchAuctionTestWrapper { - private readonly _dutchAuctionContract: DutchAuctionContract; - private readonly _web3Wrapper: Web3Wrapper; - private readonly _logDecoder: LogDecoder; - - constructor(contractInstance: DutchAuctionContract, provider: Provider) { - this._dutchAuctionContract = contractInstance; - this._web3Wrapper = new Web3Wrapper(provider); - this._logDecoder = new LogDecoder(this._web3Wrapper, { - ...artifacts, - ...tokensArtifacts, - ...protocolArtifacts, - }); - } - /** - * Matches the buy and sell orders at an amount given the following: the current block time, the auction - * start time and the auction begin amount. The sell order is a an order at the lowest amount - * at the end of the auction. Excess from the match is transferred to the seller. - * Over time the price moves from beginAmount to endAmount given the current block.timestamp. - * @param buyOrder The Buyer's order. This order is for the current expected price of the auction. - * @param sellOrder The Seller's order. This order is for the lowest amount (at the end of the auction). - * @param from Address the transaction is being sent from. - * @return Transaction receipt with decoded logs. - */ - public async matchOrdersAsync( - buyOrder: SignedOrder, - sellOrder: SignedOrder, - from: string, - ): Promise { - const txHash = await this._dutchAuctionContract.matchOrders.sendTransactionAsync( - buyOrder, - sellOrder, - buyOrder.signature, - sellOrder.signature, - { - from, - }, - ); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - /** - * Calculates the Auction Details for the given order - * @param sellOrder The Seller's order. This order is for the lowest amount (at the end of the auction). - * @return The dutch auction details. - */ - public async getAuctionDetailsAsync(sellOrder: SignedOrder): Promise { - const auctionDetails = await this._dutchAuctionContract.getAuctionDetails.callAsync(sellOrder); - return auctionDetails; - } -} diff --git a/contracts/extensions/test/utils/forwarder_wrapper.ts b/contracts/extensions/test/utils/forwarder_wrapper.ts deleted file mode 100644 index 4a43be04a..000000000 --- a/contracts/extensions/test/utils/forwarder_wrapper.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { artifacts as protocolArtifacts } from '@0x/contracts-protocol'; -import { constants, formatters, LogDecoder, MarketSellOrders } from '@0x/contracts-test-utils'; -import { artifacts as tokensArtifacts } from '@0x/contracts-tokens'; -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { Provider, TransactionReceiptWithDecodedLogs, TxDataPayable } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { ForwarderContract } from '../../generated-wrappers/forwarder'; -import { artifacts } from '../../src/artifacts'; - -export class ForwarderWrapper { - private readonly _web3Wrapper: Web3Wrapper; - private readonly _forwarderContract: ForwarderContract; - private readonly _logDecoder: LogDecoder; - public static getPercentageOfValue(value: BigNumber, percentage: number): BigNumber { - const numerator = constants.PERCENTAGE_DENOMINATOR.times(percentage).dividedToIntegerBy(100); - const newValue = value.times(numerator).dividedToIntegerBy(constants.PERCENTAGE_DENOMINATOR); - return newValue; - } - public static getWethForFeeOrders(feeAmount: BigNumber, feeOrders: SignedOrder[]): BigNumber { - let wethAmount = new BigNumber(0); - let remainingFeeAmount = feeAmount; - _.forEach(feeOrders, feeOrder => { - const feeAvailable = feeOrder.makerAssetAmount.minus(feeOrder.takerFee); - if (!remainingFeeAmount.isZero() && feeAvailable.gt(remainingFeeAmount)) { - wethAmount = wethAmount.plus( - feeOrder.takerAssetAmount - .times(remainingFeeAmount) - .dividedBy(feeAvailable) - .integerValue(BigNumber.ROUND_CEIL), - ); - remainingFeeAmount = new BigNumber(0); - } else if (!remainingFeeAmount.isZero()) { - wethAmount = wethAmount.plus(feeOrder.takerAssetAmount); - remainingFeeAmount = remainingFeeAmount.minus(feeAvailable); - } - }); - return wethAmount; - } - private static _createOptimizedOrders(signedOrders: SignedOrder[]): MarketSellOrders { - _.forEach(signedOrders, (signedOrder, index) => { - signedOrder.takerAssetData = constants.NULL_BYTES; - if (index > 0) { - signedOrder.makerAssetData = constants.NULL_BYTES; - } - }); - const params = formatters.createMarketSellOrders(signedOrders, constants.ZERO_AMOUNT); - return params; - } - private static _createOptimizedZrxOrders(signedOrders: SignedOrder[]): MarketSellOrders { - _.forEach(signedOrders, signedOrder => { - signedOrder.makerAssetData = constants.NULL_BYTES; - signedOrder.takerAssetData = constants.NULL_BYTES; - }); - const params = formatters.createMarketSellOrders(signedOrders, constants.ZERO_AMOUNT); - return params; - } - constructor(contractInstance: ForwarderContract, provider: Provider) { - this._forwarderContract = contractInstance; - this._web3Wrapper = new Web3Wrapper(provider); - this._logDecoder = new LogDecoder(this._web3Wrapper, { - ...artifacts, - ...tokensArtifacts, - ...protocolArtifacts, - }); - } - public async marketSellOrdersWithEthAsync( - orders: SignedOrder[], - feeOrders: SignedOrder[], - txData: TxDataPayable, - opts: { feePercentage?: BigNumber; feeRecipient?: string } = {}, - ): Promise { - const params = ForwarderWrapper._createOptimizedOrders(orders); - const feeParams = ForwarderWrapper._createOptimizedZrxOrders(feeOrders); - const feePercentage = _.isUndefined(opts.feePercentage) ? constants.ZERO_AMOUNT : opts.feePercentage; - const feeRecipient = _.isUndefined(opts.feeRecipient) ? constants.NULL_ADDRESS : opts.feeRecipient; - const txHash = await this._forwarderContract.marketSellOrdersWithEth.sendTransactionAsync( - params.orders, - params.signatures, - feeParams.orders, - feeParams.signatures, - feePercentage, - feeRecipient, - txData, - ); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async marketBuyOrdersWithEthAsync( - orders: SignedOrder[], - feeOrders: SignedOrder[], - makerAssetFillAmount: BigNumber, - txData: TxDataPayable, - opts: { feePercentage?: BigNumber; feeRecipient?: string } = {}, - ): Promise { - const params = ForwarderWrapper._createOptimizedOrders(orders); - const feeParams = ForwarderWrapper._createOptimizedZrxOrders(feeOrders); - const feePercentage = _.isUndefined(opts.feePercentage) ? constants.ZERO_AMOUNT : opts.feePercentage; - const feeRecipient = _.isUndefined(opts.feeRecipient) ? constants.NULL_ADDRESS : opts.feeRecipient; - const txHash = await this._forwarderContract.marketBuyOrdersWithEth.sendTransactionAsync( - params.orders, - makerAssetFillAmount, - params.signatures, - feeParams.orders, - feeParams.signatures, - feePercentage, - feeRecipient, - txData, - ); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async withdrawAssetAsync( - assetData: string, - amount: BigNumber, - txData: TxDataPayable, - ): Promise { - const txHash = await this._forwarderContract.withdrawAsset.sendTransactionAsync(assetData, amount, txData); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } -} -- cgit v1.2.3