diff options
Diffstat (limited to 'packages/order-utils/src/order_state_utils.ts')
-rw-r--r-- | packages/order-utils/src/order_state_utils.ts | 346 |
1 files changed, 0 insertions, 346 deletions
diff --git a/packages/order-utils/src/order_state_utils.ts b/packages/order-utils/src/order_state_utils.ts deleted file mode 100644 index 430178b5d..000000000 --- a/packages/order-utils/src/order_state_utils.ts +++ /dev/null @@ -1,346 +0,0 @@ -import { - ExchangeContractErrs, - ObjectMap, - OrderRelevantState, - OrderState, - OrderStateInvalid, - OrderStateValid, - SignedOrder, -} from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -import { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher'; -import { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_filled_cancelled_fetcher'; -import { assetDataUtils } from './asset_data_utils'; -import { orderHashUtils } from './order_hash'; -import { OrderValidationUtils } from './order_validation_utils'; -import { RemainingFillableCalculator } from './remaining_fillable_calculator'; -import { utils } from './utils'; - -interface SidedOrderRelevantState { - isMakerSide: boolean; - traderBalance: BigNumber; - traderIndividualBalances: ObjectMap<BigNumber>; - traderProxyAllowance: BigNumber; - traderIndividualProxyAllowances: ObjectMap<BigNumber>; - traderFeeBalance: BigNumber; - traderFeeProxyAllowance: BigNumber; - filledTakerAssetAmount: BigNumber; - remainingFillableAssetAmount: BigNumber; - isOrderCancelled: boolean; -} -interface OrderValidResult { - isValid: true; -} -interface OrderInvalidResult { - isValid: false; - error: ExchangeContractErrs; -} -type OrderValidationResult = OrderValidResult | OrderInvalidResult; - -export class OrderStateUtils { - private readonly _balanceAndProxyAllowanceFetcher: AbstractBalanceAndProxyAllowanceFetcher; - private readonly _orderFilledCancelledFetcher: AbstractOrderFilledCancelledFetcher; - private static _validateIfOrderIsValid( - signedOrder: SignedOrder, - sidedOrderRelevantState: SidedOrderRelevantState, - ): OrderValidationResult { - const isMakerSide = sidedOrderRelevantState.isMakerSide; - if (sidedOrderRelevantState.isOrderCancelled) { - return { isValid: false, error: ExchangeContractErrs.OrderCancelled }; - } - const availableTakerAssetAmount = signedOrder.takerAssetAmount.minus( - sidedOrderRelevantState.filledTakerAssetAmount, - ); - if (availableTakerAssetAmount.eq(0)) { - return { isValid: false, error: ExchangeContractErrs.OrderRemainingFillAmountZero }; - } - - if (sidedOrderRelevantState.traderBalance.eq(0)) { - const error = isMakerSide - ? ExchangeContractErrs.InsufficientMakerBalance - : ExchangeContractErrs.InsufficientTakerBalance; - return { isValid: false, error }; - } - if (sidedOrderRelevantState.traderProxyAllowance.eq(0)) { - const error = isMakerSide - ? ExchangeContractErrs.InsufficientMakerAllowance - : ExchangeContractErrs.InsufficientTakerAllowance; - return { isValid: false, error }; - } - if (!signedOrder.makerFee.eq(0)) { - if (sidedOrderRelevantState.traderFeeBalance.eq(0)) { - const error = isMakerSide - ? ExchangeContractErrs.InsufficientMakerFeeBalance - : ExchangeContractErrs.InsufficientTakerFeeBalance; - return { isValid: false, error }; - } - if (sidedOrderRelevantState.traderFeeProxyAllowance.eq(0)) { - const error = isMakerSide - ? ExchangeContractErrs.InsufficientMakerFeeAllowance - : ExchangeContractErrs.InsufficientTakerFeeAllowance; - return { isValid: false, error }; - } - } - const remainingTakerAssetAmount = signedOrder.takerAssetAmount.minus( - sidedOrderRelevantState.filledTakerAssetAmount, - ); - const isRoundingError = OrderValidationUtils.isRoundingErrorFloor( - remainingTakerAssetAmount, - signedOrder.takerAssetAmount, - signedOrder.makerAssetAmount, - ); - if (isRoundingError) { - return { isValid: false, error: ExchangeContractErrs.OrderFillRoundingError }; - } - return { isValid: true }; - } - /** - * Instantiate OrderStateUtils - * @param balanceAndProxyAllowanceFetcher A class that is capable of fetching balances - * and proxyAllowances for Ethereum addresses. It must implement AbstractBalanceAndProxyAllowanceFetcher - * @param orderFilledCancelledFetcher A class that is capable of fetching whether an order - * is cancelled and how much of it has been filled. It must implement AbstractOrderFilledCancelledFetcher - * @return Instance of OrderStateUtils - */ - constructor( - balanceAndProxyAllowanceFetcher: AbstractBalanceAndProxyAllowanceFetcher, - orderFilledCancelledFetcher: AbstractOrderFilledCancelledFetcher, - ) { - this._balanceAndProxyAllowanceFetcher = balanceAndProxyAllowanceFetcher; - this._orderFilledCancelledFetcher = orderFilledCancelledFetcher; - } - /** - * Get the orderState for an "open" order (i.e where takerAddress=NULL_ADDRESS) - * This method will only check the maker's balance/allowance to calculate the - * OrderState. - * @param signedOrder The order of interest - * @return State relevant to the signedOrder, as well as whether the signedOrder is "valid". - * Validity is defined as a non-zero amount of the order can still be filled. - */ - public async getOpenOrderStateAsync(signedOrder: SignedOrder, transactionHash?: string): Promise<OrderState> { - const orderRelevantState = await this.getOpenOrderRelevantStateAsync(signedOrder); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - const isOrderCancelled = await this._orderFilledCancelledFetcher.isOrderCancelledAsync(signedOrder); - const sidedOrderRelevantState = { - isMakerSide: true, - traderBalance: orderRelevantState.makerBalance, - traderIndividualBalances: orderRelevantState.makerIndividualBalances, - traderProxyAllowance: orderRelevantState.makerProxyAllowance, - traderIndividualProxyAllowances: orderRelevantState.makerIndividualProxyAllowances, - traderFeeBalance: orderRelevantState.makerFeeBalance, - traderFeeProxyAllowance: orderRelevantState.makerFeeProxyAllowance, - filledTakerAssetAmount: orderRelevantState.filledTakerAssetAmount, - remainingFillableAssetAmount: orderRelevantState.remainingFillableMakerAssetAmount, - isOrderCancelled, - }; - const orderValidationResult = OrderStateUtils._validateIfOrderIsValid(signedOrder, sidedOrderRelevantState); - if (orderValidationResult.isValid) { - const orderState: OrderStateValid = { - isValid: true, - orderHash, - orderRelevantState, - transactionHash, - }; - return orderState; - } else { - const orderState: OrderStateInvalid = { - isValid: false, - orderHash, - error: orderValidationResult.error, - transactionHash, - }; - return orderState; - } - } - /** - * Get state relevant to an order (i.e makerBalance, makerAllowance, filledTakerAssetAmount, etc... - * @param signedOrder Order of interest - * @return An instance of OrderRelevantState - */ - public async getOpenOrderRelevantStateAsync(signedOrder: SignedOrder): Promise<OrderRelevantState> { - const isMaker = true; - const sidedOrderRelevantState = await this._getSidedOrderRelevantStateAsync( - isMaker, - signedOrder, - signedOrder.takerAddress, - ); - const remainingFillableTakerAssetAmount = sidedOrderRelevantState.remainingFillableAssetAmount - .times(signedOrder.takerAssetAmount) - .dividedToIntegerBy(signedOrder.makerAssetAmount); - - const orderRelevantState = { - makerBalance: sidedOrderRelevantState.traderBalance, - makerIndividualBalances: sidedOrderRelevantState.traderIndividualBalances, - makerProxyAllowance: sidedOrderRelevantState.traderProxyAllowance, - makerIndividualProxyAllowances: sidedOrderRelevantState.traderIndividualProxyAllowances, - makerFeeBalance: sidedOrderRelevantState.traderFeeBalance, - makerFeeProxyAllowance: sidedOrderRelevantState.traderFeeProxyAllowance, - filledTakerAssetAmount: sidedOrderRelevantState.filledTakerAssetAmount, - remainingFillableMakerAssetAmount: sidedOrderRelevantState.remainingFillableAssetAmount, - remainingFillableTakerAssetAmount, - }; - return orderRelevantState; - } - /** - * Get the max amount of the supplied order's takerAmount that could still be filled - * @param signedOrder Order of interest - * @param takerAddress Hypothetical taker of the order - * @return fillableTakerAssetAmount - */ - public async getMaxFillableTakerAssetAmountAsync( - signedOrder: SignedOrder, - takerAddress: string, - ): Promise<BigNumber> { - // Get max fillable amount for an order, considering the makers ability to fill - let isMaker = true; - const orderRelevantMakerState = await this._getSidedOrderRelevantStateAsync( - isMaker, - signedOrder, - signedOrder.takerAddress, - ); - const remainingFillableTakerAssetAmountGivenMakersStatus = signedOrder.makerAssetAmount.eq(0) - ? new BigNumber(0) - : utils.getPartialAmountFloor( - orderRelevantMakerState.remainingFillableAssetAmount, - signedOrder.makerAssetAmount, - signedOrder.takerAssetAmount, - ); - - // Get max fillable amount for an order, considering the takers ability to fill - isMaker = false; - const orderRelevantTakerState = await this._getSidedOrderRelevantStateAsync(isMaker, signedOrder, takerAddress); - const remainingFillableTakerAssetAmountGivenTakersStatus = orderRelevantTakerState.remainingFillableAssetAmount; - - // The min of these two in the actualy max fillable by either party - const fillableTakerAssetAmount = BigNumber.min( - remainingFillableTakerAssetAmountGivenMakersStatus, - remainingFillableTakerAssetAmountGivenTakersStatus, - ); - - return fillableTakerAssetAmount; - } - private async _getSidedOrderRelevantStateAsync( - isMakerSide: boolean, - signedOrder: SignedOrder, - takerAddress: string, - ): Promise<SidedOrderRelevantState> { - let traderAddress; - let assetData; - let assetAmount; - let feeAmount; - if (isMakerSide) { - traderAddress = signedOrder.makerAddress; - assetData = signedOrder.makerAssetData; - assetAmount = signedOrder.makerAssetAmount; - feeAmount = signedOrder.makerFee; - } else { - traderAddress = takerAddress; - assetData = signedOrder.takerAssetData; - assetAmount = signedOrder.takerAssetAmount; - feeAmount = signedOrder.takerFee; - } - const zrxAssetData = this._orderFilledCancelledFetcher.getZRXAssetData(); - const isAssetZRX = assetData === zrxAssetData; - - const traderBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(assetData, traderAddress); - const traderIndividualBalances = await this._getAssetBalancesAsync(assetData, traderAddress); - const traderProxyAllowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync( - assetData, - traderAddress, - ); - const traderIndividualProxyAllowances = await this._getAssetProxyAllowancesAsync(assetData, traderAddress); - const traderFeeBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync( - zrxAssetData, - traderAddress, - ); - const traderFeeProxyAllowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync( - zrxAssetData, - traderAddress, - ); - - const transferrableTraderAssetAmount = BigNumber.min(traderProxyAllowance, traderBalance); - const transferrableFeeAssetAmount = BigNumber.min(traderFeeProxyAllowance, traderFeeBalance); - - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - const filledTakerAssetAmount = await this._orderFilledCancelledFetcher.getFilledTakerAmountAsync(orderHash); - const totalMakerAssetAmount = signedOrder.makerAssetAmount; - const totalTakerAssetAmount = signedOrder.takerAssetAmount; - const isOrderCancelled = await this._orderFilledCancelledFetcher.isOrderCancelledAsync(signedOrder); - const remainingTakerAssetAmount = isOrderCancelled - ? new BigNumber(0) - : totalTakerAssetAmount.minus(filledTakerAssetAmount); - const remainingMakerAssetAmount = remainingTakerAssetAmount.eq(0) - ? new BigNumber(0) - : remainingTakerAssetAmount.times(totalMakerAssetAmount).dividedToIntegerBy(totalTakerAssetAmount); - const remainingAssetAmount = isMakerSide ? remainingMakerAssetAmount : remainingTakerAssetAmount; - - const remainingFillableCalculator = new RemainingFillableCalculator( - feeAmount, - assetAmount, - isAssetZRX, - transferrableTraderAssetAmount, - transferrableFeeAssetAmount, - remainingAssetAmount, - ); - const remainingFillableAssetAmount = remainingFillableCalculator.computeRemainingFillable(); - - const sidedOrderRelevantState = { - isMakerSide, - traderBalance, - traderIndividualBalances, - traderProxyAllowance, - traderIndividualProxyAllowances, - traderFeeBalance, - traderFeeProxyAllowance, - filledTakerAssetAmount, - remainingFillableAssetAmount, - isOrderCancelled, - }; - return sidedOrderRelevantState; - } - private async _getAssetBalancesAsync( - assetData: string, - traderAddress: string, - initialBalances: ObjectMap<BigNumber> = {}, - ): Promise<ObjectMap<BigNumber>> { - const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData); - let balances: ObjectMap<BigNumber> = { ...initialBalances }; - if (assetDataUtils.isERC20AssetData(decodedAssetData) || assetDataUtils.isERC721AssetData(decodedAssetData)) { - const balance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(assetData, traderAddress); - const tokenAddress = decodedAssetData.tokenAddress; - balances[tokenAddress] = _.isUndefined(initialBalances[tokenAddress]) - ? balance - : balances[tokenAddress].plus(balance); - } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) { - for (const assetDataElement of decodedAssetData.nestedAssetData) { - balances = await this._getAssetBalancesAsync(assetDataElement, traderAddress, balances); - } - } - return balances; - } - private async _getAssetProxyAllowancesAsync( - assetData: string, - traderAddress: string, - initialAllowances: ObjectMap<BigNumber> = {}, - ): Promise<ObjectMap<BigNumber>> { - const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData); - let allowances: ObjectMap<BigNumber> = { ...initialAllowances }; - if (assetDataUtils.isERC20AssetData(decodedAssetData) || assetDataUtils.isERC721AssetData(decodedAssetData)) { - const allowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync( - assetData, - traderAddress, - ); - const tokenAddress = decodedAssetData.tokenAddress; - allowances[tokenAddress] = _.isUndefined(initialAllowances[tokenAddress]) - ? allowance - : allowances[tokenAddress].plus(allowance); - } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) { - for (const assetDataElement of decodedAssetData.nestedAssetData) { - allowances = await this._getAssetBalancesAsync(assetDataElement, traderAddress, allowances); - } - } - return allowances; - } -} |