aboutsummaryrefslogtreecommitdiffstats
path: root/packages/contracts/test/utils/forwarder_wrapper.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/contracts/test/utils/forwarder_wrapper.ts')
-rw-r--r--packages/contracts/test/utils/forwarder_wrapper.ts226
1 files changed, 62 insertions, 164 deletions
diff --git a/packages/contracts/test/utils/forwarder_wrapper.ts b/packages/contracts/test/utils/forwarder_wrapper.ts
index e39df14b1..ef7476e36 100644
--- a/packages/contracts/test/utils/forwarder_wrapper.ts
+++ b/packages/contracts/test/utils/forwarder_wrapper.ts
@@ -1,5 +1,4 @@
-import { assetDataUtils } from '@0xproject/order-utils';
-import { AssetProxyId, SignedOrder } from '@0xproject/types';
+import { SignedOrder } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
import { Provider, TransactionReceiptWithDecodedLogs, TxDataPayable } from 'ethereum-types';
@@ -12,209 +11,108 @@ import { formatters } from './formatters';
import { LogDecoder } from './log_decoder';
import { MarketSellOrders } from './types';
-const DEFAULT_FEE_PROPORTION = 0;
-const PERCENTAGE_DENOMINATOR = 10000;
-const ZERO_AMOUNT = new BigNumber(0);
-const INSUFFICENT_ORDERS_FOR_MAKER_AMOUNT = 'Unable to satisfy makerAssetFillAmount with provided orders';
-
export class ForwarderWrapper {
private readonly _web3Wrapper: Web3Wrapper;
private readonly _forwarderContract: ForwarderContract;
private readonly _logDecoder: LogDecoder;
- private readonly _zrxAddress: string;
- private static _createOptimizedSellOrders(signedOrders: SignedOrder[]): MarketSellOrders {
- const marketSellOrders = formatters.createMarketSellOrders(signedOrders, ZERO_AMOUNT);
- const assetDataId = assetDataUtils.decodeAssetProxyId(signedOrders[0].makerAssetData);
- // Contract will fill this in for us as all of the assetData is assumed to be the same
- for (let i = 0; i < signedOrders.length; i++) {
- if (i !== 0 && assetDataId === AssetProxyId.ERC20) {
- // Forwarding contract will fill this in from the first order
- marketSellOrders.orders[i].makerAssetData = constants.NULL_BYTES;
+ public static getPercentageOfValue(value: BigNumber, percentage: number): BigNumber {
+ const numerator = constants.PERCENTAGE_DENOMINATOR.times(percentage).dividedToIntegerBy(100);
+ const newValue = value.times(numerator).dividedToIntegerBy(constants.PERCENTAGE_DENOMINATOR);
+ return newValue;
+ }
+ public static getWethForFeeOrders(feeAmount: BigNumber, feeOrders: SignedOrder[]): BigNumber {
+ let wethAmount = new BigNumber(0);
+ let remainingFeeAmount = feeAmount;
+ _.forEach(feeOrders, feeOrder => {
+ const feeAvailable = feeOrder.makerAssetAmount.minus(feeOrder.takerFee);
+ if (!remainingFeeAmount.isZero() && feeAvailable.gt(remainingFeeAmount)) {
+ wethAmount = wethAmount
+ .plus(feeOrder.takerAssetAmount.times(remainingFeeAmount).dividedToIntegerBy(feeAvailable))
+ .plus(1);
+ remainingFeeAmount = new BigNumber(0);
+ } else if (!remainingFeeAmount.isZero()) {
+ wethAmount = wethAmount.plus(feeOrder.takerAssetAmount);
+ remainingFeeAmount = remainingFeeAmount.minus(feeAvailable);
}
- marketSellOrders.orders[i].takerAssetData = constants.NULL_BYTES;
- }
- return marketSellOrders;
+ });
+ return wethAmount;
}
- private static _createOptimizedZRXSellOrders(signedOrders: SignedOrder[]): MarketSellOrders {
- const marketSellOrders = formatters.createMarketSellOrders(signedOrders, ZERO_AMOUNT);
- // Contract will fill this in for us as all of the assetData is assumed to be the same
- for (let i = 0; i < signedOrders.length; i++) {
- marketSellOrders.orders[i].makerAssetData = constants.NULL_BYTES;
- marketSellOrders.orders[i].takerAssetData = constants.NULL_BYTES;
- }
- return marketSellOrders;
+ private static _createOptimizedOrders(signedOrders: SignedOrder[]): MarketSellOrders {
+ _.forEach(signedOrders, (signedOrder, index) => {
+ signedOrder.takerAssetData = constants.NULL_BYTES;
+ if (index > 0) {
+ signedOrder.makerAssetData = constants.NULL_BYTES;
+ }
+ });
+ const params = formatters.createMarketSellOrders(signedOrders, constants.ZERO_AMOUNT);
+ return params;
}
- private static _calculateAdditionalFeeProportionAmount(feeProportion: number, fillAmountWei: BigNumber): BigNumber {
- if (feeProportion > 0) {
- // Add to the total ETH transaction to ensure all NFTs can be filled after fees
- // 150 = 1.5% = 0.015
- const denominator = new BigNumber(1).minus(new BigNumber(feeProportion).dividedBy(PERCENTAGE_DENOMINATOR));
- return fillAmountWei.dividedBy(denominator).round(0, BigNumber.ROUND_FLOOR);
- }
- return fillAmountWei;
+ private static _createOptimizedZrxOrders(signedOrders: SignedOrder[]): MarketSellOrders {
+ _.forEach(signedOrders, signedOrder => {
+ signedOrder.makerAssetData = constants.NULL_BYTES;
+ signedOrder.takerAssetData = constants.NULL_BYTES;
+ });
+ const params = formatters.createMarketSellOrders(signedOrders, constants.ZERO_AMOUNT);
+ return params;
}
- constructor(contractInstance: ForwarderContract, provider: Provider, zrxAddress: string) {
+ constructor(contractInstance: ForwarderContract, provider: Provider) {
this._forwarderContract = contractInstance;
this._web3Wrapper = new Web3Wrapper(provider);
this._logDecoder = new LogDecoder(this._web3Wrapper, this._forwarderContract.address);
- // this._web3Wrapper.abiDecoder.addABI(contractInstance.abi);
- this._zrxAddress = zrxAddress;
}
- public async marketBuyTokensWithEthAsync(
+ public async marketSellOrdersWithEthAsync(
orders: SignedOrder[],
feeOrders: SignedOrder[],
- makerTokenBuyAmount: BigNumber,
txData: TxDataPayable,
- opts: { feeProportion?: number; feeRecipient?: string } = {},
+ opts: { feePercentage?: BigNumber; feeRecipient?: string } = {},
): Promise<TransactionReceiptWithDecodedLogs> {
- const params = ForwarderWrapper._createOptimizedSellOrders(orders);
- const feeParams = ForwarderWrapper._createOptimizedZRXSellOrders(feeOrders);
- const feeProportion = _.isUndefined(opts.feeProportion) ? DEFAULT_FEE_PROPORTION : opts.feeProportion;
+ const params = ForwarderWrapper._createOptimizedOrders(orders);
+ const feeParams = ForwarderWrapper._createOptimizedZrxOrders(feeOrders);
+ const feePercentage = _.isUndefined(opts.feePercentage) ? constants.ZERO_AMOUNT : opts.feePercentage;
const feeRecipient = _.isUndefined(opts.feeRecipient) ? constants.NULL_ADDRESS : opts.feeRecipient;
- const txHash: string = await this._forwarderContract.marketBuyTokensWithEth.sendTransactionAsync(
+ const txHash = await this._forwarderContract.marketSellOrdersWithEth.sendTransactionAsync(
params.orders,
params.signatures,
feeParams.orders,
feeParams.signatures,
- makerTokenBuyAmount,
- feeProportion,
+ feePercentage,
feeRecipient,
txData,
);
const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
return tx;
}
- public async marketSellEthForERC20Async(
+ public async marketBuyOrdersWithEthAsync(
orders: SignedOrder[],
feeOrders: SignedOrder[],
+ makerAssetFillAmount: BigNumber,
txData: TxDataPayable,
- opts: { feeProportion?: number; feeRecipient?: string } = {},
+ opts: { feePercentage?: BigNumber; feeRecipient?: string } = {},
): Promise<TransactionReceiptWithDecodedLogs> {
- const assetDataId = assetDataUtils.decodeAssetProxyId(orders[0].makerAssetData);
- if (assetDataId !== AssetProxyId.ERC20) {
- throw new Error('Asset type not supported by marketSellEthForERC20');
- }
- const params = ForwarderWrapper._createOptimizedSellOrders(orders);
- const feeParams = ForwarderWrapper._createOptimizedZRXSellOrders(feeOrders);
- const feeProportion = _.isUndefined(opts.feeProportion) ? DEFAULT_FEE_PROPORTION : opts.feeProportion;
+ const params = ForwarderWrapper._createOptimizedOrders(orders);
+ const feeParams = ForwarderWrapper._createOptimizedZrxOrders(feeOrders);
+ const feePercentage = _.isUndefined(opts.feePercentage) ? constants.ZERO_AMOUNT : opts.feePercentage;
const feeRecipient = _.isUndefined(opts.feeRecipient) ? constants.NULL_ADDRESS : opts.feeRecipient;
- const txHash: string = await this._forwarderContract.marketSellEthForERC20.sendTransactionAsync(
+ const txHash = await this._forwarderContract.marketBuyOrdersWithEth.sendTransactionAsync(
params.orders,
+ makerAssetFillAmount,
params.signatures,
feeParams.orders,
feeParams.signatures,
- feeProportion,
+ feePercentage,
feeRecipient,
txData,
);
const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
return tx;
}
- public async calculateMarketBuyFillAmountWeiAsync(
- orders: SignedOrder[],
- feeOrders: SignedOrder[],
- feeProportion: number,
- makerAssetFillAmount: BigNumber,
- ): Promise<BigNumber> {
- const assetProxyId = assetDataUtils.decodeAssetProxyId(orders[0].makerAssetData);
- switch (assetProxyId) {
- case AssetProxyId.ERC20: {
- const fillAmountWei = this._calculateMarketBuyERC20FillAmountAsync(
- orders,
- feeOrders,
- feeProportion,
- makerAssetFillAmount,
- );
- return fillAmountWei;
- }
- case AssetProxyId.ERC721: {
- const fillAmountWei = await this._calculateMarketBuyERC721FillAmountAsync(
- orders,
- feeOrders,
- feeProportion,
- );
- return fillAmountWei;
- }
- default:
- throw new Error(`Invalid Asset Proxy Id: ${assetProxyId}`);
- }
- }
- private async _calculateMarketBuyERC20FillAmountAsync(
- orders: SignedOrder[],
- feeOrders: SignedOrder[],
- feeProportion: number,
- makerAssetFillAmount: BigNumber,
- ): Promise<BigNumber> {
- const makerAssetData = assetDataUtils.decodeAssetDataOrThrow(orders[0].makerAssetData);
- const makerAssetToken = makerAssetData.tokenAddress;
- const params = formatters.createMarketBuyOrders(orders, makerAssetFillAmount);
-
- let fillAmountWei;
- if (makerAssetToken === this._zrxAddress) {
- // If buying ZRX we buy the tokens and fees from the ZRX order in one step
- const expectedBuyFeeTokensFillResults = await this._forwarderContract.calculateMarketBuyZrxResults.callAsync(
- params.orders,
- makerAssetFillAmount,
- );
- if (expectedBuyFeeTokensFillResults.makerAssetFilledAmount.lessThan(makerAssetFillAmount)) {
- throw new Error(INSUFFICENT_ORDERS_FOR_MAKER_AMOUNT);
- }
- fillAmountWei = expectedBuyFeeTokensFillResults.takerAssetFilledAmount;
- } else {
- const expectedMarketBuyFillResults = await this._forwarderContract.calculateMarketBuyResults.callAsync(
- params.orders,
- makerAssetFillAmount,
- );
- if (expectedMarketBuyFillResults.makerAssetFilledAmount.lessThan(makerAssetFillAmount)) {
- throw new Error(INSUFFICENT_ORDERS_FOR_MAKER_AMOUNT);
- }
- fillAmountWei = expectedMarketBuyFillResults.takerAssetFilledAmount;
- const expectedFeeAmount = expectedMarketBuyFillResults.takerFeePaid;
- if (expectedFeeAmount.greaterThan(ZERO_AMOUNT)) {
- const expectedFeeFillFillAmountWei = await this._calculateMarketBuyERC20FillAmountAsync(
- feeOrders,
- [],
- DEFAULT_FEE_PROPORTION,
- expectedFeeAmount,
- );
- fillAmountWei = fillAmountWei.plus(expectedFeeFillFillAmountWei);
- }
- }
- fillAmountWei = ForwarderWrapper._calculateAdditionalFeeProportionAmount(feeProportion, fillAmountWei);
- return fillAmountWei;
- }
- private async _calculateMarketBuyERC721FillAmountAsync(
- orders: SignedOrder[],
- feeOrders: SignedOrder[],
- feeProportion: number,
- ): Promise<BigNumber> {
- // Total cost when buying ERC721 is the total cost of all ERC721 orders + any fee abstraction
- let fillAmountWei = _.reduce(
- orders,
- (totalAmount: BigNumber, order: SignedOrder) => {
- return totalAmount.plus(order.takerAssetAmount);
- },
- ZERO_AMOUNT,
- );
- const totalFees = _.reduce(
- orders,
- (totalAmount: BigNumber, order: SignedOrder) => {
- return totalAmount.plus(order.takerFee);
- },
- ZERO_AMOUNT,
- );
- if (totalFees.greaterThan(ZERO_AMOUNT)) {
- // Calculate the ZRX fee abstraction cost
- const emptyFeeOrders: SignedOrder[] = [];
- const expectedFeeAmountWei = await this._calculateMarketBuyERC20FillAmountAsync(
- feeOrders,
- emptyFeeOrders,
- DEFAULT_FEE_PROPORTION,
- totalFees,
- );
- fillAmountWei = fillAmountWei.plus(expectedFeeAmountWei);
- }
- fillAmountWei = ForwarderWrapper._calculateAdditionalFeeProportionAmount(feeProportion, fillAmountWei);
- return fillAmountWei;
+ public async withdrawERC20Async(
+ tokenAddress: string,
+ amount: BigNumber,
+ txData: TxDataPayable,
+ ): Promise<TransactionReceiptWithDecodedLogs> {
+ const txHash = await this._forwarderContract.withdrawERC20.sendTransactionAsync(tokenAddress, amount, txData);
+ const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
+ return tx;
}
}