UNPKG

@colony/colony-js-contract-client

Version:

Method-like interface for Smart Contracts

161 lines (139 loc) 4.33 kB
/* @flow */ /* eslint-disable import/no-cycle */ import { makeAssert } from '@colony/colony-js-utils'; import ContractClient from './ContractClient'; import { convertInputValues, convertOutputValues, } from '../modules/paramConversion'; import { validateParams } from '../modules/paramValidation'; import type { ContractMethodArgs, DefaultValues, Params } from '../flowtypes'; /** * Abstract class for interacting with contract methods. */ export default class ContractMethod< InputValues: { [inputValueName: string]: any }, OutputValues: { [outputValueName: string]: any }, IContractClient: ContractClient, ContractData: { [dataValueName: string]: any }, > { assertValid: Function; client: IContractClient; contractData: ContractData; defaultValues: DefaultValues; functionName: string; input: Params; name: string; output: Params; /** * Given input values, method parameters and default values, iterate through * the parameters and construct and object with the properties from the * input values (if they are defined) or default values. */ static _applyDefaultValues( inputValues: InputValues, params: Params = [], defaultValues: DefaultValues = {}, ): InputValues { // XXX it's possible to do this in a more succinct way, but adding // properties in this way preserves type safety const values = Object.assign({}, inputValues); params.forEach(([name]) => { values[name] = Object.hasOwnProperty.call(values, name) ? values[name] : defaultValues[name]; }); return values; } constructor({ client, defaultValues, functionName, name, input, output, }: ContractMethodArgs<IContractClient> = {}) { this.name = name; this.client = client; this.input = input; this.functionName = functionName; this.assertValid = makeAssert(`Validation failed for ${name}`); if (defaultValues) this.defaultValues = defaultValues; if (output) this.output = output; } /** * Given named input values, transform these with the expected parameters * in order to get an array of arguments expected by the contract function. */ /** * Given arguments to call the contract method with, return * transaction data as a hex string. */ createTransactionData(callArgs: Array<any>) { return this.client.createTransactionData(this.functionName, callArgs); } /** * Given input values, apply default values and validate them against the * expected params */ validate( inputValues: any, params: Params = this.input, defaultValues: DefaultValues = this.defaultValues, ) { // eslint-disable-next-line no-underscore-dangle const values = this.constructor._applyDefaultValues( inputValues, params, defaultValues, ); return validateParams(values, params, this.assertValid); } /** * Given input values, map them against the expected parameters, * with the appropriate conversion for each type. */ convertInputValues( inputValues: InputValues, params: Params = this.input, ): Array<any> { return convertInputValues(inputValues, params); } /** * Given the result of a contract method call, transform these with the * expected output parameters in order to get named output values as the * method's `OutputValues`. */ convertOutputValues( callResult: any, // eslint-disable-next-line no-unused-vars inputValues?: InputValues, ): OutputValues { const values = [].concat(callResult); const parsedResult = this.output.reduce( (acc, [name], index) => Object.assign(acc, { [name]: values[index] }), {}, ); return convertOutputValues(parsedResult, this.output); } /** * Given input values, get default values, then validate them and return * parsed method args. */ getValidatedArgs( inputValues: any, params: Params = this.input, defaultValues: DefaultValues = this.defaultValues, ) { // eslint-disable-next-line no-underscore-dangle const values = this.constructor._applyDefaultValues( inputValues, params, defaultValues, ); this.validate(values, params); return params && params.length ? this.convertInputValues(values, params) : []; } }