aboutsummaryrefslogtreecommitdiffstats
path: root/src/contract_wrappers/exchange_wrapper.ts
blob: 691d465cc1a223a221243b772d658ffd26f42f57 (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
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
import * as _ from 'lodash';
import {Web3Wrapper} from '../web3_wrapper';
import {
    ECSignature,
    ExchangeContract,
    ExchangeContractErrs,
    OrderValues,
    OrderAddresses,
} from '../types';
import {assert} from '../utils/assert';
import {ContractWrapper} from './contract_wrapper';
import * as ExchangeArtifacts from '../artifacts/Exchange.json';
import {ecSignatureSchema} from '../schemas/ec_signature_schema';
import {ContractResponse} from '../types';
import {constants} from '../utils/constants';

export class ExchangeWrapper extends ContractWrapper {
    private exchangeContractErrToMsg = {
        [ExchangeContractErrs.ERROR_FILL_EXPIRED]: 'The order you attempted to fill is expired',
        [ExchangeContractErrs.ERROR_CANCEL_EXPIRED]: 'The order you attempted to cancel is expired',
        [ExchangeContractErrs.ERROR_FILL_NO_VALUE]: 'This order has already been filled or cancelled',
        [ExchangeContractErrs.ERROR_CANCEL_NO_VALUE]: 'This order has already been filled or cancelled',
        [ExchangeContractErrs.ERROR_FILL_TRUNCATION]: 'The rounding error was too large when filling this order',
        [ExchangeContractErrs.ERROR_FILL_BALANCE_ALLOWANCE]: 'Maker or taker has insufficient balance or allowance',
    };
    constructor(web3Wrapper: Web3Wrapper) {
        super(web3Wrapper);
    }
    public async isValidSignatureAsync(dataHex: string, ecSignature: ECSignature,
                                       signerAddressHex: string): Promise<boolean> {
        assert.isHexString('dataHex', dataHex);
        assert.doesConformToSchema('ecSignature', ecSignature, ecSignatureSchema);
        assert.isETHAddressHex('signerAddressHex', signerAddressHex);

        const senderAddress = await this.web3Wrapper.getSenderAddressOrThrowAsync();
        const exchangeInstance = await this.getExchangeInstanceOrThrowAsync();

        const isValidSignature = await exchangeInstance.isValidSignature.call(
            signerAddressHex,
            dataHex,
            ecSignature.v,
            ecSignature.r,
            ecSignature.s,
            {
                from: senderAddress,
            },
        );
        return isValidSignature;
    }
    public async fillOrderAsync(maker: string, taker: string, makerTokenAddress: string,
                                takerTokenAddress: string, makerTokenAmount: BigNumber.BigNumber,
                                takerTokenAmount: BigNumber.BigNumber, makerFee: BigNumber.BigNumber,
                                takerFee: BigNumber.BigNumber, expirationUnixTimestampSec: BigNumber.BigNumber,
                                feeRecipient: string, fillAmount: BigNumber.BigNumber,
                                ecSignature: ECSignature, salt: BigNumber.BigNumber) {
        assert.isBigNumber('salt', salt);
        assert.isBigNumber('makerFee', makerFee);
        assert.isBigNumber('takerFee', takerFee);
        assert.isBigNumber('fillAmount', fillAmount);
        assert.isBigNumber('makerTokenAmount', makerTokenAmount);
        assert.isBigNumber('takerTokenAmount', takerTokenAmount);
        assert.isBigNumber('expirationUnixTimestampSec', expirationUnixTimestampSec);
        assert.isETHAddressHex('maker', maker);
        assert.isETHAddressHex('taker', taker);
        assert.isETHAddressHex('feeRecipient', feeRecipient);
        assert.isETHAddressHex('makerTokenAddress', makerTokenAddress);
        assert.isETHAddressHex('takerTokenAddress', takerTokenAddress);
        assert.doesConformToSchema('ecSignature', ecSignature, ecSignatureSchema);

        const senderAddress = await this.web3Wrapper.getSenderAddressOrThrowAsync();
        const exchangeInstance = await this.getExchangeInstanceOrThrowAsync();

        taker = taker === '' ? constants.NULL_ADDRESS : taker;
        const shouldCheckTransfer = true;
        const orderAddresses: OrderAddresses = [
            maker,
            taker,
            makerTokenAddress,
            takerTokenAddress,
            feeRecipient,
        ];
        const orderValues: OrderValues = [
            makerTokenAmount,
            takerTokenAmount,
            makerFee,
            takerFee,
            expirationUnixTimestampSec,
            salt,
        ];
        const response: ContractResponse = await exchangeInstance.fill(
            orderAddresses,
            orderValues,
            fillAmount,
            shouldCheckTransfer,
            signatureData.v,
            signatureData.r,
            signatureData.s,
            {
                from: senderAddress,
            },
        );
        const errEvent = _.find(response.logs, {event: 'LogError'});
        if (!_.isUndefined(errEvent)) {
            const errCode = errEvent.args.errorId.toNumber();
            const humanReadableErrMessage = this.exchangeContractErrToMsg[errCode];
            throw new Error(humanReadableErrMessage);
        }
        return response;
    }
    private async getExchangeInstanceOrThrowAsync(): Promise<ExchangeContract> {
        const contractInstance = await this.instantiateContractIfExistsAsync((ExchangeArtifacts as any));
        return contractInstance as ExchangeContract;
    }
}