diff options
Diffstat (limited to 'packages/contract-wrappers/test')
14 files changed, 875 insertions, 1056 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..ae47a11ad 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,60 @@ describe('TokenWrapper', () => { it('Outstanding subscriptions are cancelled when contractWrappers.setProvider called', (done: DoneCallback) => { (async () => { const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)( +<<<<<<< HEAD:packages/contract-wrappers/test/erc20_wrapper_test.ts + (logEvent: DecodedLogEvent<ERC20TokenApprovalEventArgs>) => { +======= (_logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { +>>>>>>> v2-prototype:packages/contract-wrappers/test/token_wrapper_test.ts 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)( +<<<<<<< HEAD:packages/contract-wrappers/test/erc20_wrapper_test.ts + (logEvent: DecodedLogEvent<ERC20TokenApprovalEventArgs>) => { +======= (_logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { +>>>>>>> v2-prototype:packages/contract-wrappers/test/token_wrapper_test.ts 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 +595,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 +614,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 +630,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..e3440b9b9 --- /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.only('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/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..df80c4743 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,19 @@ 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..3ef83546b 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 = [ + '0x07f96aa816c1f244cbc6ef114bb2b023ba54a2eb', + '0x6a4a62e5a7ed13c361b176a5f62c2ee620ac0df8', + '0x6dfff22588be9b3ef8cf0ad6dc9b84796f9fb45f', + '0xcfc18cec799fbd1793b5c43e773c98d4d61cc2db', + '0xf22469f31527adc53284441bae1665a7b9214dba', +]; + +const DUMMY_ERC_721_ADRESSES = ['0x10add991de718a69dec2117cb6aa28098836511b']; + +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..641444539 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, + gasLimit: devConstants.GAS_LIMIT, +}; const provider: Provider = web3Factory.getRpcProvider({ shouldUseInProcessGanache: true }); const web3Wrapper = new Web3Wrapper(provider); -export { provider, web3Wrapper }; +export { provider, web3Wrapper, txDefaults }; |