diff options
Diffstat (limited to 'packages/contracts/test/utils')
-rw-r--r-- | packages/contracts/test/utils/artifacts.ts | 10 | ||||
-rw-r--r-- | packages/contracts/test/utils/constants.ts | 2 | ||||
-rw-r--r-- | packages/contracts/test/utils/forwarder_wrapper.ts | 226 |
3 files changed, 70 insertions, 168 deletions
diff --git a/packages/contracts/test/utils/artifacts.ts b/packages/contracts/test/utils/artifacts.ts index d3f808218..63bd555a4 100644 --- a/packages/contracts/test/utils/artifacts.ts +++ b/packages/contracts/test/utils/artifacts.ts @@ -15,12 +15,13 @@ import * as MultiSigWallet from '../../artifacts/MultiSigWallet.json'; import * as MultiSigWalletWithTimeLock from '../../artifacts/MultiSigWalletWithTimeLock.json'; import * as TestAssetProxyDispatcher from '../../artifacts/TestAssetProxyDispatcher.json'; import * as TestAssetProxyOwner from '../../artifacts/TestAssetProxyOwner.json'; +import * as TestConstants from '../../artifacts/TestConstants.json'; import * as TestLibBytes from '../../artifacts/TestLibBytes.json'; import * as TestLibs from '../../artifacts/TestLibs.json'; import * as TestSignatureValidator from '../../artifacts/TestSignatureValidator.json'; -import * as TestValidator from '../../artifacts/TestValidator.json'; -import * as TestWallet from '../../artifacts/TestWallet.json'; import * as TokenRegistry from '../../artifacts/TokenRegistry.json'; +import * as Validator from '../../artifacts/Validator.json'; +import * as Wallet from '../../artifacts/Wallet.json'; import * as EtherToken from '../../artifacts/WETH9.json'; import * as Whitelist from '../../artifacts/Whitelist.json'; import * as ZRX from '../../artifacts/ZRXToken.json'; @@ -42,11 +43,12 @@ export const artifacts = { MultiSigWalletWithTimeLock: (MultiSigWalletWithTimeLock as any) as ContractArtifact, TestAssetProxyOwner: (TestAssetProxyOwner as any) as ContractArtifact, TestAssetProxyDispatcher: (TestAssetProxyDispatcher as any) as ContractArtifact, + TestConstants: (TestConstants as any) as ContractArtifact, TestLibBytes: (TestLibBytes as any) as ContractArtifact, TestLibs: (TestLibs as any) as ContractArtifact, TestSignatureValidator: (TestSignatureValidator as any) as ContractArtifact, - TestValidator: (TestValidator as any) as ContractArtifact, - TestWallet: (TestWallet as any) as ContractArtifact, + Validator: (Validator as any) as ContractArtifact, + Wallet: (Wallet as any) as ContractArtifact, TokenRegistry: (TokenRegistry as any) as ContractArtifact, Whitelist: (Whitelist as any) as ContractArtifact, ZRX: (ZRX as any) as ContractArtifact, diff --git a/packages/contracts/test/utils/constants.ts b/packages/contracts/test/utils/constants.ts index 7dac38f56..65eaee398 100644 --- a/packages/contracts/test/utils/constants.ts +++ b/packages/contracts/test/utils/constants.ts @@ -49,4 +49,6 @@ export const constants = { takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), }, WORD_LENGTH: 32, + ZERO_AMOUNT: new BigNumber(0), + PERCENTAGE_DENOMINATOR: new BigNumber(10).pow(18), }; 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; } } |