Dutch wrapper
This commit is contained in:
parent
89fcbec43b
commit
43b648e7dc
@ -34,7 +34,7 @@ import * as _ from 'lodash';
|
||||
import { DutchAuctionContract } from '../../generated-wrappers/dutch_auction';
|
||||
import { artifacts } from '../../src/artifacts';
|
||||
|
||||
import { DutchAuctionWrapper } from '../utils/dutch_auction_wrapper';
|
||||
import { DutchAuctionTestWrapper } from '../utils/dutch_auction_test_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
@ -68,7 +68,7 @@ describe(ContractName.DutchAuction, () => {
|
||||
let erc721MakerAssetIds: BigNumber[];
|
||||
const tenMinutesInSeconds = 10 * 60;
|
||||
|
||||
let dutchAuctionWrapper: DutchAuctionWrapper;
|
||||
let dutchAuctionTestWrapper: DutchAuctionTestWrapper;
|
||||
let defaultERC20MakerAssetData: string;
|
||||
|
||||
before(async () => {
|
||||
@ -125,7 +125,7 @@ describe(ContractName.DutchAuction, () => {
|
||||
dutchAuctionInstance.address,
|
||||
provider,
|
||||
);
|
||||
dutchAuctionWrapper = new DutchAuctionWrapper(dutchAuctionInstance, provider);
|
||||
dutchAuctionTestWrapper = new DutchAuctionTestWrapper(dutchAuctionInstance, provider);
|
||||
|
||||
defaultMakerAssetAddress = erc20TokenA.address;
|
||||
const defaultTakerAssetAddress = wethContract.address;
|
||||
@ -164,7 +164,7 @@ describe(ContractName.DutchAuction, () => {
|
||||
feeRecipientAddress,
|
||||
// taker address or sender address should be set to the ducth auction contract
|
||||
takerAddress: dutchAuctionContract.address,
|
||||
makerAssetData: assetDataUtils.encodeDutchAuctionAssetData(
|
||||
makerAssetData: DutchAuctionTestWrapper.encodeDutchAuctionAssetData(
|
||||
assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||
auctionBeginTimeSeconds,
|
||||
auctionBeginAmount,
|
||||
@ -206,13 +206,13 @@ describe(ContractName.DutchAuction, () => {
|
||||
describe('matchOrders', () => {
|
||||
it('should be worth the begin price at the begining of the auction', async () => {
|
||||
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp + 2);
|
||||
const makerAssetData = assetDataUtils.encodeDutchAuctionAssetData(
|
||||
const makerAssetData = DutchAuctionTestWrapper.encodeDutchAuctionAssetData(
|
||||
defaultERC20MakerAssetData,
|
||||
auctionBeginTimeSeconds,
|
||||
auctionBeginAmount,
|
||||
);
|
||||
sellOrder = await sellerOrderFactory.newSignedOrderAsync({ makerAssetData });
|
||||
const auctionDetails = await dutchAuctionWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
const auctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
expect(auctionDetails.currentTimeSeconds).to.be.bignumber.lte(auctionBeginTimeSeconds);
|
||||
expect(auctionDetails.currentAmount).to.be.bignumber.equal(auctionBeginAmount);
|
||||
expect(auctionDetails.beginAmount).to.be.bignumber.equal(auctionBeginAmount);
|
||||
@ -220,7 +220,7 @@ describe(ContractName.DutchAuction, () => {
|
||||
it('should be be worth the end price at the end of the auction', async () => {
|
||||
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds * 2);
|
||||
auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds);
|
||||
const makerAssetData = assetDataUtils.encodeDutchAuctionAssetData(
|
||||
const makerAssetData = DutchAuctionTestWrapper.encodeDutchAuctionAssetData(
|
||||
defaultERC20MakerAssetData,
|
||||
auctionBeginTimeSeconds,
|
||||
auctionBeginAmount,
|
||||
@ -229,18 +229,18 @@ describe(ContractName.DutchAuction, () => {
|
||||
makerAssetData,
|
||||
expirationTimeSeconds: auctionEndTimeSeconds,
|
||||
});
|
||||
const auctionDetails = await dutchAuctionWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
const auctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
expect(auctionDetails.currentTimeSeconds).to.be.bignumber.gte(auctionEndTimeSeconds);
|
||||
expect(auctionDetails.currentAmount).to.be.bignumber.equal(auctionEndAmount);
|
||||
expect(auctionDetails.beginAmount).to.be.bignumber.equal(auctionBeginAmount);
|
||||
});
|
||||
it('should match orders at current amount and send excess to buyer', async () => {
|
||||
const beforeAuctionDetails = await dutchAuctionWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
const beforeAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
buyOrder = await buyerOrderFactory.newSignedOrderAsync({
|
||||
makerAssetAmount: beforeAuctionDetails.currentAmount.times(2),
|
||||
});
|
||||
await dutchAuctionWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
|
||||
const afterAuctionDetails = await dutchAuctionWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
|
||||
const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
expect(newBalances[dutchAuctionContract.address][wethContract.address]).to.be.bignumber.equal(
|
||||
constants.ZERO_AMOUNT,
|
||||
@ -259,8 +259,8 @@ describe(ContractName.DutchAuction, () => {
|
||||
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
|
||||
makerFee: new BigNumber(1),
|
||||
});
|
||||
await dutchAuctionWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
|
||||
const afterAuctionDetails = await dutchAuctionWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
|
||||
const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
|
||||
erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
|
||||
@ -273,9 +273,9 @@ describe(ContractName.DutchAuction, () => {
|
||||
buyOrder = await buyerOrderFactory.newSignedOrderAsync({
|
||||
makerFee: new BigNumber(1),
|
||||
});
|
||||
await dutchAuctionWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
|
||||
await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
const afterAuctionDetails = await dutchAuctionWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
|
||||
erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
|
||||
);
|
||||
@ -286,7 +286,7 @@ describe(ContractName.DutchAuction, () => {
|
||||
it('should revert when auction expires', async () => {
|
||||
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds * 2);
|
||||
auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds);
|
||||
const makerAssetData = assetDataUtils.encodeDutchAuctionAssetData(
|
||||
const makerAssetData = DutchAuctionTestWrapper.encodeDutchAuctionAssetData(
|
||||
defaultERC20MakerAssetData,
|
||||
auctionBeginTimeSeconds,
|
||||
auctionBeginAmount,
|
||||
@ -296,7 +296,7 @@ describe(ContractName.DutchAuction, () => {
|
||||
makerAssetData,
|
||||
});
|
||||
return expectTransactionFailedAsync(
|
||||
dutchAuctionWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
|
||||
dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
|
||||
RevertReason.AuctionExpired,
|
||||
);
|
||||
});
|
||||
@ -305,7 +305,7 @@ describe(ContractName.DutchAuction, () => {
|
||||
makerAssetAmount: sellOrder.takerAssetAmount,
|
||||
});
|
||||
return expectTransactionFailedAsync(
|
||||
dutchAuctionWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
|
||||
dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
|
||||
RevertReason.AuctionInvalidAmount,
|
||||
);
|
||||
});
|
||||
@ -314,13 +314,13 @@ describe(ContractName.DutchAuction, () => {
|
||||
takerAssetAmount: auctionBeginAmount.plus(1),
|
||||
});
|
||||
return expectTransactionFailedAsync(
|
||||
dutchAuctionWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
|
||||
dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
|
||||
RevertReason.AuctionInvalidAmount,
|
||||
);
|
||||
});
|
||||
it('begin time is less than end time', async () => {
|
||||
auctionBeginTimeSeconds = new BigNumber(auctionEndTimeSeconds).plus(tenMinutesInSeconds);
|
||||
const makerAssetData = assetDataUtils.encodeDutchAuctionAssetData(
|
||||
const makerAssetData = DutchAuctionTestWrapper.encodeDutchAuctionAssetData(
|
||||
defaultERC20MakerAssetData,
|
||||
auctionBeginTimeSeconds,
|
||||
auctionBeginAmount,
|
||||
@ -330,7 +330,7 @@ describe(ContractName.DutchAuction, () => {
|
||||
makerAssetData,
|
||||
});
|
||||
return expectTransactionFailedAsync(
|
||||
dutchAuctionWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
|
||||
dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
|
||||
RevertReason.AuctionInvalidBeginTime,
|
||||
);
|
||||
});
|
||||
@ -339,7 +339,7 @@ describe(ContractName.DutchAuction, () => {
|
||||
makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||
});
|
||||
return expectTransactionFailedAsync(
|
||||
dutchAuctionWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
|
||||
dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
|
||||
RevertReason.InvalidAssetData,
|
||||
);
|
||||
});
|
||||
@ -348,7 +348,7 @@ describe(ContractName.DutchAuction, () => {
|
||||
it('should match orders when ERC721', async () => {
|
||||
const makerAssetId = erc721MakerAssetIds[0];
|
||||
const erc721MakerAssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId);
|
||||
const makerAssetData = assetDataUtils.encodeDutchAuctionAssetData(
|
||||
const makerAssetData = DutchAuctionTestWrapper.encodeDutchAuctionAssetData(
|
||||
erc721MakerAssetData,
|
||||
auctionBeginTimeSeconds,
|
||||
auctionBeginAmount,
|
||||
@ -361,8 +361,8 @@ describe(ContractName.DutchAuction, () => {
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
takerAssetData: sellOrder.makerAssetData,
|
||||
});
|
||||
await dutchAuctionWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
|
||||
const afterAuctionDetails = await dutchAuctionWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
|
||||
const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
// HACK gte used here due to a bug in ganache where the timestamp can change
|
||||
// between multiple calls to the same block. Which can move the amount in our case
|
||||
|
@ -5,11 +5,13 @@ import { DutchAuctionDetails, SignedOrder } from '@0x/types';
|
||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
import { DutchAuctionContract } from '../../generated-wrappers/dutch_auction';
|
||||
import { artifacts } from '../../src/artifacts';
|
||||
import { DutchAuctionWrapper } from '@0x/contract-wrappers';
|
||||
|
||||
export class DutchAuctionWrapper {
|
||||
export class DutchAuctionTestWrapper {
|
||||
private readonly _dutchAuctionContract: DutchAuctionContract;
|
||||
private readonly _web3Wrapper: Web3Wrapper;
|
||||
private readonly _logDecoder: LogDecoder;
|
||||
@ -59,4 +61,16 @@ export class DutchAuctionWrapper {
|
||||
const afterAuctionDetails = await this._dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
|
||||
return afterAuctionDetails;
|
||||
}
|
||||
/**
|
||||
* Dutch auction details are encoded with the asset data for a 0x order. This function produces a hex
|
||||
* encoded assetData string, containing information both about the asset being traded and the
|
||||
* dutch auction; which is usable in the makerAssetData or takerAssetData fields in a 0x order.
|
||||
* @param assetData Hex encoded assetData string for the asset being auctioned.
|
||||
* @param beginTimeSeconds Begin time of the dutch auction.
|
||||
* @param beginAmount Starting amount being sold in the dutch auction.
|
||||
* @return The hex encoded assetData string.
|
||||
*/
|
||||
public static encodeDutchAuctionAssetData(assetData: string, beginTimeSeconds: BigNumber, beginAmount: BigNumber): string {
|
||||
return DutchAuctionWrapper.encodeDutchAuctionAssetData(assetData, beginTimeSeconds, beginAmount);
|
||||
};
|
||||
}
|
@ -18,7 +18,7 @@
|
||||
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output src/generated-wrappers --backend ethers"
|
||||
},
|
||||
"config": {
|
||||
"abis": "../contract-artifacts/artifacts/@(AssetProxyOwner|DummyERC20Token|DummyERC721Token|ERC20Proxy|ERC20Token|ERC721Proxy|ERC721Token|Exchange|Forwarder|IValidator|IWallet|OrderValidator|WETH9|ZRXToken).json"
|
||||
"abis": "../contract-artifacts/artifacts/@(AssetProxyOwner|DutchAuction|DummyERC20Token|DummyERC721Token|ERC20Proxy|ERC20Token|ERC721Proxy|ERC721Token|Exchange|Forwarder|IValidator|IWallet|OrderValidator|WETH9|ZRXToken).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -0,0 +1,322 @@
|
||||
// tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma whitespace class-name
|
||||
// tslint:disable:no-unused-variable
|
||||
// tslint:disable:no-unbound-method
|
||||
import { BaseContract } from '@0x/base-contract';
|
||||
import { BlockParam, BlockParamLiteral, CallData, ContractAbi, ContractArtifact, DecodedLogArgs, MethodAbi, Provider, TxData, TxDataPayable } from 'ethereum-types';
|
||||
import { BigNumber, classUtils, logUtils } from '@0x/utils';
|
||||
import { SimpleContractArtifact } from '@0x/types';
|
||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
import * as ethers from 'ethers';
|
||||
import * as _ from 'lodash';
|
||||
// tslint:enable:no-unused-variable
|
||||
|
||||
|
||||
/* istanbul ignore next */
|
||||
// tslint:disable:no-parameter-reassignment
|
||||
// tslint:disable-next-line:class-name
|
||||
export class DutchAuctionContract extends BaseContract {
|
||||
public getAuctionDetails = {
|
||||
async sendTransactionAsync(
|
||||
order: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
|
||||
txData: Partial<TxData> = {},
|
||||
): Promise<string> {
|
||||
const self = this as any as DutchAuctionContract;
|
||||
const inputAbi = self._lookupAbi('getAuctionDetails({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes})').inputs;
|
||||
[order
|
||||
] = BaseContract._formatABIDataItemList(inputAbi, [order
|
||||
], BaseContract._bigNumberToString.bind(self));
|
||||
BaseContract.strictArgumentEncodingCheck(inputAbi, [order
|
||||
]);
|
||||
const encodedData = self._lookupEthersInterface('getAuctionDetails({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes})').functions.getAuctionDetails.encode([order
|
||||
]);
|
||||
const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
|
||||
{
|
||||
to: self.address,
|
||||
...txData,
|
||||
data: encodedData,
|
||||
},
|
||||
self._web3Wrapper.getContractDefaults(),
|
||||
self.getAuctionDetails.estimateGasAsync.bind(
|
||||
self,
|
||||
order
|
||||
),
|
||||
);
|
||||
const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults);
|
||||
return txHash;
|
||||
},
|
||||
async estimateGasAsync(
|
||||
order: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
|
||||
txData: Partial<TxData> = {},
|
||||
): Promise<number> {
|
||||
const self = this as any as DutchAuctionContract;
|
||||
const inputAbi = self._lookupAbi('getAuctionDetails({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes})').inputs;
|
||||
[order
|
||||
] = BaseContract._formatABIDataItemList(inputAbi, [order
|
||||
], BaseContract._bigNumberToString);
|
||||
const encodedData = self._lookupEthersInterface('getAuctionDetails({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes})').functions.getAuctionDetails.encode([order
|
||||
]);
|
||||
const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
|
||||
{
|
||||
to: self.address,
|
||||
...txData,
|
||||
data: encodedData,
|
||||
},
|
||||
self._web3Wrapper.getContractDefaults(),
|
||||
);
|
||||
const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults);
|
||||
return gas;
|
||||
},
|
||||
getABIEncodedTransactionData(
|
||||
order: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
|
||||
): string {
|
||||
const self = this as any as DutchAuctionContract;
|
||||
const inputAbi = self._lookupAbi('getAuctionDetails({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes})').inputs;
|
||||
[order
|
||||
] = BaseContract._formatABIDataItemList(inputAbi, [order
|
||||
], BaseContract._bigNumberToString);
|
||||
const abiEncodedTransactionData = self._lookupEthersInterface('getAuctionDetails({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes})').functions.getAuctionDetails.encode([order
|
||||
]);
|
||||
return abiEncodedTransactionData;
|
||||
},
|
||||
async callAsync(
|
||||
order: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
|
||||
callData: Partial<CallData> = {},
|
||||
defaultBlock?: BlockParam,
|
||||
): Promise<{beginTimeSeconds: BigNumber;endTimeSeconds: BigNumber;beginAmount: BigNumber;endAmount: BigNumber;currentAmount: BigNumber;currentTimeSeconds: BigNumber}
|
||||
> {
|
||||
const self = this as any as DutchAuctionContract;
|
||||
const functionSignature = 'getAuctionDetails({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes})';
|
||||
const inputAbi = self._lookupAbi(functionSignature).inputs;
|
||||
[order
|
||||
] = BaseContract._formatABIDataItemList(inputAbi, [order
|
||||
], BaseContract._bigNumberToString.bind(self));
|
||||
BaseContract.strictArgumentEncodingCheck(inputAbi, [order
|
||||
]);
|
||||
const ethersFunction = self._lookupEthersInterface(functionSignature).functions.getAuctionDetails;
|
||||
const encodedData = ethersFunction.encode([order
|
||||
]);
|
||||
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
|
||||
{
|
||||
to: self.address,
|
||||
...callData,
|
||||
data: encodedData,
|
||||
},
|
||||
self._web3Wrapper.getContractDefaults(),
|
||||
);
|
||||
const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock);
|
||||
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
|
||||
let resultArray = ethersFunction.decode(rawCallResult);
|
||||
const outputAbi = (_.find(self.abi, {name: 'getAuctionDetails'}) as MethodAbi).outputs;
|
||||
resultArray = BaseContract._formatABIDataItemList(outputAbi, resultArray, BaseContract._lowercaseAddress.bind(this));
|
||||
resultArray = BaseContract._formatABIDataItemList(outputAbi, resultArray, BaseContract._bnToBigNumber.bind(this));
|
||||
return resultArray[0];
|
||||
},
|
||||
};
|
||||
public matchOrders = {
|
||||
async sendTransactionAsync(
|
||||
buyOrder: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
|
||||
sellOrder: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
|
||||
buySignature: string,
|
||||
sellSignature: string,
|
||||
txData: Partial<TxData> = {},
|
||||
): Promise<string> {
|
||||
const self = this as any as DutchAuctionContract;
|
||||
const inputAbi = self._lookupAbi('matchOrders({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes},{address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes},bytes,bytes)').inputs;
|
||||
[buyOrder,
|
||||
sellOrder,
|
||||
buySignature,
|
||||
sellSignature
|
||||
] = BaseContract._formatABIDataItemList(inputAbi, [buyOrder,
|
||||
sellOrder,
|
||||
buySignature,
|
||||
sellSignature
|
||||
], BaseContract._bigNumberToString.bind(self));
|
||||
BaseContract.strictArgumentEncodingCheck(inputAbi, [buyOrder,
|
||||
sellOrder,
|
||||
buySignature,
|
||||
sellSignature
|
||||
]);
|
||||
const encodedData = self._lookupEthersInterface('matchOrders({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes},{address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes},bytes,bytes)').functions.matchOrders.encode([buyOrder,
|
||||
sellOrder,
|
||||
buySignature,
|
||||
sellSignature
|
||||
]);
|
||||
const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
|
||||
{
|
||||
to: self.address,
|
||||
...txData,
|
||||
data: encodedData,
|
||||
},
|
||||
self._web3Wrapper.getContractDefaults(),
|
||||
self.matchOrders.estimateGasAsync.bind(
|
||||
self,
|
||||
buyOrder,
|
||||
sellOrder,
|
||||
buySignature,
|
||||
sellSignature
|
||||
),
|
||||
);
|
||||
const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults);
|
||||
return txHash;
|
||||
},
|
||||
async estimateGasAsync(
|
||||
buyOrder: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
|
||||
sellOrder: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
|
||||
buySignature: string,
|
||||
sellSignature: string,
|
||||
txData: Partial<TxData> = {},
|
||||
): Promise<number> {
|
||||
const self = this as any as DutchAuctionContract;
|
||||
const inputAbi = self._lookupAbi('matchOrders({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes},{address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes},bytes,bytes)').inputs;
|
||||
[buyOrder,
|
||||
sellOrder,
|
||||
buySignature,
|
||||
sellSignature
|
||||
] = BaseContract._formatABIDataItemList(inputAbi, [buyOrder,
|
||||
sellOrder,
|
||||
buySignature,
|
||||
sellSignature
|
||||
], BaseContract._bigNumberToString);
|
||||
const encodedData = self._lookupEthersInterface('matchOrders({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes},{address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes},bytes,bytes)').functions.matchOrders.encode([buyOrder,
|
||||
sellOrder,
|
||||
buySignature,
|
||||
sellSignature
|
||||
]);
|
||||
const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
|
||||
{
|
||||
to: self.address,
|
||||
...txData,
|
||||
data: encodedData,
|
||||
},
|
||||
self._web3Wrapper.getContractDefaults(),
|
||||
);
|
||||
const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults);
|
||||
return gas;
|
||||
},
|
||||
getABIEncodedTransactionData(
|
||||
buyOrder: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
|
||||
sellOrder: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
|
||||
buySignature: string,
|
||||
sellSignature: string,
|
||||
): string {
|
||||
const self = this as any as DutchAuctionContract;
|
||||
const inputAbi = self._lookupAbi('matchOrders({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes},{address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes},bytes,bytes)').inputs;
|
||||
[buyOrder,
|
||||
sellOrder,
|
||||
buySignature,
|
||||
sellSignature
|
||||
] = BaseContract._formatABIDataItemList(inputAbi, [buyOrder,
|
||||
sellOrder,
|
||||
buySignature,
|
||||
sellSignature
|
||||
], BaseContract._bigNumberToString);
|
||||
const abiEncodedTransactionData = self._lookupEthersInterface('matchOrders({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes},{address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes},bytes,bytes)').functions.matchOrders.encode([buyOrder,
|
||||
sellOrder,
|
||||
buySignature,
|
||||
sellSignature
|
||||
]);
|
||||
return abiEncodedTransactionData;
|
||||
},
|
||||
async callAsync(
|
||||
buyOrder: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
|
||||
sellOrder: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
|
||||
buySignature: string,
|
||||
sellSignature: string,
|
||||
callData: Partial<CallData> = {},
|
||||
defaultBlock?: BlockParam,
|
||||
): Promise<{left: {makerAssetFilledAmount: BigNumber;takerAssetFilledAmount: BigNumber;makerFeePaid: BigNumber;takerFeePaid: BigNumber};right: {makerAssetFilledAmount: BigNumber;takerAssetFilledAmount: BigNumber;makerFeePaid: BigNumber;takerFeePaid: BigNumber};leftMakerAssetSpreadAmount: BigNumber}
|
||||
> {
|
||||
const self = this as any as DutchAuctionContract;
|
||||
const functionSignature = 'matchOrders({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes},{address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes},bytes,bytes)';
|
||||
const inputAbi = self._lookupAbi(functionSignature).inputs;
|
||||
[buyOrder,
|
||||
sellOrder,
|
||||
buySignature,
|
||||
sellSignature
|
||||
] = BaseContract._formatABIDataItemList(inputAbi, [buyOrder,
|
||||
sellOrder,
|
||||
buySignature,
|
||||
sellSignature
|
||||
], BaseContract._bigNumberToString.bind(self));
|
||||
BaseContract.strictArgumentEncodingCheck(inputAbi, [buyOrder,
|
||||
sellOrder,
|
||||
buySignature,
|
||||
sellSignature
|
||||
]);
|
||||
const ethersFunction = self._lookupEthersInterface(functionSignature).functions.matchOrders;
|
||||
const encodedData = ethersFunction.encode([buyOrder,
|
||||
sellOrder,
|
||||
buySignature,
|
||||
sellSignature
|
||||
]);
|
||||
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
|
||||
{
|
||||
to: self.address,
|
||||
...callData,
|
||||
data: encodedData,
|
||||
},
|
||||
self._web3Wrapper.getContractDefaults(),
|
||||
);
|
||||
const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock);
|
||||
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
|
||||
let resultArray = ethersFunction.decode(rawCallResult);
|
||||
const outputAbi = (_.find(self.abi, {name: 'matchOrders'}) as MethodAbi).outputs;
|
||||
resultArray = BaseContract._formatABIDataItemList(outputAbi, resultArray, BaseContract._lowercaseAddress.bind(this));
|
||||
resultArray = BaseContract._formatABIDataItemList(outputAbi, resultArray, BaseContract._bnToBigNumber.bind(this));
|
||||
return resultArray[0];
|
||||
},
|
||||
};
|
||||
public static async deployFrom0xArtifactAsync(
|
||||
artifact: ContractArtifact | SimpleContractArtifact,
|
||||
provider: Provider,
|
||||
txDefaults: Partial<TxData>,
|
||||
_exchange: string,
|
||||
): Promise<DutchAuctionContract> {
|
||||
if (_.isUndefined(artifact.compilerOutput)) {
|
||||
throw new Error('Compiler output not found in the artifact file');
|
||||
}
|
||||
const bytecode = artifact.compilerOutput.evm.bytecode.object;
|
||||
const abi = artifact.compilerOutput.abi;
|
||||
return DutchAuctionContract.deployAsync(bytecode, abi, provider, txDefaults, _exchange
|
||||
);
|
||||
}
|
||||
public static async deployAsync(
|
||||
bytecode: string,
|
||||
abi: ContractAbi,
|
||||
provider: Provider,
|
||||
txDefaults: Partial<TxData>,
|
||||
_exchange: string,
|
||||
): Promise<DutchAuctionContract> {
|
||||
const constructorAbi = BaseContract._lookupConstructorAbi(abi);
|
||||
[_exchange
|
||||
] = BaseContract._formatABIDataItemList(
|
||||
constructorAbi.inputs,
|
||||
[_exchange
|
||||
],
|
||||
BaseContract._bigNumberToString,
|
||||
);
|
||||
const iface = new ethers.utils.Interface(abi);
|
||||
const deployInfo = iface.deployFunction;
|
||||
const txData = deployInfo.encode(bytecode, [_exchange
|
||||
]);
|
||||
const web3Wrapper = new Web3Wrapper(provider);
|
||||
const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
|
||||
{data: txData},
|
||||
txDefaults,
|
||||
web3Wrapper.estimateGasAsync.bind(web3Wrapper),
|
||||
);
|
||||
const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults);
|
||||
logUtils.log(`transactionHash: ${txHash}`);
|
||||
const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
logUtils.log(`DutchAuction successfully deployed at ${txReceipt.contractAddress}`);
|
||||
const contractInstance = new DutchAuctionContract(abi, txReceipt.contractAddress as string, provider, txDefaults);
|
||||
contractInstance.constructorArgs = [_exchange
|
||||
];
|
||||
return contractInstance;
|
||||
}
|
||||
constructor(abi: ContractAbi, address: string, provider: Provider, txDefaults?: Partial<TxData>) {
|
||||
super('DutchAuction', abi, address, provider, txDefaults);
|
||||
classUtils.bindAll(this, ['_ethersInterfacesByFunctionSignature', 'address', 'abi', '_web3Wrapper']);
|
||||
}
|
||||
} // tslint:disable:max-file-line-count
|
||||
// tslint:enable:no-unbound-method
|
@ -1,6 +1,7 @@
|
||||
export * from './generated-wrappers/asset_proxy_owner';
|
||||
export * from './generated-wrappers/dummy_erc20_token';
|
||||
export * from './generated-wrappers/dummy_erc721_token';
|
||||
export * from './generated-wrappers/dutch_auction';
|
||||
export * from './generated-wrappers/erc20_proxy';
|
||||
export * from './generated-wrappers/erc20_token';
|
||||
export * from './generated-wrappers/erc721_proxy';
|
||||
|
@ -9,6 +9,7 @@ export interface ContractAddresses {
|
||||
assetProxyOwner: string;
|
||||
forwarder: string;
|
||||
orderValidator: string;
|
||||
dutchAuction: string;
|
||||
}
|
||||
|
||||
export enum NetworkId {
|
||||
@ -29,6 +30,7 @@ const networkToAddresses: { [networkId: number]: ContractAddresses } = {
|
||||
assetProxyOwner: '0x17992e4ffb22730138e4b62aaa6367fa9d3699a6',
|
||||
forwarder: '0x5468a1dc173652ee28d249c271fa9933144746b1',
|
||||
orderValidator: '0x9463e518dea6810309563c81d5266c1b1d149138',
|
||||
dutchAuction: '0x',
|
||||
},
|
||||
3: {
|
||||
erc20Proxy: '0xb1408f4c245a23c31b98d2c626777d4c0d766caa',
|
||||
@ -39,6 +41,7 @@ const networkToAddresses: { [networkId: number]: ContractAddresses } = {
|
||||
assetProxyOwner: '0xf5fa5b5fed2727a0e44ac67f6772e97977aa358b',
|
||||
forwarder: '0x2240dab907db71e64d3e0dba4800c83b5c502d4e',
|
||||
orderValidator: '0x90431a90516ab49af23a0530e04e8c7836e7122f',
|
||||
dutchAuction: '0x',
|
||||
},
|
||||
4: {
|
||||
exchange: '0xbce0b5f6eb618c565c3e5f5cd69652bbc279f44e',
|
||||
@ -49,6 +52,7 @@ const networkToAddresses: { [networkId: number]: ContractAddresses } = {
|
||||
assetProxyOwner: '0xe1703da878afcebff5b7624a826902af475b9c03',
|
||||
forwarder: '0x2d40589abbdee84961f3a7656b9af7adb0ee5ab4',
|
||||
orderValidator: '0x0c5173a51e26b29d6126c686756fb9fbef71f762',
|
||||
dutchAuction: '0x',
|
||||
},
|
||||
42: {
|
||||
erc20Proxy: '0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e',
|
||||
@ -59,6 +63,7 @@ const networkToAddresses: { [networkId: number]: ContractAddresses } = {
|
||||
assetProxyOwner: '0x2c824d2882baa668e0d5202b1e7f2922278703f8',
|
||||
forwarder: '0x17992e4ffb22730138e4b62aaa6367fa9d3699a6',
|
||||
orderValidator: '0xb389da3d204b412df2f75c6afb3d0a7ce0bc283d',
|
||||
dutchAuction: '0x',
|
||||
},
|
||||
// NetworkId 50 represents our Ganache snapshot generated from migrations.
|
||||
50: {
|
||||
@ -70,6 +75,7 @@ const networkToAddresses: { [networkId: number]: ContractAddresses } = {
|
||||
assetProxyOwner: '0x34d402f14d58e001d8efbe6585051bf9706aa064',
|
||||
forwarder: '0xb69e673309512a9d726f87304c6984054f87a93b',
|
||||
orderValidator: '0xe86bb98fcf9bff3512c74589b78fb168200cc546',
|
||||
dutchAuction: '0x',
|
||||
},
|
||||
};
|
||||
|
||||
|
392
packages/contract-artifacts/artifacts/DutchAuction.json
generated
Normal file
392
packages/contract-artifacts/artifacts/DutchAuction.json
generated
Normal file
File diff suppressed because one or more lines are too long
@ -1,4 +1,5 @@
|
||||
import * as AssetProxyOwner from '../artifacts/AssetProxyOwner.json';
|
||||
import * as DutchAuction from '../artifacts/DutchAuction.json';
|
||||
import * as DummyERC20Token from '../artifacts/DummyERC20Token.json';
|
||||
import * as DummyERC721Token from '../artifacts/DummyERC721Token.json';
|
||||
import * as ERC20Proxy from '../artifacts/ERC20Proxy.json';
|
||||
@ -15,6 +16,7 @@ import * as ZRXToken from '../artifacts/ZRXToken.json';
|
||||
|
||||
export {
|
||||
AssetProxyOwner,
|
||||
DutchAuction,
|
||||
DummyERC20Token,
|
||||
DummyERC721Token,
|
||||
ERC20Proxy,
|
||||
|
@ -8,6 +8,7 @@
|
||||
"include": ["./src/**/*"],
|
||||
"files": [
|
||||
"./artifacts/AssetProxyOwner.json",
|
||||
"./artifacts/DutchAuction.json",
|
||||
"./artifacts/DummyERC20Token.json",
|
||||
"./artifacts/DummyERC721Token.json",
|
||||
"./artifacts/ERC20Proxy.json",
|
||||
|
@ -20,6 +20,7 @@ import { EtherTokenWrapper } from './contract_wrappers/ether_token_wrapper';
|
||||
import { ExchangeWrapper } from './contract_wrappers/exchange_wrapper';
|
||||
import { ForwarderWrapper } from './contract_wrappers/forwarder_wrapper';
|
||||
import { OrderValidatorWrapper } from './contract_wrappers/order_validator_wrapper';
|
||||
import { DutchAuctionWrapper } from './contract_wrappers/dutch_auction_wrapper';
|
||||
import { ContractWrappersConfigSchema } from './schemas/contract_wrappers_config_schema';
|
||||
import { ContractWrappersConfig } from './types';
|
||||
import { assert } from './utils/assert';
|
||||
@ -65,6 +66,10 @@ export class ContractWrappers {
|
||||
* An instance of the OrderValidatorWrapper class containing methods for interacting with any OrderValidator smart contract.
|
||||
*/
|
||||
public orderValidator: OrderValidatorWrapper;
|
||||
/**
|
||||
* An instance of the DutchAuctionWrapper class containing methods for interacting with any DutchAuction smart contract.
|
||||
*/
|
||||
public dutchAuction: DutchAuctionWrapper;
|
||||
|
||||
private readonly _web3Wrapper: Web3Wrapper;
|
||||
/**
|
||||
@ -141,6 +146,11 @@ export class ContractWrappers {
|
||||
config.networkId,
|
||||
contractAddresses.orderValidator,
|
||||
);
|
||||
this.dutchAuction = new DutchAuctionWrapper(
|
||||
this._web3Wrapper,
|
||||
config.networkId,
|
||||
contractAddresses.orderValidator,
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Unsubscribes from all subscriptions for all contracts.
|
||||
|
@ -0,0 +1,151 @@
|
||||
import { artifacts as protocolArtifacts } from '@0x/contracts-protocol';
|
||||
import { DutchAuctionContract } from '@0x/abi-gen-wrappers';
|
||||
import { DutchAuction } from '@0x/contract-artifacts';
|
||||
import { LogDecoder } from '@0x/contracts-test-utils';
|
||||
import { artifacts as tokensArtifacts } from '@0x/contracts-tokens';
|
||||
import { _getDefaultContractAddresses } from '../utils/contract_addresses';
|
||||
import { DutchAuctionDetails, SignedOrder } from '@0x/types';
|
||||
import { ContractAbi } from 'ethereum-types';
|
||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
import ethAbi = require('ethereumjs-abi');
|
||||
import { schemas } from '@0x/json-schemas';
|
||||
import { assert } from '../utils/assert';
|
||||
import ethUtil = require('ethereumjs-util');
|
||||
|
||||
import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema';
|
||||
import { txOptsSchema } from '../schemas/tx_opts_schema';
|
||||
import { OrderTransactionOpts } from '../types';
|
||||
import { ContractWrapper } from './contract_wrapper';
|
||||
import { ExchangeWrapperError } from '../types';
|
||||
|
||||
export class DutchAuctionWrapper extends ContractWrapper {
|
||||
public abi: ContractAbi = DutchAuction.compilerOutput.abi;
|
||||
public address: string;
|
||||
private _dutchAuctionContractIfExists?: DutchAuctionContract;
|
||||
/**
|
||||
* Instantiate DutchAuctionWrapper
|
||||
* @param web3Wrapper Web3Wrapper instance to use.
|
||||
* @param networkId Desired networkId.
|
||||
* @param address The address of the Dutch Auction contract. If undefined, will
|
||||
* default to the known address corresponding to the networkId.
|
||||
*/
|
||||
constructor(
|
||||
web3Wrapper: Web3Wrapper,
|
||||
networkId: number,
|
||||
address: string,
|
||||
) {
|
||||
super(web3Wrapper, networkId);
|
||||
this.address = address;
|
||||
}
|
||||
/**
|
||||
* Matches the buy and sell orders at an amount given the following: the current block time, the auction
|
||||
* start time and the auction begin amount. The sell order is a an order at the lowest amount
|
||||
* at the end of the auction. Excess from the match is transferred to the seller.
|
||||
* Over time the price moves from beginAmount to endAmount given the current block.timestamp.
|
||||
* @param buyOrder The Buyer's order. This order is for the current expected price of the auction.
|
||||
* @param sellOrder The Seller's order. This order is for the lowest amount (at the end of the auction).
|
||||
* @param from Address the transaction is being sent from.
|
||||
* @return Transaction receipt with decoded logs.
|
||||
*/
|
||||
public async matchOrdersAsync(
|
||||
buyOrder: SignedOrder,
|
||||
sellOrder: SignedOrder,
|
||||
takerAddress: string,
|
||||
orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true },
|
||||
): Promise<string> {
|
||||
// type assertions
|
||||
assert.doesConformToSchema('buyOrder', buyOrder, schemas.signedOrderSchema);
|
||||
assert.doesConformToSchema('sellOrder', sellOrder, schemas.signedOrderSchema);
|
||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||
assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]);
|
||||
const normalizedTakerAddress = takerAddress.toLowerCase();
|
||||
// other assertions
|
||||
if (
|
||||
sellOrder.makerAssetData !== buyOrder.takerAssetData ||
|
||||
sellOrder.takerAssetData !== buyOrder.makerAssetData
|
||||
) {
|
||||
throw new Error(ExchangeWrapperError.AssetDataMismatch);
|
||||
}
|
||||
// get contract
|
||||
const dutchAuctionInstance = await this._getDutchAuctionContractAsync();
|
||||
// validate transaction
|
||||
if (orderTransactionOpts.shouldValidate) {
|
||||
await dutchAuctionInstance.matchOrders.callAsync(
|
||||
buyOrder,
|
||||
sellOrder,
|
||||
buyOrder.signature,
|
||||
sellOrder.signature,
|
||||
{
|
||||
from: normalizedTakerAddress,
|
||||
gas: orderTransactionOpts.gasLimit,
|
||||
gasPrice: orderTransactionOpts.gasPrice,
|
||||
nonce: orderTransactionOpts.nonce,
|
||||
},
|
||||
);
|
||||
}
|
||||
// send transaction
|
||||
const txHash = await dutchAuctionInstance.matchOrders.sendTransactionAsync(
|
||||
buyOrder,
|
||||
sellOrder,
|
||||
buyOrder.signature,
|
||||
sellOrder.signature,
|
||||
{
|
||||
from: normalizedTakerAddress,
|
||||
gas: orderTransactionOpts.gasLimit,
|
||||
gasPrice: orderTransactionOpts.gasPrice,
|
||||
nonce: orderTransactionOpts.nonce,
|
||||
},
|
||||
);
|
||||
return txHash;
|
||||
}
|
||||
/**
|
||||
* Calculates the Auction Details for the given order
|
||||
* @param sellOrder The Seller's order. This order is for the lowest amount (at the end of the auction).
|
||||
* @return The dutch auction details.
|
||||
*/
|
||||
public async getAuctionDetailsAsync(sellOrder: SignedOrder): Promise<DutchAuctionDetails> {
|
||||
// type assertions
|
||||
assert.doesConformToSchema('sellOrder', sellOrder, schemas.signedOrderSchema);
|
||||
// get contract
|
||||
const dutchAuctionInstance = await this._getDutchAuctionContractAsync();
|
||||
// call contract
|
||||
const afterAuctionDetails = await dutchAuctionInstance.getAuctionDetails.callAsync(sellOrder);
|
||||
return afterAuctionDetails;
|
||||
}
|
||||
private async _getDutchAuctionContractAsync(): Promise<DutchAuctionContract> {
|
||||
if (!_.isUndefined(this._dutchAuctionContractIfExists)) {
|
||||
return this._dutchAuctionContractIfExists;
|
||||
}
|
||||
const contractInstance = new DutchAuctionContract(
|
||||
this.abi,
|
||||
this.address,
|
||||
this._web3Wrapper.getProvider(),
|
||||
this._web3Wrapper.getContractDefaults(),
|
||||
);
|
||||
this._dutchAuctionContractIfExists = contractInstance;
|
||||
return this._dutchAuctionContractIfExists;
|
||||
}
|
||||
/**
|
||||
* Dutch auction details are encoded with the asset data for a 0x order. This function produces a hex
|
||||
* encoded assetData string, containing information both about the asset being traded and the
|
||||
* dutch auction; which is usable in the makerAssetData or takerAssetData fields in a 0x order.
|
||||
* @param assetData Hex encoded assetData string for the asset being auctioned.
|
||||
* @param beginTimeSeconds Begin time of the dutch auction.
|
||||
* @param beginAmount Starting amount being sold in the dutch auction.
|
||||
* @return The hex encoded assetData string.
|
||||
*/
|
||||
public static encodeDutchAuctionAssetData(assetData: string, beginTimeSeconds: BigNumber, beginAmount: BigNumber): string {
|
||||
const assetDataBuffer = ethUtil.toBuffer(assetData);
|
||||
const abiEncodedAuctionData = (ethAbi as any).rawEncode(
|
||||
['uint256', 'uint256'],
|
||||
[beginTimeSeconds.toString(), beginAmount.toString()],
|
||||
);
|
||||
const abiEncodedAuctionDataBuffer = ethUtil.toBuffer(abiEncodedAuctionData);
|
||||
const dutchAuctionDataBuffer = Buffer.concat([assetDataBuffer, abiEncodedAuctionDataBuffer]);
|
||||
const dutchAuctionData = ethUtil.bufferToHex(dutchAuctionDataBuffer);
|
||||
return dutchAuctionData;
|
||||
};
|
||||
}
|
@ -34,6 +34,7 @@ export { ERC20ProxyWrapper } from './contract_wrappers/erc20_proxy_wrapper';
|
||||
export { ERC721ProxyWrapper } from './contract_wrappers/erc721_proxy_wrapper';
|
||||
export { ForwarderWrapper } from './contract_wrappers/forwarder_wrapper';
|
||||
export { OrderValidatorWrapper } from './contract_wrappers/order_validator_wrapper';
|
||||
export { DutchAuctionWrapper } from './contract_wrappers/dutch_auction_wrapper';
|
||||
|
||||
export { TransactionEncoder } from './utils/transaction_encoder';
|
||||
|
||||
|
156
packages/contract-wrappers/test/dutch_auction_wrapper_test.ts
Normal file
156
packages/contract-wrappers/test/dutch_auction_wrapper_test.ts
Normal file
@ -0,0 +1,156 @@
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { FillScenarios } from '@0x/fill-scenarios';
|
||||
import { assetDataUtils } from '@0x/order-utils';
|
||||
import { SignedOrder } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import 'mocha';
|
||||
|
||||
import { ContractWrappers, OrderStatus } from '../src';
|
||||
|
||||
import { chaiSetup } from './utils/chai_setup';
|
||||
import { constants } from './utils/constants';
|
||||
import { migrateOnceAsync } from './utils/migrate';
|
||||
import { tokenUtils } from './utils/token_utils';
|
||||
import { provider, web3Wrapper } from './utils/web3_wrapper';
|
||||
import { getLatestBlockTimestampAsync } from '@0x/contracts-test-utils';
|
||||
import { DutchAuction } from '@0x/contract-artifacts';
|
||||
import { DutchAuctionWrapper } from '../src/contract_wrappers/dutch_auction_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
// tslint:disable:custom-no-magic-numbers
|
||||
describe.only('DutchAuctionWrapper', () => {
|
||||
const fillableAmount = new BigNumber(5);
|
||||
const tenMinutesInSeconds = 10 * 60;
|
||||
let contractWrappers: ContractWrappers;
|
||||
let fillScenarios: FillScenarios;
|
||||
let exchangeContractAddress: string;
|
||||
let zrxTokenAddress: string;
|
||||
let userAddresses: string[];
|
||||
let makerAddress: string;
|
||||
let takerAddress: string;
|
||||
let makerTokenAddress: string;
|
||||
let takerTokenAddress: string;
|
||||
let makerAssetData: string;
|
||||
let takerAssetData: string;
|
||||
let buyOrder: SignedOrder;
|
||||
let sellOrder: SignedOrder;
|
||||
let makerTokenAssetData: string;
|
||||
let takerTokenAssetData: string;
|
||||
before(async () => {
|
||||
console.log(`BEOGIN DEPLOYINH`);
|
||||
const contractAddresses = await migrateOnceAsync();
|
||||
await blockchainLifecycle.startAsync();
|
||||
const config = {
|
||||
networkId: constants.TESTRPC_NETWORK_ID,
|
||||
contractAddresses,
|
||||
blockPollingIntervalMs: 10,
|
||||
};
|
||||
|
||||
contractWrappers = new ContractWrappers(provider, config);
|
||||
console.log(`DEPLOYINH`);
|
||||
exchangeContractAddress = contractWrappers.exchange.address;
|
||||
userAddresses = await web3Wrapper.getAvailableAddressesAsync();
|
||||
zrxTokenAddress = contractWrappers.exchange.zrxTokenAddress;
|
||||
fillScenarios = new FillScenarios(
|
||||
provider,
|
||||
userAddresses,
|
||||
zrxTokenAddress,
|
||||
exchangeContractAddress,
|
||||
contractWrappers.erc20Proxy.address,
|
||||
contractWrappers.erc721Proxy.address,
|
||||
);
|
||||
[, makerAddress, takerAddress] = userAddresses;
|
||||
[makerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses();
|
||||
takerTokenAddress = contractWrappers.forwarder.etherTokenAddress;
|
||||
// construct asset data for tokens being swapped
|
||||
[makerTokenAssetData, takerTokenAssetData] = [
|
||||
assetDataUtils.encodeERC20AssetData(makerTokenAddress),
|
||||
assetDataUtils.encodeERC20AssetData(takerTokenAddress),
|
||||
];
|
||||
// encode auction details in maker asset data
|
||||
const auctionBeginAmount = fillableAmount;
|
||||
const currentBlockTimestamp = await getLatestBlockTimestampAsync();
|
||||
const auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds);
|
||||
makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData(
|
||||
makerTokenAssetData,
|
||||
auctionBeginTimeSeconds,
|
||||
auctionBeginAmount
|
||||
);
|
||||
takerAssetData = takerTokenAssetData;
|
||||
// create sell / buy orders for auction
|
||||
// note that the maker/taker asset datas are swapped in the `buyOrder`
|
||||
sellOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerAssetData,
|
||||
takerAssetData,
|
||||
makerAddress,
|
||||
constants.NULL_ADDRESS,
|
||||
fillableAmount,
|
||||
);
|
||||
buyOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
takerAssetData,
|
||||
makerAssetData,
|
||||
makerAddress,
|
||||
constants.NULL_ADDRESS,
|
||||
fillableAmount,
|
||||
);
|
||||
});
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('#matchOrdersAsync', () => {
|
||||
it('should match two orders', async () => {
|
||||
const txHash = await contractWrappers.dutchAuction.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
|
||||
});
|
||||
it('should throw when invalid transaction and shouldValidate is true', async () => {
|
||||
// request match with bad buy/sell orders
|
||||
const badSellOrder = buyOrder;
|
||||
const badBuyOrder = sellOrder;
|
||||
return expect(
|
||||
await contractWrappers.dutchAuction.matchOrdersAsync(
|
||||
badBuyOrder,
|
||||
badSellOrder,
|
||||
takerAddress,
|
||||
{
|
||||
shouldValidate: true,
|
||||
},
|
||||
),
|
||||
).to.be.rejectedWith('COMPLETE_FILL_FAILED');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getAuctionDetailsAsync', () => {
|
||||
it('should be worth the begin price at the begining of the auction', async () => {
|
||||
// setup auction details
|
||||
const auctionBeginAmount = fillableAmount;
|
||||
const currentBlockTimestamp = await getLatestBlockTimestampAsync();
|
||||
const auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp + tenMinutesInSeconds);
|
||||
const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData(
|
||||
makerTokenAssetData,
|
||||
auctionBeginTimeSeconds,
|
||||
auctionBeginAmount
|
||||
);
|
||||
const order = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerAssetData,
|
||||
takerAssetData,
|
||||
makerAddress,
|
||||
constants.NULL_ADDRESS,
|
||||
fillableAmount,
|
||||
);
|
||||
const auctionDetails = await contractWrappers.dutchAuction.getAuctionDetailsAsync(order);
|
||||
expect(auctionDetails.currentTimeSeconds).to.be.bignumber.lte(auctionBeginTimeSeconds);
|
||||
expect(auctionDetails.currentAmount).to.be.bignumber.equal(auctionBeginAmount);
|
||||
expect(auctionDetails.beginAmount).to.be.bignumber.equal(auctionBeginAmount);
|
||||
});
|
||||
});
|
||||
});
|
@ -141,6 +141,14 @@ export async function runMigrationsAsync(provider: Provider, txDefaults: Partial
|
||||
zrxAssetData,
|
||||
);
|
||||
|
||||
// DutchAuction
|
||||
const dutchAuction = await wrappers.DutchAuctionContract.deployFrom0xArtifactAsync(
|
||||
artifacts.DutchAuction,
|
||||
provider,
|
||||
txDefaults,
|
||||
exchange.address,
|
||||
);
|
||||
|
||||
// Fund the Forwarder with ZRX
|
||||
const zrxDecimals = await zrxToken.decimals.callAsync();
|
||||
const zrxForwarderAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(5000), zrxDecimals);
|
||||
@ -157,6 +165,7 @@ export async function runMigrationsAsync(provider: Provider, txDefaults: Partial
|
||||
assetProxyOwner: assetProxyOwner.address,
|
||||
forwarder: forwarder.address,
|
||||
orderValidator: orderValidator.address,
|
||||
dutchAuction: dutchAuction.address,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -305,24 +305,4 @@ export const assetDataUtils = {
|
||||
throw new Error(`Unrecognized asset proxy id: ${assetProxyId}`);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Dutch auction details are encoded with the asset data for a 0x order. This function produces a hex
|
||||
* encoded assetData string, containing information both about the asset being traded and the
|
||||
* dutch auction; which is usable in the makerAssetData or takerAssetData fields in a 0x order.
|
||||
* @param assetData Hex encoded assetData string for the asset being auctioned.
|
||||
* @param beginTimeSeconds Begin time of the dutch auction.
|
||||
* @param beginAmount Starting amount being sold in the dutch auction.
|
||||
* @return The hex encoded assetData string.
|
||||
*/
|
||||
encodeDutchAuctionAssetData(assetData: string, beginTimeSeconds: BigNumber, beginAmount: BigNumber): string {
|
||||
const assetDataBuffer = ethUtil.toBuffer(assetData);
|
||||
const abiEncodedAuctionData = (ethAbi as any).rawEncode(
|
||||
['uint256', 'uint256'],
|
||||
[beginTimeSeconds.toString(), beginAmount.toString()],
|
||||
);
|
||||
const abiEncodedAuctionDataBuffer = ethUtil.toBuffer(abiEncodedAuctionData);
|
||||
const dutchAuctionDataBuffer = Buffer.concat([assetDataBuffer, abiEncodedAuctionDataBuffer]);
|
||||
const dutchAuctionData = ethUtil.bufferToHex(dutchAuctionDataBuffer);
|
||||
return dutchAuctionData;
|
||||
},
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user