154 lines
6.4 KiB
TypeScript
154 lines
6.4 KiB
TypeScript
import { DummyERC20TokenContract } from '@0x/abi-gen-wrappers';
|
|
import * as artifacts from '@0x/contract-artifacts';
|
|
import { assetDataUtils } from '@0x/order-utils';
|
|
import { orderFactory } from '@0x/order-utils/lib/src/order_factory';
|
|
import { SignedOrder } from '@0x/types';
|
|
import { BigNumber } from '@0x/utils';
|
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
|
|
|
import { DutchAuctionWrapper } from '../../src/contract_wrappers/dutch_auction_wrapper';
|
|
|
|
import { constants } from './constants';
|
|
|
|
export class DutchAuctionUtils {
|
|
private readonly _web3Wrapper: Web3Wrapper;
|
|
private readonly _coinbase: string;
|
|
private readonly _exchangeAddress: string;
|
|
private readonly _erc20ProxyAddress: string;
|
|
|
|
constructor(web3Wrapper: Web3Wrapper, coinbase: string, exchangeAddress: string, erc20ProxyAddress: string) {
|
|
this._web3Wrapper = web3Wrapper;
|
|
this._coinbase = coinbase;
|
|
this._exchangeAddress = exchangeAddress;
|
|
this._erc20ProxyAddress = erc20ProxyAddress;
|
|
}
|
|
public async createSignedSellOrderAsync(
|
|
auctionBeginTimeSections: BigNumber,
|
|
acutionEndTimeSeconds: BigNumber,
|
|
auctionBeginTakerAssetAmount: BigNumber,
|
|
auctionEndTakerAssetAmount: BigNumber,
|
|
makerAssetAmount: BigNumber,
|
|
makerAssetData: string,
|
|
takerAssetData: string,
|
|
makerAddress: string,
|
|
takerAddress: string,
|
|
senderAddress?: string,
|
|
makerFee?: BigNumber,
|
|
takerFee?: BigNumber,
|
|
feeRecipientAddress?: string,
|
|
): Promise<SignedOrder> {
|
|
// Notes on sell order:
|
|
// - The `takerAssetAmount` is set to the `auctionEndTakerAssetAmount`, which is the lowest amount the
|
|
// the seller can expect to receive
|
|
// - The `makerAssetData` is overloaded to include the auction begin time and begin taker asset amount
|
|
const makerAssetDataWithAuctionDetails = DutchAuctionWrapper.encodeDutchAuctionAssetData(
|
|
makerAssetData,
|
|
auctionBeginTimeSections,
|
|
auctionBeginTakerAssetAmount,
|
|
);
|
|
const signedOrder = await orderFactory.createSignedOrderAsync(
|
|
this._web3Wrapper.getProvider(),
|
|
makerAddress,
|
|
makerAssetAmount,
|
|
makerAssetDataWithAuctionDetails,
|
|
auctionEndTakerAssetAmount,
|
|
takerAssetData,
|
|
this._exchangeAddress,
|
|
{
|
|
takerAddress,
|
|
senderAddress,
|
|
makerFee,
|
|
takerFee,
|
|
feeRecipientAddress,
|
|
expirationTimeSeconds: acutionEndTimeSeconds,
|
|
},
|
|
);
|
|
const erc20AssetData = assetDataUtils.decodeERC20AssetData(makerAssetData);
|
|
await this._increaseERC20BalanceAndAllowanceAsync(erc20AssetData.tokenAddress, makerAddress, makerAssetAmount);
|
|
return signedOrder;
|
|
}
|
|
public async createSignedBuyOrderAsync(
|
|
sellOrder: SignedOrder,
|
|
buyerAddress: string,
|
|
senderAddress?: string,
|
|
makerFee?: BigNumber,
|
|
takerFee?: BigNumber,
|
|
feeRecipientAddress?: string,
|
|
expirationTimeSeconds?: BigNumber,
|
|
): Promise<SignedOrder> {
|
|
const dutchAuctionData = DutchAuctionWrapper.decodeDutchAuctionData(sellOrder.makerAssetData);
|
|
// Notes on buy order:
|
|
// - The `makerAssetAmount` is set to `dutchAuctionData.beginAmount`, which is
|
|
// the highest amount the buyer would have to pay out at any point during the auction.
|
|
// - The `takerAssetAmount` is set to the seller's `makerAssetAmount`, as the buyer
|
|
// receives the entire amount being sold by the seller.
|
|
// - The `makerAssetData`/`takerAssetData` are reversed from the sell order
|
|
const signedOrder = await orderFactory.createSignedOrderAsync(
|
|
this._web3Wrapper.getProvider(),
|
|
buyerAddress,
|
|
dutchAuctionData.beginAmount,
|
|
sellOrder.takerAssetData,
|
|
sellOrder.makerAssetAmount,
|
|
sellOrder.makerAssetData,
|
|
sellOrder.exchangeAddress,
|
|
{
|
|
senderAddress,
|
|
makerFee,
|
|
takerFee,
|
|
feeRecipientAddress,
|
|
expirationTimeSeconds,
|
|
},
|
|
);
|
|
const buyerERC20AssetData = assetDataUtils.decodeERC20AssetData(sellOrder.takerAssetData);
|
|
await this._increaseERC20BalanceAndAllowanceAsync(
|
|
buyerERC20AssetData.tokenAddress,
|
|
buyerAddress,
|
|
dutchAuctionData.beginAmount,
|
|
);
|
|
return signedOrder;
|
|
}
|
|
private async _increaseERC20BalanceAndAllowanceAsync(
|
|
tokenAddress: string,
|
|
address: string,
|
|
amount: BigNumber,
|
|
): Promise<void> {
|
|
if (amount.isZero() || address === constants.NULL_ADDRESS) {
|
|
return; // noop
|
|
}
|
|
await Promise.all([
|
|
this._increaseERC20BalanceAsync(tokenAddress, address, amount),
|
|
this._increaseERC20AllowanceAsync(tokenAddress, address, amount),
|
|
]);
|
|
}
|
|
private async _increaseERC20BalanceAsync(tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
|
const erc20Token = new DummyERC20TokenContract(
|
|
artifacts.DummyERC20Token.compilerOutput.abi,
|
|
tokenAddress,
|
|
this._web3Wrapper.getProvider(),
|
|
this._web3Wrapper.getContractDefaults(),
|
|
);
|
|
const txHash = await erc20Token.transfer.sendTransactionAsync(address, amount, {
|
|
from: this._coinbase,
|
|
});
|
|
await this._web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
|
|
}
|
|
private async _increaseERC20AllowanceAsync(
|
|
tokenAddress: string,
|
|
address: string,
|
|
amount: BigNumber,
|
|
): Promise<void> {
|
|
const erc20Token = new DummyERC20TokenContract(
|
|
artifacts.DummyERC20Token.compilerOutput.abi,
|
|
tokenAddress,
|
|
this._web3Wrapper.getProvider(),
|
|
this._web3Wrapper.getContractDefaults(),
|
|
);
|
|
const oldMakerAllowance = await erc20Token.allowance.callAsync(address, this._erc20ProxyAddress);
|
|
const newMakerAllowance = oldMakerAllowance.plus(amount);
|
|
const txHash = await erc20Token.approve.sendTransactionAsync(this._erc20ProxyAddress, newMakerAllowance, {
|
|
from: address,
|
|
});
|
|
await this._web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
|
|
}
|
|
}
|