Wrappers for balance threshold filter + updated some tests to use the wrapper
This commit is contained in:
parent
7e7880aea0
commit
d882133e44
@ -6,6 +6,7 @@ import { Web3Wrapper } from '@0x/web3-wrapper';
|
|||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as ethUtil from 'ethereumjs-util';
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||||
|
|
||||||
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';
|
||||||
@ -24,6 +25,7 @@ import { ExchangeWrapper } from '../utils/exchange_wrapper';
|
|||||||
import { OrderFactory } from '../utils/order_factory';
|
import { OrderFactory } from '../utils/order_factory';
|
||||||
import { orderUtils } from '../utils/order_utils';
|
import { orderUtils } from '../utils/order_utils';
|
||||||
import { TransactionFactory } from '../utils/transaction_factory';
|
import { TransactionFactory } from '../utils/transaction_factory';
|
||||||
|
import { BalanceThresholdWrapper } from '../utils/balance_threshold_wrapper';
|
||||||
import { ContractName, ERC20BalancesByOwner, SignedTransaction } from '../utils/types';
|
import { ContractName, ERC20BalancesByOwner, SignedTransaction } from '../utils/types';
|
||||||
import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
|
import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
|
||||||
|
|
||||||
@ -37,6 +39,10 @@ const expect = chai.expect;
|
|||||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||||
const DECIMALS_DEFAULT = 18;
|
const DECIMALS_DEFAULT = 18;
|
||||||
|
|
||||||
|
interface ValidatedAddressesLog {
|
||||||
|
args: {addresses: string[]}
|
||||||
|
}
|
||||||
|
|
||||||
describe.only(ContractName.BalanceThresholdFilter, () => {
|
describe.only(ContractName.BalanceThresholdFilter, () => {
|
||||||
let compliantMakerAddress: string;
|
let compliantMakerAddress: string;
|
||||||
let owner: string;
|
let owner: string;
|
||||||
@ -53,18 +59,35 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
|
|||||||
let orderFactory: OrderFactory;
|
let orderFactory: OrderFactory;
|
||||||
let erc20Wrapper: ERC20Wrapper;
|
let erc20Wrapper: ERC20Wrapper;
|
||||||
let erc20Balances: ERC20BalancesByOwner;
|
let erc20Balances: ERC20BalancesByOwner;
|
||||||
|
let balanceThresholdWrapper: BalanceThresholdWrapper;
|
||||||
|
|
||||||
let takerTransactionFactory: TransactionFactory;
|
let takerTransactionFactory: TransactionFactory;
|
||||||
let compliantSignedOrder: SignedOrder;
|
let compliantSignedOrder: SignedOrder;
|
||||||
let compliantSignedFillOrderTx: SignedTransaction;
|
let compliantSignedFillOrderTx: SignedTransaction;
|
||||||
let noncompliantSignedFillOrderTx: SignedTransaction;
|
let noncompliantSignedFillOrderTx: SignedTransaction;
|
||||||
|
|
||||||
|
let logDecoder: LogDecoder;
|
||||||
|
|
||||||
const takerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(500), DECIMALS_DEFAULT);
|
const takerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(500), DECIMALS_DEFAULT);
|
||||||
const makerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), DECIMALS_DEFAULT);
|
const makerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), DECIMALS_DEFAULT);
|
||||||
const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(250), DECIMALS_DEFAULT);
|
const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(250), DECIMALS_DEFAULT);
|
||||||
|
|
||||||
let compliantForwarderInstance: BalanceThresholdFilterContract;
|
let compliantForwarderInstance: BalanceThresholdFilterContract;
|
||||||
|
|
||||||
|
const assertValidatedAddressesLog = async (txReceipt: TransactionReceiptWithDecodedLogs, expectedValidatedAddresses: string[]) => {
|
||||||
|
expect(txReceipt.logs.length).to.be.gte(1);
|
||||||
|
const validatedAddressesLog = (txReceipt.logs[0] as any) as ValidatedAddressesLog;
|
||||||
|
const validatedAddresses = validatedAddressesLog.args.addresses;
|
||||||
|
// @HACK-hysz: Nested addresses are not translated to lower-case but this will change once
|
||||||
|
// the new ABI Encoder/Decoder is used by the contract templates.
|
||||||
|
let validatedAddressesNormalized: string[] = [];
|
||||||
|
_.each(validatedAddresses, (address) => {
|
||||||
|
const normalizedAddress = _.toLower(address);
|
||||||
|
validatedAddressesNormalized.push(normalizedAddress);
|
||||||
|
});
|
||||||
|
expect(validatedAddressesNormalized).to.be.deep.equal(expectedValidatedAddresses);
|
||||||
|
};
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
// Create accounts
|
// Create accounts
|
||||||
await blockchainLifecycle.startAsync();
|
await blockchainLifecycle.startAsync();
|
||||||
@ -190,17 +213,30 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
|
|||||||
compliantSignedOrderWithoutExchangeAddressData,
|
compliantSignedOrderWithoutExchangeAddressData,
|
||||||
);
|
);
|
||||||
|
|
||||||
/* generate selectors for every exchange method
|
/*
|
||||||
_.each(exchangeInstance.abi, (abiDefinition: AbiDefinition) => {
|
_.each(exchangeInstance.abi, (abiDefinition: AbiDefinition) => {
|
||||||
try {
|
try {
|
||||||
const method = new Method(abiDefinition as MethodAbi);
|
const method = new Method(abiDefinition as MethodAbi);
|
||||||
console.log('\n', `// ${method.getDataItem().name}`);
|
console.log(method.getSignature());
|
||||||
console.log(`bytes4 constant ${method.getDataItem().name}Selector = ${method.getSelector()};`);
|
if (!method.getSignature().startsWith('matchOrders')) {
|
||||||
console.log(`bytes4 constant ${method.getDataItem().name}SelectorGenerator = byes4(keccak256('${method.getSignature()}'));`);
|
return;
|
||||||
|
}
|
||||||
|
console.log(`FOUND IT`);
|
||||||
|
const signedOrderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(
|
||||||
|
compliantSignedOrder,
|
||||||
|
);
|
||||||
|
const args = [signedOrderWithoutExchangeAddress, signedOrderWithoutExchangeAddress, compliantSignedOrder.signature, compliantSignedOrder.signature];
|
||||||
|
console.log(method.encode(args, {annotate: true}));
|
||||||
|
//console.log('\n', `// ${method.getDataItem().name}`);
|
||||||
|
//console.log(`bytes4 constant ${method.getDataItem().name}Selector = ${method.getSelector()};`);
|
||||||
|
//console.log(`bytes4 constant ${method.getDataItem().name}SelectorGenerator = byes4(keccak256('${method.getSignature()}'));`);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
_.noop();
|
console.log(`encoding failed: ${e}`);
|
||||||
}
|
}
|
||||||
});*/
|
});
|
||||||
|
throw new Error(`w`);*/
|
||||||
|
logDecoder = new LogDecoder(web3Wrapper);
|
||||||
|
balanceThresholdWrapper = new BalanceThresholdWrapper(compliantForwarderInstance, exchangeInstance, new TransactionFactory(takerPrivateKey, exchangeInstance.address), provider);
|
||||||
});
|
});
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await blockchainLifecycle.startAsync();
|
await blockchainLifecycle.startAsync();
|
||||||
@ -208,54 +244,9 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
|
|||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
await blockchainLifecycle.revertAsync();
|
await blockchainLifecycle.revertAsync();
|
||||||
});
|
});
|
||||||
describe.only('fillOrder', () => {
|
|
||||||
beforeEach(async () => {
|
describe('General Sanity Checks', () => {
|
||||||
erc20Balances = await erc20Wrapper.getBalancesAsync();
|
it('should revert if the signed transaction is not intended for supported', async () => {
|
||||||
});
|
|
||||||
it('should transfer the correct amounts when maker and taker are compliant', async () => {
|
|
||||||
const txHash = await compliantForwarderInstance.executeTransaction.sendTransactionAsync(
|
|
||||||
compliantSignedFillOrderTx.salt,
|
|
||||||
compliantSignedFillOrderTx.signerAddress,
|
|
||||||
compliantSignedFillOrderTx.data,
|
|
||||||
compliantSignedFillOrderTx.signature,
|
|
||||||
);
|
|
||||||
const decoder = new LogDecoder(web3Wrapper);
|
|
||||||
const tx = await decoder.getTxWithDecodedLogsAsync(txHash);
|
|
||||||
console.log(JSON.stringify(tx, null, 4));
|
|
||||||
console.log('****** MAKER ADDRESS = ', compliantSignedOrder.makerAddress);
|
|
||||||
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)),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it('should revert if the signed transaction is not intended for fillOrder', async () => {
|
|
||||||
// Create signed order without the fillOrder function selector
|
// Create signed order without the fillOrder function selector
|
||||||
const txDataBuf = ethUtil.toBuffer(compliantSignedFillOrderTx.data);
|
const txDataBuf = ethUtil.toBuffer(compliantSignedFillOrderTx.data);
|
||||||
const selectorLengthInBytes = 4;
|
const selectorLengthInBytes = 4;
|
||||||
@ -297,18 +288,90 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
|
|||||||
signedFillOrderTx.signature,
|
signedFillOrderTx.signature,
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
it('should revert if taker address is not compliant (does not hold a Yes Token)', async () => {
|
// @TODO - greater than 1 balance
|
||||||
return expectTransactionFailedAsync(
|
});
|
||||||
compliantForwarderInstance.executeTransaction.sendTransactionAsync(
|
|
||||||
compliantSignedFillOrderTx.salt,
|
|
||||||
nonCompliantAddress,
|
|
||||||
compliantSignedFillOrderTx.data,
|
describe('batchFillOrders', () => {
|
||||||
compliantSignedFillOrderTx.signature,
|
beforeEach(async () => {
|
||||||
),
|
erc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||||
RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
|
});
|
||||||
|
it('should transfer the correct amounts when maker and taker are compliant', async () => {
|
||||||
|
let order2 = _.cloneDeep(compliantSignedOrder);
|
||||||
|
order2.makerAddress = `0x${_.reverse(compliantSignedOrder.makerAddress.slice(2).split('')).join('')}`;
|
||||||
|
const orders = [compliantSignedOrder, order2];
|
||||||
|
const fillAmounts = [new BigNumber(4), new BigNumber(4)];
|
||||||
|
const signatures = ["0xabcd", "0xabcd"];
|
||||||
|
const exchangeCalldata = exchangeInstance.batchFillOrders.getABIEncodedTransactionData(orders, fillAmounts, signatures);
|
||||||
|
console.log('*'.repeat(40), exchangeCalldata, '*'.repeat(40));
|
||||||
|
console.log('****** MAKER ADDRESS = ', compliantSignedOrder.makerAddress);
|
||||||
|
|
||||||
|
const txHash = await compliantForwarderInstance.executeTransaction.sendTransactionAsync(
|
||||||
|
compliantSignedFillOrderTx.salt,
|
||||||
|
compliantSignedFillOrderTx.signerAddress,
|
||||||
|
exchangeCalldata,
|
||||||
|
compliantSignedFillOrderTx.signature,
|
||||||
|
);
|
||||||
|
const decoder = new LogDecoder(web3Wrapper);
|
||||||
|
const tx = await decoder.getTxWithDecodedLogsAsync(txHash);
|
||||||
|
console.log(JSON.stringify(tx, null, 4));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('batchFillOrdersNoThrow', () => {
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('batchFillOrKillOrders', () => {
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('batchFillOrKillOrders', () => {
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.only('fillOrder', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
erc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||||
|
});
|
||||||
|
it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => {
|
||||||
|
// Execute a valid fill
|
||||||
|
const txReceipt = await balanceThresholdWrapper.fillOrderAsync(compliantSignedOrder, compliantSignedFillOrderTx.signerAddress, {takerAssetFillAmount});
|
||||||
|
// Assert validated addresses
|
||||||
|
const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedFillOrderTx.signerAddress];
|
||||||
|
assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
|
||||||
|
// Check balances
|
||||||
|
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)),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should revert if maker address is not compliant (does not hold a Yes Token)', async () => {
|
it('should revert if maker does not meet the balance threshold', async () => {
|
||||||
// Create signed order with non-compliant maker address
|
// Create signed order with non-compliant maker address
|
||||||
const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
|
const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
|
||||||
senderAddress: compliantForwarderInstance.address,
|
senderAddress: compliantForwarderInstance.address,
|
||||||
@ -336,32 +399,92 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
|
|||||||
RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
|
RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('should revert if taker does not meet the balance threshold', async () => {
|
||||||
|
return expectTransactionFailedAsync(
|
||||||
|
compliantForwarderInstance.executeTransaction.sendTransactionAsync(
|
||||||
|
compliantSignedFillOrderTx.salt,
|
||||||
|
nonCompliantAddress,
|
||||||
|
compliantSignedFillOrderTx.data,
|
||||||
|
compliantSignedFillOrderTx.signature,
|
||||||
|
),
|
||||||
|
RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('batchFillOrders', () => {
|
describe('fillOrderNoThrow', () => {
|
||||||
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('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => {
|
||||||
let order2 = _.cloneDeep(compliantSignedOrder);
|
|
||||||
order2.makerAddress = `0x${_.reverse(compliantSignedOrder.makerAddress.slice(2).split('')).join('')}`;
|
|
||||||
const orders = [compliantSignedOrder, order2];
|
|
||||||
const fillAmounts = [new BigNumber(4), new BigNumber(4)];
|
|
||||||
const signatures = ["0xabcd", "0xabcd"];
|
|
||||||
const exchangeCalldata = exchangeInstance.batchFillOrders.getABIEncodedTransactionData(orders, fillAmounts, signatures);
|
|
||||||
console.log('*'.repeat(40), exchangeCalldata, '*'.repeat(40));
|
|
||||||
console.log('****** MAKER ADDRESS = ', compliantSignedOrder.makerAddress);
|
|
||||||
|
|
||||||
const txHash = await compliantForwarderInstance.executeTransaction.sendTransactionAsync(
|
|
||||||
compliantSignedFillOrderTx.salt,
|
|
||||||
compliantSignedFillOrderTx.signerAddress,
|
|
||||||
exchangeCalldata,
|
|
||||||
compliantSignedFillOrderTx.signature,
|
|
||||||
);
|
|
||||||
const decoder = new LogDecoder(web3Wrapper);
|
|
||||||
const tx = await decoder.getTxWithDecodedLogsAsync(txHash);
|
|
||||||
console.log(JSON.stringify(tx, null, 4));
|
|
||||||
});
|
});
|
||||||
|
it('should revert if maker does not meet the balance threshold', async () => {
|
||||||
|
// Create signed order with non-compliant maker address
|
||||||
|
const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
|
||||||
|
senderAddress: compliantForwarderInstance.address,
|
||||||
|
makerAddress: nonCompliantAddress
|
||||||
|
});
|
||||||
|
const signedOrderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(
|
||||||
|
signedOrderWithBadMakerAddress,
|
||||||
|
);
|
||||||
|
const signedOrderWithoutExchangeAddressData = exchangeInstance.fillOrder.getABIEncodedTransactionData(
|
||||||
|
signedOrderWithoutExchangeAddress,
|
||||||
|
takerAssetFillAmount,
|
||||||
|
compliantSignedOrder.signature,
|
||||||
|
);
|
||||||
|
const signedFillOrderTx = takerTransactionFactory.newSignedTransaction(
|
||||||
|
signedOrderWithoutExchangeAddressData,
|
||||||
|
);
|
||||||
|
// Call compliant forwarder
|
||||||
|
return expectTransactionFailedAsync(
|
||||||
|
compliantForwarderInstance.executeTransaction.sendTransactionAsync(
|
||||||
|
signedFillOrderTx.salt,
|
||||||
|
signedFillOrderTx.signerAddress,
|
||||||
|
signedFillOrderTx.data,
|
||||||
|
signedFillOrderTx.signature,
|
||||||
|
),
|
||||||
|
RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should revert if taker does not meet the balance threshold', async () => {
|
||||||
|
return expectTransactionFailedAsync(
|
||||||
|
compliantForwarderInstance.executeTransaction.sendTransactionAsync(
|
||||||
|
compliantSignedFillOrderTx.salt,
|
||||||
|
nonCompliantAddress,
|
||||||
|
compliantSignedFillOrderTx.data,
|
||||||
|
compliantSignedFillOrderTx.signature,
|
||||||
|
),
|
||||||
|
RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('fillOrKillOrder', () => {
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('marketBuyOrders', () => {
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('marketBuyOrdersNoThrow', () => {
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('marketSellOrders', () => {
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('marketSellOrdersNoThrow', () => {
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('matchOrders', () => {
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('cancelOrder', () => {
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('batchCancelOrders', () => {
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('cancelOrdersUpTo', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// tslint:disable:max-file-line-count
|
// tslint:disable:max-file-line-count
|
||||||
|
243
packages/contracts/test/utils/balance_threshold_wrapper.ts
Normal file
243
packages/contracts/test/utils/balance_threshold_wrapper.ts
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
import { SignedOrder } from '@0x/types';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
|
import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import { ExchangeContract } from '../../generated-wrappers/exchange';
|
||||||
|
import { BalanceThresholdFilterContract } from '../../generated-wrappers/balance_threshold_filter';
|
||||||
|
|
||||||
|
import { formatters } from './formatters';
|
||||||
|
import { LogDecoder } from './log_decoder';
|
||||||
|
import { orderUtils } from './order_utils';
|
||||||
|
import { TransactionFactory } from '../utils/transaction_factory';
|
||||||
|
import { OrderInfo } from './types';
|
||||||
|
|
||||||
|
export class BalanceThresholdWrapper {
|
||||||
|
private readonly _balanceThresholdFilter: BalanceThresholdFilterContract;
|
||||||
|
private readonly _signerTransactionFactory: TransactionFactory;
|
||||||
|
private readonly _exchange: ExchangeContract;
|
||||||
|
private readonly _web3Wrapper: Web3Wrapper;
|
||||||
|
private readonly _logDecoder: LogDecoder;
|
||||||
|
constructor(balanceThresholdFilter: BalanceThresholdFilterContract, exchangeContract: ExchangeContract, signerTransactionFactory: TransactionFactory, provider: Provider) {
|
||||||
|
this._balanceThresholdFilter = balanceThresholdFilter;
|
||||||
|
this._exchange = exchangeContract;
|
||||||
|
this._signerTransactionFactory = signerTransactionFactory;
|
||||||
|
this._web3Wrapper = new Web3Wrapper(provider);
|
||||||
|
this._logDecoder = new LogDecoder(this._web3Wrapper);
|
||||||
|
}
|
||||||
|
public async fillOrderAsync(
|
||||||
|
signedOrder: SignedOrder,
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmount?: BigNumber } = {},
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||||
|
const data = this._exchange.fillOrder.getABIEncodedTransactionData(
|
||||||
|
params.order,
|
||||||
|
params.takerAssetFillAmount,
|
||||||
|
params.signature,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransaction(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async fillOrKillOrderAsync(
|
||||||
|
signedOrder: SignedOrder,
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmount?: BigNumber } = {},
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||||
|
const data = this._exchange.fillOrKillOrder.getABIEncodedTransactionData(
|
||||||
|
params.order,
|
||||||
|
params.takerAssetFillAmount,
|
||||||
|
params.signature,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransaction(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async fillOrderNoThrowAsync(
|
||||||
|
signedOrder: SignedOrder,
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmount?: BigNumber; gas?: number } = {},
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||||
|
const data = this._exchange.fillOrderNoThrow.getABIEncodedTransactionData(
|
||||||
|
params.order,
|
||||||
|
params.takerAssetFillAmount,
|
||||||
|
params.signature,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransaction(data, from, opts.gas);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async batchFillOrdersAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmounts?: BigNumber[] } = {},
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
|
||||||
|
const data = this._exchange.batchFillOrders.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.takerAssetFillAmounts,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransaction(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async batchFillOrKillOrdersAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmounts?: BigNumber[] } = {},
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
|
||||||
|
const data = this._exchange.batchFillOrKillOrders.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.takerAssetFillAmounts,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransaction(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async batchFillOrdersNoThrowAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number } = {},
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
|
||||||
|
const data = this._exchange.batchFillOrKillOrders.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.takerAssetFillAmounts,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransaction(data, from, opts.gas);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async marketSellOrdersAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmount: BigNumber },
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount);
|
||||||
|
const data = this._exchange.marketSellOrders.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.takerAssetFillAmount,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransaction(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async marketSellOrdersNoThrowAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmount: BigNumber; gas?: number },
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount);
|
||||||
|
const data = this._exchange.marketSellOrdersNoThrow.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.takerAssetFillAmount,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransaction(data, from, opts.gas);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async marketBuyOrdersAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { makerAssetFillAmount: BigNumber },
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount);
|
||||||
|
const data = this._exchange.marketBuyOrders.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.makerAssetFillAmount,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransaction(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async marketBuyOrdersNoThrowAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { makerAssetFillAmount: BigNumber; gas?: number },
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount);
|
||||||
|
const data = this._exchange.marketBuyOrdersNoThrow.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.makerAssetFillAmount,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransaction(data, from, opts.gas);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async cancelOrderAsync(signedOrder: SignedOrder, from: string): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = orderUtils.createCancel(signedOrder);
|
||||||
|
const data = this._exchange.cancelOrder.getABIEncodedTransactionData(params.order);
|
||||||
|
const txReceipt = this._executeTransaction(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async batchCancelOrdersAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createBatchCancel(orders);
|
||||||
|
const data = this._exchange.batchCancelOrders.getABIEncodedTransactionData(params.orders);
|
||||||
|
const txReceipt = this._executeTransaction(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async cancelOrdersUpToAsync(salt: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const data = this._exchange.cancelOrdersUpTo.getABIEncodedTransactionData(salt);
|
||||||
|
const txReceipt = this._executeTransaction(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise<BigNumber> {
|
||||||
|
const filledAmount = await this._exchange.filled.callAsync(orderHashHex);
|
||||||
|
return filledAmount;
|
||||||
|
}
|
||||||
|
public async isCancelledAsync(orderHashHex: string): Promise<boolean> {
|
||||||
|
const isCancelled = await this._exchange.cancelled.callAsync(orderHashHex);
|
||||||
|
return isCancelled;
|
||||||
|
}
|
||||||
|
public async getOrderEpochAsync(makerAddress: string, senderAddress: string): Promise<BigNumber> {
|
||||||
|
const orderEpoch = await this._exchange.orderEpoch.callAsync(makerAddress, senderAddress);
|
||||||
|
return orderEpoch;
|
||||||
|
}
|
||||||
|
public async getOrderInfoAsync(signedOrder: SignedOrder): Promise<OrderInfo> {
|
||||||
|
const orderInfo = (await this._exchange.getOrderInfo.callAsync(signedOrder)) as OrderInfo;
|
||||||
|
return orderInfo;
|
||||||
|
}
|
||||||
|
public async getOrdersInfoAsync(signedOrders: SignedOrder[]): Promise<OrderInfo[]> {
|
||||||
|
const ordersInfo = (await this._exchange.getOrdersInfo.callAsync(signedOrders)) as OrderInfo[];
|
||||||
|
return ordersInfo;
|
||||||
|
}
|
||||||
|
public async matchOrdersAsync(
|
||||||
|
signedOrderLeft: SignedOrder,
|
||||||
|
signedOrderRight: SignedOrder,
|
||||||
|
from: string,
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
|
||||||
|
const data = await this._exchange.matchOrders.getABIEncodedTransactionData(
|
||||||
|
params.left,
|
||||||
|
params.right,
|
||||||
|
params.leftSignature,
|
||||||
|
params.rightSignature
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransaction(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public getBalanceThresholdAddress(): string {
|
||||||
|
return this._balanceThresholdFilter.address;
|
||||||
|
}
|
||||||
|
public getExchangeAddress(): string {
|
||||||
|
return this._exchange.address;
|
||||||
|
}
|
||||||
|
private async _executeTransaction(abiEncodedExchangeTxData: string, from: string, gas?: number): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const signedExchangeTx = this._signerTransactionFactory.newSignedTransaction(abiEncodedExchangeTxData);
|
||||||
|
const txOpts = _.isUndefined(gas) ? {from} : {from, gas};
|
||||||
|
const txHash = await this._balanceThresholdFilter.executeTransaction.sendTransactionAsync(
|
||||||
|
signedExchangeTx.salt,
|
||||||
|
signedExchangeTx.signerAddress,
|
||||||
|
signedExchangeTx.data,
|
||||||
|
signedExchangeTx.signature,
|
||||||
|
txOpts,
|
||||||
|
);
|
||||||
|
const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user