1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
import * as _ from 'lodash';
import BigNumber from 'bignumber.js';
import {
ExchangeContractErrs,
SignedOrder,
OrderRelevantState,
MethodOpts,
OrderState,
OrderStateValid,
OrderStateInvalid,
} 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';
export class OrderStateUtils {
private tokenWrapper: TokenWrapper;
private exchangeWrapper: ExchangeWrapper;
constructor(tokenWrapper: TokenWrapper, exchangeWrapper: ExchangeWrapper) {
this.tokenWrapper = tokenWrapper;
this.exchangeWrapper = exchangeWrapper;
}
public async getOrderStateAsync(signedOrder: SignedOrder, methodOpts?: MethodOpts): Promise<OrderState> {
const orderRelevantState = await this.getOrderRelevantStateAsync(signedOrder, methodOpts);
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
try {
this.validateIfOrderIsValid(signedOrder, orderRelevantState);
const orderState: OrderStateValid = {
isValid: true,
orderHash,
orderRelevantState,
};
return orderState;
} catch (err) {
const orderState: OrderStateInvalid = {
isValid: false,
orderHash,
error: err.message,
};
return orderState;
}
}
public async getOrderRelevantStateAsync(
signedOrder: SignedOrder, methodOpts?: MethodOpts): Promise<OrderRelevantState> {
const zrxTokenAddress = await this.exchangeWrapper.getZRXTokenAddressAsync();
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
const makerBalance = await this.tokenWrapper.getBalanceAsync(
signedOrder.makerTokenAddress, signedOrder.maker, methodOpts,
);
const makerProxyAllowance = await this.tokenWrapper.getProxyAllowanceAsync(
signedOrder.makerTokenAddress, signedOrder.maker, methodOpts,
);
const makerFeeBalance = await this.tokenWrapper.getBalanceAsync(
zrxTokenAddress, signedOrder.maker, methodOpts,
);
const makerFeeProxyAllowance = await this.tokenWrapper.getProxyAllowanceAsync(
zrxTokenAddress, signedOrder.maker, methodOpts,
);
const filledTakerTokenAmount = await this.exchangeWrapper.getFilledTakerAmountAsync(orderHash, methodOpts);
const canceledTakerTokenAmount = await this.exchangeWrapper.getCanceledTakerAmountAsync(orderHash, methodOpts);
const unavailableTakerTokenAmount =
await this.exchangeWrapper.getUnavailableTakerAmountAsync(orderHash, methodOpts);
const totalMakerTokenAmount = signedOrder.makerTokenAmount;
const totalTakerTokenAmount = signedOrder.takerTokenAmount;
const remainingTakerTokenAmount = totalTakerTokenAmount.minus(unavailableTakerTokenAmount);
// 200 in order, 100 unavailable = 100 remaning, 0.5 remaning proportion
const remainingTakerProportion = remainingTakerTokenAmount.dividedBy(totalTakerTokenAmount);
const remainingMakerTokenAmount = remainingTakerProportion.times(totalMakerTokenAmount);
// min allowance, balance in account of maker
const fillableMakerTokenAmount = BigNumber.min([makerProxyAllowance, makerBalance]);
// min ^, remaining order maker token amount
const remainingFillableMakerTokenAmount = BigNumber.min(fillableMakerTokenAmount, remainingMakerTokenAmount);
// TODO
// edge case when maker token is ZRX
// rounding issues, check if its fillabae
const orderRelevantState = {
makerBalance,
makerProxyAllowance,
makerFeeBalance,
makerFeeProxyAllowance,
filledTakerTokenAmount,
canceledTakerTokenAmount,
remainingFillableMakerTokenAmount,
};
return orderRelevantState;
}
private validateIfOrderIsValid(signedOrder: SignedOrder, orderRelevantState: OrderRelevantState): void {
const unavailableTakerTokenAmount = orderRelevantState.canceledTakerTokenAmount.add(
orderRelevantState.filledTakerTokenAmount,
);
const availableTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
if (availableTakerTokenAmount.eq(0)) {
throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
}
if (orderRelevantState.makerBalance.eq(0)) {
throw new Error(ExchangeContractErrs.InsufficientMakerBalance);
}
if (orderRelevantState.makerProxyAllowance.eq(0)) {
throw new Error(ExchangeContractErrs.InsufficientMakerAllowance);
}
if (!signedOrder.makerFee.eq(0)) {
if (orderRelevantState.makerFeeBalance.eq(0)) {
throw new Error(ExchangeContractErrs.InsufficientMakerFeeBalance);
}
if (orderRelevantState.makerFeeProxyAllowance.eq(0)) {
throw new Error(ExchangeContractErrs.InsufficientMakerFeeAllowance);
}
}
// TODO Add linear function solver when maker token is ZRX #badass
// Return the max amount that's fillable
}
}
|