diff options
Diffstat (limited to 'packages/contract-wrappers/test')
15 files changed, 1184 insertions, 2082 deletions
diff --git a/packages/contract-wrappers/test/artifacts_test.ts b/packages/contract-wrappers/test/artifacts_test.ts index 39801df35..c05d513b3 100644 --- a/packages/contract-wrappers/test/artifacts_test.ts +++ b/packages/contract-wrappers/test/artifacts_test.ts @@ -10,7 +10,8 @@ chaiSetup.configure(); // Those tests are slower cause they're talking to a remote node const TIMEOUT = 10000; -describe('Artifacts', () => { +// TODO: Re-enable those tests after final kovan and ropsten deployments are done. +describe.skip('Artifacts', () => { describe('contracts are deployed on kovan', () => { const kovanRpcUrl = constants.KOVAN_RPC_URL; const provider = web3Factory.getRpcProvider({ rpcUrl: kovanRpcUrl }); @@ -18,14 +19,11 @@ describe('Artifacts', () => { networkId: constants.KOVAN_NETWORK_ID, }; const contractWrappers = new ContractWrappers(provider, config); - it('token registry contract is deployed', async () => { - await (contractWrappers.tokenRegistry as any)._getTokenRegistryContractAsync(); + it('erc20 proxy contract is deployed', async () => { + await (contractWrappers.erc20Proxy as any)._getTokenTransferProxyContractAsync(); }).timeout(TIMEOUT); - it('proxy contract is deployed', async () => { - await (contractWrappers.proxy as any)._getTokenTransferProxyContractAsync(); - }).timeout(TIMEOUT); - it('exchange contract is deployed', async () => { - await (contractWrappers.exchange as any)._getExchangeContractAsync(); + it('erc721 proxy contract is deployed', async () => { + await (contractWrappers.erc721Proxy as any)._getTokenTransferProxyContractAsync(); }).timeout(TIMEOUT); }); describe('contracts are deployed on ropsten', () => { @@ -35,14 +33,11 @@ describe('Artifacts', () => { networkId: constants.ROPSTEN_NETWORK_ID, }; const contractWrappers = new ContractWrappers(provider, config); - it('token registry contract is deployed', async () => { - await (contractWrappers.tokenRegistry as any)._getTokenRegistryContractAsync(); - }).timeout(TIMEOUT); - it('proxy contract is deployed', async () => { - await (contractWrappers.proxy as any)._getTokenTransferProxyContractAsync(); + it('erc20 proxy contract is deployed', async () => { + await (contractWrappers.erc20Proxy as any)._getTokenTransferProxyContractAsync(); }).timeout(TIMEOUT); - it('exchange contract is deployed', async () => { - await (contractWrappers.exchange as any)._getExchangeContractAsync(); + it('erc721 proxy contract is deployed', async () => { + await (contractWrappers.erc721Proxy as any)._getTokenTransferProxyContractAsync(); }).timeout(TIMEOUT); }); }); diff --git a/packages/contract-wrappers/test/token_transfer_proxy_wrapper_test.ts b/packages/contract-wrappers/test/erc20_proxy_wrapper_test.ts index 0b66985aa..6bf9f1e25 100644 --- a/packages/contract-wrappers/test/token_transfer_proxy_wrapper_test.ts +++ b/packages/contract-wrappers/test/erc20_proxy_wrapper_test.ts @@ -9,7 +9,7 @@ import { provider } from './utils/web3_wrapper'; chaiSetup.configure(); const expect = chai.expect; -describe('TokenTransferProxyWrapper', () => { +describe('ERC20ProxyWrapper', () => { let contractWrappers: ContractWrappers; const config = { networkId: constants.TESTRPC_NETWORK_ID, @@ -19,15 +19,15 @@ describe('TokenTransferProxyWrapper', () => { }); describe('#isAuthorizedAsync', () => { it('should return false if the address is not authorized', async () => { - const isAuthorized = await contractWrappers.proxy.isAuthorizedAsync(constants.NULL_ADDRESS); + const isAuthorized = await contractWrappers.erc20Proxy.isAuthorizedAsync(constants.NULL_ADDRESS); expect(isAuthorized).to.be.false(); }); }); describe('#getAuthorizedAddressesAsync', () => { it('should return the list of authorized addresses', async () => { - const authorizedAddresses = await contractWrappers.proxy.getAuthorizedAddressesAsync(); + const authorizedAddresses = await contractWrappers.erc20Proxy.getAuthorizedAddressesAsync(); for (const authorizedAddress of authorizedAddresses) { - const isAuthorized = await contractWrappers.proxy.isAuthorizedAsync(authorizedAddress); + const isAuthorized = await contractWrappers.erc20Proxy.isAuthorizedAsync(authorizedAddress); expect(isAuthorized).to.be.true(); } }); diff --git a/packages/contract-wrappers/test/token_wrapper_test.ts b/packages/contract-wrappers/test/erc20_wrapper_test.ts index 86b93b3f9..0011508e0 100644 --- a/packages/contract-wrappers/test/token_wrapper_test.ts +++ b/packages/contract-wrappers/test/erc20_wrapper_test.ts @@ -1,37 +1,36 @@ import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils'; import { EmptyWalletSubprovider } from '@0xproject/subproviders'; -import { DoneCallback, Provider } from '@0xproject/types'; +import { DoneCallback } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; +import { Provider } from 'ethereum-types'; import 'mocha'; import Web3ProviderEngine = require('web3-provider-engine'); import { - ApprovalContractEventArgs, BlockParamLiteral, BlockRange, ContractWrappers, ContractWrappersError, DecodedLogEvent, - Token, - TokenEvents, - TransferContractEventArgs, + ERC20TokenApprovalEventArgs, + ERC20TokenEvents, + ERC20TokenTransferEventArgs, } from '../src'; import { chaiSetup } from './utils/chai_setup'; import { constants } from './utils/constants'; -import { TokenUtils } from './utils/token_utils'; +import { tokenUtils } from './utils/token_utils'; import { provider, web3Wrapper } from './utils/web3_wrapper'; chaiSetup.configure(); const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); -describe('TokenWrapper', () => { +describe('ERC20Wrapper', () => { let contractWrappers: ContractWrappers; let userAddresses: string[]; - let tokens: Token[]; - let tokenUtils: TokenUtils; + let tokens: string[]; let coinbase: string; let addressWithoutFunds: string; const config = { @@ -40,8 +39,7 @@ describe('TokenWrapper', () => { before(async () => { contractWrappers = new ContractWrappers(provider, config); userAddresses = await web3Wrapper.getAvailableAddressesAsync(); - tokens = await contractWrappers.tokenRegistry.getTokensAsync(); - tokenUtils = new TokenUtils(tokens); + tokens = tokenUtils.getDummyERC20TokenAddresses(); coinbase = userAddresses[0]; addressWithoutFunds = userAddresses[1]; }); @@ -52,26 +50,26 @@ describe('TokenWrapper', () => { await blockchainLifecycle.revertAsync(); }); describe('#transferAsync', () => { - let token: Token; + let tokenAddress: string; let transferAmount: BigNumber; before(() => { - token = tokens[0]; + tokenAddress = tokens[0]; transferAmount = new BigNumber(42); }); it('should successfully transfer tokens', async () => { const fromAddress = coinbase; const toAddress = addressWithoutFunds; - const preBalance = await contractWrappers.token.getBalanceAsync(token.address, toAddress); + const preBalance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, toAddress); expect(preBalance).to.be.bignumber.equal(0); - await contractWrappers.token.transferAsync(token.address, fromAddress, toAddress, transferAmount); - const postBalance = await contractWrappers.token.getBalanceAsync(token.address, toAddress); + await contractWrappers.erc20Token.transferAsync(tokenAddress, fromAddress, toAddress, transferAmount); + const postBalance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, toAddress); return expect(postBalance).to.be.bignumber.equal(transferAmount); }); it('should fail to transfer tokens if fromAddress has an insufficient balance', async () => { const fromAddress = addressWithoutFunds; const toAddress = coinbase; return expect( - contractWrappers.token.transferAsync(token.address, fromAddress, toAddress, transferAmount), + contractWrappers.erc20Token.transferAsync(tokenAddress, fromAddress, toAddress, transferAmount), ).to.be.rejectedWith(ContractWrappersError.InsufficientBalanceForTransfer); }); it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => { @@ -79,16 +77,21 @@ describe('TokenWrapper', () => { const fromAddress = coinbase; const toAddress = coinbase; return expect( - contractWrappers.token.transferAsync(nonExistentTokenAddress, fromAddress, toAddress, transferAmount), - ).to.be.rejectedWith(ContractWrappersError.TokenContractDoesNotExist); + contractWrappers.erc20Token.transferAsync( + nonExistentTokenAddress, + fromAddress, + toAddress, + transferAmount, + ), + ).to.be.rejectedWith(ContractWrappersError.ERC20TokenContractDoesNotExist); }); }); describe('#transferFromAsync', () => { - let token: Token; + let tokenAddress: string; let toAddress: string; let senderAddress: string; before(async () => { - token = tokens[0]; + tokenAddress = tokens[0]; toAddress = addressWithoutFunds; senderAddress = userAddresses[2]; }); @@ -96,19 +99,19 @@ describe('TokenWrapper', () => { const fromAddress = coinbase; const transferAmount = new BigNumber(42); - const fromAddressBalance = await contractWrappers.token.getBalanceAsync(token.address, fromAddress); + const fromAddressBalance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, fromAddress); expect(fromAddressBalance).to.be.bignumber.greaterThan(transferAmount); - const fromAddressAllowance = await contractWrappers.token.getAllowanceAsync( - token.address, + const fromAddressAllowance = await contractWrappers.erc20Token.getAllowanceAsync( + tokenAddress, fromAddress, toAddress, ); expect(fromAddressAllowance).to.be.bignumber.equal(0); return expect( - contractWrappers.token.transferFromAsync( - token.address, + contractWrappers.erc20Token.transferFromAsync( + tokenAddress, fromAddress, toAddress, senderAddress, @@ -120,11 +123,11 @@ describe('TokenWrapper', () => { const fromAddress = coinbase; const transferAmount = new BigNumber(42); - await contractWrappers.token.setAllowanceAsync(token.address, fromAddress, toAddress, transferAmount); + await contractWrappers.erc20Token.setAllowanceAsync(tokenAddress, fromAddress, toAddress, transferAmount); return expect( - contractWrappers.token.transferFromAsync( - token.address, + contractWrappers.erc20Token.transferFromAsync( + tokenAddress, fromAddress, toAddress, senderAddress, @@ -136,20 +139,25 @@ describe('TokenWrapper', () => { const fromAddress = addressWithoutFunds; const transferAmount = new BigNumber(42); - const fromAddressBalance = await contractWrappers.token.getBalanceAsync(token.address, fromAddress); + const fromAddressBalance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, fromAddress); expect(fromAddressBalance).to.be.bignumber.equal(0); - await contractWrappers.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount); - const fromAddressAllowance = await contractWrappers.token.getAllowanceAsync( - token.address, + await contractWrappers.erc20Token.setAllowanceAsync( + tokenAddress, + fromAddress, + senderAddress, + transferAmount, + ); + const fromAddressAllowance = await contractWrappers.erc20Token.getAllowanceAsync( + tokenAddress, fromAddress, senderAddress, ); expect(fromAddressAllowance).to.be.bignumber.equal(transferAmount); return expect( - contractWrappers.token.transferFromAsync( - token.address, + contractWrappers.erc20Token.transferFromAsync( + tokenAddress, fromAddress, toAddress, senderAddress, @@ -160,42 +168,47 @@ describe('TokenWrapper', () => { it('should successfully transfer tokens', async () => { const fromAddress = coinbase; - const preBalance = await contractWrappers.token.getBalanceAsync(token.address, toAddress); + const preBalance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, toAddress); expect(preBalance).to.be.bignumber.equal(0); const transferAmount = new BigNumber(42); - await contractWrappers.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount); + await contractWrappers.erc20Token.setAllowanceAsync( + tokenAddress, + fromAddress, + senderAddress, + transferAmount, + ); - await contractWrappers.token.transferFromAsync( - token.address, + await contractWrappers.erc20Token.transferFromAsync( + tokenAddress, fromAddress, toAddress, senderAddress, transferAmount, ); - const postBalance = await contractWrappers.token.getBalanceAsync(token.address, toAddress); + const postBalance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, toAddress); return expect(postBalance).to.be.bignumber.equal(transferAmount); }); it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => { const fromAddress = coinbase; const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065'; return expect( - contractWrappers.token.transferFromAsync( + contractWrappers.erc20Token.transferFromAsync( nonExistentTokenAddress, fromAddress, toAddress, senderAddress, new BigNumber(42), ), - ).to.be.rejectedWith(ContractWrappersError.TokenContractDoesNotExist); + ).to.be.rejectedWith(ContractWrappersError.ERC20TokenContractDoesNotExist); }); }); describe('#getBalanceAsync', () => { describe('With provider with accounts', () => { it('should return the balance for an existing ERC20 token', async () => { - const token = tokens[0]; + const tokenAddress = tokens[0]; const ownerAddress = coinbase; - const balance = await contractWrappers.token.getBalanceAsync(token.address, ownerAddress); + const balance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, ownerAddress); const expectedBalance = new BigNumber('1000000000000000000000000000'); return expect(balance).to.be.bignumber.equal(expectedBalance); }); @@ -203,13 +216,13 @@ describe('TokenWrapper', () => { const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065'; const ownerAddress = coinbase; return expect( - contractWrappers.token.getBalanceAsync(nonExistentTokenAddress, ownerAddress), - ).to.be.rejectedWith(ContractWrappersError.TokenContractDoesNotExist); + contractWrappers.erc20Token.getBalanceAsync(nonExistentTokenAddress, ownerAddress), + ).to.be.rejectedWith(ContractWrappersError.ERC20TokenContractDoesNotExist); }); it('should return a balance of 0 for a non-existent owner address', async () => { - const token = tokens[0]; + const tokenAddress = tokens[0]; const nonExistentOwner = '0x198c6ad858f213fb31b6fe809e25040e6b964593'; - const balance = await contractWrappers.token.getBalanceAsync(token.address, nonExistentOwner); + const balance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, nonExistentOwner); const expectedBalance = new BigNumber(0); return expect(balance).to.be.bignumber.equal(expectedBalance); }); @@ -221,9 +234,12 @@ describe('TokenWrapper', () => { zeroExContractWithoutAccounts = new ContractWrappers(emptyWalletProvider, config); }); it('should return balance even when called with provider instance without addresses', async () => { - const token = tokens[0]; + const tokenAddress = tokens[0]; const ownerAddress = coinbase; - const balance = await zeroExContractWithoutAccounts.token.getBalanceAsync(token.address, ownerAddress); + const balance = await zeroExContractWithoutAccounts.erc20Token.getBalanceAsync( + tokenAddress, + ownerAddress, + ); const expectedBalance = new BigNumber('1000000000000000000000000000'); return expect(balance).to.be.bignumber.equal(expectedBalance); }); @@ -231,12 +247,12 @@ describe('TokenWrapper', () => { }); describe('#setAllowanceAsync', () => { it("should set the spender's allowance", async () => { - const token = tokens[0]; + const tokenAddress = tokens[0]; const ownerAddress = coinbase; const spenderAddress = addressWithoutFunds; - const allowanceBeforeSet = await contractWrappers.token.getAllowanceAsync( - token.address, + const allowanceBeforeSet = await contractWrappers.erc20Token.getAllowanceAsync( + tokenAddress, ownerAddress, spenderAddress, ); @@ -244,15 +260,15 @@ describe('TokenWrapper', () => { expect(allowanceBeforeSet).to.be.bignumber.equal(expectedAllowanceBeforeAllowanceSet); const amountInBaseUnits = new BigNumber(50); - await contractWrappers.token.setAllowanceAsync( - token.address, + await contractWrappers.erc20Token.setAllowanceAsync( + tokenAddress, ownerAddress, spenderAddress, amountInBaseUnits, ); - const allowanceAfterSet = await contractWrappers.token.getAllowanceAsync( - token.address, + const allowanceAfterSet = await contractWrappers.erc20Token.getAllowanceAsync( + tokenAddress, ownerAddress, spenderAddress, ); @@ -262,44 +278,50 @@ describe('TokenWrapper', () => { }); describe('#setUnlimitedAllowanceAsync', () => { it("should set the unlimited spender's allowance", async () => { - const token = tokens[0]; + const tokenAddress = tokens[0]; const ownerAddress = coinbase; const spenderAddress = addressWithoutFunds; - await contractWrappers.token.setUnlimitedAllowanceAsync(token.address, ownerAddress, spenderAddress); - const allowance = await contractWrappers.token.getAllowanceAsync( - token.address, + await contractWrappers.erc20Token.setUnlimitedAllowanceAsync(tokenAddress, ownerAddress, spenderAddress); + const allowance = await contractWrappers.erc20Token.getAllowanceAsync( + tokenAddress, ownerAddress, spenderAddress, ); - return expect(allowance).to.be.bignumber.equal(contractWrappers.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS); + return expect(allowance).to.be.bignumber.equal( + contractWrappers.erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, + ); }); it('should reduce the gas cost for transfers including tokens with unlimited allowance support', async () => { const transferAmount = new BigNumber(5); - const zrx = tokenUtils.getProtocolTokenOrThrow(); + const zrxAddress = tokenUtils.getProtocolTokenAddress(); const [, userWithNormalAllowance, userWithUnlimitedAllowance] = userAddresses; - await contractWrappers.token.setAllowanceAsync( - zrx.address, + await contractWrappers.erc20Token.setAllowanceAsync( + zrxAddress, coinbase, userWithNormalAllowance, transferAmount, ); - await contractWrappers.token.setUnlimitedAllowanceAsync(zrx.address, coinbase, userWithUnlimitedAllowance); + await contractWrappers.erc20Token.setUnlimitedAllowanceAsync( + zrxAddress, + coinbase, + userWithUnlimitedAllowance, + ); const initBalanceWithNormalAllowance = await web3Wrapper.getBalanceInWeiAsync(userWithNormalAllowance); const initBalanceWithUnlimitedAllowance = await web3Wrapper.getBalanceInWeiAsync( userWithUnlimitedAllowance, ); - await contractWrappers.token.transferFromAsync( - zrx.address, + await contractWrappers.erc20Token.transferFromAsync( + zrxAddress, coinbase, userWithNormalAllowance, userWithNormalAllowance, transferAmount, ); - await contractWrappers.token.transferFromAsync( - zrx.address, + await contractWrappers.erc20Token.transferFromAsync( + zrxAddress, coinbase, userWithUnlimitedAllowance, userWithUnlimitedAllowance, @@ -323,20 +345,20 @@ describe('TokenWrapper', () => { describe('#getAllowanceAsync', () => { describe('With provider with accounts', () => { it('should get the proxy allowance', async () => { - const token = tokens[0]; + const tokenAddress = tokens[0]; const ownerAddress = coinbase; const spenderAddress = addressWithoutFunds; const amountInBaseUnits = new BigNumber(50); - await contractWrappers.token.setAllowanceAsync( - token.address, + await contractWrappers.erc20Token.setAllowanceAsync( + tokenAddress, ownerAddress, spenderAddress, amountInBaseUnits, ); - const allowance = await contractWrappers.token.getAllowanceAsync( - token.address, + const allowance = await contractWrappers.erc20Token.getAllowanceAsync( + tokenAddress, ownerAddress, spenderAddress, ); @@ -344,11 +366,11 @@ describe('TokenWrapper', () => { return expect(allowance).to.be.bignumber.equal(expectedAllowance); }); it('should return 0 if no allowance set yet', async () => { - const token = tokens[0]; + const tokenAddress = tokens[0]; const ownerAddress = coinbase; const spenderAddress = addressWithoutFunds; - const allowance = await contractWrappers.token.getAllowanceAsync( - token.address, + const allowance = await contractWrappers.erc20Token.getAllowanceAsync( + tokenAddress, ownerAddress, spenderAddress, ); @@ -363,20 +385,20 @@ describe('TokenWrapper', () => { zeroExContractWithoutAccounts = new ContractWrappers(emptyWalletProvider, config); }); it('should get the proxy allowance', async () => { - const token = tokens[0]; + const tokenAddress = tokens[0]; const ownerAddress = coinbase; const spenderAddress = addressWithoutFunds; const amountInBaseUnits = new BigNumber(50); - await contractWrappers.token.setAllowanceAsync( - token.address, + await contractWrappers.erc20Token.setAllowanceAsync( + tokenAddress, ownerAddress, spenderAddress, amountInBaseUnits, ); - const allowance = await zeroExContractWithoutAccounts.token.getAllowanceAsync( - token.address, + const allowance = await zeroExContractWithoutAccounts.erc20Token.getAllowanceAsync( + tokenAddress, ownerAddress, spenderAddress, ); @@ -387,42 +409,50 @@ describe('TokenWrapper', () => { }); describe('#getProxyAllowanceAsync', () => { it('should get the proxy allowance', async () => { - const token = tokens[0]; + const tokenAddress = tokens[0]; const ownerAddress = coinbase; const amountInBaseUnits = new BigNumber(50); - await contractWrappers.token.setProxyAllowanceAsync(token.address, ownerAddress, amountInBaseUnits); + await contractWrappers.erc20Token.setProxyAllowanceAsync(tokenAddress, ownerAddress, amountInBaseUnits); - const allowance = await contractWrappers.token.getProxyAllowanceAsync(token.address, ownerAddress); + const allowance = await contractWrappers.erc20Token.getProxyAllowanceAsync(tokenAddress, ownerAddress); const expectedAllowance = amountInBaseUnits; return expect(allowance).to.be.bignumber.equal(expectedAllowance); }); }); describe('#setProxyAllowanceAsync', () => { it('should set the proxy allowance', async () => { - const token = tokens[0]; + const tokenAddress = tokens[0]; const ownerAddress = coinbase; - const allowanceBeforeSet = await contractWrappers.token.getProxyAllowanceAsync(token.address, ownerAddress); + const allowanceBeforeSet = await contractWrappers.erc20Token.getProxyAllowanceAsync( + tokenAddress, + ownerAddress, + ); const expectedAllowanceBeforeAllowanceSet = new BigNumber(0); expect(allowanceBeforeSet).to.be.bignumber.equal(expectedAllowanceBeforeAllowanceSet); const amountInBaseUnits = new BigNumber(50); - await contractWrappers.token.setProxyAllowanceAsync(token.address, ownerAddress, amountInBaseUnits); + await contractWrappers.erc20Token.setProxyAllowanceAsync(tokenAddress, ownerAddress, amountInBaseUnits); - const allowanceAfterSet = await contractWrappers.token.getProxyAllowanceAsync(token.address, ownerAddress); + const allowanceAfterSet = await contractWrappers.erc20Token.getProxyAllowanceAsync( + tokenAddress, + ownerAddress, + ); const expectedAllowanceAfterAllowanceSet = amountInBaseUnits; return expect(allowanceAfterSet).to.be.bignumber.equal(expectedAllowanceAfterAllowanceSet); }); }); describe('#setUnlimitedProxyAllowanceAsync', () => { it('should set the unlimited proxy allowance', async () => { - const token = tokens[0]; + const tokenAddress = tokens[0]; const ownerAddress = coinbase; - await contractWrappers.token.setUnlimitedProxyAllowanceAsync(token.address, ownerAddress); - const allowance = await contractWrappers.token.getProxyAllowanceAsync(token.address, ownerAddress); - return expect(allowance).to.be.bignumber.equal(contractWrappers.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS); + await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(tokenAddress, ownerAddress); + const allowance = await contractWrappers.erc20Token.getProxyAllowanceAsync(tokenAddress, ownerAddress); + return expect(allowance).to.be.bignumber.equal( + contractWrappers.erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, + ); }); }); describe('#subscribe', () => { @@ -431,11 +461,10 @@ describe('TokenWrapper', () => { const transferAmount = new BigNumber(42); const allowanceAmount = new BigNumber(42); before(() => { - const token = tokens[0]; - tokenAddress = token.address; + tokenAddress = tokens[0]; }); afterEach(() => { - contractWrappers.token.unsubscribeAll(); + contractWrappers.erc20Token.unsubscribeAll(); }); // Hack: Mocha does not allow a test to be both async and have a `done` callback // Since we need to await the receipt of the event in the `subscribe` callback, @@ -445,7 +474,7 @@ describe('TokenWrapper', () => { it('Should receive the Transfer event when tokens are transfered', (done: DoneCallback) => { (async () => { const callback = callbackErrorReporter.reportNodeCallbackErrors(done)( - (logEvent: DecodedLogEvent<TransferContractEventArgs>) => { + (logEvent: DecodedLogEvent<ERC20TokenTransferEventArgs>) => { expect(logEvent.isRemoved).to.be.false(); expect(logEvent.log.logIndex).to.be.equal(0); expect(logEvent.log.transactionIndex).to.be.equal(0); @@ -456,14 +485,24 @@ describe('TokenWrapper', () => { expect(args._value).to.be.bignumber.equal(transferAmount); }, ); - contractWrappers.token.subscribe(tokenAddress, TokenEvents.Transfer, indexFilterValues, callback); - await contractWrappers.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount); + contractWrappers.erc20Token.subscribe( + tokenAddress, + ERC20TokenEvents.Transfer, + indexFilterValues, + callback, + ); + await contractWrappers.erc20Token.transferAsync( + tokenAddress, + coinbase, + addressWithoutFunds, + transferAmount, + ); })().catch(done); }); it('Should receive the Approval event when allowance is being set', (done: DoneCallback) => { (async () => { const callback = callbackErrorReporter.reportNodeCallbackErrors(done)( - (logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { + (logEvent: DecodedLogEvent<ERC20TokenApprovalEventArgs>) => { expect(logEvent).to.not.be.undefined(); expect(logEvent.isRemoved).to.be.false(); const args = logEvent.log.args; @@ -472,8 +511,13 @@ describe('TokenWrapper', () => { expect(args._value).to.be.bignumber.equal(allowanceAmount); }, ); - contractWrappers.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback); - await contractWrappers.token.setAllowanceAsync( + contractWrappers.erc20Token.subscribe( + tokenAddress, + ERC20TokenEvents.Approval, + indexFilterValues, + callback, + ); + await contractWrappers.erc20Token.setAllowanceAsync( tokenAddress, coinbase, addressWithoutFunds, @@ -484,42 +528,52 @@ describe('TokenWrapper', () => { it('Outstanding subscriptions are cancelled when contractWrappers.setProvider called', (done: DoneCallback) => { (async () => { const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)( - (_logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { + (_logEvent: DecodedLogEvent<ERC20TokenApprovalEventArgs>) => { done(new Error('Expected this subscription to have been cancelled')); }, ); - contractWrappers.token.subscribe( + contractWrappers.erc20Token.subscribe( tokenAddress, - TokenEvents.Transfer, + ERC20TokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled, ); const callbackToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)(); contractWrappers.setProvider(provider, constants.TESTRPC_NETWORK_ID); - contractWrappers.token.subscribe( + contractWrappers.erc20Token.subscribe( tokenAddress, - TokenEvents.Transfer, + ERC20TokenEvents.Transfer, indexFilterValues, callbackToBeCalled, ); - await contractWrappers.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount); + await contractWrappers.erc20Token.transferAsync( + tokenAddress, + coinbase, + addressWithoutFunds, + transferAmount, + ); })().catch(done); }); it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => { (async () => { const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)( - (_logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { + (_logEvent: DecodedLogEvent<ERC20TokenApprovalEventArgs>) => { done(new Error('Expected this subscription to have been cancelled')); }, ); - const subscriptionToken = contractWrappers.token.subscribe( + const subscriptionToken = contractWrappers.erc20Token.subscribe( tokenAddress, - TokenEvents.Transfer, + ERC20TokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled, ); - contractWrappers.token.unsubscribe(subscriptionToken); - await contractWrappers.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount); + contractWrappers.erc20Token.unsubscribe(subscriptionToken); + await contractWrappers.erc20Token.transferAsync( + tokenAddress, + coinbase, + addressWithoutFunds, + transferAmount, + ); done(); })().catch(done); }); @@ -533,16 +587,15 @@ describe('TokenWrapper', () => { }; let txHash: string; before(() => { - const token = tokens[0]; - tokenAddress = token.address; - tokenTransferProxyAddress = contractWrappers.proxy.getContractAddress(); + tokenAddress = tokens[0]; + tokenTransferProxyAddress = contractWrappers.erc20Proxy.getContractAddress(); }); it('should get logs with decoded args emitted by Approval', async () => { - txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - const eventName = TokenEvents.Approval; + txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const eventName = ERC20TokenEvents.Approval; const indexFilterValues = {}; - const logs = await contractWrappers.token.getLogsAsync<ApprovalContractEventArgs>( + const logs = await contractWrappers.erc20Token.getLogsAsync<ERC20TokenApprovalEventArgs>( tokenAddress, eventName, blockRange, @@ -553,14 +606,14 @@ describe('TokenWrapper', () => { expect(logs[0].event).to.be.equal(eventName); expect(args._owner).to.be.equal(coinbase); expect(args._spender).to.be.equal(tokenTransferProxyAddress); - expect(args._value).to.be.bignumber.equal(contractWrappers.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS); + expect(args._value).to.be.bignumber.equal(contractWrappers.erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS); }); it('should only get the logs with the correct event name', async () => { - txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - const differentEventName = TokenEvents.Transfer; + txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const differentEventName = ERC20TokenEvents.Transfer; const indexFilterValues = {}; - const logs = await contractWrappers.token.getLogsAsync( + const logs = await contractWrappers.erc20Token.getLogsAsync( tokenAddress, differentEventName, blockRange, @@ -569,15 +622,18 @@ describe('TokenWrapper', () => { expect(logs).to.have.length(0); }); it('should only get the logs with the correct indexed fields', async () => { - txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(tokenAddress, addressWithoutFunds); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - const eventName = TokenEvents.Approval; + txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync( + tokenAddress, + addressWithoutFunds, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const eventName = ERC20TokenEvents.Approval; const indexFilterValues = { _owner: coinbase, }; - const logs = await contractWrappers.token.getLogsAsync<ApprovalContractEventArgs>( + const logs = await contractWrappers.erc20Token.getLogsAsync<ERC20TokenApprovalEventArgs>( tokenAddress, eventName, blockRange, diff --git a/packages/contract-wrappers/test/erc721_proxy_wrapper_test.ts b/packages/contract-wrappers/test/erc721_proxy_wrapper_test.ts new file mode 100644 index 000000000..9473d930b --- /dev/null +++ b/packages/contract-wrappers/test/erc721_proxy_wrapper_test.ts @@ -0,0 +1,35 @@ +import * as chai from 'chai'; + +import { ContractWrappers } from '../src'; + +import { chaiSetup } from './utils/chai_setup'; +import { constants } from './utils/constants'; +import { provider } from './utils/web3_wrapper'; + +chaiSetup.configure(); +const expect = chai.expect; + +describe('ERC721ProxyWrapper', () => { + let contractWrappers: ContractWrappers; + const config = { + networkId: constants.TESTRPC_NETWORK_ID, + }; + before(async () => { + contractWrappers = new ContractWrappers(provider, config); + }); + describe('#isAuthorizedAsync', () => { + it('should return false if the address is not authorized', async () => { + const isAuthorized = await contractWrappers.erc721Proxy.isAuthorizedAsync(constants.NULL_ADDRESS); + expect(isAuthorized).to.be.false(); + }); + }); + describe('#getAuthorizedAddressesAsync', () => { + it('should return the list of authorized addresses', async () => { + const authorizedAddresses = await contractWrappers.erc721Proxy.getAuthorizedAddressesAsync(); + for (const authorizedAddress of authorizedAddresses) { + const isAuthorized = await contractWrappers.erc721Proxy.isAuthorizedAsync(authorizedAddress); + expect(isAuthorized).to.be.true(); + } + }); + }); +}); diff --git a/packages/contract-wrappers/test/erc721_wrapper_test.ts b/packages/contract-wrappers/test/erc721_wrapper_test.ts new file mode 100644 index 000000000..96b8fcf1d --- /dev/null +++ b/packages/contract-wrappers/test/erc721_wrapper_test.ts @@ -0,0 +1,472 @@ +import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils'; +import { EmptyWalletSubprovider } from '@0xproject/subproviders'; +import { DoneCallback } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; +import * as chai from 'chai'; +import { Provider } from 'ethereum-types'; +import 'mocha'; +import Web3ProviderEngine = require('web3-provider-engine'); + +import { + BlockParamLiteral, + BlockRange, + ContractWrappers, + ContractWrappersError, + DecodedLogEvent, + ERC721TokenApprovalEventArgs, + ERC721TokenApprovalForAllEventArgs, + ERC721TokenEvents, + ERC721TokenTransferEventArgs, +} from '../src'; + +import { chaiSetup } from './utils/chai_setup'; +import { constants } from './utils/constants'; +import { tokenUtils } from './utils/token_utils'; +import { provider, web3Wrapper } from './utils/web3_wrapper'; + +chaiSetup.configure(); +const expect = chai.expect; +const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); + +describe('ERC721Wrapper', () => { + let contractWrappers: ContractWrappers; + let userAddresses: string[]; + let tokens: string[]; + let ownerAddress: string; + let tokenAddress: string; + let anotherOwnerAddress: string; + let operatorAddress: string; + let approvedAddress: string; + let receiverAddress: string; + const config = { + networkId: constants.TESTRPC_NETWORK_ID, + }; + before(async () => { + contractWrappers = new ContractWrappers(provider, config); + userAddresses = await web3Wrapper.getAvailableAddressesAsync(); + tokens = tokenUtils.getDummyERC721TokenAddresses(); + tokenAddress = tokens[0]; + [ownerAddress, operatorAddress, anotherOwnerAddress, approvedAddress, receiverAddress] = userAddresses; + }); + beforeEach(async () => { + await blockchainLifecycle.startAsync(); + }); + afterEach(async () => { + await blockchainLifecycle.revertAsync(); + }); + describe('#transferFromAsync', () => { + it('should fail to transfer NFT if fromAddress has no approvals set', async () => { + const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); + return expect( + contractWrappers.erc721Token.transferFromAsync(tokenAddress, receiverAddress, approvedAddress, tokenId), + ).to.be.rejectedWith(ContractWrappersError.ERC721NoApproval); + }); + it('should successfully transfer tokens when sender is an approved address', async () => { + const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); + let txHash = await contractWrappers.erc721Token.setApprovalAsync(tokenAddress, approvedAddress, tokenId); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const owner = await contractWrappers.erc721Token.getOwnerOfAsync(tokenAddress, tokenId); + expect(owner).to.be.equal(ownerAddress); + txHash = await contractWrappers.erc721Token.transferFromAsync( + tokenAddress, + receiverAddress, + approvedAddress, + tokenId, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const newOwner = await contractWrappers.erc721Token.getOwnerOfAsync(tokenAddress, tokenId); + expect(newOwner).to.be.equal(receiverAddress); + }); + it('should successfully transfer tokens when sender is an approved operator', async () => { + const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); + const isApprovedForAll = true; + let txHash = await contractWrappers.erc721Token.setApprovalForAllAsync( + tokenAddress, + ownerAddress, + operatorAddress, + isApprovedForAll, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const owner = await contractWrappers.erc721Token.getOwnerOfAsync(tokenAddress, tokenId); + expect(owner).to.be.equal(ownerAddress); + txHash = await contractWrappers.erc721Token.transferFromAsync( + tokenAddress, + receiverAddress, + operatorAddress, + tokenId, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const newOwner = await contractWrappers.erc721Token.getOwnerOfAsync(tokenAddress, tokenId); + expect(newOwner).to.be.equal(receiverAddress); + }); + }); + describe('#getTokenCountAsync', () => { + describe('With provider with accounts', () => { + it('should return the count for an existing ERC721 token', async () => { + let tokenCount = await contractWrappers.erc721Token.getTokenCountAsync(tokenAddress, ownerAddress); + expect(tokenCount).to.be.bignumber.equal(0); + await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); + tokenCount = await contractWrappers.erc721Token.getTokenCountAsync(tokenAddress, ownerAddress); + expect(tokenCount).to.be.bignumber.equal(1); + }); + it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => { + const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065'; + return expect( + contractWrappers.erc721Token.getTokenCountAsync(nonExistentTokenAddress, ownerAddress), + ).to.be.rejectedWith(ContractWrappersError.ERC721TokenContractDoesNotExist); + }); + it('should return a balance of 0 for a non-existent owner address', async () => { + const nonExistentOwner = '0x198c6ad858f213fb31b6fe809e25040e6b964593'; + const balance = await contractWrappers.erc721Token.getTokenCountAsync(tokenAddress, nonExistentOwner); + const expectedBalance = new BigNumber(0); + return expect(balance).to.be.bignumber.equal(expectedBalance); + }); + }); + describe('With provider without accounts', () => { + let zeroExContractWithoutAccounts: ContractWrappers; + before(async () => { + const emptyWalletProvider = addEmptyWalletSubprovider(provider); + zeroExContractWithoutAccounts = new ContractWrappers(emptyWalletProvider, config); + }); + it('should return balance even when called with provider instance without addresses', async () => { + const balance = await zeroExContractWithoutAccounts.erc721Token.getTokenCountAsync( + tokenAddress, + ownerAddress, + ); + return expect(balance).to.be.bignumber.equal(0); + }); + }); + }); + describe('#getOwnerOfAsync', () => { + it('should return the owner for an existing ERC721 token', async () => { + const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); + const tokenOwner = await contractWrappers.erc721Token.getOwnerOfAsync(tokenAddress, tokenId); + expect(tokenOwner).to.be.bignumber.equal(ownerAddress); + }); + it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => { + const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065'; + const fakeTokenId = new BigNumber(42); + return expect( + contractWrappers.erc721Token.getOwnerOfAsync(nonExistentTokenAddress, fakeTokenId), + ).to.be.rejectedWith(ContractWrappersError.ERC721TokenContractDoesNotExist); + }); + it('should return undefined not 0 for a non-existent ERC721', async () => { + const fakeTokenId = new BigNumber(42); + return expect(contractWrappers.erc721Token.getOwnerOfAsync(tokenAddress, fakeTokenId)).to.be.rejectedWith( + ContractWrappersError.ERC721OwnerNotFound, + ); + }); + }); + describe('#setApprovalForAllAsync/isApprovedForAllAsync', () => { + it('should check if operator address is approved', async () => { + let isApprovedForAll = await contractWrappers.erc721Token.isApprovedForAllAsync( + tokenAddress, + ownerAddress, + operatorAddress, + ); + expect(isApprovedForAll).to.be.false(); + // set + isApprovedForAll = true; + let txHash = await contractWrappers.erc721Token.setApprovalForAllAsync( + tokenAddress, + ownerAddress, + operatorAddress, + isApprovedForAll, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + isApprovedForAll = await contractWrappers.erc721Token.isApprovedForAllAsync( + tokenAddress, + ownerAddress, + operatorAddress, + ); + expect(isApprovedForAll).to.be.true(); + // unset + txHash = await contractWrappers.erc721Token.setApprovalForAllAsync( + tokenAddress, + ownerAddress, + operatorAddress, + false, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + isApprovedForAll = await contractWrappers.erc721Token.isApprovedForAllAsync( + tokenAddress, + ownerAddress, + operatorAddress, + ); + expect(isApprovedForAll).to.be.false(); + }); + }); + describe('#setProxyApprovalForAllAsync/isProxyApprovedForAllAsync', () => { + it('should check if proxy address is approved', async () => { + let isApprovedForAll = true; + const txHash = await contractWrappers.erc721Token.setProxyApprovalForAllAsync( + tokenAddress, + ownerAddress, + isApprovedForAll, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + isApprovedForAll = await contractWrappers.erc721Token.isProxyApprovedForAllAsync( + tokenAddress, + ownerAddress, + ); + expect(isApprovedForAll).to.be.true(); + }); + }); + describe('#setApprovalAsync/getApprovedIfExistsAsync', () => { + it("should set the spender's approval", async () => { + const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); + + const approvalBeforeSet = await contractWrappers.erc721Token.getApprovedIfExistsAsync( + tokenAddress, + tokenId, + ); + expect(approvalBeforeSet).to.be.undefined(); + await contractWrappers.erc721Token.setApprovalAsync(tokenAddress, approvedAddress, tokenId); + const approvalAfterSet = await contractWrappers.erc721Token.getApprovedIfExistsAsync(tokenAddress, tokenId); + expect(approvalAfterSet).to.be.equal(approvedAddress); + }); + }); + describe('#setProxyApprovalAsync/isProxyApprovedAsync', () => { + it('should set the proxy approval', async () => { + const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); + + const approvalBeforeSet = await contractWrappers.erc721Token.isProxyApprovedAsync(tokenAddress, tokenId); + expect(approvalBeforeSet).to.be.false(); + await contractWrappers.erc721Token.setProxyApprovalAsync(tokenAddress, tokenId); + const approvalAfterSet = await contractWrappers.erc721Token.isProxyApprovedAsync(tokenAddress, tokenId); + expect(approvalAfterSet).to.be.true(); + }); + }); + describe('#subscribe', () => { + const indexFilterValues = {}; + afterEach(() => { + contractWrappers.erc721Token.unsubscribeAll(); + }); + // Hack: Mocha does not allow a test to be both async and have a `done` callback + // Since we need to await the receipt of the event in the `subscribe` callback, + // we do need both. A hack is to make the top-level a sync fn w/ a done callback and then + // wrap the rest of the test in an async block + // Source: https://github.com/mochajs/mocha/issues/2407 + it('Should receive the Transfer event when tokens are transfered', (done: DoneCallback) => { + (async () => { + const callback = callbackErrorReporter.reportNodeCallbackErrors(done)( + (logEvent: DecodedLogEvent<ERC721TokenTransferEventArgs>) => { + expect(logEvent.isRemoved).to.be.false(); + expect(logEvent.log.logIndex).to.be.equal(0); + expect(logEvent.log.transactionIndex).to.be.equal(0); + expect(logEvent.log.blockNumber).to.be.a('number'); + const args = logEvent.log.args; + expect(args._from).to.be.equal(ownerAddress); + expect(args._to).to.be.equal(receiverAddress); + expect(args._tokenId).to.be.bignumber.equal(tokenId); + }, + ); + const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); + const isApprovedForAll = true; + await web3Wrapper.awaitTransactionSuccessAsync( + await contractWrappers.erc721Token.setApprovalForAllAsync( + tokenAddress, + ownerAddress, + operatorAddress, + isApprovedForAll, + ), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + contractWrappers.erc721Token.subscribe( + tokenAddress, + ERC721TokenEvents.Transfer, + indexFilterValues, + callback, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await contractWrappers.erc721Token.transferFromAsync( + tokenAddress, + receiverAddress, + operatorAddress, + tokenId, + ), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + })().catch(done); + }); + it('Should receive the Approval event when allowance is being set', (done: DoneCallback) => { + (async () => { + const callback = callbackErrorReporter.reportNodeCallbackErrors(done)( + (logEvent: DecodedLogEvent<ERC721TokenApprovalEventArgs>) => { + expect(logEvent).to.not.be.undefined(); + expect(logEvent.isRemoved).to.be.false(); + const args = logEvent.log.args; + expect(args._owner).to.be.equal(ownerAddress); + expect(args._approved).to.be.equal(approvedAddress); + expect(args._tokenId).to.be.bignumber.equal(tokenId); + }, + ); + contractWrappers.erc721Token.subscribe( + tokenAddress, + ERC721TokenEvents.Approval, + indexFilterValues, + callback, + ); + const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); + await web3Wrapper.awaitTransactionSuccessAsync( + await contractWrappers.erc721Token.setApprovalAsync(tokenAddress, approvedAddress, tokenId), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + })().catch(done); + }); + it('Outstanding subscriptions are cancelled when contractWrappers.setProvider called', (done: DoneCallback) => { + (async () => { + const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)( + (logEvent: DecodedLogEvent<ERC721TokenApprovalEventArgs>) => { + done(new Error('Expected this subscription to have been cancelled')); + }, + ); + contractWrappers.erc721Token.subscribe( + tokenAddress, + ERC721TokenEvents.Transfer, + indexFilterValues, + callbackNeverToBeCalled, + ); + const callbackToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)(); + contractWrappers.setProvider(provider, constants.TESTRPC_NETWORK_ID); + contractWrappers.erc721Token.subscribe( + tokenAddress, + ERC721TokenEvents.Approval, + indexFilterValues, + callbackToBeCalled, + ); + const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); + await web3Wrapper.awaitTransactionSuccessAsync( + await contractWrappers.erc721Token.setApprovalAsync(tokenAddress, approvedAddress, tokenId), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + done(); + })().catch(done); + }); + it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => { + (async () => { + const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)( + (logEvent: DecodedLogEvent<ERC721TokenApprovalForAllEventArgs>) => { + done(new Error('Expected this subscription to have been cancelled')); + }, + ); + const subscriptionToken = contractWrappers.erc721Token.subscribe( + tokenAddress, + ERC721TokenEvents.ApprovalForAll, + indexFilterValues, + callbackNeverToBeCalled, + ); + contractWrappers.erc721Token.unsubscribe(subscriptionToken); + + const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); + const isApproved = true; + await web3Wrapper.awaitTransactionSuccessAsync( + await contractWrappers.erc721Token.setApprovalForAllAsync( + tokenAddress, + ownerAddress, + operatorAddress, + isApproved, + ), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + done(); + })().catch(done); + }); + }); + describe('#getLogsAsync', () => { + let tokenTransferProxyAddress: string; + const blockRange: BlockRange = { + fromBlock: 0, + toBlock: BlockParamLiteral.Latest, + }; + let txHash: string; + before(() => { + tokenTransferProxyAddress = contractWrappers.erc721Proxy.getContractAddress(); + }); + it('should get logs with decoded args emitted by ApprovalForAll', async () => { + const isApprovedForAll = true; + txHash = await contractWrappers.erc721Token.setApprovalForAllAsync( + tokenAddress, + ownerAddress, + operatorAddress, + isApprovedForAll, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const eventName = ERC721TokenEvents.ApprovalForAll; + const indexFilterValues = {}; + const logs = await contractWrappers.erc721Token.getLogsAsync<ERC721TokenApprovalForAllEventArgs>( + tokenAddress, + eventName, + blockRange, + indexFilterValues, + ); + expect(logs).to.have.length(1); + const args = logs[0].args; + expect(logs[0].event).to.be.equal(eventName); + expect(args._owner).to.be.equal(ownerAddress); + expect(args._operator).to.be.equal(operatorAddress); + expect(args._approved).to.be.equal(isApprovedForAll); + }); + it('should only get the logs with the correct event name', async () => { + const isApprovedForAll = true; + txHash = await contractWrappers.erc721Token.setApprovalForAllAsync( + tokenAddress, + ownerAddress, + operatorAddress, + isApprovedForAll, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const differentEventName = ERC721TokenEvents.Transfer; + const indexFilterValues = {}; + const logs = await contractWrappers.erc721Token.getLogsAsync( + tokenAddress, + differentEventName, + blockRange, + indexFilterValues, + ); + expect(logs).to.have.length(0); + }); + it('should only get the logs with the correct indexed fields', async () => { + const isApprovedForAll = true; + txHash = await contractWrappers.erc721Token.setApprovalForAllAsync( + tokenAddress, + ownerAddress, + operatorAddress, + isApprovedForAll, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + txHash = await contractWrappers.erc721Token.setApprovalForAllAsync( + tokenAddress, + anotherOwnerAddress, + operatorAddress, + isApprovedForAll, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const eventName = ERC721TokenEvents.ApprovalForAll; + const indexFilterValues = { + _owner: anotherOwnerAddress, + }; + const logs = await contractWrappers.erc721Token.getLogsAsync<ERC721TokenApprovalForAllEventArgs>( + tokenAddress, + eventName, + blockRange, + indexFilterValues, + ); + expect(logs).to.have.length(1); + const args = logs[0].args; + expect(args._owner).to.be.equal(anotherOwnerAddress); + }); + }); +}); +// tslint:disable:max-file-line-count + +function addEmptyWalletSubprovider(p: Provider): Provider { + const providerEngine = new Web3ProviderEngine(); + providerEngine.addProvider(new EmptyWalletSubprovider()); + const currentSubproviders = (p as any)._providers; + for (const subprovider of currentSubproviders) { + providerEngine.addProvider(subprovider); + } + providerEngine.start(); + return providerEngine; +} diff --git a/packages/contract-wrappers/test/ether_token_wrapper_test.ts b/packages/contract-wrappers/test/ether_token_wrapper_test.ts index f401ef90a..0a860884a 100644 --- a/packages/contract-wrappers/test/ether_token_wrapper_test.ts +++ b/packages/contract-wrappers/test/ether_token_wrapper_test.ts @@ -6,22 +6,21 @@ import * as chai from 'chai'; import 'mocha'; import { - ApprovalContractEventArgs, BlockParamLiteral, BlockRange, ContractWrappers, ContractWrappersError, DecodedLogEvent, - DepositContractEventArgs, - EtherTokenEvents, - Token, - TransferContractEventArgs, - WithdrawalContractEventArgs, + WETH9ApprovalEventArgs, + WETH9DepositEventArgs, + WETH9Events, + WETH9TransferEventArgs, + WETH9WithdrawalEventArgs, } from '../src'; import { chaiSetup } from './utils/chai_setup'; import { constants } from './utils/constants'; -import { TokenUtils } from './utils/token_utils'; +import { tokenUtils } from './utils/token_utils'; import { provider, web3Wrapper } from './utils/web3_wrapper'; chaiSetup.configure(); @@ -36,7 +35,6 @@ const MAX_REASONABLE_GAS_COST_IN_WEI = 62517; describe('EtherTokenWrapper', () => { let contractWrappers: ContractWrappers; - let tokens: Token[]; let userAddresses: string[]; let addressWithETH: string; let wethContractAddress: string; @@ -54,7 +52,6 @@ describe('EtherTokenWrapper', () => { const withdrawalAmount = new BigNumber(42); before(async () => { contractWrappers = new ContractWrappers(provider, zeroExConfig); - tokens = await contractWrappers.tokenRegistry.getTokensAsync(); userAddresses = await web3Wrapper.getAvailableAddressesAsync(); addressWithETH = userAddresses[0]; wethContractAddress = contractWrappers.etherToken.getContractAddressIfExists() as string; @@ -85,7 +82,10 @@ describe('EtherTokenWrapper', () => { describe('#depositAsync', () => { it('should successfully deposit ETH and issue Wrapped ETH tokens', async () => { const preETHBalance = await web3Wrapper.getBalanceInWeiAsync(addressWithETH); - const preWETHBalance = await contractWrappers.token.getBalanceAsync(wethContractAddress, addressWithETH); + const preWETHBalance = await contractWrappers.erc20Token.getBalanceAsync( + wethContractAddress, + addressWithETH, + ); expect(preETHBalance).to.be.bignumber.gt(0); expect(preWETHBalance).to.be.bignumber.equal(0); @@ -94,10 +94,10 @@ describe('EtherTokenWrapper', () => { depositWeiAmount, addressWithETH, ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); const postETHBalanceInWei = await web3Wrapper.getBalanceInWeiAsync(addressWithETH); - const postWETHBalanceInBaseUnits = await contractWrappers.token.getBalanceAsync( + const postWETHBalanceInBaseUnits = await contractWrappers.erc20Token.getBalanceAsync( wethContractAddress, addressWithETH, ); @@ -126,7 +126,10 @@ describe('EtherTokenWrapper', () => { const expectedPreETHBalance = ETHBalanceInWei.minus(depositWeiAmount); const preETHBalance = await web3Wrapper.getBalanceInWeiAsync(addressWithETH); - const preWETHBalance = await contractWrappers.token.getBalanceAsync(wethContractAddress, addressWithETH); + const preWETHBalance = await contractWrappers.erc20Token.getBalanceAsync( + wethContractAddress, + addressWithETH, + ); let gasCost = expectedPreETHBalance.minus(preETHBalance); expect(gasCost).to.be.bignumber.lte(MAX_REASONABLE_GAS_COST_IN_WEI); expect(preWETHBalance).to.be.bignumber.equal(depositWeiAmount); @@ -136,10 +139,10 @@ describe('EtherTokenWrapper', () => { depositWeiAmount, addressWithETH, ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); const postETHBalance = await web3Wrapper.getBalanceInWeiAsync(addressWithETH); - const postWETHBalanceInBaseUnits = await contractWrappers.token.getBalanceAsync( + const postWETHBalanceInBaseUnits = await contractWrappers.erc20Token.getBalanceAsync( wethContractAddress, addressWithETH, ); @@ -150,7 +153,10 @@ describe('EtherTokenWrapper', () => { expect(gasCost).to.be.bignumber.lte(MAX_REASONABLE_GAS_COST_IN_WEI); }); it('should throw if user has insufficient WETH balance for withdrawal', async () => { - const preWETHBalance = await contractWrappers.token.getBalanceAsync(wethContractAddress, addressWithETH); + const preWETHBalance = await contractWrappers.erc20Token.getBalanceAsync( + wethContractAddress, + addressWithETH, + ); expect(preWETHBalance).to.be.bignumber.equal(0); // tslint:disable-next-line:custom-no-magic-numbers @@ -164,10 +170,8 @@ describe('EtherTokenWrapper', () => { describe('#subscribe', () => { const indexFilterValues = {}; let etherTokenAddress: string; - before(() => { - const tokenUtils = new TokenUtils(tokens); - const etherToken = tokenUtils.getWethTokenOrThrow(); - etherTokenAddress = etherToken.address; + before(async () => { + etherTokenAddress = tokenUtils.getWethTokenAddress(); }); afterEach(() => { contractWrappers.etherToken.unsubscribeAll(); @@ -180,7 +184,7 @@ describe('EtherTokenWrapper', () => { it('Should receive the Transfer event when tokens are transfered', (done: DoneCallback) => { (async () => { const callback = callbackErrorReporter.reportNodeCallbackErrors(done)( - (logEvent: DecodedLogEvent<TransferContractEventArgs>) => { + (logEvent: DecodedLogEvent<WETH9TransferEventArgs>) => { expect(logEvent).to.not.be.undefined(); expect(logEvent.isRemoved).to.be.false(); expect(logEvent.log.logIndex).to.be.equal(0); @@ -195,11 +199,11 @@ describe('EtherTokenWrapper', () => { await contractWrappers.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH); contractWrappers.etherToken.subscribe( etherTokenAddress, - EtherTokenEvents.Transfer, + WETH9Events.Transfer, indexFilterValues, callback, ); - await contractWrappers.token.transferAsync( + await contractWrappers.erc20Token.transferAsync( etherTokenAddress, addressWithETH, addressWithoutFunds, @@ -210,7 +214,7 @@ describe('EtherTokenWrapper', () => { it('Should receive the Approval event when allowance is being set', (done: DoneCallback) => { (async () => { const callback = callbackErrorReporter.reportNodeCallbackErrors(done)( - (logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { + (logEvent: DecodedLogEvent<WETH9ApprovalEventArgs>) => { expect(logEvent).to.not.be.undefined(); expect(logEvent.isRemoved).to.be.false(); const args = logEvent.log.args; @@ -221,11 +225,11 @@ describe('EtherTokenWrapper', () => { ); contractWrappers.etherToken.subscribe( etherTokenAddress, - EtherTokenEvents.Approval, + WETH9Events.Approval, indexFilterValues, callback, ); - await contractWrappers.token.setAllowanceAsync( + await contractWrappers.erc20Token.setAllowanceAsync( etherTokenAddress, addressWithETH, addressWithoutFunds, @@ -236,7 +240,7 @@ describe('EtherTokenWrapper', () => { it('Should receive the Deposit event when ether is being deposited', (done: DoneCallback) => { (async () => { const callback = callbackErrorReporter.reportNodeCallbackErrors(done)( - (logEvent: DecodedLogEvent<DepositContractEventArgs>) => { + (logEvent: DecodedLogEvent<WETH9DepositEventArgs>) => { expect(logEvent).to.not.be.undefined(); expect(logEvent.isRemoved).to.be.false(); const args = logEvent.log.args; @@ -246,7 +250,7 @@ describe('EtherTokenWrapper', () => { ); contractWrappers.etherToken.subscribe( etherTokenAddress, - EtherTokenEvents.Deposit, + WETH9Events.Deposit, indexFilterValues, callback, ); @@ -256,7 +260,7 @@ describe('EtherTokenWrapper', () => { it('Should receive the Withdrawal event when ether is being withdrawn', (done: DoneCallback) => { (async () => { const callback = callbackErrorReporter.reportNodeCallbackErrors(done)( - (logEvent: DecodedLogEvent<WithdrawalContractEventArgs>) => { + (logEvent: DecodedLogEvent<WETH9WithdrawalEventArgs>) => { expect(logEvent).to.not.be.undefined(); expect(logEvent.isRemoved).to.be.false(); const args = logEvent.log.args; @@ -267,7 +271,7 @@ describe('EtherTokenWrapper', () => { await contractWrappers.etherToken.depositAsync(etherTokenAddress, depositAmount, addressWithETH); contractWrappers.etherToken.subscribe( etherTokenAddress, - EtherTokenEvents.Withdrawal, + WETH9Events.Withdrawal, indexFilterValues, callback, ); @@ -277,13 +281,13 @@ describe('EtherTokenWrapper', () => { it('should cancel outstanding subscriptions when ZeroEx.setProvider is called', (done: DoneCallback) => { (async () => { const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)( - (_logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { + (_logEvent: DecodedLogEvent<WETH9ApprovalEventArgs>) => { done(new Error('Expected this subscription to have been cancelled')); }, ); contractWrappers.etherToken.subscribe( etherTokenAddress, - EtherTokenEvents.Transfer, + WETH9Events.Transfer, indexFilterValues, callbackNeverToBeCalled, ); @@ -292,11 +296,11 @@ describe('EtherTokenWrapper', () => { await contractWrappers.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH); contractWrappers.etherToken.subscribe( etherTokenAddress, - EtherTokenEvents.Transfer, + WETH9Events.Transfer, indexFilterValues, callbackToBeCalled, ); - await contractWrappers.token.transferAsync( + await contractWrappers.erc20Token.transferAsync( etherTokenAddress, addressWithETH, addressWithoutFunds, @@ -307,19 +311,19 @@ describe('EtherTokenWrapper', () => { it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => { (async () => { const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)( - (_logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { + (_logEvent: DecodedLogEvent<WETH9ApprovalEventArgs>) => { done(new Error('Expected this subscription to have been cancelled')); }, ); await contractWrappers.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH); const subscriptionToken = contractWrappers.etherToken.subscribe( etherTokenAddress, - EtherTokenEvents.Transfer, + WETH9Events.Transfer, indexFilterValues, callbackNeverToBeCalled, ); contractWrappers.etherToken.unsubscribe(subscriptionToken); - await contractWrappers.token.transferAsync( + await contractWrappers.erc20Token.transferAsync( etherTokenAddress, addressWithETH, addressWithoutFunds, @@ -331,7 +335,7 @@ describe('EtherTokenWrapper', () => { }); describe('#getLogsAsync', () => { let etherTokenAddress: string; - let tokenTransferProxyAddress: string; + let erc20ProxyAddress: string; const blockRange: BlockRange = { fromBlock: 0, toBlock: BlockParamLiteral.Latest, @@ -339,17 +343,18 @@ describe('EtherTokenWrapper', () => { let txHash: string; before(() => { addressWithETH = userAddresses[0]; - const tokenUtils = new TokenUtils(tokens); - const etherToken = tokenUtils.getWethTokenOrThrow(); - etherTokenAddress = etherToken.address; - tokenTransferProxyAddress = contractWrappers.proxy.getContractAddress(); + etherTokenAddress = tokenUtils.getWethTokenAddress(); + erc20ProxyAddress = contractWrappers.erc20Proxy.getContractAddress(); }); it('should get logs with decoded args emitted by Approval', async () => { - txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithETH); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - const eventName = EtherTokenEvents.Approval; + txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync( + etherTokenAddress, + addressWithETH, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const eventName = WETH9Events.Approval; const indexFilterValues = {}; - const logs = await contractWrappers.etherToken.getLogsAsync<ApprovalContractEventArgs>( + const logs = await contractWrappers.etherToken.getLogsAsync<WETH9ApprovalEventArgs>( etherTokenAddress, eventName, blockRange, @@ -359,14 +364,14 @@ describe('EtherTokenWrapper', () => { const args = logs[0].args; expect(logs[0].event).to.be.equal(eventName); expect(args._owner).to.be.equal(addressWithETH); - expect(args._spender).to.be.equal(tokenTransferProxyAddress); - expect(args._value).to.be.bignumber.equal(contractWrappers.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS); + expect(args._spender).to.be.equal(erc20ProxyAddress); + expect(args._value).to.be.bignumber.equal(contractWrappers.erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS); }); it('should get logs with decoded args emitted by Deposit', async () => { await contractWrappers.etherToken.depositAsync(etherTokenAddress, depositAmount, addressWithETH); - const eventName = EtherTokenEvents.Deposit; + const eventName = WETH9Events.Deposit; const indexFilterValues = {}; - const logs = await contractWrappers.etherToken.getLogsAsync<DepositContractEventArgs>( + const logs = await contractWrappers.etherToken.getLogsAsync<WETH9DepositEventArgs>( etherTokenAddress, eventName, blockRange, @@ -379,9 +384,12 @@ describe('EtherTokenWrapper', () => { expect(args._value).to.be.bignumber.equal(depositAmount); }); it('should only get the logs with the correct event name', async () => { - txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithETH); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - const differentEventName = EtherTokenEvents.Transfer; + txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync( + etherTokenAddress, + addressWithETH, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const differentEventName = WETH9Events.Transfer; const indexFilterValues = {}; const logs = await contractWrappers.etherToken.getLogsAsync( etherTokenAddress, @@ -392,18 +400,21 @@ describe('EtherTokenWrapper', () => { expect(logs).to.have.length(0); }); it('should only get the logs with the correct indexed fields', async () => { - txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithETH); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync( + txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync( + etherTokenAddress, + addressWithETH, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync( etherTokenAddress, addressWithoutFunds, ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - const eventName = EtherTokenEvents.Approval; + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const eventName = WETH9Events.Approval; const indexFilterValues = { _owner: addressWithETH, }; - const logs = await contractWrappers.etherToken.getLogsAsync<ApprovalContractEventArgs>( + const logs = await contractWrappers.etherToken.getLogsAsync<WETH9ApprovalEventArgs>( etherTokenAddress, eventName, blockRange, diff --git a/packages/contract-wrappers/test/exchange_transfer_simulator_test.ts b/packages/contract-wrappers/test/exchange_transfer_simulator_test.ts deleted file mode 100644 index cbc52df7f..000000000 --- a/packages/contract-wrappers/test/exchange_transfer_simulator_test.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { BlockchainLifecycle } from '@0xproject/dev-utils'; -import { BlockParamLiteral, Token } from '@0xproject/types'; -import { BigNumber } from '@0xproject/utils'; -import * as chai from 'chai'; - -import { ContractWrappers, ExchangeContractErrs } from '../src'; -import { BalanceAndProxyAllowanceLazyStore } from '../src/stores/balance_proxy_allowance_lazy_store'; -import { TradeSide, TransferType } from '../src/types'; -import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator'; - -import { chaiSetup } from './utils/chai_setup'; -import { constants } from './utils/constants'; -import { provider, web3Wrapper } from './utils/web3_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -describe('ExchangeTransferSimulator', () => { - const config = { - networkId: constants.TESTRPC_NETWORK_ID, - }; - const contractWrappers = new ContractWrappers(provider, config); - const transferAmount = new BigNumber(5); - let userAddresses: string[]; - let tokens: Token[]; - let coinbase: string; - let sender: string; - let recipient: string; - let exampleTokenAddress: string; - let exchangeTransferSimulator: ExchangeTransferSimulator; - let txHash: string; - before(async () => { - userAddresses = await web3Wrapper.getAvailableAddressesAsync(); - [coinbase, sender, recipient] = userAddresses; - tokens = await contractWrappers.tokenRegistry.getTokensAsync(); - exampleTokenAddress = tokens[0].address; - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - describe('#transferFromAsync', () => { - beforeEach(() => { - const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore( - contractWrappers.token, - BlockParamLiteral.Latest, - ); - exchangeTransferSimulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore); - }); - it("throws if the user doesn't have enough allowance", async () => { - return expect( - exchangeTransferSimulator.transferFromAsync( - exampleTokenAddress, - sender, - recipient, - transferAmount, - TradeSide.Taker, - TransferType.Trade, - ), - ).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerAllowance); - }); - it("throws if the user doesn't have enough balance", async () => { - txHash = await contractWrappers.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - return expect( - exchangeTransferSimulator.transferFromAsync( - exampleTokenAddress, - sender, - recipient, - transferAmount, - TradeSide.Maker, - TransferType.Trade, - ), - ).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance); - }); - it('updates balances and proxyAllowance after transfer', async () => { - txHash = await contractWrappers.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - txHash = await contractWrappers.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - await exchangeTransferSimulator.transferFromAsync( - exampleTokenAddress, - sender, - recipient, - transferAmount, - TradeSide.Taker, - TransferType.Trade, - ); - const store = (exchangeTransferSimulator as any)._store; - const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender); - const recipientBalance = await store.getBalanceAsync(exampleTokenAddress, recipient); - const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleTokenAddress, sender); - expect(senderBalance).to.be.bignumber.equal(0); - expect(recipientBalance).to.be.bignumber.equal(transferAmount); - expect(senderProxyAllowance).to.be.bignumber.equal(0); - }); - it("doesn't update proxyAllowance after transfer if unlimited", async () => { - txHash = await contractWrappers.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(exampleTokenAddress, sender); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - await exchangeTransferSimulator.transferFromAsync( - exampleTokenAddress, - sender, - recipient, - transferAmount, - TradeSide.Taker, - TransferType.Trade, - ); - const store = (exchangeTransferSimulator as any)._store; - const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender); - const recipientBalance = await store.getBalanceAsync(exampleTokenAddress, recipient); - const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleTokenAddress, sender); - expect(senderBalance).to.be.bignumber.equal(0); - expect(recipientBalance).to.be.bignumber.equal(transferAmount); - expect(senderProxyAllowance).to.be.bignumber.equal( - contractWrappers.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, - ); - }); - }); -}); diff --git a/packages/contract-wrappers/test/exchange_wrapper_test.ts b/packages/contract-wrappers/test/exchange_wrapper_test.ts index c945b4c70..b2c716008 100644 --- a/packages/contract-wrappers/test/exchange_wrapper_test.ts +++ b/packages/contract-wrappers/test/exchange_wrapper_test.ts @@ -1,57 +1,91 @@ import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils'; import { FillScenarios } from '@0xproject/fill-scenarios'; -import { getOrderHashHex } from '@0xproject/order-utils'; -import { BlockParamLiteral, DoneCallback, OrderState } from '@0xproject/types'; +import { assetProxyUtils, orderHashUtils } from '@0xproject/order-utils'; +import { DoneCallback, SignedOrder } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; -import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as chai from 'chai'; +import { BlockParamLiteral } from 'ethereum-types'; import 'mocha'; import { - BlockRange, ContractWrappers, DecodedLogEvent, - ExchangeContractErrs, + ExchangeCancelEventArgs, ExchangeEvents, - LogCancelContractEventArgs, - LogFillContractEventArgs, - OrderCancellationRequest, - OrderFillRequest, - SignedOrder, - Token, + ExchangeFillEventArgs, + OrderStatus, } from '../src'; import { chaiSetup } from './utils/chai_setup'; import { constants } from './utils/constants'; -import { TokenUtils } from './utils/token_utils'; +import { tokenUtils } from './utils/token_utils'; import { provider, web3Wrapper } from './utils/web3_wrapper'; chaiSetup.configure(); const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); -const NON_EXISTENT_ORDER_HASH = '0x79370342234e7acd6bbeac335bd3bb1d368383294b64b8160a00f4060e4d3777'; - describe('ExchangeWrapper', () => { let contractWrappers: ContractWrappers; - let tokenUtils: TokenUtils; - let tokens: Token[]; let userAddresses: string[]; let zrxTokenAddress: string; let fillScenarios: FillScenarios; let exchangeContractAddress: string; + let makerTokenAddress: string; + let takerTokenAddress: string; + let coinbase: string; + let makerAddress: string; + let anotherMakerAddress: string; + let takerAddress: string; + let makerAssetData: string; + let takerAssetData: string; + let feeRecipient: string; + let txHash: string; + const fillableAmount = new BigNumber(5); + const takerTokenFillAmount = new BigNumber(5); + let signedOrder: SignedOrder; + let anotherSignedOrder: SignedOrder; const config = { networkId: constants.TESTRPC_NETWORK_ID, + blockPollingIntervalMs: 0, }; before(async () => { + await blockchainLifecycle.startAsync(); contractWrappers = new ContractWrappers(provider, config); exchangeContractAddress = contractWrappers.exchange.getContractAddress(); + const erc20ProxyAddress = contractWrappers.erc20Proxy.getContractAddress(); userAddresses = await web3Wrapper.getAvailableAddressesAsync(); - tokens = await contractWrappers.tokenRegistry.getTokensAsync(); - tokenUtils = new TokenUtils(tokens); - zrxTokenAddress = tokenUtils.getProtocolTokenOrThrow().address; - fillScenarios = new FillScenarios(provider, userAddresses, tokens, zrxTokenAddress, exchangeContractAddress); - await fillScenarios.initTokenBalancesAsync(); + zrxTokenAddress = tokenUtils.getProtocolTokenAddress(); + fillScenarios = new FillScenarios( + provider, + userAddresses, + zrxTokenAddress, + exchangeContractAddress, + erc20ProxyAddress, + ); + [coinbase, makerAddress, takerAddress, feeRecipient, anotherMakerAddress] = userAddresses; + [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); + [makerAssetData, takerAssetData] = [ + assetProxyUtils.encodeERC20AssetData(makerTokenAddress), + assetProxyUtils.encodeERC20AssetData(takerTokenAddress), + ]; + signedOrder = await fillScenarios.createFillableSignedOrderAsync( + makerAssetData, + takerAssetData, + makerAddress, + takerAddress, + fillableAmount, + ); + anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync( + makerAssetData, + takerAssetData, + makerAddress, + takerAddress, + fillableAmount, + ); + }); + after(async () => { + await blockchainLifecycle.revertAsync(); }); beforeEach(async () => { await blockchainLifecycle.startAsync(); @@ -59,903 +93,279 @@ describe('ExchangeWrapper', () => { afterEach(async () => { await blockchainLifecycle.revertAsync(); }); - describe('fillOrKill order(s)', () => { - let makerTokenAddress: string; - let takerTokenAddress: string; - let coinbase: string; - let makerAddress: string; - let takerAddress: string; - let feeRecipient: string; - const takerTokenFillAmount = new BigNumber(5); - before(async () => { - [coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses; - tokens = await contractWrappers.tokenRegistry.getTokensAsync(); - const [makerToken, takerToken] = tokenUtils.getDummyTokens(); - makerTokenAddress = makerToken.address; - takerTokenAddress = takerToken.address; - }); - describe('#batchFillOrKillAsync', () => { - it('successfully batch fillOrKill', async () => { - const fillableAmount = new BigNumber(5); - const partialFillTakerAmount = new BigNumber(2); - const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, + describe('fill order(s)', () => { + describe('#fillOrderAsync', () => { + it('should fill a valid order', async () => { + txHash = await contractWrappers.exchange.fillOrderAsync( + signedOrder, + takerTokenFillAmount, takerAddress, - fillableAmount, ); - const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + }); + }); + describe('#fillOrderNoThrowAsync', () => { + it('should fill a valid order', async () => { + txHash = await contractWrappers.exchange.fillOrderNoThrowAsync( + signedOrder, + takerTokenFillAmount, takerAddress, - fillableAmount, ); - const orderFillRequests = [ - { - signedOrder, - takerTokenFillAmount: partialFillTakerAmount, - }, - { - signedOrder: anotherSignedOrder, - takerTokenFillAmount: partialFillTakerAmount, - }, - ]; - await contractWrappers.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress); - }); - describe('order transaction options', () => { - let signedOrder: SignedOrder; - let orderFillRequests: OrderFillRequest[]; - const fillableAmount = new BigNumber(5); - beforeEach(async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - ); - orderFillRequests = [ - { - signedOrder, - takerTokenFillAmount: new BigNumber(0), - }, - ]; - }); - it('should validate when orderTransactionOptions are not present', async () => { - return expect( - contractWrappers.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress), - ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); - }); - it('should validate when orderTransactionOptions specify to validate', async () => { - return expect( - contractWrappers.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, { - shouldValidate: true, - }), - ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); - }); - it('should not validate when orderTransactionOptions specify not to validate', async () => { - return expect( - contractWrappers.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, { - shouldValidate: false, - }), - ).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); - }); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); + expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FULLY_FILLED); }); }); describe('#fillOrKillOrderAsync', () => { - let signedOrder: SignedOrder; - const fillableAmount = new BigNumber(5); - beforeEach(async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, + it('should fill or kill a valid order', async () => { + txHash = await contractWrappers.exchange.fillOrKillOrderAsync( + signedOrder, + takerTokenFillAmount, takerAddress, - fillableAmount, ); - }); - describe('successful fills', () => { - it('should fill a valid order', async () => { - expect( - await contractWrappers.token.getBalanceAsync(makerTokenAddress, makerAddress), - ).to.be.bignumber.equal(fillableAmount); - expect( - await contractWrappers.token.getBalanceAsync(takerTokenAddress, makerAddress), - ).to.be.bignumber.equal(0); - expect( - await contractWrappers.token.getBalanceAsync(makerTokenAddress, takerAddress), - ).to.be.bignumber.equal(0); - expect( - await contractWrappers.token.getBalanceAsync(takerTokenAddress, takerAddress), - ).to.be.bignumber.equal(fillableAmount); - await contractWrappers.exchange.fillOrKillOrderAsync( - signedOrder, - takerTokenFillAmount, - takerAddress, - ); - expect( - await contractWrappers.token.getBalanceAsync(makerTokenAddress, makerAddress), - ).to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount)); - expect( - await contractWrappers.token.getBalanceAsync(takerTokenAddress, makerAddress), - ).to.be.bignumber.equal(takerTokenFillAmount); - expect( - await contractWrappers.token.getBalanceAsync(makerTokenAddress, takerAddress), - ).to.be.bignumber.equal(takerTokenFillAmount); - expect( - await contractWrappers.token.getBalanceAsync(takerTokenAddress, takerAddress), - ).to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount)); - }); - it('should partially fill a valid order', async () => { - const partialFillAmount = new BigNumber(3); - await contractWrappers.exchange.fillOrKillOrderAsync(signedOrder, partialFillAmount, takerAddress); - expect( - await contractWrappers.token.getBalanceAsync(makerTokenAddress, makerAddress), - ).to.be.bignumber.equal(fillableAmount.minus(partialFillAmount)); - expect( - await contractWrappers.token.getBalanceAsync(takerTokenAddress, makerAddress), - ).to.be.bignumber.equal(partialFillAmount); - expect( - await contractWrappers.token.getBalanceAsync(makerTokenAddress, takerAddress), - ).to.be.bignumber.equal(partialFillAmount); - expect( - await contractWrappers.token.getBalanceAsync(takerTokenAddress, takerAddress), - ).to.be.bignumber.equal(fillableAmount.minus(partialFillAmount)); - }); - }); - describe('order transaction options', () => { - const emptyFillableAmount = new BigNumber(0); - it('should validate when orderTransactionOptions are not present', async () => { - return expect( - contractWrappers.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress), - ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); - }); - it('should validate when orderTransactionOptions specify to validate', async () => { - return expect( - contractWrappers.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, { - shouldValidate: true, - }), - ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); - }); - it('should not validate when orderTransactionOptions specify not to validate', async () => { - return expect( - contractWrappers.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, { - shouldValidate: false, - }), - ).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); - }); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); - }); - describe('fill order(s)', () => { - let makerTokenAddress: string; - let takerTokenAddress: string; - let coinbase: string; - let makerAddress: string; - let takerAddress: string; - let feeRecipient: string; - const fillableAmount = new BigNumber(5); - const takerTokenFillAmount = new BigNumber(5); - const shouldThrowOnInsufficientBalanceOrAllowance = true; - before(async () => { - [coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses; - tokens = await contractWrappers.tokenRegistry.getTokensAsync(); - const [makerToken, takerToken] = tokenUtils.getDummyTokens(); - makerTokenAddress = makerToken.address; - takerTokenAddress = takerToken.address; - }); - describe('#fillOrderAsync', () => { - describe('successful fills', () => { - it('should fill a valid order', async () => { - const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - ); - expect( - await contractWrappers.token.getBalanceAsync(makerTokenAddress, makerAddress), - ).to.be.bignumber.equal(fillableAmount); - expect( - await contractWrappers.token.getBalanceAsync(takerTokenAddress, makerAddress), - ).to.be.bignumber.equal(0); - expect( - await contractWrappers.token.getBalanceAsync(makerTokenAddress, takerAddress), - ).to.be.bignumber.equal(0); - expect( - await contractWrappers.token.getBalanceAsync(takerTokenAddress, takerAddress), - ).to.be.bignumber.equal(fillableAmount); - const txHash = await contractWrappers.exchange.fillOrderAsync( - signedOrder, - takerTokenFillAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - expect( - await contractWrappers.token.getBalanceAsync(makerTokenAddress, makerAddress), - ).to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount)); - expect( - await contractWrappers.token.getBalanceAsync(takerTokenAddress, makerAddress), - ).to.be.bignumber.equal(takerTokenFillAmount); - expect( - await contractWrappers.token.getBalanceAsync(makerTokenAddress, takerAddress), - ).to.be.bignumber.equal(takerTokenFillAmount); - expect( - await contractWrappers.token.getBalanceAsync(takerTokenAddress, takerAddress), - ).to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount)); - }); - it('should partially fill the valid order', async () => { - const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - ); - const partialFillAmount = new BigNumber(3); - const txHash = await contractWrappers.exchange.fillOrderAsync( - signedOrder, - partialFillAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - expect( - await contractWrappers.token.getBalanceAsync(makerTokenAddress, makerAddress), - ).to.be.bignumber.equal(fillableAmount.minus(partialFillAmount)); - expect( - await contractWrappers.token.getBalanceAsync(takerTokenAddress, makerAddress), - ).to.be.bignumber.equal(partialFillAmount); - expect( - await contractWrappers.token.getBalanceAsync(makerTokenAddress, takerAddress), - ).to.be.bignumber.equal(partialFillAmount); - expect( - await contractWrappers.token.getBalanceAsync(takerTokenAddress, takerAddress), - ).to.be.bignumber.equal(fillableAmount.minus(partialFillAmount)); - }); - it('should fill the valid orders with fees', async () => { - const makerFee = new BigNumber(1); - const takerFee = new BigNumber(2); - const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerTokenAddress, - takerTokenAddress, - makerFee, - takerFee, - makerAddress, - takerAddress, - fillableAmount, - feeRecipient, - ); - const txHash = await contractWrappers.exchange.fillOrderAsync( - signedOrder, - takerTokenFillAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - expect( - await contractWrappers.token.getBalanceAsync(zrxTokenAddress, feeRecipient), - ).to.be.bignumber.equal(makerFee.plus(takerFee)); - }); - }); - describe('order transaction options', () => { - let signedOrder: SignedOrder; - const emptyFillTakerAmount = new BigNumber(0); - beforeEach(async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - ); - }); - it('should validate when orderTransactionOptions are not present', async () => { - return expect( - contractWrappers.exchange.fillOrderAsync( - signedOrder, - emptyFillTakerAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - ), - ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); - }); - it('should validate when orderTransactionOptions specify to validate', async () => { - return expect( - contractWrappers.exchange.fillOrderAsync( - signedOrder, - emptyFillTakerAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - { - shouldValidate: true, - }, - ), - ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); - }); - it('should not validate when orderTransactionOptions specify not to validate', async () => { - return expect( - contractWrappers.exchange.fillOrderAsync( - signedOrder, - emptyFillTakerAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - { - shouldValidate: false, - }, - ), - ).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); - }); + describe('#batchFillOrdersAsync', () => { + it('should fill a batch of valid orders', async () => { + const signedOrders = [signedOrder, anotherSignedOrder]; + const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount]; + txHash = await contractWrappers.exchange.batchFillOrdersAsync( + signedOrders, + takerAssetFillAmounts, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); - describe('negative fill amount', async () => { - let signedOrder: SignedOrder; - const negativeFillTakerAmount = new BigNumber(-100); - beforeEach(async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - ); - }); - it('should not allow the exchange wrapper to fill if amount is negative', async () => { - return expect( - contractWrappers.exchange.fillOrderAsync( - signedOrder, - negativeFillTakerAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - ), - ).to.be.rejected(); - }); + }); + describe('#marketBuyOrdersAsync', () => { + it('should maker buy', async () => { + const signedOrders = [signedOrder, anotherSignedOrder]; + const makerAssetFillAmount = takerTokenFillAmount; + txHash = await contractWrappers.exchange.marketBuyOrdersAsync( + signedOrders, + makerAssetFillAmount, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); - describe('#batchFillOrdersAsync', () => { - let signedOrder: SignedOrder; - let signedOrderHashHex: string; - let anotherSignedOrder: SignedOrder; - let anotherOrderHashHex: string; - let orderFillBatch: OrderFillRequest[]; - beforeEach(async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, + describe('#marketBuyOrdersNoThrowAsync', () => { + it('should no throw maker buy', async () => { + const signedOrders = [signedOrder, anotherSignedOrder]; + const makerAssetFillAmount = takerTokenFillAmount; + txHash = await contractWrappers.exchange.marketBuyOrdersNoThrowAsync( + signedOrders, + makerAssetFillAmount, takerAddress, - fillableAmount, ); - signedOrderHashHex = getOrderHashHex(signedOrder); - anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); + expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FULLY_FILLED); + }); + }); + describe('#marketSellOrdersAsync', () => { + it('should maker sell', async () => { + const signedOrders = [signedOrder, anotherSignedOrder]; + const takerAssetFillAmount = takerTokenFillAmount; + txHash = await contractWrappers.exchange.marketSellOrdersAsync( + signedOrders, + takerAssetFillAmount, takerAddress, - fillableAmount, ); - anotherOrderHashHex = getOrderHashHex(anotherSignedOrder); - }); - describe('successful batch fills', () => { - beforeEach(() => { - orderFillBatch = [ - { - signedOrder, - takerTokenFillAmount, - }, - { - signedOrder: anotherSignedOrder, - takerTokenFillAmount, - }, - ]; - }); - it('should throw if a batch is empty', async () => { - return expect( - contractWrappers.exchange.batchFillOrdersAsync( - [], - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - ), - ).to.be.rejectedWith(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem); - }); - it('should successfully fill multiple orders', async () => { - const txHash = await contractWrappers.exchange.batchFillOrdersAsync( - orderFillBatch, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - const filledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(signedOrderHashHex); - const anotherFilledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync( - anotherOrderHashHex, - ); - expect(filledAmount).to.be.bignumber.equal(takerTokenFillAmount); - expect(anotherFilledAmount).to.be.bignumber.equal(takerTokenFillAmount); - }); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); - describe('order transaction options', () => { - beforeEach(async () => { - const emptyFillTakerAmount = new BigNumber(0); - orderFillBatch = [ - { - signedOrder, - takerTokenFillAmount: emptyFillTakerAmount, - }, - { - signedOrder: anotherSignedOrder, - takerTokenFillAmount: emptyFillTakerAmount, - }, - ]; - }); - it('should validate when orderTransactionOptions are not present', async () => { - return expect( - contractWrappers.exchange.batchFillOrdersAsync( - orderFillBatch, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - ), - ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); - }); - it('should validate when orderTransactionOptions specify to validate', async () => { - return expect( - contractWrappers.exchange.batchFillOrdersAsync( - orderFillBatch, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - { - shouldValidate: true, - }, - ), - ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); - }); - it('should not validate when orderTransactionOptions specify not to validate', async () => { - return expect( - contractWrappers.exchange.batchFillOrdersAsync( - orderFillBatch, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - { - shouldValidate: false, - }, - ), - ).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); - }); - }); - describe('negative batch fill amount', async () => { - beforeEach(async () => { - const negativeFillTakerAmount = new BigNumber(-100); - orderFillBatch = [ - { - signedOrder, - takerTokenFillAmount, - }, - { - signedOrder: anotherSignedOrder, - takerTokenFillAmount: negativeFillTakerAmount, - }, - ]; - }); - it('should not allow the exchange wrapper to batch fill if any amount is negative', async () => { - return expect( - contractWrappers.exchange.batchFillOrdersAsync( - orderFillBatch, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - ), - ).to.be.rejected(); - }); + }); + describe('#marketSellOrdersNoThrowAsync', () => { + it('should no throw maker sell', async () => { + const signedOrders = [signedOrder, anotherSignedOrder]; + const takerAssetFillAmount = takerTokenFillAmount; + txHash = await contractWrappers.exchange.marketSellOrdersNoThrowAsync( + signedOrders, + takerAssetFillAmount, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); + expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FULLY_FILLED); + }); + }); + describe('#batchFillOrdersNoThrowAsync', () => { + it('should fill a batch of valid orders', async () => { + const signedOrders = [signedOrder, anotherSignedOrder]; + const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount]; + txHash = await contractWrappers.exchange.batchFillOrdersNoThrowAsync( + signedOrders, + takerAssetFillAmounts, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + let orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); + expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FULLY_FILLED); + orderInfo = await contractWrappers.exchange.getOrderInfoAsync(anotherSignedOrder); + expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FULLY_FILLED); + }); + }); + describe('#batchFillOrKillOrdersAsync', () => { + it('should fill or kill a batch of valid orders', async () => { + const signedOrders = [signedOrder, anotherSignedOrder]; + const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount]; + txHash = await contractWrappers.exchange.batchFillOrKillOrdersAsync( + signedOrders, + takerAssetFillAmounts, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); - describe('#fillOrdersUpTo', () => { - let signedOrder: SignedOrder; - let signedOrderHashHex: string; - let anotherSignedOrder: SignedOrder; - let anotherOrderHashHex: string; - let signedOrders: SignedOrder[]; - const fillUpToAmount = fillableAmount.plus(fillableAmount).minus(1); - beforeEach(async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, + describe('#matchOrdersAsync', () => { + it('should match two valid ordersr', async () => { + const matchingSignedOrder = await fillScenarios.createFillableSignedOrderAsync( + takerAssetData, + makerAssetData, makerAddress, takerAddress, fillableAmount, ); - signedOrderHashHex = getOrderHashHex(signedOrder); - anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, + txHash = await contractWrappers.exchange.matchOrdersAsync( + signedOrder, + matchingSignedOrder, takerAddress, - fillableAmount, ); - anotherOrderHashHex = getOrderHashHex(anotherSignedOrder); - signedOrders = [signedOrder, anotherSignedOrder]; - }); - describe('successful batch fills', () => { - it('should throw if a batch is empty', async () => { - return expect( - contractWrappers.exchange.fillOrdersUpToAsync( - [], - fillUpToAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - ), - ).to.be.rejectedWith(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem); - }); - it('should successfully fill up to specified amount when all orders are fully funded', async () => { - const txHash = await contractWrappers.exchange.fillOrdersUpToAsync( - signedOrders, - fillUpToAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - const filledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(signedOrderHashHex); - const anotherFilledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync( - anotherOrderHashHex, - ); - expect(filledAmount).to.be.bignumber.equal(fillableAmount); - const remainingFillAmount = fillableAmount.minus(1); - expect(anotherFilledAmount).to.be.bignumber.equal(remainingFillAmount); - }); - it('should successfully fill up to specified amount and leave the rest of the orders untouched', async () => { - const txHash = await contractWrappers.exchange.fillOrdersUpToAsync( - signedOrders, - fillableAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - const filledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(signedOrderHashHex); - const zeroAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(anotherOrderHashHex); - expect(filledAmount).to.be.bignumber.equal(fillableAmount); - expect(zeroAmount).to.be.bignumber.equal(0); - }); - it('should successfully fill up to specified amount even if filling all orders would fail', async () => { - const missingBalance = new BigNumber(1); // User will still have enough balance to fill up to 9, - // but won't have 10 to fully fill all orders in a batch. - await contractWrappers.token.transferAsync( - makerTokenAddress, - makerAddress, - coinbase, - missingBalance, - ); - const txHash = await contractWrappers.exchange.fillOrdersUpToAsync( - signedOrders, - fillUpToAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - const filledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(signedOrderHashHex); - const anotherFilledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync( - anotherOrderHashHex, - ); - expect(filledAmount).to.be.bignumber.equal(fillableAmount); - const remainingFillAmount = fillableAmount.minus(1); - expect(anotherFilledAmount).to.be.bignumber.equal(remainingFillAmount); - }); - }); - describe('failed batch fills', () => { - it("should fail validation if user doesn't have enough balance without fill up to", async () => { - const missingBalance = new BigNumber(2); // User will only have enough balance to fill up to 8 - await contractWrappers.token.transferAsync( - makerTokenAddress, - makerAddress, - coinbase, - missingBalance, - ); - return expect( - contractWrappers.exchange.fillOrdersUpToAsync( - signedOrders, - fillUpToAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - ), - ).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance); - }); - }); - describe('order transaction options', () => { - const emptyFillUpToAmount = new BigNumber(0); - it('should validate when orderTransactionOptions are not present', async () => { - return expect( - contractWrappers.exchange.fillOrdersUpToAsync( - signedOrders, - emptyFillUpToAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - ), - ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); - }); - it('should validate when orderTransactionOptions specify to validate', async () => { - return expect( - contractWrappers.exchange.fillOrdersUpToAsync( - signedOrders, - emptyFillUpToAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - { - shouldValidate: true, - }, - ), - ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); - }); - it('should not validate when orderTransactionOptions specify not to validate', async () => { - return expect( - contractWrappers.exchange.fillOrdersUpToAsync( - signedOrders, - emptyFillUpToAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - { - shouldValidate: false, - }, - ), - ).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); - }); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); }); describe('cancel order(s)', () => { - let makerTokenAddress: string; - let takerTokenAddress: string; - let coinbase: string; - let makerAddress: string; - let takerAddress: string; - const fillableAmount = new BigNumber(5); - let signedOrder: SignedOrder; - let orderHashHex: string; - const cancelAmount = new BigNumber(3); - beforeEach(async () => { - [coinbase, makerAddress, takerAddress] = userAddresses; - const [makerToken, takerToken] = tokenUtils.getDummyTokens(); - makerTokenAddress = makerToken.address; - takerTokenAddress = takerToken.address; - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - ); - orderHashHex = getOrderHashHex(signedOrder); - }); describe('#cancelOrderAsync', () => { - describe('successful cancels', () => { - it('should cancel an order', async () => { - const txHash = await contractWrappers.exchange.cancelOrderAsync(signedOrder, cancelAmount); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - const cancelledAmount = await contractWrappers.exchange.getCancelledTakerAmountAsync(orderHashHex); - expect(cancelledAmount).to.be.bignumber.equal(cancelAmount); - }); - }); - describe('order transaction options', () => { - const emptyCancelTakerTokenAmount = new BigNumber(0); - it('should validate when orderTransactionOptions are not present', async () => { - return expect( - contractWrappers.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount), - ).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); - }); - it('should validate when orderTransactionOptions specify to validate', async () => { - return expect( - contractWrappers.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, { - shouldValidate: true, - }), - ).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); - }); - it('should not validate when orderTransactionOptions specify not to validate', async () => { - return expect( - contractWrappers.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, { - shouldValidate: false, - }), - ).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); - }); + it('should cancel a valid order', async () => { + txHash = await contractWrappers.exchange.cancelOrderAsync(signedOrder); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); describe('#batchCancelOrdersAsync', () => { - let anotherSignedOrder: SignedOrder; - let anotherOrderHashHex: string; - let cancelBatch: OrderCancellationRequest[]; - beforeEach(async () => { - anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, + it('should cancel a batch of valid orders', async () => { + const orders = [signedOrder, anotherSignedOrder]; + txHash = await contractWrappers.exchange.batchCancelOrdersAsync(orders); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + }); + }); + describe('#cancelOrdersUpTo/getOrderEpochAsync', () => { + it('should cancel orders up to target order epoch', async () => { + const targetOrderEpoch = new BigNumber(42); + txHash = await contractWrappers.exchange.cancelOrdersUpToAsync(targetOrderEpoch, makerAddress); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const orderEpoch = await contractWrappers.exchange.getOrderEpochAsync( makerAddress, - takerAddress, - fillableAmount, + constants.NULL_ADDRESS, ); - anotherOrderHashHex = getOrderHashHex(anotherSignedOrder); - cancelBatch = [ - { - order: signedOrder, - takerTokenCancelAmount: cancelAmount, - }, - { - order: anotherSignedOrder, - takerTokenCancelAmount: cancelAmount, - }, - ]; - }); - describe('failed batch cancels', () => { - it('should throw when orders have different makers', async () => { - const signedOrderWithDifferentMaker = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - takerAddress, - takerAddress, - fillableAmount, - ); - return expect( - contractWrappers.exchange.batchCancelOrdersAsync([ - cancelBatch[0], - { - order: signedOrderWithDifferentMaker, - takerTokenCancelAmount: cancelAmount, - }, - ]), - ).to.be.rejectedWith(ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed); - }); - }); - describe('successful batch cancels', () => { - it('should cancel a batch of orders', async () => { - await contractWrappers.exchange.batchCancelOrdersAsync(cancelBatch); - const cancelledAmount = await contractWrappers.exchange.getCancelledTakerAmountAsync(orderHashHex); - const anotherCancelledAmount = await contractWrappers.exchange.getCancelledTakerAmountAsync( - anotherOrderHashHex, - ); - expect(cancelledAmount).to.be.bignumber.equal(cancelAmount); - expect(anotherCancelledAmount).to.be.bignumber.equal(cancelAmount); - }); - }); - describe('order transaction options', () => { - beforeEach(async () => { - const emptyTakerTokenCancelAmount = new BigNumber(0); - cancelBatch = [ - { - order: signedOrder, - takerTokenCancelAmount: emptyTakerTokenCancelAmount, - }, - { - order: anotherSignedOrder, - takerTokenCancelAmount: emptyTakerTokenCancelAmount, - }, - ]; - }); - it('should validate when orderTransactionOptions are not present', async () => { - return expect(contractWrappers.exchange.batchCancelOrdersAsync(cancelBatch)).to.be.rejectedWith( - ExchangeContractErrs.OrderCancelAmountZero, - ); - }); - it('should validate when orderTransactionOptions specify to validate', async () => { - return expect( - contractWrappers.exchange.batchCancelOrdersAsync(cancelBatch, { - shouldValidate: true, - }), - ).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); - }); - it('should not validate when orderTransactionOptions specify not to validate', async () => { - return expect( - contractWrappers.exchange.batchCancelOrdersAsync(cancelBatch, { - shouldValidate: false, - }), - ).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); - }); + expect(orderEpoch).to.be.bignumber.equal(targetOrderEpoch.plus(1)); }); }); }); - describe('tests that require partially filled order', () => { - let makerTokenAddress: string; - let takerTokenAddress: string; - let takerAddress: string; - let fillableAmount: BigNumber; - let partialFillAmount: BigNumber; - let signedOrder: SignedOrder; - let orderHash: string; - before(() => { - takerAddress = userAddresses[1]; - tokenUtils = new TokenUtils(tokens); - const [makerToken, takerToken] = tokenUtils.getDummyTokens(); - makerTokenAddress = makerToken.address; - takerTokenAddress = takerToken.address; + describe('#getZRXAssetData', () => { + it('should get the asset data', async () => { + const ZRX_ASSET_DATA = await contractWrappers.exchange.getZRXAssetDataAsync(); + const ASSET_DATA_HEX_LENGTH = 74; + expect(ZRX_ASSET_DATA).to.have.length(ASSET_DATA_HEX_LENGTH); }); - beforeEach(async () => { - fillableAmount = new BigNumber(5); - partialFillAmount = new BigNumber(2); - signedOrder = await fillScenarios.createPartiallyFilledSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - takerAddress, - fillableAmount, - partialFillAmount, + }); + describe('#getOrderInfoAsync', () => { + it('should get the order info', async () => { + const orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); + const orderHash = orderHashUtils.getOrderHashHex(signedOrder); + expect(orderInfo.orderHash).to.be.equal(orderHash); + }); + }); + describe('#isValidSignature', () => { + it('should check if the signature is valid', async () => { + const orderHash = orderHashUtils.getOrderHashHex(signedOrder); + let isValid = await contractWrappers.exchange.isValidSignatureAsync( + orderHash, + signedOrder.makerAddress, + signedOrder.signature, + ); + expect(isValid).to.be.true(); + isValid = await contractWrappers.exchange.isValidSignatureAsync( + orderHash, + signedOrder.takerAddress, + signedOrder.signature, ); - orderHash = getOrderHashHex(signedOrder); + expect(isValid).to.be.false(); }); - describe('#getUnavailableTakerAmountAsync', () => { - it('should throw if passed an invalid orderHash', async () => { - const invalidOrderHashHex = '0x123'; - return expect( - contractWrappers.exchange.getUnavailableTakerAmountAsync(invalidOrderHashHex), - ).to.be.rejected(); - }); - it('should return zero if passed a valid but non-existent orderHash', async () => { - const unavailableValueT = await contractWrappers.exchange.getUnavailableTakerAmountAsync( - NON_EXISTENT_ORDER_HASH, - ); - expect(unavailableValueT).to.be.bignumber.equal(0); - }); - it('should return the unavailableValueT for a valid and partially filled orderHash', async () => { - const unavailableValueT = await contractWrappers.exchange.getUnavailableTakerAmountAsync(orderHash); - expect(unavailableValueT).to.be.bignumber.equal(partialFillAmount); - }); + }); + describe('#isAllowedValidatorAsync', () => { + it('should check if the validator is alllowed', async () => { + const signerAddress = makerAddress; + const validatorAddress = constants.NULL_ADDRESS; + const isAllowed = await contractWrappers.exchange.isAllowedValidatorAsync(signerAddress, validatorAddress); + expect(isAllowed).to.be.false(); }); - describe('#getFilledTakerAmountAsync', () => { - it('should throw if passed an invalid orderHash', async () => { - const invalidOrderHashHex = '0x123'; - return expect( - contractWrappers.exchange.getFilledTakerAmountAsync(invalidOrderHashHex), - ).to.be.rejected(); - }); - it('should return zero if passed a valid but non-existent orderHash', async () => { - const filledValueT = await contractWrappers.exchange.getFilledTakerAmountAsync(NON_EXISTENT_ORDER_HASH); - expect(filledValueT).to.be.bignumber.equal(0); - }); - it('should return the filledValueT for a valid and partially filled orderHash', async () => { - const filledValueT = await contractWrappers.exchange.getFilledTakerAmountAsync(orderHash); - expect(filledValueT).to.be.bignumber.equal(partialFillAmount); - }); + }); + describe('#setSignatureValidatorApproval', () => { + it('should set signature validator approval', async () => { + const validatorAddress = constants.NULL_ADDRESS; + const isApproved = true; + const senderAddress = makerAddress; + txHash = await contractWrappers.exchange.setSignatureValidatorApprovalAsync( + validatorAddress, + isApproved, + senderAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); - describe('#getCancelledTakerAmountAsync', () => { - it('should throw if passed an invalid orderHash', async () => { - const invalidOrderHashHex = '0x123'; - return expect( - contractWrappers.exchange.getCancelledTakerAmountAsync(invalidOrderHashHex), - ).to.be.rejected(); - }); - it('should return zero if passed a valid but non-existent orderHash', async () => { - const cancelledValueT = await contractWrappers.exchange.getCancelledTakerAmountAsync( - NON_EXISTENT_ORDER_HASH, - ); - expect(cancelledValueT).to.be.bignumber.equal(0); - }); - it('should return the cancelledValueT for a valid and partially filled orderHash', async () => { - const cancelledValueT = await contractWrappers.exchange.getCancelledTakerAmountAsync(orderHash); - expect(cancelledValueT).to.be.bignumber.equal(0); - }); - it('should return the cancelledValueT for a valid and cancelled orderHash', async () => { - const cancelAmount = fillableAmount.minus(partialFillAmount); - await contractWrappers.exchange.cancelOrderAsync(signedOrder, cancelAmount); - const cancelledValueT = await contractWrappers.exchange.getCancelledTakerAmountAsync(orderHash); - expect(cancelledValueT).to.be.bignumber.equal(cancelAmount); - }); + }); + describe('#isTransactionExecutedAsync', () => { + it('should check if the transaction is executed', async () => { + const transactionHash = '0x0000000000000000000000000000000000000000000000000000000000000000'; + const isExecuted = await contractWrappers.exchange.isTransactionExecutedAsync(transactionHash); + expect(isExecuted).to.be.false(); + }); + }); + describe('#getAssetProxyBySignatureAsync', () => { + it('should fill or kill a valid order', async () => { + const erc20ProxyId = await contractWrappers.erc20Proxy.getProxyIdAsync(); + const erc20ProxyAddressById = await contractWrappers.exchange.getAssetProxyBySignatureAsync(erc20ProxyId); + const erc20ProxyAddress = contractWrappers.erc20Proxy.getContractAddress(); + expect(erc20ProxyAddressById).to.be.equal(erc20ProxyAddress); + const erc721ProxyId = await contractWrappers.erc721Proxy.getProxyIdAsync(); + const erc721ProxyAddressById = await contractWrappers.exchange.getAssetProxyBySignatureAsync(erc721ProxyId); + const erc721ProxyAddress = contractWrappers.erc721Proxy.getContractAddress(); + expect(erc721ProxyAddressById).to.be.equal(erc721ProxyAddress); + }); + }); + describe('#preSignAsync/isPreSignedAsync', () => { + it('should preSign the hash', async () => { + const senderAddress = takerAddress; + const hash = orderHashUtils.getOrderHashHex(signedOrder); + const signerAddress = signedOrder.makerAddress; + let isPreSigned = await contractWrappers.exchange.isPreSignedAsync(hash, signerAddress); + expect(isPreSigned).to.be.false(); + txHash = await contractWrappers.exchange.preSignAsync( + hash, + signerAddress, + signedOrder.signature, + senderAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + isPreSigned = await contractWrappers.exchange.isPreSignedAsync(hash, signerAddress); + expect(isPreSigned).to.be.true(); + }); + }); + describe('#getVersionAsync', () => { + it('should return version the hash', async () => { + const version = await contractWrappers.exchange.getVersionAsync(); + const VERSION = '2.0.1-alpha'; + expect(version).to.be.equal(VERSION); }); }); describe('#subscribe', () => { const indexFilterValues = {}; - const shouldThrowOnInsufficientBalanceOrAllowance = true; - let makerTokenAddress: string; - let takerTokenAddress: string; - let coinbase: string; - let takerAddress: string; - let makerAddress: string; - let fillableAmount: BigNumber; - let signedOrder: SignedOrder; const takerTokenFillAmountInBaseUnits = new BigNumber(1); - const cancelTakerAmountInBaseUnits = new BigNumber(1); - before(() => { - [coinbase, makerAddress, takerAddress] = userAddresses; - const [makerToken, takerToken] = tokenUtils.getDummyTokens(); - makerTokenAddress = makerToken.address; - takerTokenAddress = takerToken.address; - }); beforeEach(async () => { - fillableAmount = new BigNumber(5); signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, + makerAssetData, + takerAssetData, makerAddress, takerAddress, fillableAmount, @@ -969,18 +379,17 @@ describe('ExchangeWrapper', () => { // we do need both. A hack is to make the top-level a sync fn w/ a done callback and then // wrap the rest of the test in an async block // Source: https://github.com/mochajs/mocha/issues/2407 - it('Should receive the LogFill event when an order is filled', (done: DoneCallback) => { + it('Should receive the Fill event when an order is filled', (done: DoneCallback) => { (async () => { const callback = callbackErrorReporter.reportNodeCallbackErrors(done)( - (logEvent: DecodedLogEvent<LogFillContractEventArgs>) => { - expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill); + (logEvent: DecodedLogEvent<ExchangeFillEventArgs>) => { + expect(logEvent.log.event).to.be.equal(ExchangeEvents.Fill); }, ); - contractWrappers.exchange.subscribe(ExchangeEvents.LogFill, indexFilterValues, callback); + contractWrappers.exchange.subscribe(ExchangeEvents.Fill, indexFilterValues, callback); await contractWrappers.exchange.fillOrderAsync( signedOrder, takerTokenFillAmountInBaseUnits, - shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, ); })().catch(done); @@ -988,35 +397,34 @@ describe('ExchangeWrapper', () => { it('Should receive the LogCancel event when an order is cancelled', (done: DoneCallback) => { (async () => { const callback = callbackErrorReporter.reportNodeCallbackErrors(done)( - (logEvent: DecodedLogEvent<LogCancelContractEventArgs>) => { - expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogCancel); + (logEvent: DecodedLogEvent<ExchangeCancelEventArgs>) => { + expect(logEvent.log.event).to.be.equal(ExchangeEvents.Cancel); }, ); - contractWrappers.exchange.subscribe(ExchangeEvents.LogCancel, indexFilterValues, callback); - await contractWrappers.exchange.cancelOrderAsync(signedOrder, cancelTakerAmountInBaseUnits); + contractWrappers.exchange.subscribe(ExchangeEvents.Cancel, indexFilterValues, callback); + await contractWrappers.exchange.cancelOrderAsync(signedOrder); })().catch(done); }); it('Outstanding subscriptions are cancelled when contractWrappers.setProvider called', (done: DoneCallback) => { (async () => { const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)( - (_logEvent: DecodedLogEvent<LogFillContractEventArgs>) => { + (logEvent: DecodedLogEvent<ExchangeFillEventArgs>) => { done(new Error('Expected this subscription to have been cancelled')); }, ); - contractWrappers.exchange.subscribe(ExchangeEvents.LogFill, indexFilterValues, callbackNeverToBeCalled); + contractWrappers.exchange.subscribe(ExchangeEvents.Fill, indexFilterValues, callbackNeverToBeCalled); contractWrappers.setProvider(provider, constants.TESTRPC_NETWORK_ID); const callback = callbackErrorReporter.reportNodeCallbackErrors(done)( - (logEvent: DecodedLogEvent<LogFillContractEventArgs>) => { - expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill); + (logEvent: DecodedLogEvent<ExchangeFillEventArgs>) => { + expect(logEvent.log.event).to.be.equal(ExchangeEvents.Fill); }, ); - contractWrappers.exchange.subscribe(ExchangeEvents.LogFill, indexFilterValues, callback); + contractWrappers.exchange.subscribe(ExchangeEvents.Fill, indexFilterValues, callback); await contractWrappers.exchange.fillOrderAsync( signedOrder, takerTokenFillAmountInBaseUnits, - shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, ); })().catch(done); @@ -1024,12 +432,12 @@ describe('ExchangeWrapper', () => { it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => { (async () => { const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)( - (_logEvent: DecodedLogEvent<LogFillContractEventArgs>) => { + (_logEvent: DecodedLogEvent<ExchangeFillEventArgs>) => { done(new Error('Expected this subscription to have been cancelled')); }, ); const subscriptionToken = contractWrappers.exchange.subscribe( - ExchangeEvents.LogFill, + ExchangeEvents.Fill, indexFilterValues, callbackNeverToBeCalled, ); @@ -1037,102 +445,36 @@ describe('ExchangeWrapper', () => { await contractWrappers.exchange.fillOrderAsync( signedOrder, takerTokenFillAmountInBaseUnits, - shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, ); done(); })().catch(done); }); }); - describe('#getOrderHashHexUsingContractCallAsync', () => { - let makerTokenAddress: string; - let takerTokenAddress: string; - let makerAddress: string; - let takerAddress: string; - const fillableAmount = new BigNumber(5); - before(async () => { - [, makerAddress, takerAddress] = userAddresses; - const [makerToken, takerToken] = tokenUtils.getDummyTokens(); - makerTokenAddress = makerToken.address; - takerTokenAddress = takerToken.address; - }); - it("get's the same hash as the local function", async () => { - const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - ); - const orderHash = getOrderHashHex(signedOrder); - const orderHashFromContract = await (contractWrappers.exchange as any)._getOrderHashHexUsingContractCallAsync( - signedOrder, - ); - expect(orderHash).to.equal(orderHashFromContract); - }); - }); describe('#getZRXTokenAddressAsync', () => { it('gets the same token as is in token registry', () => { - const zrxAddress = contractWrappers.exchange.getZRXTokenAddress(); - const zrxToken = tokenUtils.getProtocolTokenOrThrow(); - expect(zrxAddress).to.equal(zrxToken.address); + const zrxAddressFromExchangeWrapper = contractWrappers.exchange.getZRXTokenAddress(); + const zrxAddress = tokenUtils.getProtocolTokenAddress(); + expect(zrxAddressFromExchangeWrapper).to.equal(zrxAddress); }); }); describe('#getLogsAsync', () => { - let makerTokenAddress: string; - let takerTokenAddress: string; - let makerAddress: string; - let takerAddress: string; - const fillableAmount = new BigNumber(5); - const shouldThrowOnInsufficientBalanceOrAllowance = true; - const blockRange: BlockRange = { + const blockRange = { fromBlock: 0, toBlock: BlockParamLiteral.Latest, }; - let txHash: string; - before(async () => { - [, makerAddress, takerAddress] = userAddresses; - const [makerToken, takerToken] = tokenUtils.getDummyTokens(); - makerTokenAddress = makerToken.address; - takerTokenAddress = takerToken.address; - }); - it('should get logs with decoded args emitted by LogFill', async () => { - const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - ); - txHash = await contractWrappers.exchange.fillOrderAsync( - signedOrder, - fillableAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - const eventName = ExchangeEvents.LogFill; + it('should get logs with decoded args emitted by Fill', async () => { + txHash = await contractWrappers.exchange.fillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress); + const eventName = ExchangeEvents.Fill; const indexFilterValues = {}; const logs = await contractWrappers.exchange.getLogsAsync(eventName, blockRange, indexFilterValues); expect(logs).to.have.length(1); expect(logs[0].event).to.be.equal(eventName); }); it('should only get the logs with the correct event name', async () => { - const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - ); - txHash = await contractWrappers.exchange.fillOrderAsync( - signedOrder, - fillableAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - const differentEventName = ExchangeEvents.LogCancel; + txHash = await contractWrappers.exchange.fillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const differentEventName = ExchangeEvents.Cancel; const indexFilterValues = {}; const logs = await contractWrappers.exchange.getLogsAsync( differentEventName, @@ -1142,86 +484,34 @@ describe('ExchangeWrapper', () => { expect(logs).to.have.length(0); }); it('should only get the logs with the correct indexed fields', async () => { - const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - ); - txHash = await contractWrappers.exchange.fillOrderAsync( - signedOrder, - fillableAmount, - shouldThrowOnInsufficientBalanceOrAllowance, - takerAddress, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); - - const differentMakerAddress = userAddresses[2]; - const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - differentMakerAddress, + txHash = await contractWrappers.exchange.fillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const signedOrderWithAnotherMakerAddress = await fillScenarios.createFillableSignedOrderAsync( + makerAssetData, + takerAssetData, + anotherMakerAddress, takerAddress, fillableAmount, ); txHash = await contractWrappers.exchange.fillOrderAsync( - anotherSignedOrder, - fillableAmount, - shouldThrowOnInsufficientBalanceOrAllowance, + signedOrderWithAnotherMakerAddress, + takerTokenFillAmount, takerAddress, ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const eventName = ExchangeEvents.LogFill; + const eventName = ExchangeEvents.Fill; const indexFilterValues = { - maker: differentMakerAddress, + makerAddress: anotherMakerAddress, }; - const logs = await contractWrappers.exchange.getLogsAsync<LogFillContractEventArgs>( + const logs = await contractWrappers.exchange.getLogsAsync<ExchangeFillEventArgs>( eventName, blockRange, indexFilterValues, ); expect(logs).to.have.length(1); const args = logs[0].args; - expect(args.maker).to.be.equal(differentMakerAddress); - }); - }); - describe('#getOrderStateAsync', () => { - let maker: string; - let taker: string; - let makerToken: Token; - let takerToken: Token; - let signedOrder: SignedOrder; - let orderState: OrderState; - const fillableAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(5), constants.ZRX_DECIMALS); - before(async () => { - [, maker, taker] = userAddresses; - tokens = await contractWrappers.tokenRegistry.getTokensAsync(); - [makerToken, takerToken] = tokenUtils.getDummyTokens(); - }); - it('should report orderStateValid when order is fillable', async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerToken.address, - takerToken.address, - maker, - taker, - fillableAmount, - ); - orderState = await contractWrappers.exchange.getOrderStateAsync(signedOrder); - expect(orderState.isValid).to.be.true(); - }); - it('should report orderStateInvalid when maker allowance set to 0', async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerToken.address, - takerToken.address, - maker, - taker, - fillableAmount, - ); - await contractWrappers.token.setProxyAllowanceAsync(makerToken.address, maker, new BigNumber(0)); - orderState = await contractWrappers.exchange.getOrderStateAsync(signedOrder); - expect(orderState.isValid).to.be.false(); + expect(args.makerAddress).to.be.equal(anotherMakerAddress); }); }); }); // tslint:disable:max-file-line-count diff --git a/packages/contract-wrappers/test/global_hooks.ts b/packages/contract-wrappers/test/global_hooks.ts index 52a384ada..bf80e0908 100644 --- a/packages/contract-wrappers/test/global_hooks.ts +++ b/packages/contract-wrappers/test/global_hooks.ts @@ -1,5 +1,5 @@ import { devConstants } from '@0xproject/dev-utils'; -import { runV1MigrationsAsync } from '@0xproject/migrations'; +import { runV2MigrationsAsync } from '@0xproject/migrations'; import { provider } from './utils/web3_wrapper'; @@ -12,6 +12,6 @@ before('migrate contracts', async function(): Promise<void> { gas: devConstants.GAS_LIMIT, from: devConstants.TESTRPC_FIRST_ADDRESS, }; - const artifactsDir = `../migrations/artifacts/1.0.0`; - await runV1MigrationsAsync(provider, artifactsDir, txDefaults); + const artifactsDir = `../migrations/artifacts/2.0.0`; + await runV2MigrationsAsync(provider, artifactsDir, txDefaults); }); diff --git a/packages/contract-wrappers/test/order_validation_test.ts b/packages/contract-wrappers/test/order_validation_test.ts deleted file mode 100644 index 2afea2d5f..000000000 --- a/packages/contract-wrappers/test/order_validation_test.ts +++ /dev/null @@ -1,539 +0,0 @@ -import { BlockchainLifecycle } from '@0xproject/dev-utils'; -import { FillScenarios } from '@0xproject/fill-scenarios'; -import { OrderError } from '@0xproject/order-utils'; -import { BlockParamLiteral } from '@0xproject/types'; -import { BigNumber } from '@0xproject/utils'; -import * as chai from 'chai'; -import * as Sinon from 'sinon'; - -import { ContractWrappers, ExchangeContractErrs, SignedOrder, Token } from '../src'; -import { BalanceAndProxyAllowanceLazyStore } from '../src/stores/balance_proxy_allowance_lazy_store'; -import { TradeSide, TransferType } from '../src/types'; -import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator'; -import { OrderValidationUtils } from '../src/utils/order_validation_utils'; - -import { chaiSetup } from './utils/chai_setup'; -import { constants } from './utils/constants'; -import { TokenUtils } from './utils/token_utils'; -import { provider, web3Wrapper } from './utils/web3_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -describe('OrderValidation', () => { - let contractWrappers: ContractWrappers; - let userAddresses: string[]; - let tokens: Token[]; - let tokenUtils: TokenUtils; - let exchangeContractAddress: string; - let zrxTokenAddress: string; - let fillScenarios: FillScenarios; - let makerTokenAddress: string; - let takerTokenAddress: string; - let coinbase: string; - let makerAddress: string; - let takerAddress: string; - let feeRecipient: string; - const fillableAmount = new BigNumber(5); - const fillTakerAmount = new BigNumber(5); - const config = { - networkId: constants.TESTRPC_NETWORK_ID, - }; - before(async () => { - contractWrappers = new ContractWrappers(provider, config); - exchangeContractAddress = contractWrappers.exchange.getContractAddress(); - userAddresses = await web3Wrapper.getAvailableAddressesAsync(); - [coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses; - tokens = await contractWrappers.tokenRegistry.getTokensAsync(); - tokenUtils = new TokenUtils(tokens); - zrxTokenAddress = tokenUtils.getProtocolTokenOrThrow().address; - fillScenarios = new FillScenarios(provider, userAddresses, tokens, zrxTokenAddress, exchangeContractAddress); - const [makerToken, takerToken] = tokenUtils.getDummyTokens(); - makerTokenAddress = makerToken.address; - takerTokenAddress = takerToken.address; - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - describe('validateOrderFillableOrThrowAsync', () => { - it('should succeed if the order is fillable', async () => { - const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - ); - await contractWrappers.exchange.validateOrderFillableOrThrowAsync(signedOrder); - }); - it('should succeed if the maker is buying ZRX and has no ZRX balance', async () => { - const makerFee = new BigNumber(2); - const takerFee = new BigNumber(2); - const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerTokenAddress, - zrxTokenAddress, - makerFee, - takerFee, - makerAddress, - takerAddress, - fillableAmount, - feeRecipient, - ); - const zrxMakerBalance = await contractWrappers.token.getBalanceAsync(zrxTokenAddress, makerAddress); - await contractWrappers.token.transferAsync(zrxTokenAddress, makerAddress, takerAddress, zrxMakerBalance); - await contractWrappers.exchange.validateOrderFillableOrThrowAsync(signedOrder); - }); - it('should succeed if the maker is buying ZRX and has no ZRX balance and there is no specified taker', async () => { - const makerFee = new BigNumber(2); - const takerFee = new BigNumber(2); - const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerTokenAddress, - zrxTokenAddress, - makerFee, - takerFee, - makerAddress, - constants.NULL_ADDRESS, - fillableAmount, - feeRecipient, - ); - const zrxMakerBalance = await contractWrappers.token.getBalanceAsync(zrxTokenAddress, makerAddress); - await contractWrappers.token.transferAsync(zrxTokenAddress, makerAddress, takerAddress, zrxMakerBalance); - await contractWrappers.exchange.validateOrderFillableOrThrowAsync(signedOrder); - }); - it('should succeed if the order is asymmetric and fillable', async () => { - const makerFillableAmount = fillableAmount; - // tslint:disable-next-line:custom-no-magic-numbers - const takerFillableAmount = fillableAmount.minus(4); - const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - makerFillableAmount, - takerFillableAmount, - ); - await contractWrappers.exchange.validateOrderFillableOrThrowAsync(signedOrder); - }); - it('should throw when the order is fully filled or cancelled', async () => { - const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - ); - await contractWrappers.exchange.cancelOrderAsync(signedOrder, fillableAmount); - return expect(contractWrappers.exchange.validateOrderFillableOrThrowAsync(signedOrder)).to.be.rejectedWith( - ExchangeContractErrs.OrderRemainingFillAmountZero, - ); - }); - it('should throw when order is expired', async () => { - const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017 - const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - expirationInPast, - ); - return expect(contractWrappers.exchange.validateOrderFillableOrThrowAsync(signedOrder)).to.be.rejectedWith( - ExchangeContractErrs.OrderFillExpired, - ); - }); - }); - describe('validateFillOrderAndThrowIfInvalidAsync', () => { - it('should throw when the fill amount is zero', async () => { - const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - ); - const zeroFillAmount = new BigNumber(0); - return expect( - contractWrappers.exchange.validateFillOrderThrowIfInvalidAsync( - signedOrder, - zeroFillAmount, - takerAddress, - ), - ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); - }); - it('should throw when the signature is invalid', async () => { - const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - ); - // 27 <--> 28 - // tslint:disable-next-line:custom-no-magic-numbers - signedOrder.ecSignature.v = 28 - signedOrder.ecSignature.v + 27; - return expect( - contractWrappers.exchange.validateFillOrderThrowIfInvalidAsync( - signedOrder, - fillableAmount, - takerAddress, - ), - ).to.be.rejectedWith(OrderError.InvalidSignature); - }); - it('should throw when the order is fully filled or cancelled', async () => { - const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - ); - await contractWrappers.exchange.cancelOrderAsync(signedOrder, fillableAmount); - return expect( - contractWrappers.exchange.validateFillOrderThrowIfInvalidAsync( - signedOrder, - fillableAmount, - takerAddress, - ), - ).to.be.rejectedWith(ExchangeContractErrs.OrderRemainingFillAmountZero); - }); - it('should throw when sender is not a taker', async () => { - const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - ); - // tslint:disable-next-line:custom-no-magic-numbers - const nonTakerAddress = userAddresses[6]; - return expect( - contractWrappers.exchange.validateFillOrderThrowIfInvalidAsync( - signedOrder, - fillTakerAmount, - nonTakerAddress, - ), - ).to.be.rejectedWith(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker); - }); - it('should throw when order is expired', async () => { - const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017 - const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - expirationInPast, - ); - return expect( - contractWrappers.exchange.validateFillOrderThrowIfInvalidAsync( - signedOrder, - fillTakerAmount, - takerAddress, - ), - ).to.be.rejectedWith(ExchangeContractErrs.OrderFillExpired); - }); - it('should throw when there a rounding error would have occurred', async () => { - const makerAmount = new BigNumber(3); - const takerAmount = new BigNumber(5); - const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - makerAmount, - takerAmount, - ); - const fillTakerAmountThatCausesRoundingError = new BigNumber(3); - return expect( - contractWrappers.exchange.validateFillOrderThrowIfInvalidAsync( - signedOrder, - fillTakerAmountThatCausesRoundingError, - takerAddress, - ), - ).to.be.rejectedWith(ExchangeContractErrs.OrderFillRoundingError); - }); - }); - describe('#validateFillOrKillOrderAndThrowIfInvalidAsync', () => { - it('should throw if remaining fillAmount is less then the desired fillAmount', async () => { - const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - ); - const tooLargeFillAmount = new BigNumber(7); - const fillAmountDifference = tooLargeFillAmount.minus(fillableAmount); - await contractWrappers.token.transferAsync(takerTokenAddress, coinbase, takerAddress, fillAmountDifference); - await contractWrappers.token.setProxyAllowanceAsync(takerTokenAddress, takerAddress, tooLargeFillAmount); - await contractWrappers.token.transferAsync(makerTokenAddress, coinbase, makerAddress, fillAmountDifference); - await contractWrappers.token.setProxyAllowanceAsync(makerTokenAddress, makerAddress, tooLargeFillAmount); - - return expect( - contractWrappers.exchange.validateFillOrKillOrderThrowIfInvalidAsync( - signedOrder, - tooLargeFillAmount, - takerAddress, - ), - ).to.be.rejectedWith(ExchangeContractErrs.InsufficientRemainingFillAmount); - }); - }); - describe('validateCancelOrderAndThrowIfInvalidAsync', () => { - let signedOrder: SignedOrder; - const cancelAmount = new BigNumber(3); - beforeEach(async () => { - [coinbase, makerAddress, takerAddress] = userAddresses; - const [makerToken, takerToken] = tokenUtils.getDummyTokens(); - makerTokenAddress = makerToken.address; - takerTokenAddress = takerToken.address; - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - ); - }); - it('should throw when cancel amount is zero', async () => { - const zeroCancelAmount = new BigNumber(0); - return expect( - contractWrappers.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, zeroCancelAmount), - ).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); - }); - it('should throw when order is expired', async () => { - const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017 - const expiredSignedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - fillableAmount, - expirationInPast, - ); - return expect( - contractWrappers.exchange.validateCancelOrderThrowIfInvalidAsync(expiredSignedOrder, cancelAmount), - ).to.be.rejectedWith(ExchangeContractErrs.OrderCancelExpired); - }); - it('should throw when order is already cancelled or filled', async () => { - await contractWrappers.exchange.cancelOrderAsync(signedOrder, fillableAmount); - return expect( - contractWrappers.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, fillableAmount), - ).to.be.rejectedWith(ExchangeContractErrs.OrderAlreadyCancelledOrFilled); - }); - }); - describe('#validateFillOrderBalancesAllowancesThrowIfInvalidAsync', () => { - let exchangeTransferSimulator: ExchangeTransferSimulator; - let transferFromAsync: Sinon.SinonSpy; - const bigNumberMatch = (expected: BigNumber) => { - return Sinon.match((value: BigNumber) => value.eq(expected)); - }; - beforeEach('create exchangeTransferSimulator', async () => { - const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore( - contractWrappers.token, - BlockParamLiteral.Latest, - ); - exchangeTransferSimulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore); - transferFromAsync = Sinon.spy(); - exchangeTransferSimulator.transferFromAsync = transferFromAsync as any; - }); - it('should call exchangeTransferSimulator.transferFrom in a correct order', async () => { - const makerFee = new BigNumber(2); - const takerFee = new BigNumber(2); - const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerTokenAddress, - takerTokenAddress, - makerFee, - takerFee, - makerAddress, - takerAddress, - fillableAmount, - feeRecipient, - ); - await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( - exchangeTransferSimulator, - signedOrder, - fillableAmount, - takerAddress, - zrxTokenAddress, - ); - // tslint:disable-next-line:custom-no-magic-numbers - expect(transferFromAsync.callCount).to.be.equal(4); - expect( - transferFromAsync - .getCall(0) - .calledWith( - makerTokenAddress, - makerAddress, - takerAddress, - bigNumberMatch(fillableAmount), - TradeSide.Maker, - TransferType.Trade, - ), - ).to.be.true(); - expect( - transferFromAsync - .getCall(1) - .calledWith( - takerTokenAddress, - takerAddress, - makerAddress, - bigNumberMatch(fillableAmount), - TradeSide.Taker, - TransferType.Trade, - ), - ).to.be.true(); - expect( - transferFromAsync - .getCall(2) - .calledWith( - zrxTokenAddress, - makerAddress, - feeRecipient, - bigNumberMatch(makerFee), - TradeSide.Maker, - TransferType.Fee, - ), - ).to.be.true(); - expect( - transferFromAsync - .getCall(3) - .calledWith( - zrxTokenAddress, - takerAddress, - feeRecipient, - bigNumberMatch(takerFee), - TradeSide.Taker, - TransferType.Fee, - ), - ).to.be.true(); - }); - it('should call exchangeTransferSimulator.transferFrom with correct values for an open order', async () => { - const makerFee = new BigNumber(2); - const takerFee = new BigNumber(2); - const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerTokenAddress, - takerTokenAddress, - makerFee, - takerFee, - makerAddress, - constants.NULL_ADDRESS, - fillableAmount, - feeRecipient, - ); - await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( - exchangeTransferSimulator, - signedOrder, - fillableAmount, - takerAddress, - zrxTokenAddress, - ); - // tslint:disable-next-line:custom-no-magic-numbers - expect(transferFromAsync.callCount).to.be.equal(4); - expect( - transferFromAsync - .getCall(0) - .calledWith( - makerTokenAddress, - makerAddress, - takerAddress, - bigNumberMatch(fillableAmount), - TradeSide.Maker, - TransferType.Trade, - ), - ).to.be.true(); - expect( - transferFromAsync - .getCall(1) - .calledWith( - takerTokenAddress, - takerAddress, - makerAddress, - bigNumberMatch(fillableAmount), - TradeSide.Taker, - TransferType.Trade, - ), - ).to.be.true(); - expect( - transferFromAsync - .getCall(2) - .calledWith( - zrxTokenAddress, - makerAddress, - feeRecipient, - bigNumberMatch(makerFee), - TradeSide.Maker, - TransferType.Fee, - ), - ).to.be.true(); - expect( - transferFromAsync - .getCall(3) - .calledWith( - zrxTokenAddress, - takerAddress, - feeRecipient, - bigNumberMatch(takerFee), - TradeSide.Taker, - TransferType.Fee, - ), - ).to.be.true(); - }); - it('should correctly round the fillMakerTokenAmount', async () => { - const makerTokenAmount = new BigNumber(3); - const takerTokenAmount = new BigNumber(1); - const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync( - makerTokenAddress, - takerTokenAddress, - makerAddress, - takerAddress, - makerTokenAmount, - takerTokenAmount, - ); - await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( - exchangeTransferSimulator, - signedOrder, - takerTokenAmount, - takerAddress, - zrxTokenAddress, - ); - // tslint:disable-next-line:custom-no-magic-numbers - expect(transferFromAsync.callCount).to.be.equal(4); - const makerFillAmount = transferFromAsync.getCall(0).args[3]; - expect(makerFillAmount).to.be.bignumber.equal(makerTokenAmount); - }); - it('should correctly round the makerFeeAmount', async () => { - const makerFee = new BigNumber(2); - const takerFee = new BigNumber(4); - const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerTokenAddress, - takerTokenAddress, - makerFee, - takerFee, - makerAddress, - takerAddress, - fillableAmount, - constants.NULL_ADDRESS, - ); - const fillTakerTokenAmount = fillableAmount.div(2).round(0); - await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( - exchangeTransferSimulator, - signedOrder, - fillTakerTokenAmount, - takerAddress, - zrxTokenAddress, - ); - const makerPartialFee = makerFee.div(2); - const takerPartialFee = takerFee.div(2); - // tslint:disable-next-line:custom-no-magic-numbers - expect(transferFromAsync.callCount).to.be.equal(4); - const partialMakerFee = transferFromAsync.getCall(2).args[3]; - expect(partialMakerFee).to.be.bignumber.equal(makerPartialFee); - const partialTakerFee = transferFromAsync.getCall(3).args[3]; - expect(partialTakerFee).to.be.bignumber.equal(takerPartialFee); - }); - }); -}); // tslint:disable-line:max-file-line-count diff --git a/packages/contract-wrappers/test/subscription_test.ts b/packages/contract-wrappers/test/subscription_test.ts index b9417ca3d..adda4ab78 100644 --- a/packages/contract-wrappers/test/subscription_test.ts +++ b/packages/contract-wrappers/test/subscription_test.ts @@ -5,10 +5,11 @@ import * as _ from 'lodash'; import 'mocha'; import * as Sinon from 'sinon'; -import { ApprovalContractEventArgs, ContractWrappers, DecodedLogEvent, Token, TokenEvents } from '../src'; +import { ContractWrappers, DecodedLogEvent, ERC20TokenApprovalEventArgs, ERC20TokenEvents, Token } from '../src'; import { chaiSetup } from './utils/chai_setup'; import { constants } from './utils/constants'; +import { tokenUtils } from './utils/token_utils'; import { provider, web3Wrapper } from './utils/web3_wrapper'; chaiSetup.configure(); @@ -17,7 +18,6 @@ const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); describe('SubscriptionTest', () => { let contractWrappers: ContractWrappers; let userAddresses: string[]; - let tokens: Token[]; let coinbase: string; let addressWithoutFunds: string; const config = { @@ -26,7 +26,6 @@ describe('SubscriptionTest', () => { before(async () => { contractWrappers = new ContractWrappers(provider, config); userAddresses = await web3Wrapper.getAvailableAddressesAsync(); - tokens = await contractWrappers.tokenRegistry.getTokensAsync(); coinbase = userAddresses[0]; addressWithoutFunds = userAddresses[1]; }); @@ -42,11 +41,11 @@ describe('SubscriptionTest', () => { const allowanceAmount = new BigNumber(42); let stubs: Sinon.SinonStub[] = []; before(() => { - const token = tokens[0]; - tokenAddress = token.address; + const tokenAddresses = tokenUtils.getDummyERC20TokenAddresses(); + tokenAddress = tokenAddresses[0]; }); afterEach(() => { - contractWrappers.token.unsubscribeAll(); + contractWrappers.erc20Token.unsubscribeAll(); _.each(stubs, s => s.restore()); stubs = []; }); @@ -55,8 +54,13 @@ describe('SubscriptionTest', () => { const errMsg = 'Error fetching block'; const callback = callbackErrorReporter.assertNodeCallbackError(done, errMsg); stubs = [Sinon.stub((contractWrappers as any)._web3Wrapper, 'getBlockAsync').throws(new Error(errMsg))]; - contractWrappers.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback); - await contractWrappers.token.setAllowanceAsync( + contractWrappers.erc20Token.subscribe( + tokenAddress, + ERC20TokenEvents.Approval, + indexFilterValues, + callback, + ); + await contractWrappers.erc20Token.setAllowanceAsync( tokenAddress, coinbase, addressWithoutFunds, @@ -69,8 +73,13 @@ describe('SubscriptionTest', () => { const errMsg = 'Error fetching logs'; const callback = callbackErrorReporter.assertNodeCallbackError(done, errMsg); stubs = [Sinon.stub((contractWrappers as any)._web3Wrapper, 'getLogsAsync').throws(new Error(errMsg))]; - contractWrappers.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback); - await contractWrappers.token.setAllowanceAsync( + contractWrappers.erc20Token.subscribe( + tokenAddress, + ERC20TokenEvents.Approval, + indexFilterValues, + callback, + ); + await contractWrappers.erc20Token.setAllowanceAsync( tokenAddress, coinbase, addressWithoutFunds, @@ -80,14 +89,20 @@ describe('SubscriptionTest', () => { }); it('Should allow unsubscribeAll to be called successfully after an error', (done: DoneCallback) => { (async () => { - const callback = (_err: Error | null, _logEvent?: DecodedLogEvent<ApprovalContractEventArgs>) => _.noop; - contractWrappers.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback); + const callback = (err: Error | null, _logEvent?: DecodedLogEvent<ERC20TokenApprovalEventArgs>) => + _.noop; + contractWrappers.erc20Token.subscribe( + tokenAddress, + ERC20TokenEvents.Approval, + indexFilterValues, + callback, + ); stubs = [ Sinon.stub((contractWrappers as any)._web3Wrapper, 'getBlockAsync').throws( new Error('JSON RPC error'), ), ]; - contractWrappers.token.unsubscribeAll(); + contractWrappers.erc20Token.unsubscribeAll(); done(); })().catch(done); }); diff --git a/packages/contract-wrappers/test/token_registry_wrapper_test.ts b/packages/contract-wrappers/test/token_registry_wrapper_test.ts deleted file mode 100644 index 6576d789d..000000000 --- a/packages/contract-wrappers/test/token_registry_wrapper_test.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { BlockchainLifecycle } from '@0xproject/dev-utils'; -import { schemas, SchemaValidator } from '@0xproject/json-schemas'; -import * as chai from 'chai'; -import * as _ from 'lodash'; -import 'mocha'; - -import { ContractWrappers, Token } from '../src'; - -import { chaiSetup } from './utils/chai_setup'; -import { constants } from './utils/constants'; -import { provider, web3Wrapper } from './utils/web3_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -const TOKEN_REGISTRY_SIZE_AFTER_MIGRATION = 7; - -describe('TokenRegistryWrapper', () => { - let contractWrappers: ContractWrappers; - let tokens: Token[]; - const tokenAddressBySymbol: { [symbol: string]: string } = {}; - const tokenAddressByName: { [symbol: string]: string } = {}; - const tokenBySymbol: { [symbol: string]: Token } = {}; - const tokenByName: { [symbol: string]: Token } = {}; - const registeredSymbol = 'ZRX'; - const registeredName = '0x Protocol Token'; - const unregisteredSymbol = 'MAL'; - const unregisteredName = 'Malicious Token'; - const config = { - networkId: constants.TESTRPC_NETWORK_ID, - }; - before(async () => { - contractWrappers = new ContractWrappers(provider, config); - tokens = await contractWrappers.tokenRegistry.getTokensAsync(); - _.map(tokens, token => { - tokenAddressBySymbol[token.symbol] = token.address; - tokenAddressByName[token.name] = token.address; - tokenBySymbol[token.symbol] = token; - tokenByName[token.name] = token; - }); - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - describe('#getTokensAsync', () => { - it('should return all the tokens added to the tokenRegistry during the migration', async () => { - expect(tokens).to.have.lengthOf(TOKEN_REGISTRY_SIZE_AFTER_MIGRATION); - - const schemaValidator = new SchemaValidator(); - _.each(tokens, token => { - const validationResult = schemaValidator.validate(token, schemas.tokenSchema); - expect(validationResult.errors).to.have.lengthOf(0); - }); - }); - }); - describe('#getTokenAddressesAsync', () => { - it('should return all the token addresses added to the tokenRegistry during the migration', async () => { - const tokenAddresses = await contractWrappers.tokenRegistry.getTokenAddressesAsync(); - expect(tokenAddresses).to.have.lengthOf(TOKEN_REGISTRY_SIZE_AFTER_MIGRATION); - - const schemaValidator = new SchemaValidator(); - _.each(tokenAddresses, tokenAddress => { - const validationResult = schemaValidator.validate(tokenAddress, schemas.addressSchema); - expect(validationResult.errors).to.have.lengthOf(0); - expect(tokenAddress).to.not.be.equal(constants.NULL_ADDRESS); - }); - }); - }); - describe('#getTokenAddressBySymbol', () => { - it('should return correct address for a token in the registry', async () => { - const tokenAddress = await contractWrappers.tokenRegistry.getTokenAddressBySymbolIfExistsAsync( - registeredSymbol, - ); - expect(tokenAddress).to.be.equal(tokenAddressBySymbol[registeredSymbol]); - }); - it('should return undefined for a token out of registry', async () => { - const tokenAddress = await contractWrappers.tokenRegistry.getTokenAddressBySymbolIfExistsAsync( - unregisteredSymbol, - ); - expect(tokenAddress).to.be.undefined(); - }); - }); - describe('#getTokenAddressByName', () => { - it('should return correct address for a token in the registry', async () => { - const tokenAddress = await contractWrappers.tokenRegistry.getTokenAddressByNameIfExistsAsync( - registeredName, - ); - expect(tokenAddress).to.be.equal(tokenAddressByName[registeredName]); - }); - it('should return undefined for a token out of registry', async () => { - const tokenAddress = await contractWrappers.tokenRegistry.getTokenAddressByNameIfExistsAsync( - unregisteredName, - ); - expect(tokenAddress).to.be.undefined(); - }); - }); - describe('#getTokenBySymbol', () => { - it('should return correct token for a token in the registry', async () => { - const token = await contractWrappers.tokenRegistry.getTokenBySymbolIfExistsAsync(registeredSymbol); - expect(token).to.be.deep.equal(tokenBySymbol[registeredSymbol]); - }); - it('should return undefined for a token out of registry', async () => { - const token = await contractWrappers.tokenRegistry.getTokenBySymbolIfExistsAsync(unregisteredSymbol); - expect(token).to.be.undefined(); - }); - }); - describe('#getTokenByName', () => { - it('should return correct token for a token in the registry', async () => { - const token = await contractWrappers.tokenRegistry.getTokenByNameIfExistsAsync(registeredName); - expect(token).to.be.deep.equal(tokenByName[registeredName]); - }); - it('should return undefined for a token out of registry', async () => { - const token = await contractWrappers.tokenRegistry.getTokenByNameIfExistsAsync(unregisteredName); - expect(token).to.be.undefined(); - }); - }); - describe('#getTokenIfExistsAsync', () => { - it('should return the token added to the tokenRegistry during the migration', async () => { - const aToken = tokens[0]; - - const token = await contractWrappers.tokenRegistry.getTokenIfExistsAsync(aToken.address); - const schemaValidator = new SchemaValidator(); - const validationResult = schemaValidator.validate(token, schemas.tokenSchema); - expect(validationResult.errors).to.have.lengthOf(0); - }); - it('should return return undefined when passed a token address not in the tokenRegistry', async () => { - const unregisteredTokenAddress = '0x5409ed021d9299bf6814279a6a1411a7e866a631'; - const tokenIfExists = await contractWrappers.tokenRegistry.getTokenIfExistsAsync(unregisteredTokenAddress); - expect(tokenIfExists).to.be.undefined(); - }); - }); -}); diff --git a/packages/contract-wrappers/test/utils/constants.ts b/packages/contract-wrappers/test/utils/constants.ts index cf030259c..60c3370a2 100644 --- a/packages/contract-wrappers/test/utils/constants.ts +++ b/packages/contract-wrappers/test/utils/constants.ts @@ -1,9 +1,18 @@ +import { BigNumber } from '@0xproject/utils'; + export const constants = { NULL_ADDRESS: '0x0000000000000000000000000000000000000000', ROPSTEN_NETWORK_ID: 3, KOVAN_NETWORK_ID: 42, TESTRPC_NETWORK_ID: 50, + AWAIT_TRANSACTION_MINED_MS: 0, KOVAN_RPC_URL: 'https://kovan.infura.io/', ROPSTEN_RPC_URL: 'https://ropsten.infura.io/', ZRX_DECIMALS: 18, + DUMMY_TOKEN_NAME: '', + DUMMY_TOKEN_SYMBOL: '', + DUMMY_TOKEN_DECIMALS: 18, + DUMMY_TOKEN_TOTAL_SUPPLY: new BigNumber(10 ** 27), // tslint:disable-line:custom-no-magic-numbers + NUM_DUMMY_ERC20_TO_DEPLOY: 3, + NUM_DUMMY_ERC721_TO_DEPLOY: 1, }; diff --git a/packages/contract-wrappers/test/utils/token_utils.ts b/packages/contract-wrappers/test/utils/token_utils.ts index fe85de085..06a82ff6e 100644 --- a/packages/contract-wrappers/test/utils/token_utils.ts +++ b/packages/contract-wrappers/test/utils/token_utils.ts @@ -1,33 +1,47 @@ -import * as _ from 'lodash'; +import { generatePseudoRandomSalt } from '@0xproject/order-utils'; +import { BigNumber } from '@0xproject/utils'; -import { InternalContractWrappersError, Token } from '../../src/types'; +import { artifacts } from '../../src/artifacts'; +import { DummyERC721TokenContract } from '../../src/contract_wrappers/generated/dummy_erc721_token'; -const PROTOCOL_TOKEN_SYMBOL = 'ZRX'; -const WETH_TOKEN_SYMBOL = 'WETH'; +import { constants } from './constants'; +import { provider, txDefaults, web3Wrapper } from './web3_wrapper'; -export class TokenUtils { - private _tokens: Token[]; - constructor(tokens: Token[]) { - this._tokens = tokens; - } - public getProtocolTokenOrThrow(): Token { - const zrxToken = _.find(this._tokens, { symbol: PROTOCOL_TOKEN_SYMBOL }); - if (_.isUndefined(zrxToken)) { - throw new Error(InternalContractWrappersError.ZrxNotInTokenRegistry); - } - return zrxToken; - } - public getWethTokenOrThrow(): Token { - const wethToken = _.find(this._tokens, { symbol: WETH_TOKEN_SYMBOL }); - if (_.isUndefined(wethToken)) { - throw new Error(InternalContractWrappersError.WethNotInTokenRegistry); - } - return wethToken; - } - public getDummyTokens(): Token[] { - const dummyTokens = _.filter(this._tokens, token => { - return !_.includes([PROTOCOL_TOKEN_SYMBOL, WETH_TOKEN_SYMBOL], token.symbol); - }); - return dummyTokens; - } -} +// Those addresses come from migrations. They're deterministic so it's relatively safe to hard-code them here. +// Before we were fetching them from the TokenRegistry but now we can't as it's deprecated and removed. +const DUMMY_ERC_20_ADRESSES = [ + '0x6dfff22588be9b3ef8cf0ad6dc9b84796f9fb45f', + '0xcfc18cec799fbd1793b5c43e773c98d4d61cc2db', + '0xf22469f31527adc53284441bae1665a7b9214dba', + '0x10add991de718a69dec2117cb6aa28098836511b', + '0x8d61158a366019ac78db4149d75fff9dda51160d', +]; + +const DUMMY_ERC_721_ADRESSES = ['0x131855dda0aaff096f6854854c55a4debf61077a']; + +export const tokenUtils = { + getProtocolTokenAddress(): string { + return artifacts.ZRXToken.networks[constants.TESTRPC_NETWORK_ID].address; + }, + getWethTokenAddress(): string { + return artifacts.EtherToken.networks[constants.TESTRPC_NETWORK_ID].address; + }, + getDummyERC20TokenAddresses(): string[] { + return DUMMY_ERC_20_ADRESSES; + }, + getDummyERC721TokenAddresses(): string[] { + return DUMMY_ERC_721_ADRESSES; + }, + async mintDummyERC721Async(address: string, tokenOwner: string): Promise<BigNumber> { + const erc721 = new DummyERC721TokenContract( + artifacts.DummyERC721Token.compilerOutput.abi, + address, + provider, + txDefaults, + ); + const tokenId = generatePseudoRandomSalt(); + const txHash = await erc721.mint.sendTransactionAsync(tokenOwner, tokenId); + web3Wrapper.awaitTransactionSuccessAsync(txHash); + return tokenId; + }, +}; diff --git a/packages/contract-wrappers/test/utils/web3_wrapper.ts b/packages/contract-wrappers/test/utils/web3_wrapper.ts index f7d11f138..02c8c5918 100644 --- a/packages/contract-wrappers/test/utils/web3_wrapper.ts +++ b/packages/contract-wrappers/test/utils/web3_wrapper.ts @@ -1,8 +1,12 @@ -import { web3Factory } from '@0xproject/dev-utils'; -import { Provider } from '@0xproject/types'; +import { devConstants, web3Factory } from '@0xproject/dev-utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import { Provider } from 'ethereum-types'; +const txDefaults = { + from: devConstants.TESTRPC_FIRST_ADDRESS, + gas: devConstants.GAS_LIMIT, +}; const provider: Provider = web3Factory.getRpcProvider({ shouldUseInProcessGanache: true }); const web3Wrapper = new Web3Wrapper(provider); -export { provider, web3Wrapper }; +export { provider, web3Wrapper, txDefaults }; |