aboutsummaryrefslogtreecommitdiffstats
path: root/packages/order-utils/src/order_state_utils.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/order-utils/src/order_state_utils.ts')
-rw-r--r--packages/order-utils/src/order_state_utils.ts346
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;
- }
-}