diff options
Diffstat (limited to 'packages/abi-gen')
-rw-r--r-- | packages/abi-gen/CHANGELOG.md | 6 | ||||
-rw-r--r-- | packages/abi-gen/src/index.ts | 14 | ||||
-rw-r--r-- | packages/abi-gen/src/types.ts | 6 | ||||
-rw-r--r-- | packages/abi-gen/src/utils.ts | 46 |
4 files changed, 61 insertions, 11 deletions
diff --git a/packages/abi-gen/CHANGELOG.md b/packages/abi-gen/CHANGELOG.md index c86d6fb55..d9198d3ed 100644 --- a/packages/abi-gen/CHANGELOG.md +++ b/packages/abi-gen/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## v0.2.3 - _TBD, 2018_ + + * Add a `backend` parameter that allows you to specify the Ethereum library you use in your templates (`web3` or `ethers`). Ethers auto-converts small ints to numbers whereas Web3 doesn't. Defaults to `web3` (#413) + * Add support for [tuple types](https://solidity.readthedocs.io/en/develop/abi-spec.html#handling-tuple-types) (#413) + * Add `hasReturnValue` to context data (#413) + ## v0.2.1 - _February 9, 2018_ * Fix publishing issue where .npmignore was not properly excluding undesired content (#389) diff --git a/packages/abi-gen/src/index.ts b/packages/abi-gen/src/index.ts index bc5a974a9..7c29f7d1d 100644 --- a/packages/abi-gen/src/index.ts +++ b/packages/abi-gen/src/index.ts @@ -11,13 +11,14 @@ import * as yargs from 'yargs'; import toSnakeCase = require('to-snake-case'); import * as Web3 from 'web3'; -import { ContextData, ParamKind } from './types'; +import { ContextData, ContractsBackend, ParamKind } from './types'; import { utils } from './utils'; const ABI_TYPE_CONSTRUCTOR = 'constructor'; const ABI_TYPE_METHOD = 'function'; const ABI_TYPE_EVENT = 'event'; const DEFAULT_NETWORK_ID = 50; +const DEFAULT_BACKEND = 'web3'; const args = yargs .option('abis', { @@ -43,6 +44,12 @@ const args = yargs demandOption: true, normalize: true, }) + .option('backend', { + describe: `The backing Ethereum library your app uses. Either 'web3' or 'ethers'. Ethers auto-converts small ints to numbers whereas Web3 doesn't.`, + type: 'string', + choices: [ContractsBackend.Web3, ContractsBackend.Ethers], + default: DEFAULT_BACKEND, + }) .option('network-id', { describe: 'ID of the network where contract ABIs are nested in artifacts', type: 'number', @@ -73,8 +80,8 @@ function writeOutputFile(name: string, renderedTsCode: string): void { utils.log(`Created: ${chalk.bold(filePath)}`); } -Handlebars.registerHelper('parameterType', utils.solTypeToTsType.bind(utils, ParamKind.Input)); -Handlebars.registerHelper('returnType', utils.solTypeToTsType.bind(utils, ParamKind.Output)); +Handlebars.registerHelper('parameterType', utils.solTypeToTsType.bind(utils, ParamKind.Input, args.backend)); +Handlebars.registerHelper('returnType', utils.solTypeToTsType.bind(utils, ParamKind.Output, args.backend)); if (args.partials) { registerPartials(args.partials); @@ -129,6 +136,7 @@ for (const abiFileName of abiFileNames) { const methodData = { ...methodAbi, singleReturnValue: methodAbi.outputs.length === 1, + hasReturnValue: methodAbi.outputs.length !== 0, }; return methodData; }); diff --git a/packages/abi-gen/src/types.ts b/packages/abi-gen/src/types.ts index e82ab824b..deddb1857 100644 --- a/packages/abi-gen/src/types.ts +++ b/packages/abi-gen/src/types.ts @@ -12,8 +12,14 @@ export enum AbiType { Fallback = 'fallback', } +export enum ContractsBackend { + Web3 = 'web3', + Ethers = 'ethers', +} + export interface Method extends Web3.MethodAbi { singleReturnValue: boolean; + hasReturnValue: boolean; } export interface ContextData { diff --git a/packages/abi-gen/src/utils.ts b/packages/abi-gen/src/utils.ts index 14255643a..3e4ff619a 100644 --- a/packages/abi-gen/src/utils.ts +++ b/packages/abi-gen/src/utils.ts @@ -3,17 +3,23 @@ import * as _ from 'lodash'; import * as path from 'path'; import * as Web3 from 'web3'; -import { AbiType, ParamKind } from './types'; +import { AbiType, ContractsBackend, ParamKind } from './types'; export const utils = { - solTypeToTsType(paramKind: ParamKind, solType: string): string { + solTypeToTsType( + paramKind: ParamKind, + backend: ContractsBackend, + solType: string, + components?: Web3.DataItem[], + ): string { const trailingArrayRegex = /\[\d*\]$/; if (solType.match(trailingArrayRegex)) { const arrayItemSolType = solType.replace(trailingArrayRegex, ''); - const arrayItemTsType = utils.solTypeToTsType(paramKind, arrayItemSolType); - const arrayTsType = utils.isUnionType(arrayItemTsType) - ? `Array<${arrayItemTsType}>` - : `${arrayItemTsType}[]`; + const arrayItemTsType = utils.solTypeToTsType(paramKind, backend, arrayItemSolType, components); + const arrayTsType = + utils.isUnionType(arrayItemTsType) || utils.isObjectType(arrayItemTsType) + ? `Array<${arrayItemTsType}>` + : `${arrayItemTsType}[]`; return arrayTsType; } else { const solTypeRegexToTsType = [ @@ -24,25 +30,49 @@ export const utils = { { regex: '^bytes\\d*$', tsType: 'string' }, ]; if (paramKind === ParamKind.Input) { - // web3 allows to pass those an non-bignumbers and that's nice - // but it always returns stuff as BigNumbers + // web3 and ethers allow to pass those as numbers instead of bignumbers solTypeRegexToTsType.unshift({ regex: '^u?int(8|16|32)?$', tsType: 'number|BigNumber', }); } + if (backend === ContractsBackend.Ethers && paramKind === ParamKind.Output) { + // ethers-contracts automatically converts small BigNumbers to numbers + solTypeRegexToTsType.unshift({ + regex: '^u?int(8|16|32|48)?$', + tsType: 'number', + }); + } for (const regexAndTxType of solTypeRegexToTsType) { const { regex, tsType } = regexAndTxType; if (solType.match(regex)) { return tsType; } } + const TUPLE_TYPE_REGEX = '^tuple$'; + if (solType.match(TUPLE_TYPE_REGEX)) { + const componentsType = _.map(components, component => { + const componentValueType = utils.solTypeToTsType( + paramKind, + backend, + component.type, + component.components, + ); + const componentType = `${component.name}: ${componentValueType}`; + return componentType; + }); + const tsType = `{${componentsType}}`; + return tsType; + } throw new Error(`Unknown Solidity type found: ${solType}`); } }, isUnionType(tsType: string): boolean { return tsType === 'number|BigNumber'; }, + isObjectType(tsType: string): boolean { + return /^{.*}$/.test(tsType); + }, log(...args: any[]): void { console.log(...args); // tslint:disable-line:no-console }, |