aboutsummaryrefslogtreecommitdiffstats
path: root/src/utils/order_validation_utils.ts
blob: 4452a7aefe8dc5adc473eb675bfb72556bd9f956 (plain) (blame)
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
import {ExchangeContractErrs, SignedOrder} from '../types';
import {TokenWrapper} from '../contract_wrappers/token_wrapper';

export class OrderValidationUtils {
    public static async validateFillOrderBalancesAndAllowancesAndThrowIfInvalidAsync(
        tokenWrapper: TokenWrapper, signedOrder: SignedOrder, fillTakerAmount: BigNumber.BigNumber,
        senderAddress: string, zrxTokenAddress: string): Promise<void> {
        await OrderValidationUtils.validateFillOrderMakerBalancesAndAllowancesAndThrowIfInvalidAsync(
            tokenWrapper, signedOrder, fillTakerAmount, zrxTokenAddress,
        );
        await OrderValidationUtils.validateFillOrderTakerBalancesAndAllowancesAndThrowIfInvalidAsync(
            tokenWrapper, signedOrder, fillTakerAmount, senderAddress, zrxTokenAddress,
        );
    }
    private static async validateFillOrderMakerBalancesAndAllowancesAndThrowIfInvalidAsync(
        tokenWrapper: TokenWrapper, signedOrder: SignedOrder, fillTakerAmount: BigNumber.BigNumber,
        zrxTokenAddress: string,
    ): Promise<void> {
        const makerBalance = await tokenWrapper.getBalanceAsync(signedOrder.makerTokenAddress, signedOrder.maker);
        const makerAllowance = await 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);

        if (isMakerTokenZRX) {
            const requiredMakerAmount = fillMakerAmount.plus(signedOrder.makerFee);
            if (requiredMakerAmount.greaterThan(makerBalance)) {
                throw new Error(ExchangeContractErrs.InsufficientMakerBalance);
            }
            if (requiredMakerAmount.greaterThan(makerAllowance)) {
                throw new Error(ExchangeContractErrs.InsufficientMakerAllowance);
            }
        } else {
            const makerZRXBalance = await tokenWrapper.getBalanceAsync(zrxTokenAddress, signedOrder.maker);
            const makerZRXAllowance = await tokenWrapper.getProxyAllowanceAsync(zrxTokenAddress, signedOrder.maker);

            if (fillMakerAmount.greaterThan(makerBalance)) {
                throw new Error(ExchangeContractErrs.InsufficientMakerBalance);
            }
            if (fillMakerAmount.greaterThan(makerAllowance)) {
                throw new Error(ExchangeContractErrs.InsufficientMakerAllowance);
            }
            if (signedOrder.makerFee.greaterThan(makerZRXBalance)) {
                throw new Error(ExchangeContractErrs.InsufficientMakerFeeBalance);
            }
            if (signedOrder.makerFee.greaterThan(makerZRXAllowance)) {
                throw new Error(ExchangeContractErrs.InsufficientMakerFeeAllowance);
            }
        }
    }
    private static async validateFillOrderTakerBalancesAndAllowancesAndThrowIfInvalidAsync(
        tokenWrapper: TokenWrapper, signedOrder: SignedOrder, fillTakerAmount: BigNumber.BigNumber,
        senderAddress: string, zrxTokenAddress: string,
    ): Promise<void> {
        const takerBalance = await tokenWrapper.getBalanceAsync(signedOrder.takerTokenAddress, senderAddress);
        const takerAllowance = await tokenWrapper.getProxyAllowanceAsync(signedOrder.takerTokenAddress, senderAddress);

        const isTakerTokenZRX = signedOrder.takerTokenAddress === zrxTokenAddress;

        if (isTakerTokenZRX) {
            const requiredTakerAmount = fillTakerAmount.plus(signedOrder.takerFee);
            if (requiredTakerAmount.greaterThan(takerBalance)) {
                throw new Error(ExchangeContractErrs.InsufficientTakerBalance);
            }
            if (requiredTakerAmount.greaterThan(takerAllowance)) {
                throw new Error(ExchangeContractErrs.InsufficientTakerAllowance);
            }
        } else {
            const takerZRXBalance = await tokenWrapper.getBalanceAsync(zrxTokenAddress, senderAddress);
            const takerZRXAllowance = await tokenWrapper.getProxyAllowanceAsync(zrxTokenAddress, senderAddress);

            if (fillTakerAmount.greaterThan(takerBalance)) {
                throw new Error(ExchangeContractErrs.InsufficientTakerBalance);
            }
            if (fillTakerAmount.greaterThan(takerAllowance)) {
                throw new Error(ExchangeContractErrs.InsufficientTakerAllowance);
            }
            if (signedOrder.takerFee.greaterThan(takerZRXBalance)) {
                throw new Error(ExchangeContractErrs.InsufficientTakerFeeBalance);
            }
            if (signedOrder.takerFee.greaterThan(takerZRXAllowance)) {
                throw new Error(ExchangeContractErrs.InsufficientTakerFeeAllowance);
            }
        }
    }
}