More tests + require instead of revert in compliance contract

This commit is contained in:
Greg Hysen 2018-11-29 13:56:39 -08:00
parent 989b5b0a98
commit 33e41dd500
3 changed files with 92 additions and 18 deletions

View File

@ -52,7 +52,13 @@ contract CompliantForwarder {
revert("EXCHANGE_TRANSACTION_NOT_FILL_ORDER"); revert("EXCHANGE_TRANSACTION_NOT_FILL_ORDER");
} }
// Extract maker address from fill order transaction // Taker must be compliant
require(
COMPLIANCE_TOKEN.balanceOf(signerAddress) > 0,
"TAKER_UNVERIFIED"
);
// Extract maker address from fill order transaction and ensure maker is compliant
// Below is the table of calldata offsets into a fillOrder transaction. // Below is the table of calldata offsets into a fillOrder transaction.
/** /**
### parameters ### parameters
@ -82,13 +88,10 @@ contract CompliantForwarder {
// Add 0xc to the makerAddress since abi-encoded addresses are left padded with 12 bytes. // Add 0xc to the makerAddress since abi-encoded addresses are left padded with 12 bytes.
// Putting this together: makerAddress = 0x60 + 0x4 + 0xc = 0x70 // Putting this together: makerAddress = 0x60 + 0x4 + 0xc = 0x70
address makerAddress = signedFillOrderTransaction.readAddress(0x70); address makerAddress = signedFillOrderTransaction.readAddress(0x70);
require(
// Verify maker/taker have been verified by the compliance token. COMPLIANCE_TOKEN.balanceOf(makerAddress) > 0,
if (COMPLIANCE_TOKEN.balanceOf(makerAddress) == 0) { "MAKER_UNVERIFIED"
revert("MAKER_UNVERIFIED"); );
} else if (COMPLIANCE_TOKEN.balanceOf(signerAddress) == 0) {
revert("TAKER_UNVERIFIED");
}
// All entities are verified. Execute fillOrder. // All entities are verified. Execute fillOrder.
EXCHANGE.executeTransaction( EXCHANGE.executeTransaction(

View File

@ -4,6 +4,7 @@ import { RevertReason, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils'; import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper'; import { Web3Wrapper } from '@0x/web3-wrapper';
import * as chai from 'chai'; import * as chai from 'chai';
import * as ethUtil from 'ethereumjs-util';
import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token'; import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
import { ExchangeContract } from '../../generated-wrappers/exchange'; import { ExchangeContract } from '../../generated-wrappers/exchange';
@ -12,9 +13,8 @@ import { YesComplianceTokenContract } from '../../generated-wrappers/yes_complia
import { artifacts } from '../../src/artifacts'; import { artifacts } from '../../src/artifacts';
import { import {
expectContractCreationFailedAsync,
expectTransactionFailedAsync, expectTransactionFailedAsync,
sendTransactionResult, expectTransactionFailedWithoutReasonAsync,
} from '../utils/assertions'; } from '../utils/assertions';
import { chaiSetup } from '../utils/chai_setup'; import { chaiSetup } from '../utils/chai_setup';
import { constants } from '../utils/constants'; import { constants } from '../utils/constants';
@ -36,17 +36,19 @@ describe.only(ContractName.CompliantForwarder, () => {
let owner: string; let owner: string;
let compliantTakerAddress: string; let compliantTakerAddress: string;
let feeRecipientAddress: string; let feeRecipientAddress: string;
let noncompliantAddress: string; let nonCompliantAddress: string;
let defaultMakerAssetAddress: string; let defaultMakerAssetAddress: string;
let defaultTakerAssetAddress: string; let defaultTakerAssetAddress: string;
let zrxAssetData: string; let zrxAssetData: string;
let zrxToken: DummyERC20TokenContract; let zrxToken: DummyERC20TokenContract;
let exchangeInstance: ExchangeContract;
let exchangeWrapper: ExchangeWrapper; let exchangeWrapper: ExchangeWrapper;
let orderFactory: OrderFactory; let orderFactory: OrderFactory;
let erc20Wrapper: ERC20Wrapper; let erc20Wrapper: ERC20Wrapper;
let erc20Balances: ERC20BalancesByOwner; let erc20Balances: ERC20BalancesByOwner;
let takerTransactionFactory: TransactionFactory;
let compliantSignedOrder: SignedOrder; let compliantSignedOrder: SignedOrder;
let compliantSignedFillOrderTx: SignedTransaction; let compliantSignedFillOrderTx: SignedTransaction;
let noncompliantSignedFillOrderTx: SignedTransaction; let noncompliantSignedFillOrderTx: SignedTransaction;
@ -66,7 +68,7 @@ describe.only(ContractName.CompliantForwarder, () => {
compliantMakerAddress, compliantMakerAddress,
compliantTakerAddress, compliantTakerAddress,
feeRecipientAddress, feeRecipientAddress,
noncompliantAddress, nonCompliantAddress,
] = accounts); ] = accounts);
// Create wrappers // Create wrappers
erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
@ -91,7 +93,7 @@ describe.only(ContractName.CompliantForwarder, () => {
const erc20Proxy = await erc20Wrapper.deployProxyAsync(); const erc20Proxy = await erc20Wrapper.deployProxyAsync();
await erc20Wrapper.setBalancesAndAllowancesAsync(); await erc20Wrapper.setBalancesAndAllowancesAsync();
// Deploy Exchange congtract // Deploy Exchange congtract
const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync( exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
artifacts.Exchange, artifacts.Exchange,
provider, provider,
txDefaults, txDefaults,
@ -164,7 +166,7 @@ describe.only(ContractName.CompliantForwarder, () => {
); );
// Create Valid/Invalid orders // Create Valid/Invalid orders
const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(compliantTakerAddress)]; const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(compliantTakerAddress)];
const takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchangeInstance.address); takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchangeInstance.address);
compliantSignedOrder = await orderFactory.newSignedOrderAsync({ compliantSignedOrder = await orderFactory.newSignedOrderAsync({
senderAddress: compliantForwarderInstance.address, senderAddress: compliantForwarderInstance.address,
}); });
@ -190,8 +192,7 @@ describe.only(ContractName.CompliantForwarder, () => {
beforeEach(async () => { beforeEach(async () => {
erc20Balances = await erc20Wrapper.getBalancesAsync(); erc20Balances = await erc20Wrapper.getBalancesAsync();
}); });
it('should transfer the correct amounts when maker and taker are compliant', async () => {
it.only('should transfer the correct amounts when maker and taker are verified', async () => {
await compliantForwarderInstance.fillOrder.sendTransactionAsync( await compliantForwarderInstance.fillOrder.sendTransactionAsync(
compliantSignedFillOrderTx.salt, compliantSignedFillOrderTx.salt,
compliantSignedFillOrderTx.signerAddress, compliantSignedFillOrderTx.signerAddress,
@ -230,8 +231,76 @@ describe.only(ContractName.CompliantForwarder, () => {
erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)), erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)),
); );
}); });
// @TODO: Should fail if order's senderAddress is not set to the compliant forwarding contract it('should revert if the signed transaction is not intended for fillOrder', async () => {
// @TODO: Should fail if the signed transaction is not intended for fillOrder // Create signed order without the fillOrder function selector
const txDataBuf = ethUtil.toBuffer(compliantSignedFillOrderTx.data);
const selectorLengthInBytes = 4;
const txDataBufMinusSelector = txDataBuf.slice(selectorLengthInBytes);
const badSelector = '0x00000000';
const badSelectorBuf = ethUtil.toBuffer(badSelector);
const txDataBufWithBadSelector = Buffer.concat([badSelectorBuf, txDataBufMinusSelector]);
const txDataBufWithBadSelectorHex = ethUtil.bufferToHex(txDataBufWithBadSelector);
// Call compliant forwarder
return expectTransactionFailedWithoutReasonAsync(compliantForwarderInstance.fillOrder.sendTransactionAsync(
compliantSignedFillOrderTx.salt,
compliantSignedFillOrderTx.signerAddress,
txDataBufWithBadSelectorHex,
compliantSignedFillOrderTx.signature,
));
});
it('should revert if senderAddress is not set to the compliant forwarding contract', async () => {
// Create signed order with incorrect senderAddress
const notCompliantForwarderAddress = zrxToken.address;
const signedOrderWithBadSenderAddress = await orderFactory.newSignedOrderAsync({
senderAddress: notCompliantForwarderAddress,
});
const signedOrderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(
signedOrderWithBadSenderAddress,
);
const signedOrderWithoutExchangeAddressData = exchangeInstance.fillOrder.getABIEncodedTransactionData(
signedOrderWithoutExchangeAddress,
takerAssetFillAmount,
compliantSignedOrder.signature,
);
const signedFillOrderTx = takerTransactionFactory.newSignedTransaction(
signedOrderWithoutExchangeAddressData,
);
// Call compliant forwarder
return expectTransactionFailedWithoutReasonAsync(compliantForwarderInstance.fillOrder.sendTransactionAsync(
signedFillOrderTx.salt,
signedFillOrderTx.signerAddress,
signedFillOrderTx.data,
signedFillOrderTx.signature,
));
});
it('should revert if maker address is not compliant (does not hold a Yes Token)', async () => {
// Create signed order with non-compliant maker address
const signedOrderWithBadSenderAddress = await orderFactory.newSignedOrderAsync({
senderAddress: compliantForwarderInstance.address,
makerAddress: nonCompliantAddress
});
const signedOrderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(
signedOrderWithBadSenderAddress,
);
const signedOrderWithoutExchangeAddressData = exchangeInstance.fillOrder.getABIEncodedTransactionData(
signedOrderWithoutExchangeAddress,
takerAssetFillAmount,
compliantSignedOrder.signature,
);
const signedFillOrderTx = takerTransactionFactory.newSignedTransaction(
signedOrderWithoutExchangeAddressData,
);
// Call compliant forwarder
return expectTransactionFailedAsync(
compliantForwarderInstance.fillOrder.sendTransactionAsync(
signedFillOrderTx.salt,
signedFillOrderTx.signerAddress,
signedFillOrderTx.data,
signedFillOrderTx.signature,
),
RevertReason.MakerUnverified
);
});
// @TODO: Should fail if maker is not verified // @TODO: Should fail if maker is not verified
// @TODO: Should fail it taker is not verified // @TODO: Should fail it taker is not verified
}); });

View File

@ -243,6 +243,8 @@ export enum RevertReason {
AuctionNotStarted = 'AUCTION_NOT_STARTED', AuctionNotStarted = 'AUCTION_NOT_STARTED',
AuctionInvalidBeginTime = 'INVALID_BEGIN_TIME', AuctionInvalidBeginTime = 'INVALID_BEGIN_TIME',
InvalidAssetData = 'INVALID_ASSET_DATA', InvalidAssetData = 'INVALID_ASSET_DATA',
MakerUnverified = 'MAKER_UNVERIFED',
TakerUnverified = 'TAKER_UNVERIFIED',
} }
export enum StatusCodes { export enum StatusCodes {