import { Address } from "@celo/utils/lib/address"; import invariant from "tiny-invariant"; import { TransactionReceipt } from "web3-core"; import { Contract, ContractOptions } from "web3-eth-contract"; import { AbiItem } from "web3-utils"; import { Wallet } from "../wallet"; type MethodSignature = (...params: any[]) => { call: ( config: any, callback?: (err: any, result: any) => void ) => Promise; send: ( config: any, callback?: (err: any, result: any) => void ) => Promise; estimateGas: ( config: any, callback?: (err: any, gasAmount: number) => void ) => Promise; encodeABI: () => string; }; interface MethodsType { [method: string]: MethodSignature; } // Wrap the send function to route through the wallet object function wrapSend( method: MethodSignature, wallet: Wallet, contractAddress: Address ): MethodSignature { return (...params: any[]) => { const result = method(...params); const send = async ( config: any, callback?: (err: any, result: any) => void ) => { const abi = result.encodeABI(); const gas = await result.estimateGas({ from: wallet.address, ...config }); try { const receipt = await wallet.signAndSendTransaction([ { to: contractAddress, data: abi, from: wallet.address, gas, }, ]); if (callback) callback(null, receipt); return receipt; } catch (e) { if (callback) callback(e, null); invariant(false, e as unknown as string); } }; return { ...result, send, }; }; } export class NodeContract extends Contract { constructor( abi: AbiItem[], private address: string, private wallet: Wallet, options?: ContractOptions ) { super(abi, address, options); this.methods = Object.entries(super.methods).reduce( (accum: MethodsType, [method, func]) => ({ ...accum, [method]: wrapSend(func as MethodSignature, this.wallet, this.address), }), {} ); } }