diff options
author | Leonid Logvinov <logvinov.leon@gmail.com> | 2017-10-09 18:07:48 +0800 |
---|---|---|
committer | Leonid Logvinov <logvinov.leon@gmail.com> | 2017-10-09 18:07:48 +0800 |
commit | 1424a7302a1d1b3a9c36b3a6ce5a344f8045400d (patch) | |
tree | 5266fdd4b0f167fc1fa5131fc422f2196a4bf2ff /src/utils/order_validation_utils.ts | |
parent | 54ac354809c493cedfec5cd19b4707341b2c9f93 (diff) | |
download | dexon-sol-tools-1424a7302a1d1b3a9c36b3a6ce5a344f8045400d.tar dexon-sol-tools-1424a7302a1d1b3a9c36b3a6ce5a344f8045400d.tar.gz dexon-sol-tools-1424a7302a1d1b3a9c36b3a6ce5a344f8045400d.tar.bz2 dexon-sol-tools-1424a7302a1d1b3a9c36b3a6ce5a344f8045400d.tar.lz dexon-sol-tools-1424a7302a1d1b3a9c36b3a6ce5a344f8045400d.tar.xz dexon-sol-tools-1424a7302a1d1b3a9c36b3a6ce5a344f8045400d.tar.zst dexon-sol-tools-1424a7302a1d1b3a9c36b3a6ce5a344f8045400d.zip |
Implement transfer Emulator and rewrite tests
Diffstat (limited to 'src/utils/order_validation_utils.ts')
-rw-r--r-- | src/utils/order_validation_utils.ts | 153 |
1 files changed, 52 insertions, 101 deletions
diff --git a/src/utils/order_validation_utils.ts b/src/utils/order_validation_utils.ts index 0450d26a6..5d14602db 100644 --- a/src/utils/order_validation_utils.ts +++ b/src/utils/order_validation_utils.ts @@ -1,10 +1,11 @@ import * as _ from 'lodash'; -import {ExchangeContractErrs, SignedOrder, Order, ZeroExError} from '../types'; +import {ExchangeContractErrs, SignedOrder, Order, ZeroExError, TradeSide, TransferType} from '../types'; import {ZeroEx} from '../0x'; import {TokenWrapper} from '../contract_wrappers/token_wrapper'; import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper'; import {utils} from '../utils/utils'; import {constants} from '../utils/constants'; +import {ExchangeTransferSimulator} from './exchange_transfer_simulator'; export class OrderValidationUtils { private tokenWrapper: TokenWrapper; @@ -14,8 +15,8 @@ export class OrderValidationUtils { this.exchangeWrapper = exchangeWrapper; } public async validateOrderFillableOrThrowAsync( - signedOrder: SignedOrder, zrxTokenAddress: string, expectedFillTakerTokenAmount?: BigNumber.BigNumber, - ): Promise<void> { + exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder, zrxTokenAddress: string, + expectedFillTakerTokenAmount?: BigNumber.BigNumber): Promise<void> { const orderHash = utils.getOrderHashHex(signedOrder); const unavailableTakerTokenAmount = await this.exchangeWrapper.getUnavailableTakerAmountAsync(orderHash); this.validateRemainingFillAmountNotZeroOrThrow( @@ -26,14 +27,20 @@ export class OrderValidationUtils { if (!_.isUndefined(expectedFillTakerTokenAmount)) { fillTakerTokenAmount = expectedFillTakerTokenAmount; } - await this.validateFillOrderMakerBalancesAllowancesThrowIfInvalidAsync( - signedOrder, fillTakerTokenAmount, zrxTokenAddress, + const fillMakerTokenAmount = this.getFillMakerTokenAmount(signedOrder, fillTakerTokenAmount); + await exchangeTradeEmulator.transferFromAsync( + signedOrder.makerTokenAddress, signedOrder.maker, signedOrder.taker, fillMakerTokenAmount, + TradeSide.Maker, TransferType.Trade, + ); + await exchangeTradeEmulator.transferFromAsync( + zrxTokenAddress, signedOrder.maker, signedOrder.feeRecipient, signedOrder.makerFee, + TradeSide.Maker, TransferType.Fee, ); } - public async validateFillOrderThrowIfInvalidAsync(signedOrder: SignedOrder, - fillTakerTokenAmount: BigNumber.BigNumber, - takerAddress: string, - zrxTokenAddress: string): Promise<void> { + public async validateFillOrderThrowIfInvalidAsync( + exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder, + fillTakerTokenAmount: BigNumber.BigNumber, takerAddress: string, + zrxTokenAddress: string): Promise<BigNumber.BigNumber> { if (fillTakerTokenAmount.eq(0)) { throw new Error(ExchangeContractErrs.OrderFillAmountZero); } @@ -49,29 +56,29 @@ export class OrderValidationUtils { throw new Error(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker); } this.validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec); + const remainingTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount); + const filledTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount) ? + remainingTakerTokenAmount : + fillTakerTokenAmount; await this.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( - signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress, + exchangeTradeEmulator, signedOrder, filledTakerTokenAmount, takerAddress, zrxTokenAddress, ); const wouldRoundingErrorOccur = await this.exchangeWrapper.isRoundingErrorAsync( - fillTakerTokenAmount, signedOrder.takerTokenAmount, signedOrder.makerTokenAmount, + filledTakerTokenAmount, signedOrder.takerTokenAmount, signedOrder.makerTokenAmount, ); if (wouldRoundingErrorOccur) { throw new Error(ExchangeContractErrs.OrderFillRoundingError); } + return filledTakerTokenAmount; } - public async validateFillOrKillOrderThrowIfInvalidAsync(signedOrder: SignedOrder, - fillTakerTokenAmount: BigNumber.BigNumber, - takerAddress: string, - zrxTokenAddress: string): Promise<void> { - await this.validateFillOrderThrowIfInvalidAsync( - signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress, + public async validateFillOrKillOrderThrowIfInvalidAsync( + exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder, + fillTakerTokenAmount: BigNumber.BigNumber, takerAddress: string, zrxTokenAddress: string): Promise<void> { + const filledTakerTokenAmount = await this.validateFillOrderThrowIfInvalidAsync( + exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress, ); - // Check that fillValue available >= fillTakerAmount - const orderHashHex = utils.getOrderHashHex(signedOrder); - const unavailableTakerAmount = await this.exchangeWrapper.getUnavailableTakerAmountAsync(orderHashHex); - const remainingTakerAmount = signedOrder.takerTokenAmount.minus(unavailableTakerAmount); - if (remainingTakerAmount < fillTakerTokenAmount) { + if (filledTakerTokenAmount !== fillTakerTokenAmount) { throw new Error(ExchangeContractErrs.InsufficientRemainingFillAmount); } } @@ -91,87 +98,25 @@ export class OrderValidationUtils { } } public async validateFillOrderBalancesAllowancesThrowIfInvalidAsync( - signedOrder: SignedOrder, fillTakerAmount: BigNumber.BigNumber, senderAddress: string, zrxTokenAddress: string, - ): Promise<void> { - await this.validateFillOrderMakerBalancesAllowancesThrowIfInvalidAsync( - signedOrder, fillTakerAmount, zrxTokenAddress, + exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder, + fillTakerTokenAmount: BigNumber.BigNumber, senderAddress: string, zrxTokenAddress: string): Promise<void> { + const fillMakerTokenAmount = this.getFillMakerTokenAmount(signedOrder, fillTakerTokenAmount); + await exchangeTradeEmulator.transferFromAsync( + signedOrder.makerTokenAddress, signedOrder.maker, signedOrder.taker, fillMakerTokenAmount, + TradeSide.Maker, TransferType.Trade, ); - await this.validateFillOrderTakerBalancesAllowancesThrowIfInvalidAsync( - signedOrder, fillTakerAmount, senderAddress, zrxTokenAddress, + await exchangeTradeEmulator.transferFromAsync( + signedOrder.takerTokenAddress, signedOrder.taker, signedOrder.maker, fillTakerTokenAmount, + TradeSide.Taker, TransferType.Trade, + ); + await exchangeTradeEmulator.transferFromAsync( + zrxTokenAddress, signedOrder.maker, signedOrder.feeRecipient, signedOrder.makerFee, TradeSide.Maker, + TransferType.Fee, + ); + await exchangeTradeEmulator.transferFromAsync( + zrxTokenAddress, signedOrder.taker, signedOrder.feeRecipient, signedOrder.takerFee, TradeSide.Taker, + TransferType.Fee, ); - } - private async validateFillOrderMakerBalancesAllowancesThrowIfInvalidAsync( - signedOrder: SignedOrder, fillTakerAmount: BigNumber.BigNumber, zrxTokenAddress: string, - ): Promise<void> { - const makerBalance = await this.tokenWrapper.getBalanceAsync(signedOrder.makerTokenAddress, signedOrder.maker); - const makerAllowance = await this.tokenWrapper.getProxyAllowanceAsync( - signedOrder.makerTokenAddress, signedOrder.maker); - - const isMakerTokenZRX = signedOrder.makerTokenAddress === zrxTokenAddress; - // exchangeRate is the price of one maker token denominated in taker tokens - const exchangeRate = signedOrder.takerTokenAmount.div(signedOrder.makerTokenAmount); - const fillMakerAmount = fillTakerAmount.div(exchangeRate); - - const requiredMakerAmount = isMakerTokenZRX ? fillMakerAmount.plus(signedOrder.makerFee) : fillMakerAmount; - if (requiredMakerAmount.greaterThan(makerBalance)) { - throw new Error(ExchangeContractErrs.InsufficientMakerBalance); - } - if (requiredMakerAmount.greaterThan(makerAllowance)) { - throw new Error(ExchangeContractErrs.InsufficientMakerAllowance); - } - - if (!isMakerTokenZRX) { - let makerZRXBalance = await this.tokenWrapper.getBalanceAsync(zrxTokenAddress, signedOrder.maker); - const isTakerTokenZRX = signedOrder.takerTokenAddress === zrxTokenAddress; - if (isTakerTokenZRX) { - makerZRXBalance = makerZRXBalance.plus(fillTakerAmount); - } - const makerZRXAllowance = await this.tokenWrapper.getProxyAllowanceAsync( - zrxTokenAddress, signedOrder.maker); - - if (signedOrder.makerFee.greaterThan(makerZRXBalance)) { - throw new Error(ExchangeContractErrs.InsufficientMakerFeeBalance); - } - if (signedOrder.makerFee.greaterThan(makerZRXAllowance)) { - throw new Error(ExchangeContractErrs.InsufficientMakerFeeAllowance); - } - } - } - private async validateFillOrderTakerBalancesAllowancesThrowIfInvalidAsync( - signedOrder: SignedOrder, fillTakerAmount: BigNumber.BigNumber, senderAddress: string, zrxTokenAddress: string, - ): Promise<void> { - const takerBalance = await this.tokenWrapper.getBalanceAsync(signedOrder.takerTokenAddress, senderAddress); - const takerAllowance = await this.tokenWrapper.getProxyAllowanceAsync( - signedOrder.takerTokenAddress, senderAddress); - - const isTakerTokenZRX = signedOrder.takerTokenAddress === zrxTokenAddress; - // exchangeRate is the price of one maker token denominated in taker tokens - const exchangeRate = signedOrder.takerTokenAmount.div(signedOrder.makerTokenAmount); - const fillMakerAmount = fillTakerAmount.div(exchangeRate); - - const requiredTakerAmount = isTakerTokenZRX ? fillTakerAmount.plus(signedOrder.takerFee) : fillTakerAmount; - if (requiredTakerAmount.greaterThan(takerBalance)) { - throw new Error(ExchangeContractErrs.InsufficientTakerBalance); - } - if (requiredTakerAmount.greaterThan(takerAllowance)) { - throw new Error(ExchangeContractErrs.InsufficientTakerAllowance); - } - - if (!isTakerTokenZRX) { - const isMakerTokenZRX = signedOrder.makerTokenAddress === zrxTokenAddress; - let takerZRXBalance = await this.tokenWrapper.getBalanceAsync(zrxTokenAddress, senderAddress); - if (isMakerTokenZRX) { - takerZRXBalance = takerZRXBalance.plus(fillMakerAmount); - } - const takerZRXAllowance = await this.tokenWrapper.getProxyAllowanceAsync(zrxTokenAddress, senderAddress); - - if (signedOrder.takerFee.greaterThan(takerZRXBalance)) { - throw new Error(ExchangeContractErrs.InsufficientTakerFeeBalance); - } - if (signedOrder.takerFee.greaterThan(takerZRXAllowance)) { - throw new Error(ExchangeContractErrs.InsufficientTakerFeeAllowance); - } - } } private validateRemainingFillAmountNotZeroOrThrow( takerTokenAmount: BigNumber.BigNumber, unavailableTakerTokenAmount: BigNumber.BigNumber, @@ -186,4 +131,10 @@ export class OrderValidationUtils { throw new Error(ExchangeContractErrs.OrderFillExpired); } } + private getFillMakerTokenAmount(signedOrder: Order, + fillTakerTokenAmount: BigNumber.BigNumber): BigNumber.BigNumber { + const exchangeRate = signedOrder.takerTokenAmount.div(signedOrder.makerTokenAmount); + const fillMakerTokenAmount = fillTakerTokenAmount.div(exchangeRate); + return fillMakerTokenAmount; + } } |