aboutsummaryrefslogblamecommitdiffstats
path: root/packages/contracts/test/extensions/compliant_forwarder.ts
blob: 932012c0d7caf064e47318cbb75cfa4492882488 (plain) (tree)
1
2
3
4
5
6
7
8
9





                                                      


                                                                                     
                                                                                          
                                                                                           
 








                                                      
                                                            
                                                      


                                                                                       





                                                                          
 
                                                      
                                      
                      
                                      
                                    
                                    
                                         
                                         
                             
                                          

                                         


                                            
 



                                                         


                                                                                                    

                                                               

                        
                          

                                                                        






                                  
                          
                                                                        
                              
                                        


                                                                                         


                                           

                                                       
                                                                             
                           
                                                                                            



                                         
                         

                                                                 
                                    






                                                                                  
                           
                                                                                 


                                                                                              
                                   

                                                      
                                                


                                                                                          



                                                                                         
          
                                                                                                   
                                                                        

                                                                                                
                                         


                                     
                                     
          

                                                                          



                                               

                                                                                      






                                                                                                              



                                                             






                                          



                                                             






                                          



                                                                                                          
                                                              
           


                                                                                                     



                                                                                                                       
          


                                                                                  


                                               



                                                
                                      



                                                                  
                                                                                                      




                                                                            
              
                                                                      








                                                                           

                                                                                                           
              

                                                                                                         



                                                                                               

                                                                                                           
              

                                                                                                         







                                                                                                         



                                                                                                      



                                              
import { BlockchainLifecycle } from '@0x/dev-utils';
import { assetDataUtils } from '@0x/order-utils';
import { RevertReason, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import * as chai from 'chai';

import { 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 { artifacts } from '../../src/artifacts';
import {
    expectContractCreationFailedAsync,
    expectTransactionFailedAsync,
    sendTransactionResult,
} from '../utils/assertions';
import { chaiSetup } from '../utils/chai_setup';
import { constants } from '../utils/constants';
import { ERC20Wrapper } from '../utils/erc20_wrapper';
import { ExchangeWrapper } from '../utils/exchange_wrapper';
import { OrderFactory } from '../utils/order_factory';
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();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
const DECIMALS_DEFAULT = 18;

describe.only(ContractName.CompliantForwarder, () => {
    let compliantMakerAddress: string;
    let owner: string;
    let compliantTakerAddress: string;
    let feeRecipientAddress: string;
    let noncompliantAddress: string;
    let defaultMakerAssetAddress: string;
    let defaultTakerAssetAddress: string;
    let zrxAssetData: string;
    let zrxToken: DummyERC20TokenContract;
    let exchangeWrapper: ExchangeWrapper;

    let orderFactory: OrderFactory;
    let erc20Wrapper: ERC20Wrapper;
    let erc20Balances: ERC20BalancesByOwner;

    let compliantSignedOrder: SignedOrder;
    let compliantSignedFillOrderTx: SignedTransaction;
    let noncompliantSignedFillOrderTx: SignedTransaction;

    const takerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(500), DECIMALS_DEFAULT);
    const makerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), DECIMALS_DEFAULT);
    const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(250), DECIMALS_DEFAULT);

    let compliantForwarderInstance: CompliantForwarderContract;

    before(async () => {
        // Create accounts
        await blockchainLifecycle.startAsync();
        const accounts = await web3Wrapper.getAvailableAddressesAsync();
        const usedAddresses = ([
            owner,
            compliantMakerAddress,
            compliantTakerAddress,
            feeRecipientAddress,
            noncompliantAddress,
        ] = accounts);
        // Create wrappers
        erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
        // Deploy ERC20 tokens
        const numDummyErc20ToDeploy = 3;
        let erc20TokenA: DummyERC20TokenContract;
        let erc20TokenB: DummyERC20TokenContract;
        [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
            numDummyErc20ToDeploy,
            constants.DUMMY_TOKEN_DECIMALS,
        );
        defaultMakerAssetAddress = erc20TokenA.address;
        defaultTakerAssetAddress = erc20TokenB.address;
        zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
        // Deploy Yes Token
        const yesTokenInstance = await YesComplianceTokenContract.deployFrom0xArtifactAsync(
            artifacts.YesComplianceToken,
            provider,
            txDefaults,
        );
        // Create proxies
        const erc20Proxy = await erc20Wrapper.deployProxyAsync();
        await erc20Wrapper.setBalancesAndAllowancesAsync();
        // Deploy Exchange congtract
        const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
            artifacts.Exchange,
            provider,
            txDefaults,
            zrxAssetData,
        );
        exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider);
        // Register proxies
        await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
        await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
            from: owner,
        });
        // Default order parameters
        const defaultOrderParams = {
            exchangeAddress: exchangeInstance.address,
            makerAddress: compliantMakerAddress,
            feeRecipientAddress,
            makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
            takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
            makerAssetAmount,
            takerAssetAmount,
            makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), DECIMALS_DEFAULT),
            takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(150), DECIMALS_DEFAULT),
        };
        const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(compliantMakerAddress)];
        orderFactory = new OrderFactory(privateKey, defaultOrderParams);
        // Deploy Compliant Forwarder
        compliantForwarderInstance = await CompliantForwarderContract.deployFrom0xArtifactAsync(
            artifacts.CompliantForwarder,
            provider,
            txDefaults,
            exchangeInstance.address,
            yesTokenInstance.address,
        );
        /*
        const compliantForwarderContract = new CompliantForwarderContract(
            compliantForwarderInstance.abi,
            compliantForwarderInstance.address,
            provider,
        );
        forwarderWrapper = new ForwarderWrapper(compliantForwarderContract, provider);
        */
        // Initialize Yes Token
        await yesTokenInstance._upgradeable_initialize.sendTransactionAsync({ from: owner });
        const yesTokenName = 'YesToken';
        const yesTokenTicker = 'YEET';
        await yesTokenInstance.initialize.sendTransactionAsync(yesTokenName, yesTokenTicker, { from: owner });
        // Verify Maker / Taker
        const addressesCanControlTheirToken = true;
        const compliantMakerCountryCode = new BigNumber(519);
        const compliantMakerYesMark = new BigNumber(1);
        const compliantMakerEntityId = new BigNumber(2);
        await yesTokenInstance.mint2.sendTransactionAsync(
            compliantMakerAddress,
            compliantMakerEntityId,
            addressesCanControlTheirToken,
            compliantMakerCountryCode,
            [compliantMakerYesMark],
            { from: owner },
        );
        const compliantTakerCountryCode = new BigNumber(519);
        const compliantTakerYesMark = new BigNumber(1);
        const compliantTakerEntityId = new BigNumber(2);
        await yesTokenInstance.mint2.sendTransactionAsync(
            compliantTakerAddress,
            compliantTakerEntityId,
            addressesCanControlTheirToken,
            compliantTakerCountryCode,
            [compliantTakerYesMark],
            { from: owner },
        );
        // 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: compliantForwarderInstance.address,
        });
        const compliantSignedOrderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(
            compliantSignedOrder,
        );
        const compliantSignedOrderWithoutExchangeAddressData = exchangeInstance.fillOrder.getABIEncodedTransactionData(
            compliantSignedOrderWithoutExchangeAddress,
            takerAssetFillAmount,
            compliantSignedOrder.signature,
        );
        compliantSignedFillOrderTx = takerTransactionFactory.newSignedTransaction(
            compliantSignedOrderWithoutExchangeAddressData,
        );
    });
    beforeEach(async () => {
        await blockchainLifecycle.startAsync();
    });
    afterEach(async () => {
        await blockchainLifecycle.revertAsync();
    });
    describe.only('fillOrder', () => {
        beforeEach(async () => {
            erc20Balances = await erc20Wrapper.getBalancesAsync();
        });

        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][defaultMakerAssetAddress]).to.be.bignumber.equal(
                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
            );
            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
            );
            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
                erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid),
            );
            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
            );
            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].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)),
            );
        });
        // @TODO: Should fail if order's senderAddress is not set to the compliant forwarding contract
        // @TODO: Should fail if the signed transaction is not intended for fillOrder
        // @TODO: Should fail if maker is not verified
        // @TODO: Should fail it taker is not verified
    });
});
// tslint:disable:max-file-line-count
// tslint:enable:no-unnecessary-type-assertion