Add example whitelist contract and minimum tests
This commit is contained in:
		@@ -19,22 +19,24 @@
 | 
			
		||||
pragma solidity ^0.4.21;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "../../protocol/Exchange/mixins/MTransactions.sol";
 | 
			
		||||
import "../../protocol/Exchange/Exchange.sol";
 | 
			
		||||
import "../../protocol/Exchange/LibOrder.sol";
 | 
			
		||||
import "../../utils/Ownable/Ownable.sol";
 | 
			
		||||
 | 
			
		||||
contract Whitelist is Ownable {
 | 
			
		||||
 | 
			
		||||
    mapping (address => bool) public isWhitelisted;
 | 
			
		||||
    MTransactions EXCHANGE;
 | 
			
		||||
    Exchange EXCHANGE;
 | 
			
		||||
 | 
			
		||||
    bytes txOriginSignatureType = new bytes(1);
 | 
			
		||||
    bytes txOriginSignature = new bytes(1);
 | 
			
		||||
    bytes4 fillOrderFunctionSelector;
 | 
			
		||||
 | 
			
		||||
    function Whitelist(address _exchange)
 | 
			
		||||
        public
 | 
			
		||||
    {
 | 
			
		||||
        EXCHANGE = MTransactions(_exchange);
 | 
			
		||||
        txOriginSignatureType[0] = 0x04;
 | 
			
		||||
        EXCHANGE = Exchange(_exchange);
 | 
			
		||||
        txOriginSignature[0] = 0x04;
 | 
			
		||||
        fillOrderFunctionSelector = EXCHANGE.fillOrder.selector;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function updateWhitelistStatus(address target, bool isApproved)
 | 
			
		||||
@@ -48,11 +50,31 @@ contract Whitelist is Ownable {
 | 
			
		||||
        LibOrder.Order memory order,
 | 
			
		||||
        uint256 takerAssetFillAmount,
 | 
			
		||||
        uint256 salt,
 | 
			
		||||
        bytes memory signature)
 | 
			
		||||
        bytes memory orderSignature)
 | 
			
		||||
        public
 | 
			
		||||
    {
 | 
			
		||||
        require(isWhitelisted[msg.sender]);
 | 
			
		||||
        bytes memory data = abi.encode(order, takerAssetFillAmount, signature);
 | 
			
		||||
        EXCHANGE.executeTransaction(salt, msg.sender, data, txOriginSignatureType);
 | 
			
		||||
        address takerAddress = msg.sender;
 | 
			
		||||
    
 | 
			
		||||
        // This contract must be the entry point for the transaction.
 | 
			
		||||
        require(takerAddress == tx.origin);
 | 
			
		||||
 | 
			
		||||
        // Check if sender is on the whitelist.
 | 
			
		||||
        require(isWhitelisted[takerAddress]);
 | 
			
		||||
 | 
			
		||||
        // Encode arguments into byte array.
 | 
			
		||||
        bytes memory data = abi.encodeWithSelector(
 | 
			
		||||
            fillOrderFunctionSelector,
 | 
			
		||||
            order,
 | 
			
		||||
            takerAssetFillAmount,
 | 
			
		||||
            orderSignature
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Call `fillOrder`via `executeTransaction`.
 | 
			
		||||
        EXCHANGE.executeTransaction(
 | 
			
		||||
            salt,
 | 
			
		||||
            takerAddress,
 | 
			
		||||
            data,
 | 
			
		||||
            txOriginSignature
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -111,6 +111,7 @@ export enum ContractName {
 | 
			
		||||
    DummyERC721Token = 'DummyERC721Token',
 | 
			
		||||
    TestLibBytes = 'TestLibBytes',
 | 
			
		||||
    Authorizable = 'Authorizable',
 | 
			
		||||
    Whitelist = 'Whitelist',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum SignatureType {
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import * as Web3 from 'web3';
 | 
			
		||||
import { DummyERC20TokenContract } from '../../src/contract_wrappers/generated/dummy_e_r_c20_token';
 | 
			
		||||
import { ERC20ProxyContract } from '../../src/contract_wrappers/generated/e_r_c20_proxy';
 | 
			
		||||
import { ExchangeContract } from '../../src/contract_wrappers/generated/exchange';
 | 
			
		||||
import { WhitelistContract } from '../../src/contract_wrappers/generated/whitelist';
 | 
			
		||||
import { artifacts } from '../../src/utils/artifacts';
 | 
			
		||||
import { assetProxyUtils } from '../../src/utils/asset_proxy_utils';
 | 
			
		||||
import { chaiSetup } from '../../src/utils/chai_setup';
 | 
			
		||||
@@ -55,6 +56,8 @@ describe('Exchange transactions', () => {
 | 
			
		||||
 | 
			
		||||
    let defaultMakerTokenAddress: string;
 | 
			
		||||
    let defaultTakerTokenAddress: string;
 | 
			
		||||
    let makerPrivateKey: Buffer;
 | 
			
		||||
    let takerPrivateKey: Buffer;
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
@@ -98,8 +101,8 @@ describe('Exchange transactions', () => {
 | 
			
		||||
            makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultMakerTokenAddress),
 | 
			
		||||
            takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultTakerTokenAddress),
 | 
			
		||||
        };
 | 
			
		||||
        const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
 | 
			
		||||
        const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)];
 | 
			
		||||
        makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
 | 
			
		||||
        takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)];
 | 
			
		||||
        orderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams);
 | 
			
		||||
        makerTransactionFactory = new TransactionFactory(makerPrivateKey, exchange.address);
 | 
			
		||||
        takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchange.address);
 | 
			
		||||
@@ -203,4 +206,88 @@ describe('Exchange transactions', () => {
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('Whitelist', () => {
 | 
			
		||||
        let whitelist: WhitelistContract;
 | 
			
		||||
        let whitelistOrderFactory: OrderFactory;
 | 
			
		||||
 | 
			
		||||
        before(async () => {
 | 
			
		||||
            const whitelistInstance = await deployer.deployAsync(ContractName.Whitelist, [exchange.address]);
 | 
			
		||||
            whitelist = new WhitelistContract(whitelistInstance.abi, whitelistInstance.address, provider);
 | 
			
		||||
            const defaultOrderParams = {
 | 
			
		||||
                ...constants.STATIC_ORDER_PARAMS,
 | 
			
		||||
                senderAddress: whitelist.address,
 | 
			
		||||
                exchangeAddress: exchange.address,
 | 
			
		||||
                makerAddress,
 | 
			
		||||
                feeRecipientAddress,
 | 
			
		||||
                makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultMakerTokenAddress),
 | 
			
		||||
                takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultTakerTokenAddress),
 | 
			
		||||
            };
 | 
			
		||||
            whitelistOrderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        beforeEach(async () => {
 | 
			
		||||
            signedOrder = whitelistOrderFactory.newSignedOrder();
 | 
			
		||||
            erc20Balances = await erc20Wrapper.getBalancesAsync();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should revert if taker has not been whitelisted', async () => {
 | 
			
		||||
            const orderStruct = orderUtils.getOrderStruct(signedOrder);
 | 
			
		||||
            const takerAssetFillAmount = signedOrder.takerAssetAmount;
 | 
			
		||||
            const salt = ZeroEx.generatePseudoRandomSalt();
 | 
			
		||||
            return expect(
 | 
			
		||||
                whitelist.fillOrderIfWhitelisted.sendTransactionAsync(
 | 
			
		||||
                    orderStruct,
 | 
			
		||||
                    takerAssetFillAmount,
 | 
			
		||||
                    salt,
 | 
			
		||||
                    signedOrder.signature,
 | 
			
		||||
                    { from: takerAddress },
 | 
			
		||||
                ),
 | 
			
		||||
            ).to.be.rejectedWith(constants.REVERT);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should fill the order if taker has been whitelisted', async () => {
 | 
			
		||||
            const isApproved = true;
 | 
			
		||||
            await whitelist.updateWhitelistStatus.sendTransactionAsync(takerAddress, isApproved, { from: owner });
 | 
			
		||||
 | 
			
		||||
            const orderStruct = orderUtils.getOrderStruct(signedOrder);
 | 
			
		||||
            const takerAssetFillAmount = signedOrder.takerAssetAmount;
 | 
			
		||||
            const salt = ZeroEx.generatePseudoRandomSalt();
 | 
			
		||||
            await whitelist.fillOrderIfWhitelisted.sendTransactionAsync(
 | 
			
		||||
                orderStruct,
 | 
			
		||||
                takerAssetFillAmount,
 | 
			
		||||
                salt,
 | 
			
		||||
                signedOrder.signature,
 | 
			
		||||
                { from: takerAddress },
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            const newBalances = await erc20Wrapper.getBalancesAsync();
 | 
			
		||||
 | 
			
		||||
            const makerAssetFillAmount = signedOrder.makerAssetAmount;
 | 
			
		||||
            const makerFeePaid = signedOrder.makerFee;
 | 
			
		||||
            const takerFeePaid = signedOrder.takerFee;
 | 
			
		||||
 | 
			
		||||
            expect(newBalances[makerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal(
 | 
			
		||||
                erc20Balances[makerAddress][defaultMakerTokenAddress].minus(makerAssetFillAmount),
 | 
			
		||||
            );
 | 
			
		||||
            expect(newBalances[makerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal(
 | 
			
		||||
                erc20Balances[makerAddress][defaultTakerTokenAddress].add(takerAssetFillAmount),
 | 
			
		||||
            );
 | 
			
		||||
            expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
 | 
			
		||||
                erc20Balances[makerAddress][zrxToken.address].minus(makerFeePaid),
 | 
			
		||||
            );
 | 
			
		||||
            expect(newBalances[takerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal(
 | 
			
		||||
                erc20Balances[takerAddress][defaultTakerTokenAddress].minus(takerAssetFillAmount),
 | 
			
		||||
            );
 | 
			
		||||
            expect(newBalances[takerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal(
 | 
			
		||||
                erc20Balances[takerAddress][defaultMakerTokenAddress].add(makerAssetFillAmount),
 | 
			
		||||
            );
 | 
			
		||||
            expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
 | 
			
		||||
                erc20Balances[takerAddress][zrxToken.address].minus(takerFeePaid),
 | 
			
		||||
            );
 | 
			
		||||
            expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
 | 
			
		||||
                erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)),
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user