1
0
mirror of https://github.com/oceanprotocol-archive/squid-js.git synced 2024-02-02 15:31:51 +01:00
squid-js/src/keeper/contracts/ContractBase.ts
2019-03-25 15:21:23 +01:00

123 lines
4.5 KiB
TypeScript

import { Contract } from "web3-eth-contract"
import { TransactionReceipt } from "web3-core"
import ContractHandler from "../ContractHandler"
import { Instantiable, InstantiableConfig } from "../../Instantiable.abstract"
export default abstract class ContractBase extends Instantiable {
protected static instance = null
public contractName: string
private contract: Contract = null
constructor(contractName) {
super()
this.contractName = contractName
}
public async getEventData(eventName: any, options: any) {
if (!this.contract.events[eventName]) {
throw new Error(`Event "${eventName}" not found on contract "${this.contractName}"`)
}
return this.contract.getPastEvents(eventName, options)
}
public getAddress(): string {
return this.contract.options.address
}
public getSignatureOfMethod(methodName: string): string {
const foundMethod = this.searchMethod(methodName)
return foundMethod.signature
}
public getInputsOfMethod(methodName: string): any[] {
const foundMethod = this.searchMethod(methodName)
return foundMethod.inputs
}
protected async init(config: InstantiableConfig) {
this.setInstanceConfig(config)
const contractHandler = new ContractHandler(config)
this.contract = await contractHandler.get(this.contractName)
}
protected async getFromAddress(from?: string): Promise<string> {
if (!from) {
from = (await this.web3.eth.getAccounts())[0]
}
return from
}
protected async sendFrom(name: string, args: any[], from?: string): Promise<TransactionReceipt> {
from = await this.getFromAddress(from)
return this.send(name, from, args)
}
protected async send(name: string, from: string, args: any[]): Promise<TransactionReceipt> {
if (!this.contract.methods[name]) {
throw new Error(`Method "${name}" is not part of contract "${this.contractName}"`)
}
// Logger.log(name, args)
const method = this.contract.methods[name]
try {
const methodInstance = method(...args)
const estimatedGas = await methodInstance.estimateGas(args, {
from,
})
const tx = methodInstance.send({
from,
gas: estimatedGas,
})
return tx
} catch (err) {
const mappedArgs = this.searchMethod(name, args).inputs.map((input, i) => {
return {
name: input.name,
value: args[i],
}
})
this.logger.error("-".repeat(40))
this.logger.error(`Sending transaction "${name}" on contract "${this.contractName}" failed.`)
this.logger.error(`Error: ${err.message}`)
this.logger.error(`From: ${from}`)
this.logger.error(`Parameters: ${JSON.stringify(mappedArgs, null, 2)}`)
this.logger.error("-".repeat(40))
throw err
}
}
protected async call<T extends any>(name: string, args: any[], from?: string): Promise<T> {
if (!this.contract.methods[name]) {
throw new Error(`Method ${name} is not part of contract ${this.contractName}`)
}
// Logger.log(name)
try {
const method = this.contract.methods[name](...args)
return method.call(from ? {from} : null)
} catch (err) {
this.logger.error(`Calling method "${name}" on contract "${this.contractName}" failed. Args: ${args}`, err)
throw err
}
}
protected getEvent(eventName: string, filter: {[key: string]: any}) {
if (!this.contract.events[eventName]) {
throw new Error(`Event ${eventName} is not part of contract ${this.contractName}`)
}
return this.ocean.keeper.utils.eventHandler.getEvent(this, eventName, filter)
}
private searchMethod(methodName: string, args: any[] = []) {
const methods = this.contract.options.jsonInterface
.map((method) => ({...method, signature: (method as any).signature}))
.filter((method: any) => method.name === methodName)
const foundMethod = methods.find(({inputs}) => inputs.length === args.length) || methods[0]
if (!foundMethod) {
throw new Error(`Method "${methodName}" is not part of contract "${this.contractName}"`)
}
return foundMethod
}
}