Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
);
minSet.push(maxTakerAssetFillAmountGivenMakerConstraints);
// Calculate min of balance & allowance of taker's Fee -> translate into takerAsset amount
if (!signedOrder.takerFee.eq(0)) {
const takerFeeAvailable = BigNumber.min(traderInfo.takerFeeBalance, traderInfo.takerFeeAllowance);
const maxTakerAssetFillAmountGivenTakerFeeConstraints = takerFeeAvailable
.multipliedBy(signedOrder.takerAssetAmount)
.div(signedOrder.takerFee)
.integerValue(BigNumber.ROUND_FLOOR);
minSet.push(maxTakerAssetFillAmountGivenTakerFeeConstraints);
}
// Calculate min of balance & allowance of maker's Fee -> translate into takerAsset amount
if (!signedOrder.makerFee.eq(0)) {
const makerFeeAvailable = BigNumber.min(traderInfo.makerFeeBalance, traderInfo.makerFeeAllowance);
const maxTakerAssetFillAmountGivenMakerFeeConstraints = makerFeeAvailable
.multipliedBy(signedOrder.takerAssetAmount)
.div(signedOrder.makerFee)
.integerValue(BigNumber.ROUND_FLOOR);
minSet.push(maxTakerAssetFillAmountGivenMakerFeeConstraints);
}
const remainingTakerAssetFillAmount = signedOrder.takerAssetAmount.minus(orderInfo.orderTakerAssetFilledAmount);
minSet.push(remainingTakerAssetFillAmount);
const maxTakerAssetFillAmount = BigNumber.min(...minSet);
return maxTakerAssetFillAmount;
}
private static _getOrdersFromDecodedCalldata(decodedCalldata: DecodedCalldata, chainId: number): Order[] {
(accOrders, order, index) => {
// get corresponding on-chain state for the order
const { orderInfo, traderInfo } = ordersAndTradersInfo[index];
// if the order IS NOT fillable, do not add anything to the accumulations and continue iterating
if (orderInfo.orderStatus !== OrderStatus.Fillable) {
return accOrders;
}
// if the order IS fillable, add the order and calculate the remaining fillable amount
const transferrableAssetAmount = BigNumber.min(traderInfo.makerAllowance, traderInfo.makerBalance);
const transferrableFeeAssetAmount = BigNumber.min(traderInfo.makerZrxAllowance, traderInfo.makerZrxBalance);
const remainingTakerAssetAmount = order.takerAssetAmount.minus(orderInfo.orderTakerAssetFilledAmount);
const remainingMakerAssetAmount = orderCalculationUtils.getMakerFillAmount(
order,
remainingTakerAssetAmount,
);
const remainingFillableCalculator = new RemainingFillableCalculator(
order.makerFee,
order.makerAssetAmount,
isMakerAssetZrxToken,
transferrableAssetAmount,
transferrableFeeAssetAmount,
remainingMakerAssetAmount,
);
const remainingFillableAmount = remainingFillableCalculator.computeRemainingFillable();
// if the order does not have any remaining fillable makerAsset, do not add anything to the accumulations and continue iterating
if (remainingFillableAmount.lte(constants.ZERO_AMOUNT)) {
(accOrders, order, index) => {
// get corresponding on-chain state for the order
const { orderInfo, traderInfo } = ordersAndTradersInfo[index];
// if the order IS NOT fillable, do not add anything to the accumulations and continue iterating
if (orderInfo.orderStatus !== OrderStatus.Fillable) {
return accOrders;
}
// if the order IS fillable, add the order and calculate the remaining fillable amount
const transferrableAssetAmount = BigNumber.min(traderInfo.makerAllowance, traderInfo.makerBalance);
const transferrableFeeAssetAmount = BigNumber.min(traderInfo.makerZrxAllowance, traderInfo.makerZrxBalance);
const remainingTakerAssetAmount = order.takerAssetAmount.minus(orderInfo.orderTakerAssetFilledAmount);
const remainingMakerAssetAmount = orderCalculationUtils.getMakerFillAmount(
order,
remainingTakerAssetAmount,
);
const remainingFillableCalculator = new RemainingFillableCalculator(
order.makerFee,
order.makerAssetAmount,
isMakerAssetZrxToken,
transferrableAssetAmount,
transferrableFeeAssetAmount,
remainingMakerAssetAmount,
);
const remainingFillableAmount = remainingFillableCalculator.computeRemainingFillable();
// if the order does not have any remaining fillable makerAsset, do not add anything to the accumulations and continue iterating
private _calculatePartiallyFillableAssetAmount(): BigNumber {
// Given an order for 200 wei for 2 ZRXwei fee, find 100 wei for 1 ZRXwei. Order ratio is then 100:1
const orderToFeeRatio = this._orderAssetAmount.dividedBy(this._orderFee);
// The number of times the trader (maker or taker) can fill the order, if each fill only required the transfer of a single
// baseUnit of fee tokens.
// Given 2 ZRXwei, the maximum amount of times trader can fill this order, in terms of fees, is 2
const fillableTimesInFeeBaseUnits = BigNumber.min(this._transferrableFeeAmount, this._remainingOrderFeeAmount);
// The number of times the trader can fill the order, given the traders asset Balance
// Assuming a balance of 150 wei, and an orderToFeeRatio of 100:1, trader can fill this order 1 time.
let fillableTimesInAssetUnits = this._transferrableAssetAmount.dividedBy(orderToFeeRatio);
if (this._isPercentageFee) {
// If ZRX is the trader asset, the Fee and the trader fill amount need to be removed from the same pool;
// 200 ZRXwei for 2ZRXwei fee can only be filled once (need 202 ZRXwei)
const totalAssetPooled = this._transferrableAssetAmount;
// The purchasing power here is less as the tokens are taken from the same Pool
// For every one number of fills, we have to take an extra ZRX out of the pool
fillableTimesInAssetUnits = totalAssetPooled.dividedBy(orderToFeeRatio.plus(new BigNumber(1)));
}
// When Ratio is not fully divisible there can be remainders which cannot be represented, so they are floored.
// This can result in a RoundingError being thrown by the Exchange Contract.
const partiallyFillableAssetAmount = fillableTimesInAssetUnits
.times(this._orderAssetAmount)
.dividedToIntegerBy(this._orderFee);
// If ZRX is the trader asset, the Fee and the trader fill amount need to be removed from the same pool;
// 200 ZRXwei for 2ZRXwei fee can only be filled once (need 202 ZRXwei)
const totalZRXTokenPooled = this._transferrableAssetAmount;
// The purchasing power here is less as the tokens are taken from the same Pool
// For every one number of fills, we have to take an extra ZRX out of the pool
fillableTimesInAssetUnits = totalZRXTokenPooled.dividedBy(orderToFeeRatio.plus(new BigNumber(1)));
}
// When Ratio is not fully divisible there can be remainders which cannot be represented, so they are floored.
// This can result in a RoundingError being thrown by the Exchange Contract.
const partiallyFillableAssetAmount = fillableTimesInAssetUnits
.times(this._orderAssetAmount)
.dividedToIntegerBy(this._orderFee);
const partiallyFillableFeeAmount = fillableTimesInFeeBaseUnits
.times(this._orderAssetAmount)
.dividedToIntegerBy(this._orderFee);
const partiallyFillableAmount = BigNumber.min(partiallyFillableAssetAmount, partiallyFillableFeeAmount);
return partiallyFillableAmount;
}
}
public computeRemainingFillable(): BigNumber {
if (this._hasSufficientFundsForFeeAndTransferAmount()) {
return this._remainingOrderAssetAmount;
}
if (this._orderFee.isZero()) {
return BigNumber.min(this._remainingOrderAssetAmount, this._transferrableAssetAmount);
}
return this._calculatePartiallyFillableAssetAmount();
}
private _hasSufficientFundsForFeeAndTransferAmount(): boolean {
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,
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(