From b4aca370defb9dfe6c01b60d1b522d4a7b731f43 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 28 Nov 2018 18:09:50 -0800 Subject: Writing tests for Compliant Forwarder --- contracts/extensions/test/extensions/forwarder.ts | 1 + .../test/extensions/compliant_forwarder.ts | 172 +++++++++++++++------ 2 files changed, 126 insertions(+), 47 deletions(-) diff --git a/contracts/extensions/test/extensions/forwarder.ts b/contracts/extensions/test/extensions/forwarder.ts index 4027f493d..a4afa283e 100644 --- a/contracts/extensions/test/extensions/forwarder.ts +++ b/contracts/extensions/test/extensions/forwarder.ts @@ -61,6 +61,7 @@ describe(ContractName.Forwarder, () => { let wethContract: WETH9Contract; let forwarderWrapper: ForwarderWrapper; let exchangeWrapper: ExchangeWrapper; + let takerPrivateKey: Buffer; let orderWithoutFee: SignedOrder; let orderWithFee: SignedOrder; diff --git a/packages/contracts/test/extensions/compliant_forwarder.ts b/packages/contracts/test/extensions/compliant_forwarder.ts index bb9493aaa..9100c32f8 100644 --- a/packages/contracts/test/extensions/compliant_forwarder.ts +++ b/packages/contracts/test/extensions/compliant_forwarder.ts @@ -9,6 +9,7 @@ import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token'; import { ExchangeContract } from '../../generated-wrappers/exchange'; import { CompliantForwarderContract } from '../../generated-wrappers/compliant_forwarder'; +import { YesComplianceTokenContract } from '../../generated-wrappers/yes_compliance_token'; import { WETH9Contract } from '../../generated-wrappers/weth9'; import { artifacts } from '../../src/artifacts'; @@ -24,7 +25,9 @@ import { ERC721Wrapper } from '../utils/erc721_wrapper'; import { ExchangeWrapper } from '../utils/exchange_wrapper'; import { ForwarderWrapper } from '../utils/forwarder_wrapper'; import { OrderFactory } from '../utils/order_factory'; -import { ContractName, ERC20BalancesByOwner } from '../utils/types'; +import { orderUtils } from '../utils/order_utils'; +import { TransactionFactory } from '../utils/transaction_factory'; +import { ContractName, ERC20BalancesByOwner, SignedTransaction } from '../utils/types'; import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; chaiSetup.configure(); @@ -33,12 +36,12 @@ const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); const DECIMALS_DEFAULT = 18; const MAX_WETH_FILL_PERCENTAGE = 95; -describe(ContractName.Forwarder, () => { - let makerAddress: string; +describe.only(ContractName.Forwarder, () => { + let compliantMakerAddress: string; let owner: string; - let takerAddress: string; + let compliantTakerAddress: string; let feeRecipientAddress: string; - let otherAddress: string; + let noncompliantAddress: string; let defaultMakerAssetAddress: string; let zrxAssetData: string; let wethAssetData: string; @@ -46,6 +49,7 @@ describe(ContractName.Forwarder, () => { let weth: DummyERC20TokenContract; let zrxToken: DummyERC20TokenContract; let erc20TokenA: DummyERC20TokenContract; + let yesComplianceToken: YesComplianceTokenContract; let compliantForwarderContract: CompliantForwarderContract; let wethContract: WETH9Contract; let forwarderWrapper: ForwarderWrapper; @@ -59,37 +63,73 @@ describe(ContractName.Forwarder, () => { let erc20Balances: ERC20BalancesByOwner; let tx: TransactionReceiptWithDecodedLogs; + let makerAssetAddress: string; + let takerAssetAddress: string; + let erc721MakerAssetIds: BigNumber[]; let takerEthBalanceBefore: BigNumber; let feePercentage: BigNumber; - let gasPrice: BigNumber; + + let compliantSignedOrder: SignedOrder; + let compliantSignedFillOrderTx: SignedTransaction; + let noncompliantSignedFillOrderTx: SignedTransaction; + + const compliantMakerCountryCode = new BigNumber(519); + const compliantMakerYesMark = new BigNumber(1); + const compliantMakerEntityId = new BigNumber(2); + let compliantMakerYesTokenId; + + const compliantTakerCountryCode = new BigNumber(519); + const compliantTakerYesMark = new BigNumber(1); + const compliantTakerEntityId = new BigNumber(2); + let compliantTakerYesTokenId; + + const takerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(500), DECIMALS_DEFAULT); + const makerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), DECIMALS_DEFAULT); + const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(250), DECIMALS_DEFAULT); + const salt = new BigNumber(0); + + let compliantForwarderInstance: CompliantForwarderContract; before(async () => { + // Create accounts await blockchainLifecycle.startAsync(); const accounts = await web3Wrapper.getAvailableAddressesAsync(); - const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress, otherAddress] = accounts); - - const txHash = await web3Wrapper.sendTransactionAsync({ from: accounts[0], to: accounts[0], value: 0 }); - const transaction = await web3Wrapper.getTransactionByHashAsync(txHash); - gasPrice = new BigNumber(transaction.gasPrice); - + const usedAddresses = ([owner, compliantMakerAddress, compliantTakerAddress, feeRecipientAddress, noncompliantAddress] = accounts); + // Create wrappers const erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner); erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); - + // Deploy ERC20 tokens const numDummyErc20ToDeploy = 3; - [erc20TokenA, zrxToken] = await erc20Wrapper.deployDummyTokensAsync( + let erc20TokenA: DummyERC20TokenContract; + let erc20TokenB: DummyERC20TokenContract; + [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync( numDummyErc20ToDeploy, constants.DUMMY_TOKEN_DECIMALS, ); + makerAssetAddress = erc20TokenA.address; + takerAssetAddress = erc20TokenB.address; + // Deploy Yes Token + const yesTokenInstance = await YesComplianceTokenContract.deployFrom0xArtifactAsync( + artifacts.YesComplianceToken, + provider, + txDefaults, + ); + compliantForwarderContract = new CompliantForwarderContract( + yesTokenInstance.abi, + yesTokenInstance.address, + provider, + ); + // Create proxies const erc20Proxy = await erc20Wrapper.deployProxyAsync(); await erc20Wrapper.setBalancesAndAllowancesAsync(); - + // Deploy tokens & set asset data wethContract = await WETH9Contract.deployFrom0xArtifactAsync(artifacts.WETH9, provider, txDefaults); weth = new DummyERC20TokenContract(wethContract.abi, wethContract.address, provider); erc20Wrapper.addDummyTokenContract(weth); - wethAssetData = assetDataUtils.encodeERC20AssetData(wethContract.address); zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address); + // Deploy Exchange congtract const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync( artifacts.Exchange, provider, @@ -97,36 +137,35 @@ describe(ContractName.Forwarder, () => { zrxAssetData, ); exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider); + // Register proxies await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); - await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, { from: owner, }); - + // Default order parameters defaultMakerAssetAddress = erc20TokenA.address; const defaultTakerAssetAddress = wethContract.address; const defaultOrderParams = { exchangeAddress: exchangeInstance.address, - makerAddress, + compliantMakerAddress, feeRecipientAddress, makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress), - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), DECIMALS_DEFAULT), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), DECIMALS_DEFAULT), + makerAssetAmount: makerAssetAmount, + takerAssetAmount: takerAssetAmount, makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT), - takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), DECIMALS_DEFAULT), + takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT), }; - const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)]; + const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(compliantMakerAddress)]; orderFactory = new OrderFactory(privateKey, defaultOrderParams); - - const compliantForwarderInstance = await CompliantForwarderContract.deployFrom0xArtifactAsync( + // Deploy Compliant Forwarder + compliantForwarderInstance = await CompliantForwarderContract.deployFrom0xArtifactAsync( artifacts.CompliantForwarder, provider, txDefaults, exchangeInstance.address, - exchangeInstance.address, // @TODO CHANGE to Yes Token + yesTokenInstance.address, ); - compliantForwarderContract = new CompliantForwarderContract( compliantForwarderInstance.abi, compliantForwarderInstance.address, @@ -135,35 +174,74 @@ describe(ContractName.Forwarder, () => { /* forwarderWrapper = new ForwarderWrapper(compliantForwarderContract, provider); */ - - const zrxDepositAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 18); - await web3Wrapper.awaitTransactionSuccessAsync( - await zrxToken.transfer.sendTransactionAsync(compliantForwarderContract.address, zrxDepositAmount), + // Verify Maker / Taker + const addressesCanControlTheirToken = true; + compliantMakerYesTokenId = await yesTokenInstance.mint2.sendTransactionAsync(compliantMakerAddress, compliantMakerEntityId, addressesCanControlTheirToken, compliantMakerCountryCode, [compliantMakerYesMark]); + compliantTakerYesTokenId = await yesTokenInstance.mint2.sendTransactionAsync(compliantTakerAddress, compliantTakerEntityId, addressesCanControlTheirToken, compliantTakerCountryCode, [compliantTakerYesMark]); + // Create Valid/Invalid orders + const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(compliantTakerAddress)]; + const takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchangeInstance.address); + compliantSignedOrder = await orderFactory.newSignedOrderAsync({ + senderAddress: compliantForwarderContract.address, + }); + const compliantSignedOrderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(compliantSignedOrder); + const compliantSignedOrderWithoutExchangeAddressData = exchangeInstance.fillOrder.getABIEncodedTransactionData( + compliantSignedOrderWithoutExchangeAddress, + takerAssetFillAmount, + compliantSignedOrder.signature, ); - erc20Wrapper.addTokenOwnerAddress(compliantForwarderInstance.address); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); + compliantSignedFillOrderTx = takerTransactionFactory.newSignedTransaction(compliantSignedOrderWithoutExchangeAddressData); }); beforeEach(async () => { await blockchainLifecycle.startAsync(); - erc20Balances = await erc20Wrapper.getBalancesAsync(); - takerEthBalanceBefore = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - orderWithoutFee = await orderFactory.newSignedOrderAsync(); - feeOrder = await orderFactory.newSignedOrderAsync({ - makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address), - takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT), - }); - orderWithFee = await orderFactory.newSignedOrderAsync({ - takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT), - }); }); afterEach(async () => { await blockchainLifecycle.revertAsync(); }); - describe('constructor', () => { - it('should revert if assetProxy is unregistered', async () => {}); + describe.only('fillOrder', () => { + let takerAssetFillAmount: BigNumber; + beforeEach(async () => { + erc20Balances = await erc20Wrapper.getBalancesAsync(); + }); + + // @TODO: Should fail if order's senderAddress is not set to the compliant forwarding contract + // @TODO: Should fail if the + + it.only('should transfer the correct amounts when maker and taker are verified', async () => { + await compliantForwarderInstance.fillOrder.sendTransactionAsync(compliantSignedFillOrderTx.salt, compliantSignedFillOrderTx.signerAddress, compliantSignedFillOrderTx.data, compliantSignedFillOrderTx.signature); + const newBalances = await erc20Wrapper.getBalancesAsync(); + const makerAssetFillAmount = takerAssetFillAmount + .times(compliantSignedOrder.makerAssetAmount) + .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount); + const makerFeePaid = compliantSignedOrder.makerFee + .times(makerAssetFillAmount) + .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount); + const takerFeePaid = compliantSignedOrder.takerFee + .times(makerAssetFillAmount) + .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount); + expect(newBalances[compliantMakerAddress][makerAssetAddress]).to.be.bignumber.equal( + erc20Balances[compliantMakerAddress][makerAssetAddress].minus(makerAssetFillAmount), + ); + expect(newBalances[compliantMakerAddress][takerAssetAddress]).to.be.bignumber.equal( + erc20Balances[compliantMakerAddress][takerAssetAddress].add(takerAssetFillAmount), + ); + expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid), + ); + expect(newBalances[compliantTakerAddress][takerAssetAddress]).to.be.bignumber.equal( + erc20Balances[compliantTakerAddress][takerAssetAddress].minus(takerAssetFillAmount), + ); + expect(newBalances[compliantTakerAddress][makerAssetAddress]).to.be.bignumber.equal( + erc20Balances[compliantTakerAddress][makerAssetAddress].add(makerAssetFillAmount), + ); + expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid), + ); + expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)), + ); + }); }); }); // tslint:disable:max-file-line-count -- cgit v1.2.3