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");
}
// 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.
/**
### parameters
@ -82,13 +88,10 @@ contract CompliantForwarder {
// Add 0xc to the makerAddress since abi-encoded addresses are left padded with 12 bytes.
// Putting this together: makerAddress = 0x60 + 0x4 + 0xc = 0x70
address makerAddress = signedFillOrderTransaction.readAddress(0x70);
// Verify maker/taker have been verified by the compliance token.
if (COMPLIANCE_TOKEN.balanceOf(makerAddress) == 0) {
revert("MAKER_UNVERIFIED");
} else if (COMPLIANCE_TOKEN.balanceOf(signerAddress) == 0) {
revert("TAKER_UNVERIFIED");
}
require(
COMPLIANCE_TOKEN.balanceOf(makerAddress) > 0,
"MAKER_UNVERIFIED"
);
// All entities are verified. Execute fillOrder.
EXCHANGE.executeTransaction(

View File

@ -4,6 +4,7 @@ import { RevertReason, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import * as chai from 'chai';
import * as ethUtil from 'ethereumjs-util';
import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
import { ExchangeContract } from '../../generated-wrappers/exchange';
@ -12,9 +13,8 @@ import { YesComplianceTokenContract } from '../../generated-wrappers/yes_complia
import { artifacts } from '../../src/artifacts';
import {
expectContractCreationFailedAsync,
expectTransactionFailedAsync,
sendTransactionResult,
expectTransactionFailedWithoutReasonAsync,
} from '../utils/assertions';
import { chaiSetup } from '../utils/chai_setup';
import { constants } from '../utils/constants';
@ -36,17 +36,19 @@ describe.only(ContractName.CompliantForwarder, () => {
let owner: string;
let compliantTakerAddress: string;
let feeRecipientAddress: string;
let noncompliantAddress: string;
let nonCompliantAddress: string;
let defaultMakerAssetAddress: string;
let defaultTakerAssetAddress: string;
let zrxAssetData: string;
let zrxToken: DummyERC20TokenContract;
let exchangeInstance: ExchangeContract;
let exchangeWrapper: ExchangeWrapper;
let orderFactory: OrderFactory;
let erc20Wrapper: ERC20Wrapper;
let erc20Balances: ERC20BalancesByOwner;
let takerTransactionFactory: TransactionFactory;
let compliantSignedOrder: SignedOrder;
let compliantSignedFillOrderTx: SignedTransaction;
let noncompliantSignedFillOrderTx: SignedTransaction;
@ -66,7 +68,7 @@ describe.only(ContractName.CompliantForwarder, () => {
compliantMakerAddress,
compliantTakerAddress,
feeRecipientAddress,
noncompliantAddress,
nonCompliantAddress,
] = accounts);
// Create wrappers
erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
@ -91,7 +93,7 @@ describe.only(ContractName.CompliantForwarder, () => {
const erc20Proxy = await erc20Wrapper.deployProxyAsync();
await erc20Wrapper.setBalancesAndAllowancesAsync();
// Deploy Exchange congtract
const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
artifacts.Exchange,
provider,
txDefaults,
@ -164,7 +166,7 @@ describe.only(ContractName.CompliantForwarder, () => {
);
// Create Valid/Invalid orders
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({
senderAddress: compliantForwarderInstance.address,
});
@ -190,8 +192,7 @@ describe.only(ContractName.CompliantForwarder, () => {
beforeEach(async () => {
erc20Balances = await erc20Wrapper.getBalancesAsync();
});
it.only('should transfer the correct amounts when maker and taker are verified', async () => {
it('should transfer the correct amounts when maker and taker are compliant', async () => {
await compliantForwarderInstance.fillOrder.sendTransactionAsync(
compliantSignedFillOrderTx.salt,
compliantSignedFillOrderTx.signerAddress,
@ -230,8 +231,76 @@ describe.only(ContractName.CompliantForwarder, () => {
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
it('should revert if the signed transaction is not intended for fillOrder', async () => {
// 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 it taker is not verified
});

View File

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