aboutsummaryrefslogtreecommitdiffstats
path: root/packages/web3-wrapper/src/base_contract.ts
blob: 997ce97d37ea5b63743177fa4051946c892ed1e1 (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
import { TxData, TxDataPayable } from '@0xproject/types';
import * as ethersContracts from 'ethers-contracts';
import * as _ from 'lodash';
import * as Web3 from 'web3';

import { Web3Wrapper } from './web3_wrapper';

export class BaseContract {
    protected _ethersInterface: ethersContracts.Interface;
    protected _web3Wrapper: Web3Wrapper;
    public abi: Web3.ContractAbi;
    public address: string;
    protected static _transformABIData(
        abis: Web3.DataItem[],
        values: any[],
        transformation: (type: string, value: any) => any,
    ): any {
        return _.map(values, (value: any, i: number) =>
            BaseContract._transformTypedData(abis[i].type, value, transformation),
        );
    }
    protected static _lowercaseAddress(type: string, value: string): string {
        return type === 'address' ? value.toLowerCase() : value;
    }
    protected static _bigNumberToString(type: string, value: string): string {
        return _.isObject(value) && (value as any).isBigNumber ? value.toString() : value;
    }
    private static _transformTypedData(
        type: string,
        values: any,
        transformation: (type: string, value: any) => any,
    ): any {
        const trailingArrayRegex = /\[\d*\]$/;
        if (type.match(trailingArrayRegex)) {
            const arrayItemType = type.replace(trailingArrayRegex, '');
            return _.map(values, value => this._transformTypedData(arrayItemType, value, transformation));
        } else {
            return transformation(type, values);
        }
    }
    protected async _applyDefaultsToTxDataAsync<T extends Partial<TxData | TxDataPayable>>(
        txData: T,
        estimateGasAsync?: (txData: T) => Promise<number>,
    ): Promise<TxData> {
        // Gas amount sourced with the following priorities:
        // 1. Optional param passed in to public method call
        // 2. Global config passed in at library instantiation
        // 3. Gas estimate calculation + safety margin
        const removeUndefinedProperties = _.pickBy;
        const txDataWithDefaults = {
            to: this.address,
            ...removeUndefinedProperties(this._web3Wrapper.getContractDefaults()),
            ...removeUndefinedProperties(txData as any),
            // HACK: TS can't prove that T is spreadable.
            // Awaiting https://github.com/Microsoft/TypeScript/pull/13288 to be merged
        };
        if (_.isUndefined(txDataWithDefaults.gas) && !_.isUndefined(estimateGasAsync)) {
            const estimatedGas = await estimateGasAsync(txData);
            txDataWithDefaults.gas = estimatedGas;
        }
        return txDataWithDefaults;
    }
    constructor(web3Wrapper: Web3Wrapper, abi: Web3.ContractAbi, address: string) {
        this._web3Wrapper = web3Wrapper;
        this.abi = abi;
        this.address = address;
        this._ethersInterface = new ethersContracts.Interface(abi);
    }
}