diff options
38 files changed, 2758 insertions, 305 deletions
diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json index 97aff0581..341b12188 100644 --- a/packages/0x.js/package.json +++ b/packages/0x.js/package.json @@ -16,6 +16,7 @@ "build": "run-p build:umd:prod build:commonjs; exit 0;", "docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_DIR", "upload_docs_json": "aws s3 cp generated_docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type application/json", + "generate_contract_wrappers": "abi-gen --abiGlob 'src/artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry).json' --templates ../abi-gen-templates/ --output src/contract_wrappers/generated --fileExtension ts", "lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'", "test:circleci": "run-s test:coverage report_test_coverage && if [ $CIRCLE_BRANCH = \"development\" ]; then yarn test:umd; fi", "test": "run-s clean test:commonjs", @@ -45,6 +46,8 @@ }, "devDependencies": { "@0xproject/tslint-config": "^0.2.0", + "abi-gen": "^0.0.0", + "abi-gen-templates": "^0.0.0", "@types/bintrees": "^1.0.2", "@types/jsonschema": "^1.1.1", "@types/lodash": "^4.14.64", @@ -89,7 +92,6 @@ "bintrees": "^1.0.2", "bn.js": "4.11.8", "compare-versions": "^3.0.1", - "es6-promisify": "^5.0.0", "ethereumjs-abi": "^0.6.4", "ethereumjs-blockstream": "^2.0.6", "ethereumjs-util": "^5.1.1", diff --git a/packages/0x.js/src/contract.ts b/packages/0x.js/src/contract.ts deleted file mode 100644 index a4ee03910..000000000 --- a/packages/0x.js/src/contract.ts +++ /dev/null @@ -1,98 +0,0 @@ -import {schemas, SchemaValidator} from '@0xproject/json-schemas'; -import promisify = require('es6-promisify'); -import * as _ from 'lodash'; -import * as Web3 from 'web3'; - -import {AbiType} from './types'; - -// HACK: Gas estimates on testrpc don't take into account gas refunds. -// Our calls can trigger max 8 gas refunds for SSTORE per transaction for 15k gas each which gives 120k. -const GAS_MARGIN = 120000; - -export class Contract implements Web3.ContractInstance { - public address: string; - public abi: Web3.ContractAbi; - private contract: Web3.ContractInstance; - private defaults: Partial<Web3.TxData>; - private validator: SchemaValidator; - // This class instance is going to be populated with functions and events depending on the ABI - // and we don't know their types in advance - [name: string]: any; - constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<Web3.TxData>) { - this.contract = web3ContractInstance; - this.address = web3ContractInstance.address; - this.abi = web3ContractInstance.abi; - this.defaults = defaults; - this.populateEvents(); - this.populateFunctions(); - this.validator = new SchemaValidator(); - } - private populateFunctions(): void { - const functionsAbi = _.filter(this.abi, abiPart => abiPart.type === AbiType.Function); - _.forEach(functionsAbi, (functionAbi: Web3.MethodAbi) => { - if (functionAbi.constant) { - const cbStyleCallFunction = this.contract[functionAbi.name].call; - this[functionAbi.name] = { - callAsync: promisify(cbStyleCallFunction, this.contract), - }; - } else { - const cbStyleFunction = this.contract[functionAbi.name]; - const cbStyleEstimateGasFunction = this.contract[functionAbi.name].estimateGas; - const estimateGasAsync = promisify(cbStyleEstimateGasFunction, this.contract); - this[functionAbi.name] = { - estimateGasAsync, - sendTransactionAsync: this.promisifyWithDefaultParams(cbStyleFunction, estimateGasAsync), - }; - } - }); - } - private populateEvents(): void { - const eventsAbi = _.filter(this.abi, abiPart => abiPart.type === AbiType.Event); - _.forEach(eventsAbi, (eventAbi: Web3.EventAbi) => { - this[eventAbi.name] = this.contract[eventAbi.name]; - }); - } - private promisifyWithDefaultParams( - web3CbStyleFunction: (...args: any[]) => void, - estimateGasAsync: (...args: any[]) => Promise<number>, - ): (...args: any[]) => Promise<any> { - const promisifiedWithDefaultParams = async (...args: any[]) => { - const promise = new Promise(async (resolve, reject) => { - const lastArg = args[args.length - 1]; - let txData: Partial<Web3.TxData> = {}; - if (!_.isUndefined(lastArg) && this.isTxData(lastArg)) { - txData = args.pop(); - } - // 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; - txData = { - ...removeUndefinedProperties(this.defaults), - ...removeUndefinedProperties(txData), - }; - if (_.isUndefined(txData.gas)) { - try { - const estimatedGas = await estimateGasAsync.apply(this.contract, [...args, txData]); - const gas = estimatedGas + GAS_MARGIN; - txData.gas = gas; - } catch (err) { - reject(err); - return; - } - } - const callback = (err: Error, data: any) => _.isNull(err) ? resolve(data) : reject(err); - args.push(txData); - args.push(callback); - web3CbStyleFunction.apply(this.contract, args); - }); - return promise; - }; - return promisifiedWithDefaultParams; - } - private isTxData(lastArg: any): boolean { - const isValid = this.validator.isValid(lastArg, schemas.txDataSchema); - return isValid; - } -} diff --git a/packages/0x.js/src/contract_wrappers/contract_wrapper.ts b/packages/0x.js/src/contract_wrappers/contract_wrapper.ts index 8c92931b4..5e5a38f8c 100644 --- a/packages/0x.js/src/contract_wrappers/contract_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/contract_wrapper.ts @@ -90,11 +90,13 @@ export class ContractWrapper { const logWithDecodedArgs = this._abiDecoder.tryToDecodeLogOrNoop(log); return logWithDecodedArgs; } - protected async _instantiateContractIfExistsAsync<ContractType extends Web3.ContractInstance>( - artifact: Artifact, addressIfExists?: string): Promise<ContractType> { - const contractInstance = - await this._web3Wrapper.getContractInstanceFromArtifactAsync<ContractType>(artifact, addressIfExists); - return contractInstance; + protected async _instantiateContractIfExistsAsync( + artifact: Artifact, addressIfExists?: string, + ): Promise<Web3.ContractInstance> { + const web3ContractInstance = await this._web3Wrapper.getContractInstanceFromArtifactAsync( + artifact, addressIfExists, + ); + return web3ContractInstance; } protected _getContractAddress(artifact: Artifact, addressIfExists?: string): string { if (_.isUndefined(addressIfExists)) { diff --git a/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts b/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts index ede0460bd..26025f6f9 100644 --- a/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts @@ -2,11 +2,12 @@ import BigNumber from 'bignumber.js'; import * as _ from 'lodash'; import {artifacts} from '../artifacts'; -import {EtherTokenContract, TransactionOpts, ZeroExError} from '../types'; +import {TransactionOpts, ZeroExError} from '../types'; import {assert} from '../utils/assert'; import {Web3Wrapper} from '../web3_wrapper'; import {ContractWrapper} from './contract_wrapper'; +import {EtherTokenContract} from './generated/ether_token'; import {TokenWrapper} from './token_wrapper'; /** @@ -92,9 +93,10 @@ export class EtherTokenWrapper extends ContractWrapper { if (!_.isUndefined(this._etherTokenContractIfExists)) { return this._etherTokenContractIfExists; } - const contractInstance = await this._instantiateContractIfExistsAsync<EtherTokenContract>( + const web3ContractInstance = await this._instantiateContractIfExistsAsync( artifacts.EtherTokenArtifact, this._contractAddressIfExists, ); + const contractInstance = new EtherTokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults()); this._etherTokenContractIfExists = contractInstance; return this._etherTokenContractIfExists; } diff --git a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts b/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts index 273b348ff..aaf6256a3 100644 --- a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts @@ -9,7 +9,6 @@ import { DecodedLogArgs, ECSignature, EventCallback, - ExchangeContract, ExchangeContractErrCodes, ExchangeContractErrs, ExchangeContractEventArgs, @@ -40,6 +39,7 @@ import {utils} from '../utils/utils'; import {Web3Wrapper} from '../web3_wrapper'; import {ContractWrapper} from './contract_wrapper'; +import {ExchangeContract} from './generated/exchange'; import {TokenWrapper} from './token_wrapper'; const SHOULD_VALIDATE_BY_DEFAULT = true; @@ -789,9 +789,10 @@ export class ExchangeWrapper extends ContractWrapper { if (!_.isUndefined(this._exchangeContractIfExists)) { return this._exchangeContractIfExists; } - const contractInstance = await this._instantiateContractIfExistsAsync<ExchangeContract>( + const web3ContractInstance = await this._instantiateContractIfExistsAsync( artifacts.ExchangeArtifact, this._contractAddressIfExists, ); + const contractInstance = new ExchangeContract(web3ContractInstance, this._web3Wrapper.getContractDefaults()); this._exchangeContractIfExists = contractInstance; return this._exchangeContractIfExists; } diff --git a/packages/0x.js/src/contract_wrappers/generated/base_contract.ts b/packages/0x.js/src/contract_wrappers/generated/base_contract.ts new file mode 100644 index 000000000..396a4d593 --- /dev/null +++ b/packages/0x.js/src/contract_wrappers/generated/base_contract.ts @@ -0,0 +1,34 @@ +import * as _ from 'lodash'; +import * as Web3 from 'web3'; + +import {TxData, TxDataPayable} from '../../types'; + +export class BaseContract { + protected web3ContractInstance: Web3.ContractInstance; + protected defaults: Partial<TxData>; + protected async applyDefaultsToTxDataAsync<T extends 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 = { + ...removeUndefinedProperties(this.defaults), + ...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(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) { + this.web3ContractInstance = web3ContractInstance; + this.defaults = defaults; + } +} diff --git a/packages/0x.js/src/contract_wrappers/generated/ether_token.ts b/packages/0x.js/src/contract_wrappers/generated/ether_token.ts new file mode 100644 index 000000000..eed5e4686 --- /dev/null +++ b/packages/0x.js/src/contract_wrappers/generated/ether_token.ts @@ -0,0 +1,363 @@ +/** + * This file is auto-generated using abi-gen. Don't edit directly. + * Templates can be found at https://github.com/0xProject/0x.js/tree/development/packages/abi-gen-templates. + */ +import {BigNumber} from 'bignumber.js'; +import * as Web3 from 'web3'; + +import {TxData, TxDataPayable} from '../../types'; +import {classUtils} from '../../utils/class_utils'; +import {promisify} from '../../utils/promisify'; + +import {BaseContract} from './base_contract'; + +export class EtherTokenContract extends BaseContract { + public name = { + async callAsync( + defaultBlock?: Web3.BlockParam, + ): Promise<string + > { + const self = this as EtherTokenContract; + const result = await promisify<string + >( + self.web3ContractInstance.name.call, + self.web3ContractInstance, + )( + ); + return result; + }, + }; + public approve = { + async sendTransactionAsync( + _spender: string, + _value: BigNumber, + txData: TxData = {}, + ): Promise<string> { + const self = this as EtherTokenContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.approve.estimateGasAsync.bind( + self, + _spender, + _value, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.approve, self.web3ContractInstance, + )( + _spender, + _value, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + _spender: string, + _value: BigNumber, + txData: TxData = {}, + ): Promise<number> { + const self = this as EtherTokenContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.approve.estimateGas, self.web3ContractInstance, + )( + _spender, + _value, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + _spender: string, + _value: BigNumber, + txData: TxData = {}, + ): string { + const self = this as EtherTokenContract; + const abiEncodedTransactionData = self.web3ContractInstance.approve.getData(); + return abiEncodedTransactionData; + }, + }; + public totalSupply = { + async callAsync( + defaultBlock?: Web3.BlockParam, + ): Promise<BigNumber + > { + const self = this as EtherTokenContract; + const result = await promisify<BigNumber + >( + self.web3ContractInstance.totalSupply.call, + self.web3ContractInstance, + )( + ); + return result; + }, + }; + public transferFrom = { + async sendTransactionAsync( + _from: string, + _to: string, + _value: BigNumber, + txData: TxData = {}, + ): Promise<string> { + const self = this as EtherTokenContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.transferFrom.estimateGasAsync.bind( + self, + _from, + _to, + _value, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.transferFrom, self.web3ContractInstance, + )( + _from, + _to, + _value, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + _from: string, + _to: string, + _value: BigNumber, + txData: TxData = {}, + ): Promise<number> { + const self = this as EtherTokenContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.transferFrom.estimateGas, self.web3ContractInstance, + )( + _from, + _to, + _value, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + _from: string, + _to: string, + _value: BigNumber, + txData: TxData = {}, + ): string { + const self = this as EtherTokenContract; + const abiEncodedTransactionData = self.web3ContractInstance.transferFrom.getData(); + return abiEncodedTransactionData; + }, + }; + public withdraw = { + async sendTransactionAsync( + amount: BigNumber, + txData: TxData = {}, + ): Promise<string> { + const self = this as EtherTokenContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.withdraw.estimateGasAsync.bind( + self, + amount, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.withdraw, self.web3ContractInstance, + )( + amount, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + amount: BigNumber, + txData: TxData = {}, + ): Promise<number> { + const self = this as EtherTokenContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.withdraw.estimateGas, self.web3ContractInstance, + )( + amount, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + amount: BigNumber, + txData: TxData = {}, + ): string { + const self = this as EtherTokenContract; + const abiEncodedTransactionData = self.web3ContractInstance.withdraw.getData(); + return abiEncodedTransactionData; + }, + }; + public decimals = { + async callAsync( + defaultBlock?: Web3.BlockParam, + ): Promise<BigNumber + > { + const self = this as EtherTokenContract; + const result = await promisify<BigNumber + >( + self.web3ContractInstance.decimals.call, + self.web3ContractInstance, + )( + ); + return result; + }, + }; + public balanceOf = { + async callAsync( + _owner: string, + defaultBlock?: Web3.BlockParam, + ): Promise<BigNumber + > { + const self = this as EtherTokenContract; + const result = await promisify<BigNumber + >( + self.web3ContractInstance.balanceOf.call, + self.web3ContractInstance, + )( + _owner, + ); + return result; + }, + }; + public symbol = { + async callAsync( + defaultBlock?: Web3.BlockParam, + ): Promise<string + > { + const self = this as EtherTokenContract; + const result = await promisify<string + >( + self.web3ContractInstance.symbol.call, + self.web3ContractInstance, + )( + ); + return result; + }, + }; + public transfer = { + async sendTransactionAsync( + _to: string, + _value: BigNumber, + txData: TxData = {}, + ): Promise<string> { + const self = this as EtherTokenContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.transfer.estimateGasAsync.bind( + self, + _to, + _value, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.transfer, self.web3ContractInstance, + )( + _to, + _value, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + _to: string, + _value: BigNumber, + txData: TxData = {}, + ): Promise<number> { + const self = this as EtherTokenContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.transfer.estimateGas, self.web3ContractInstance, + )( + _to, + _value, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + _to: string, + _value: BigNumber, + txData: TxData = {}, + ): string { + const self = this as EtherTokenContract; + const abiEncodedTransactionData = self.web3ContractInstance.transfer.getData(); + return abiEncodedTransactionData; + }, + }; + public deposit = { + async sendTransactionAsync( + txData: TxDataPayable = {}, + ): Promise<string> { + const self = this as EtherTokenContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.deposit.estimateGasAsync.bind( + self, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.deposit, self.web3ContractInstance, + )( + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + txData: TxData = {}, + ): Promise<number> { + const self = this as EtherTokenContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.deposit.estimateGas, self.web3ContractInstance, + )( + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + txData: TxData = {}, + ): string { + const self = this as EtherTokenContract; + const abiEncodedTransactionData = self.web3ContractInstance.deposit.getData(); + return abiEncodedTransactionData; + }, + }; + public allowance = { + async callAsync( + _owner: string, + _spender: string, + defaultBlock?: Web3.BlockParam, + ): Promise<BigNumber + > { + const self = this as EtherTokenContract; + const result = await promisify<BigNumber + >( + self.web3ContractInstance.allowance.call, + self.web3ContractInstance, + )( + _owner, + _spender, + ); + return result; + }, + }; + constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) { + super(web3ContractInstance, defaults); + classUtils.bindAll(this, ['web3ContractInstance', 'defaults']); + } +} // tslint:disable:max-file-line-count diff --git a/packages/0x.js/src/contract_wrappers/generated/exchange.ts b/packages/0x.js/src/contract_wrappers/generated/exchange.ts new file mode 100644 index 000000000..8c25ca014 --- /dev/null +++ b/packages/0x.js/src/contract_wrappers/generated/exchange.ts @@ -0,0 +1,730 @@ +/** + * This file is auto-generated using abi-gen. Don't edit directly. + * Templates can be found at https://github.com/0xProject/0x.js/tree/development/packages/abi-gen-templates. + */ +import {BigNumber} from 'bignumber.js'; +import * as Web3 from 'web3'; + +import {TxData, TxDataPayable} from '../../types'; +import {classUtils} from '../../utils/class_utils'; +import {promisify} from '../../utils/promisify'; + +import {BaseContract} from './base_contract'; + +export class ExchangeContract extends BaseContract { + public isRoundingError = { + async callAsync( + numerator: BigNumber, + denominator: BigNumber, + target: BigNumber, + defaultBlock?: Web3.BlockParam, + ): Promise<boolean + > { + const self = this as ExchangeContract; + const result = await promisify<boolean + >( + self.web3ContractInstance.isRoundingError.call, + self.web3ContractInstance, + )( + numerator, + denominator, + target, + ); + return result; + }, + }; + public filled = { + async callAsync( + index: string, + defaultBlock?: Web3.BlockParam, + ): Promise<BigNumber + > { + const self = this as ExchangeContract; + const result = await promisify<BigNumber + >( + self.web3ContractInstance.filled.call, + self.web3ContractInstance, + )( + index, + ); + return result; + }, + }; + public cancelled = { + async callAsync( + index: string, + defaultBlock?: Web3.BlockParam, + ): Promise<BigNumber + > { + const self = this as ExchangeContract; + const result = await promisify<BigNumber + >( + self.web3ContractInstance.cancelled.call, + self.web3ContractInstance, + )( + index, + ); + return result; + }, + }; + public fillOrdersUpTo = { + async sendTransactionAsync( + orderAddresses: string[][], + orderValues: BigNumber[][], + fillTakerTokenAmount: BigNumber, + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + v: number|BigNumber[], + r: string[], + s: string[], + txData: TxData = {}, + ): Promise<string> { + const self = this as ExchangeContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.fillOrdersUpTo.estimateGasAsync.bind( + self, + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.fillOrdersUpTo, self.web3ContractInstance, + )( + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + orderAddresses: string[][], + orderValues: BigNumber[][], + fillTakerTokenAmount: BigNumber, + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + v: number|BigNumber[], + r: string[], + s: string[], + txData: TxData = {}, + ): Promise<number> { + const self = this as ExchangeContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.fillOrdersUpTo.estimateGas, self.web3ContractInstance, + )( + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + orderAddresses: string[][], + orderValues: BigNumber[][], + fillTakerTokenAmount: BigNumber, + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + v: number|BigNumber[], + r: string[], + s: string[], + txData: TxData = {}, + ): string { + const self = this as ExchangeContract; + const abiEncodedTransactionData = self.web3ContractInstance.fillOrdersUpTo.getData(); + return abiEncodedTransactionData; + }, + }; + public cancelOrder = { + async sendTransactionAsync( + orderAddresses: string[], + orderValues: BigNumber[], + cancelTakerTokenAmount: BigNumber, + txData: TxData = {}, + ): Promise<string> { + const self = this as ExchangeContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.cancelOrder.estimateGasAsync.bind( + self, + orderAddresses, + orderValues, + cancelTakerTokenAmount, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.cancelOrder, self.web3ContractInstance, + )( + orderAddresses, + orderValues, + cancelTakerTokenAmount, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + orderAddresses: string[], + orderValues: BigNumber[], + cancelTakerTokenAmount: BigNumber, + txData: TxData = {}, + ): Promise<number> { + const self = this as ExchangeContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.cancelOrder.estimateGas, self.web3ContractInstance, + )( + orderAddresses, + orderValues, + cancelTakerTokenAmount, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + orderAddresses: string[], + orderValues: BigNumber[], + cancelTakerTokenAmount: BigNumber, + txData: TxData = {}, + ): string { + const self = this as ExchangeContract; + const abiEncodedTransactionData = self.web3ContractInstance.cancelOrder.getData(); + return abiEncodedTransactionData; + }, + }; + public ZRX_TOKEN_CONTRACT = { + async callAsync( + defaultBlock?: Web3.BlockParam, + ): Promise<string + > { + const self = this as ExchangeContract; + const result = await promisify<string + >( + self.web3ContractInstance.ZRX_TOKEN_CONTRACT.call, + self.web3ContractInstance, + )( + ); + return result; + }, + }; + public batchFillOrKillOrders = { + async sendTransactionAsync( + orderAddresses: string[][], + orderValues: BigNumber[][], + fillTakerTokenAmounts: BigNumber[], + v: number|BigNumber[], + r: string[], + s: string[], + txData: TxData = {}, + ): Promise<string> { + const self = this as ExchangeContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.batchFillOrKillOrders.estimateGasAsync.bind( + self, + orderAddresses, + orderValues, + fillTakerTokenAmounts, + v, + r, + s, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.batchFillOrKillOrders, self.web3ContractInstance, + )( + orderAddresses, + orderValues, + fillTakerTokenAmounts, + v, + r, + s, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + orderAddresses: string[][], + orderValues: BigNumber[][], + fillTakerTokenAmounts: BigNumber[], + v: number|BigNumber[], + r: string[], + s: string[], + txData: TxData = {}, + ): Promise<number> { + const self = this as ExchangeContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.batchFillOrKillOrders.estimateGas, self.web3ContractInstance, + )( + orderAddresses, + orderValues, + fillTakerTokenAmounts, + v, + r, + s, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + orderAddresses: string[][], + orderValues: BigNumber[][], + fillTakerTokenAmounts: BigNumber[], + v: number|BigNumber[], + r: string[], + s: string[], + txData: TxData = {}, + ): string { + const self = this as ExchangeContract; + const abiEncodedTransactionData = self.web3ContractInstance.batchFillOrKillOrders.getData(); + return abiEncodedTransactionData; + }, + }; + public fillOrKillOrder = { + async sendTransactionAsync( + orderAddresses: string[], + orderValues: BigNumber[], + fillTakerTokenAmount: BigNumber, + v: number|BigNumber, + r: string, + s: string, + txData: TxData = {}, + ): Promise<string> { + const self = this as ExchangeContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.fillOrKillOrder.estimateGasAsync.bind( + self, + orderAddresses, + orderValues, + fillTakerTokenAmount, + v, + r, + s, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.fillOrKillOrder, self.web3ContractInstance, + )( + orderAddresses, + orderValues, + fillTakerTokenAmount, + v, + r, + s, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + orderAddresses: string[], + orderValues: BigNumber[], + fillTakerTokenAmount: BigNumber, + v: number|BigNumber, + r: string, + s: string, + txData: TxData = {}, + ): Promise<number> { + const self = this as ExchangeContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.fillOrKillOrder.estimateGas, self.web3ContractInstance, + )( + orderAddresses, + orderValues, + fillTakerTokenAmount, + v, + r, + s, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + orderAddresses: string[], + orderValues: BigNumber[], + fillTakerTokenAmount: BigNumber, + v: number|BigNumber, + r: string, + s: string, + txData: TxData = {}, + ): string { + const self = this as ExchangeContract; + const abiEncodedTransactionData = self.web3ContractInstance.fillOrKillOrder.getData(); + return abiEncodedTransactionData; + }, + }; + public getUnavailableTakerTokenAmount = { + async callAsync( + orderHash: string, + defaultBlock?: Web3.BlockParam, + ): Promise<BigNumber + > { + const self = this as ExchangeContract; + const result = await promisify<BigNumber + >( + self.web3ContractInstance.getUnavailableTakerTokenAmount.call, + self.web3ContractInstance, + )( + orderHash, + ); + return result; + }, + }; + public isValidSignature = { + async callAsync( + signer: string, + hash: string, + v: number|BigNumber, + r: string, + s: string, + defaultBlock?: Web3.BlockParam, + ): Promise<boolean + > { + const self = this as ExchangeContract; + const result = await promisify<boolean + >( + self.web3ContractInstance.isValidSignature.call, + self.web3ContractInstance, + )( + signer, + hash, + v, + r, + s, + ); + return result; + }, + }; + public getPartialAmount = { + async callAsync( + numerator: BigNumber, + denominator: BigNumber, + target: BigNumber, + defaultBlock?: Web3.BlockParam, + ): Promise<BigNumber + > { + const self = this as ExchangeContract; + const result = await promisify<BigNumber + >( + self.web3ContractInstance.getPartialAmount.call, + self.web3ContractInstance, + )( + numerator, + denominator, + target, + ); + return result; + }, + }; + public TOKEN_TRANSFER_PROXY_CONTRACT = { + async callAsync( + defaultBlock?: Web3.BlockParam, + ): Promise<string + > { + const self = this as ExchangeContract; + const result = await promisify<string + >( + self.web3ContractInstance.TOKEN_TRANSFER_PROXY_CONTRACT.call, + self.web3ContractInstance, + )( + ); + return result; + }, + }; + public batchFillOrders = { + async sendTransactionAsync( + orderAddresses: string[][], + orderValues: BigNumber[][], + fillTakerTokenAmounts: BigNumber[], + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + v: number|BigNumber[], + r: string[], + s: string[], + txData: TxData = {}, + ): Promise<string> { + const self = this as ExchangeContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.batchFillOrders.estimateGasAsync.bind( + self, + orderAddresses, + orderValues, + fillTakerTokenAmounts, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.batchFillOrders, self.web3ContractInstance, + )( + orderAddresses, + orderValues, + fillTakerTokenAmounts, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + orderAddresses: string[][], + orderValues: BigNumber[][], + fillTakerTokenAmounts: BigNumber[], + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + v: number|BigNumber[], + r: string[], + s: string[], + txData: TxData = {}, + ): Promise<number> { + const self = this as ExchangeContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.batchFillOrders.estimateGas, self.web3ContractInstance, + )( + orderAddresses, + orderValues, + fillTakerTokenAmounts, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + orderAddresses: string[][], + orderValues: BigNumber[][], + fillTakerTokenAmounts: BigNumber[], + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + v: number|BigNumber[], + r: string[], + s: string[], + txData: TxData = {}, + ): string { + const self = this as ExchangeContract; + const abiEncodedTransactionData = self.web3ContractInstance.batchFillOrders.getData(); + return abiEncodedTransactionData; + }, + }; + public batchCancelOrders = { + async sendTransactionAsync( + orderAddresses: string[][], + orderValues: BigNumber[][], + cancelTakerTokenAmounts: BigNumber[], + txData: TxData = {}, + ): Promise<string> { + const self = this as ExchangeContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.batchCancelOrders.estimateGasAsync.bind( + self, + orderAddresses, + orderValues, + cancelTakerTokenAmounts, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.batchCancelOrders, self.web3ContractInstance, + )( + orderAddresses, + orderValues, + cancelTakerTokenAmounts, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + orderAddresses: string[][], + orderValues: BigNumber[][], + cancelTakerTokenAmounts: BigNumber[], + txData: TxData = {}, + ): Promise<number> { + const self = this as ExchangeContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.batchCancelOrders.estimateGas, self.web3ContractInstance, + )( + orderAddresses, + orderValues, + cancelTakerTokenAmounts, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + orderAddresses: string[][], + orderValues: BigNumber[][], + cancelTakerTokenAmounts: BigNumber[], + txData: TxData = {}, + ): string { + const self = this as ExchangeContract; + const abiEncodedTransactionData = self.web3ContractInstance.batchCancelOrders.getData(); + return abiEncodedTransactionData; + }, + }; + public fillOrder = { + async sendTransactionAsync( + orderAddresses: string[], + orderValues: BigNumber[], + fillTakerTokenAmount: BigNumber, + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + v: number|BigNumber, + r: string, + s: string, + txData: TxData = {}, + ): Promise<string> { + const self = this as ExchangeContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.fillOrder.estimateGasAsync.bind( + self, + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.fillOrder, self.web3ContractInstance, + )( + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + orderAddresses: string[], + orderValues: BigNumber[], + fillTakerTokenAmount: BigNumber, + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + v: number|BigNumber, + r: string, + s: string, + txData: TxData = {}, + ): Promise<number> { + const self = this as ExchangeContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.fillOrder.estimateGas, self.web3ContractInstance, + )( + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + orderAddresses: string[], + orderValues: BigNumber[], + fillTakerTokenAmount: BigNumber, + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + v: number|BigNumber, + r: string, + s: string, + txData: TxData = {}, + ): string { + const self = this as ExchangeContract; + const abiEncodedTransactionData = self.web3ContractInstance.fillOrder.getData(); + return abiEncodedTransactionData; + }, + }; + public getOrderHash = { + async callAsync( + orderAddresses: string[], + orderValues: BigNumber[], + defaultBlock?: Web3.BlockParam, + ): Promise<string + > { + const self = this as ExchangeContract; + const result = await promisify<string + >( + self.web3ContractInstance.getOrderHash.call, + self.web3ContractInstance, + )( + orderAddresses, + orderValues, + ); + return result; + }, + }; + public EXTERNAL_QUERY_GAS_LIMIT = { + async callAsync( + defaultBlock?: Web3.BlockParam, + ): Promise<BigNumber + > { + const self = this as ExchangeContract; + const result = await promisify<BigNumber + >( + self.web3ContractInstance.EXTERNAL_QUERY_GAS_LIMIT.call, + self.web3ContractInstance, + )( + ); + return result; + }, + }; + public VERSION = { + async callAsync( + defaultBlock?: Web3.BlockParam, + ): Promise<string + > { + const self = this as ExchangeContract; + const result = await promisify<string + >( + self.web3ContractInstance.VERSION.call, + self.web3ContractInstance, + )( + ); + return result; + }, + }; + constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) { + super(web3ContractInstance, defaults); + classUtils.bindAll(this, ['web3ContractInstance', 'defaults']); + } +} // tslint:disable:max-file-line-count diff --git a/packages/0x.js/src/contract_wrappers/generated/token.ts b/packages/0x.js/src/contract_wrappers/generated/token.ts new file mode 100644 index 000000000..30b06292f --- /dev/null +++ b/packages/0x.js/src/contract_wrappers/generated/token.ts @@ -0,0 +1,232 @@ +/** + * This file is auto-generated using abi-gen. Don't edit directly. + * Templates can be found at https://github.com/0xProject/0x.js/tree/development/packages/abi-gen-templates. + */ +import {BigNumber} from 'bignumber.js'; +import * as Web3 from 'web3'; + +import {TxData, TxDataPayable} from '../../types'; +import {classUtils} from '../../utils/class_utils'; +import {promisify} from '../../utils/promisify'; + +import {BaseContract} from './base_contract'; + +export class TokenContract extends BaseContract { + public approve = { + async sendTransactionAsync( + _spender: string, + _value: BigNumber, + txData: TxData = {}, + ): Promise<string> { + const self = this as TokenContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.approve.estimateGasAsync.bind( + self, + _spender, + _value, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.approve, self.web3ContractInstance, + )( + _spender, + _value, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + _spender: string, + _value: BigNumber, + txData: TxData = {}, + ): Promise<number> { + const self = this as TokenContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.approve.estimateGas, self.web3ContractInstance, + )( + _spender, + _value, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + _spender: string, + _value: BigNumber, + txData: TxData = {}, + ): string { + const self = this as TokenContract; + const abiEncodedTransactionData = self.web3ContractInstance.approve.getData(); + return abiEncodedTransactionData; + }, + }; + public totalSupply = { + async callAsync( + defaultBlock?: Web3.BlockParam, + ): Promise<BigNumber + > { + const self = this as TokenContract; + const result = await promisify<BigNumber + >( + self.web3ContractInstance.totalSupply.call, + self.web3ContractInstance, + )( + ); + return result; + }, + }; + public transferFrom = { + async sendTransactionAsync( + _from: string, + _to: string, + _value: BigNumber, + txData: TxData = {}, + ): Promise<string> { + const self = this as TokenContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.transferFrom.estimateGasAsync.bind( + self, + _from, + _to, + _value, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.transferFrom, self.web3ContractInstance, + )( + _from, + _to, + _value, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + _from: string, + _to: string, + _value: BigNumber, + txData: TxData = {}, + ): Promise<number> { + const self = this as TokenContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.transferFrom.estimateGas, self.web3ContractInstance, + )( + _from, + _to, + _value, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + _from: string, + _to: string, + _value: BigNumber, + txData: TxData = {}, + ): string { + const self = this as TokenContract; + const abiEncodedTransactionData = self.web3ContractInstance.transferFrom.getData(); + return abiEncodedTransactionData; + }, + }; + public balanceOf = { + async callAsync( + _owner: string, + defaultBlock?: Web3.BlockParam, + ): Promise<BigNumber + > { + const self = this as TokenContract; + const result = await promisify<BigNumber + >( + self.web3ContractInstance.balanceOf.call, + self.web3ContractInstance, + )( + _owner, + ); + return result; + }, + }; + public transfer = { + async sendTransactionAsync( + _to: string, + _value: BigNumber, + txData: TxData = {}, + ): Promise<string> { + const self = this as TokenContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.transfer.estimateGasAsync.bind( + self, + _to, + _value, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.transfer, self.web3ContractInstance, + )( + _to, + _value, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + _to: string, + _value: BigNumber, + txData: TxData = {}, + ): Promise<number> { + const self = this as TokenContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.transfer.estimateGas, self.web3ContractInstance, + )( + _to, + _value, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + _to: string, + _value: BigNumber, + txData: TxData = {}, + ): string { + const self = this as TokenContract; + const abiEncodedTransactionData = self.web3ContractInstance.transfer.getData(); + return abiEncodedTransactionData; + }, + }; + public allowance = { + async callAsync( + _owner: string, + _spender: string, + defaultBlock?: Web3.BlockParam, + ): Promise<BigNumber + > { + const self = this as TokenContract; + const result = await promisify<BigNumber + >( + self.web3ContractInstance.allowance.call, + self.web3ContractInstance, + )( + _owner, + _spender, + ); + return result; + }, + }; + constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) { + super(web3ContractInstance, defaults); + classUtils.bindAll(this, ['web3ContractInstance', 'defaults']); + } +} // tslint:disable:max-file-line-count diff --git a/packages/0x.js/src/contract_wrappers/generated/token_registry.ts b/packages/0x.js/src/contract_wrappers/generated/token_registry.ts new file mode 100644 index 000000000..6aacc4336 --- /dev/null +++ b/packages/0x.js/src/contract_wrappers/generated/token_registry.ts @@ -0,0 +1,550 @@ +/** + * This file is auto-generated using abi-gen. Don't edit directly. + * Templates can be found at https://github.com/0xProject/0x.js/tree/development/packages/abi-gen-templates. + */ +import {BigNumber} from 'bignumber.js'; +import * as Web3 from 'web3'; + +import {TxData, TxDataPayable} from '../../types'; +import {classUtils} from '../../utils/class_utils'; +import {promisify} from '../../utils/promisify'; + +import {BaseContract} from './base_contract'; + +export class TokenRegistryContract extends BaseContract { + public removeToken = { + async sendTransactionAsync( + _token: string, + _index: BigNumber, + txData: TxData = {}, + ): Promise<string> { + const self = this as TokenRegistryContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.removeToken.estimateGasAsync.bind( + self, + _token, + _index, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.removeToken, self.web3ContractInstance, + )( + _token, + _index, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + _token: string, + _index: BigNumber, + txData: TxData = {}, + ): Promise<number> { + const self = this as TokenRegistryContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.removeToken.estimateGas, self.web3ContractInstance, + )( + _token, + _index, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + _token: string, + _index: BigNumber, + txData: TxData = {}, + ): string { + const self = this as TokenRegistryContract; + const abiEncodedTransactionData = self.web3ContractInstance.removeToken.getData(); + return abiEncodedTransactionData; + }, + }; + public getTokenAddressByName = { + async callAsync( + _name: string, + defaultBlock?: Web3.BlockParam, + ): Promise<string + > { + const self = this as TokenRegistryContract; + const result = await promisify<string + >( + self.web3ContractInstance.getTokenAddressByName.call, + self.web3ContractInstance, + )( + _name, + ); + return result; + }, + }; + public getTokenAddressBySymbol = { + async callAsync( + _symbol: string, + defaultBlock?: Web3.BlockParam, + ): Promise<string + > { + const self = this as TokenRegistryContract; + const result = await promisify<string + >( + self.web3ContractInstance.getTokenAddressBySymbol.call, + self.web3ContractInstance, + )( + _symbol, + ); + return result; + }, + }; + public setTokenSwarmHash = { + async sendTransactionAsync( + _token: string, + _swarmHash: string, + txData: TxData = {}, + ): Promise<string> { + const self = this as TokenRegistryContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.setTokenSwarmHash.estimateGasAsync.bind( + self, + _token, + _swarmHash, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.setTokenSwarmHash, self.web3ContractInstance, + )( + _token, + _swarmHash, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + _token: string, + _swarmHash: string, + txData: TxData = {}, + ): Promise<number> { + const self = this as TokenRegistryContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.setTokenSwarmHash.estimateGas, self.web3ContractInstance, + )( + _token, + _swarmHash, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + _token: string, + _swarmHash: string, + txData: TxData = {}, + ): string { + const self = this as TokenRegistryContract; + const abiEncodedTransactionData = self.web3ContractInstance.setTokenSwarmHash.getData(); + return abiEncodedTransactionData; + }, + }; + public getTokenMetaData = { + async callAsync( + _token: string, + defaultBlock?: Web3.BlockParam, + ): Promise<[string, string, string, BigNumber, string, string] + > { + const self = this as TokenRegistryContract; + const result = await promisify<[string, string, string, BigNumber, string, string] + >( + self.web3ContractInstance.getTokenMetaData.call, + self.web3ContractInstance, + )( + _token, + ); + return result; + }, + }; + public owner = { + async callAsync( + defaultBlock?: Web3.BlockParam, + ): Promise<string + > { + const self = this as TokenRegistryContract; + const result = await promisify<string + >( + self.web3ContractInstance.owner.call, + self.web3ContractInstance, + )( + ); + return result; + }, + }; + public addToken = { + async sendTransactionAsync( + _token: string, + _name: string, + _symbol: string, + _decimals: number|BigNumber, + _ipfsHash: string, + _swarmHash: string, + txData: TxData = {}, + ): Promise<string> { + const self = this as TokenRegistryContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.addToken.estimateGasAsync.bind( + self, + _token, + _name, + _symbol, + _decimals, + _ipfsHash, + _swarmHash, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.addToken, self.web3ContractInstance, + )( + _token, + _name, + _symbol, + _decimals, + _ipfsHash, + _swarmHash, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + _token: string, + _name: string, + _symbol: string, + _decimals: number|BigNumber, + _ipfsHash: string, + _swarmHash: string, + txData: TxData = {}, + ): Promise<number> { + const self = this as TokenRegistryContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.addToken.estimateGas, self.web3ContractInstance, + )( + _token, + _name, + _symbol, + _decimals, + _ipfsHash, + _swarmHash, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + _token: string, + _name: string, + _symbol: string, + _decimals: number|BigNumber, + _ipfsHash: string, + _swarmHash: string, + txData: TxData = {}, + ): string { + const self = this as TokenRegistryContract; + const abiEncodedTransactionData = self.web3ContractInstance.addToken.getData(); + return abiEncodedTransactionData; + }, + }; + public setTokenName = { + async sendTransactionAsync( + _token: string, + _name: string, + txData: TxData = {}, + ): Promise<string> { + const self = this as TokenRegistryContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.setTokenName.estimateGasAsync.bind( + self, + _token, + _name, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.setTokenName, self.web3ContractInstance, + )( + _token, + _name, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + _token: string, + _name: string, + txData: TxData = {}, + ): Promise<number> { + const self = this as TokenRegistryContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.setTokenName.estimateGas, self.web3ContractInstance, + )( + _token, + _name, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + _token: string, + _name: string, + txData: TxData = {}, + ): string { + const self = this as TokenRegistryContract; + const abiEncodedTransactionData = self.web3ContractInstance.setTokenName.getData(); + return abiEncodedTransactionData; + }, + }; + public tokens = { + async callAsync( + index: string, + defaultBlock?: Web3.BlockParam, + ): Promise<[string, string, string, BigNumber, string, string] + > { + const self = this as TokenRegistryContract; + const result = await promisify<[string, string, string, BigNumber, string, string] + >( + self.web3ContractInstance.tokens.call, + self.web3ContractInstance, + )( + index, + ); + return result; + }, + }; + public tokenAddresses = { + async callAsync( + index: BigNumber, + defaultBlock?: Web3.BlockParam, + ): Promise<string + > { + const self = this as TokenRegistryContract; + const result = await promisify<string + >( + self.web3ContractInstance.tokenAddresses.call, + self.web3ContractInstance, + )( + index, + ); + return result; + }, + }; + public getTokenByName = { + async callAsync( + _name: string, + defaultBlock?: Web3.BlockParam, + ): Promise<[string, string, string, BigNumber, string, string] + > { + const self = this as TokenRegistryContract; + const result = await promisify<[string, string, string, BigNumber, string, string] + >( + self.web3ContractInstance.getTokenByName.call, + self.web3ContractInstance, + )( + _name, + ); + return result; + }, + }; + public getTokenAddresses = { + async callAsync( + defaultBlock?: Web3.BlockParam, + ): Promise<string[] + > { + const self = this as TokenRegistryContract; + const result = await promisify<string[] + >( + self.web3ContractInstance.getTokenAddresses.call, + self.web3ContractInstance, + )( + ); + return result; + }, + }; + public setTokenIpfsHash = { + async sendTransactionAsync( + _token: string, + _ipfsHash: string, + txData: TxData = {}, + ): Promise<string> { + const self = this as TokenRegistryContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.setTokenIpfsHash.estimateGasAsync.bind( + self, + _token, + _ipfsHash, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.setTokenIpfsHash, self.web3ContractInstance, + )( + _token, + _ipfsHash, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + _token: string, + _ipfsHash: string, + txData: TxData = {}, + ): Promise<number> { + const self = this as TokenRegistryContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.setTokenIpfsHash.estimateGas, self.web3ContractInstance, + )( + _token, + _ipfsHash, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + _token: string, + _ipfsHash: string, + txData: TxData = {}, + ): string { + const self = this as TokenRegistryContract; + const abiEncodedTransactionData = self.web3ContractInstance.setTokenIpfsHash.getData(); + return abiEncodedTransactionData; + }, + }; + public getTokenBySymbol = { + async callAsync( + _symbol: string, + defaultBlock?: Web3.BlockParam, + ): Promise<[string, string, string, BigNumber, string, string] + > { + const self = this as TokenRegistryContract; + const result = await promisify<[string, string, string, BigNumber, string, string] + >( + self.web3ContractInstance.getTokenBySymbol.call, + self.web3ContractInstance, + )( + _symbol, + ); + return result; + }, + }; + public setTokenSymbol = { + async sendTransactionAsync( + _token: string, + _symbol: string, + txData: TxData = {}, + ): Promise<string> { + const self = this as TokenRegistryContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.setTokenSymbol.estimateGasAsync.bind( + self, + _token, + _symbol, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.setTokenSymbol, self.web3ContractInstance, + )( + _token, + _symbol, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + _token: string, + _symbol: string, + txData: TxData = {}, + ): Promise<number> { + const self = this as TokenRegistryContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.setTokenSymbol.estimateGas, self.web3ContractInstance, + )( + _token, + _symbol, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + _token: string, + _symbol: string, + txData: TxData = {}, + ): string { + const self = this as TokenRegistryContract; + const abiEncodedTransactionData = self.web3ContractInstance.setTokenSymbol.getData(); + return abiEncodedTransactionData; + }, + }; + public transferOwnership = { + async sendTransactionAsync( + newOwner: string, + txData: TxData = {}, + ): Promise<string> { + const self = this as TokenRegistryContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.transferOwnership.estimateGasAsync.bind( + self, + newOwner, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.transferOwnership, self.web3ContractInstance, + )( + newOwner, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + newOwner: string, + txData: TxData = {}, + ): Promise<number> { + const self = this as TokenRegistryContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.transferOwnership.estimateGas, self.web3ContractInstance, + )( + newOwner, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + newOwner: string, + txData: TxData = {}, + ): string { + const self = this as TokenRegistryContract; + const abiEncodedTransactionData = self.web3ContractInstance.transferOwnership.getData(); + return abiEncodedTransactionData; + }, + }; + constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) { + super(web3ContractInstance, defaults); + classUtils.bindAll(this, ['web3ContractInstance', 'defaults']); + } +} // tslint:disable:max-file-line-count diff --git a/packages/0x.js/src/contract_wrappers/generated/token_transfer_proxy.ts b/packages/0x.js/src/contract_wrappers/generated/token_transfer_proxy.ts new file mode 100644 index 000000000..50f1c8f25 --- /dev/null +++ b/packages/0x.js/src/contract_wrappers/generated/token_transfer_proxy.ts @@ -0,0 +1,285 @@ +/** + * This file is auto-generated using abi-gen. Don't edit directly. + * Templates can be found at https://github.com/0xProject/0x.js/tree/development/packages/abi-gen-templates. + */ +import {BigNumber} from 'bignumber.js'; +import * as Web3 from 'web3'; + +import {TxData, TxDataPayable} from '../../types'; +import {classUtils} from '../../utils/class_utils'; +import {promisify} from '../../utils/promisify'; + +import {BaseContract} from './base_contract'; + +export class TokenTransferProxyContract extends BaseContract { + public transferFrom = { + async sendTransactionAsync( + token: string, + from: string, + to: string, + value: BigNumber, + txData: TxData = {}, + ): Promise<string> { + const self = this as TokenTransferProxyContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.transferFrom.estimateGasAsync.bind( + self, + token, + from, + to, + value, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.transferFrom, self.web3ContractInstance, + )( + token, + from, + to, + value, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + token: string, + from: string, + to: string, + value: BigNumber, + txData: TxData = {}, + ): Promise<number> { + const self = this as TokenTransferProxyContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.transferFrom.estimateGas, self.web3ContractInstance, + )( + token, + from, + to, + value, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + token: string, + from: string, + to: string, + value: BigNumber, + txData: TxData = {}, + ): string { + const self = this as TokenTransferProxyContract; + const abiEncodedTransactionData = self.web3ContractInstance.transferFrom.getData(); + return abiEncodedTransactionData; + }, + }; + public addAuthorizedAddress = { + async sendTransactionAsync( + target: string, + txData: TxData = {}, + ): Promise<string> { + const self = this as TokenTransferProxyContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.addAuthorizedAddress.estimateGasAsync.bind( + self, + target, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.addAuthorizedAddress, self.web3ContractInstance, + )( + target, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + target: string, + txData: TxData = {}, + ): Promise<number> { + const self = this as TokenTransferProxyContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.addAuthorizedAddress.estimateGas, self.web3ContractInstance, + )( + target, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + target: string, + txData: TxData = {}, + ): string { + const self = this as TokenTransferProxyContract; + const abiEncodedTransactionData = self.web3ContractInstance.addAuthorizedAddress.getData(); + return abiEncodedTransactionData; + }, + }; + public authorities = { + async callAsync( + index: BigNumber, + defaultBlock?: Web3.BlockParam, + ): Promise<string + > { + const self = this as TokenTransferProxyContract; + const result = await promisify<string + >( + self.web3ContractInstance.authorities.call, + self.web3ContractInstance, + )( + index, + ); + return result; + }, + }; + public removeAuthorizedAddress = { + async sendTransactionAsync( + target: string, + txData: TxData = {}, + ): Promise<string> { + const self = this as TokenTransferProxyContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.removeAuthorizedAddress.estimateGasAsync.bind( + self, + target, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.removeAuthorizedAddress, self.web3ContractInstance, + )( + target, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + target: string, + txData: TxData = {}, + ): Promise<number> { + const self = this as TokenTransferProxyContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.removeAuthorizedAddress.estimateGas, self.web3ContractInstance, + )( + target, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + target: string, + txData: TxData = {}, + ): string { + const self = this as TokenTransferProxyContract; + const abiEncodedTransactionData = self.web3ContractInstance.removeAuthorizedAddress.getData(); + return abiEncodedTransactionData; + }, + }; + public owner = { + async callAsync( + defaultBlock?: Web3.BlockParam, + ): Promise<string + > { + const self = this as TokenTransferProxyContract; + const result = await promisify<string + >( + self.web3ContractInstance.owner.call, + self.web3ContractInstance, + )( + ); + return result; + }, + }; + public authorized = { + async callAsync( + index: string, + defaultBlock?: Web3.BlockParam, + ): Promise<boolean + > { + const self = this as TokenTransferProxyContract; + const result = await promisify<boolean + >( + self.web3ContractInstance.authorized.call, + self.web3ContractInstance, + )( + index, + ); + return result; + }, + }; + public getAuthorizedAddresses = { + async callAsync( + defaultBlock?: Web3.BlockParam, + ): Promise<string[] + > { + const self = this as TokenTransferProxyContract; + const result = await promisify<string[] + >( + self.web3ContractInstance.getAuthorizedAddresses.call, + self.web3ContractInstance, + )( + ); + return result; + }, + }; + public transferOwnership = { + async sendTransactionAsync( + newOwner: string, + txData: TxData = {}, + ): Promise<string> { + const self = this as TokenTransferProxyContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.transferOwnership.estimateGasAsync.bind( + self, + newOwner, + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.transferOwnership, self.web3ContractInstance, + )( + newOwner, + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + newOwner: string, + txData: TxData = {}, + ): Promise<number> { + const self = this as TokenTransferProxyContract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.transferOwnership.estimateGas, self.web3ContractInstance, + )( + newOwner, + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + newOwner: string, + txData: TxData = {}, + ): string { + const self = this as TokenTransferProxyContract; + const abiEncodedTransactionData = self.web3ContractInstance.transferOwnership.getData(); + return abiEncodedTransactionData; + }, + }; + constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) { + super(web3ContractInstance, defaults); + classUtils.bindAll(this, ['web3ContractInstance', 'defaults']); + } +} // tslint:disable:max-file-line-count diff --git a/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts b/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts index 35337fa35..27ecb8bde 100644 --- a/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts @@ -1,12 +1,13 @@ import * as _ from 'lodash'; import {artifacts} from '../artifacts'; -import {Token, TokenMetadata, TokenRegistryContract, ZeroExError} from '../types'; +import {Token, TokenMetadata, ZeroExError} from '../types'; import {assert} from '../utils/assert'; import {constants} from '../utils/constants'; import {Web3Wrapper} from '../web3_wrapper'; import {ContractWrapper} from './contract_wrapper'; +import {TokenRegistryContract} from './generated/token_registry'; /** * This class includes all the functionality related to interacting with the 0x Token Registry smart contract. @@ -116,9 +117,12 @@ export class TokenRegistryWrapper extends ContractWrapper { if (!_.isUndefined(this._tokenRegistryContractIfExists)) { return this._tokenRegistryContractIfExists; } - const contractInstance = await this._instantiateContractIfExistsAsync<TokenRegistryContract>( + const web3ContractInstance = await this._instantiateContractIfExistsAsync( artifacts.TokenRegistryArtifact, this._contractAddressIfExists, ); + const contractInstance = new TokenRegistryContract( + web3ContractInstance, this._web3Wrapper.getContractDefaults(), + ); this._tokenRegistryContractIfExists = contractInstance; return this._tokenRegistryContractIfExists; } diff --git a/packages/0x.js/src/contract_wrappers/token_transfer_proxy_wrapper.ts b/packages/0x.js/src/contract_wrappers/token_transfer_proxy_wrapper.ts index c3df7d3eb..edc702672 100644 --- a/packages/0x.js/src/contract_wrappers/token_transfer_proxy_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/token_transfer_proxy_wrapper.ts @@ -1,10 +1,11 @@ import * as _ from 'lodash'; import {artifacts} from '../artifacts'; -import {TokenTransferProxyContract, ZeroExError} from '../types'; +import {ZeroExError} from '../types'; import {Web3Wrapper} from '../web3_wrapper'; import {ContractWrapper} from './contract_wrapper'; +import {TokenTransferProxyContract} from './generated/token_transfer_proxy'; /** * This class includes the functionality related to interacting with the TokenTransferProxy contract. @@ -53,9 +54,12 @@ export class TokenTransferProxyWrapper extends ContractWrapper { if (!_.isUndefined(this._tokenTransferProxyContractIfExists)) { return this._tokenTransferProxyContractIfExists; } - const contractInstance = await this._instantiateContractIfExistsAsync<TokenTransferProxyContract>( + const web3ContractInstance = await this._instantiateContractIfExistsAsync( artifacts.TokenTransferProxyArtifact, this._contractAddressIfExists, ); + const contractInstance = new TokenTransferProxyContract( + web3ContractInstance, this._web3Wrapper.getContractDefaults(), + ); this._tokenTransferProxyContractIfExists = contractInstance; return this._tokenTransferProxyContractIfExists; } diff --git a/packages/0x.js/src/contract_wrappers/token_wrapper.ts b/packages/0x.js/src/contract_wrappers/token_wrapper.ts index 4a1dfcf8d..630ab6e3b 100644 --- a/packages/0x.js/src/contract_wrappers/token_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/token_wrapper.ts @@ -9,7 +9,6 @@ import { LogWithDecodedArgs, MethodOpts, SubscriptionOpts, - TokenContract, TokenContractEventArgs, TokenEvents, TransactionOpts, @@ -21,6 +20,7 @@ import {constants} from '../utils/constants'; import {Web3Wrapper} from '../web3_wrapper'; import {ContractWrapper} from './contract_wrapper'; +import {TokenContract} from './generated/token'; import {TokenTransferProxyWrapper} from './token_transfer_proxy_wrapper'; const ALLOWANCE_TO_ZERO_GAS_AMOUNT = 47275; @@ -313,9 +313,12 @@ export class TokenWrapper extends ContractWrapper { if (!_.isUndefined(tokenContract)) { return tokenContract; } - const contractInstance = await this._instantiateContractIfExistsAsync<TokenContract>( + const web3ContractInstance = await this._instantiateContractIfExistsAsync( artifacts.TokenArtifact, tokenAddress, ); + const contractInstance = new TokenContract( + web3ContractInstance, this._web3Wrapper.getContractDefaults(), + ); tokenContract = contractInstance; this._tokenContractsByAddress[tokenAddress] = tokenContract; return tokenContract; diff --git a/packages/0x.js/src/globals.d.ts b/packages/0x.js/src/globals.d.ts index cb3800056..4fa1cfd9c 100644 --- a/packages/0x.js/src/globals.d.ts +++ b/packages/0x.js/src/globals.d.ts @@ -39,12 +39,6 @@ declare module 'compare-versions' { export = compareVersions; } -// es6-promisify declarations -declare function promisify(original: any, settings?: any): ((...arg: any[]) => Promise<any>); -declare module 'es6-promisify' { - export = promisify; -} - declare module 'ethereumjs-abi' { const soliditySHA3: (argTypes: string[], args: any[]) => Buffer; } diff --git a/packages/0x.js/src/types.ts b/packages/0x.js/src/types.ts index 5363b02ff..3586919cb 100644 --- a/packages/0x.js/src/types.ts +++ b/packages/0x.js/src/types.ts @@ -52,156 +52,6 @@ export interface DecodedLogEvent<ArgsType> { export type EventCallback<ArgsType> = (err: null|Error, log?: DecodedLogEvent<ArgsType>) => void; export type EventWatcherCallback = (log: LogEvent) => void; -export interface ExchangeContract extends Web3.ContractInstance { - isValidSignature: { - callAsync: (signerAddressHex: string, dataHex: string, v: number, r: string, s: string, - txOpts?: TxOpts) => Promise<boolean>; - }; - ZRX_TOKEN_CONTRACT: { - callAsync: () => Promise<string>; - }; - TOKEN_TRANSFER_PROXY_CONTRACT: { - callAsync: () => Promise<string>; - }; - getUnavailableTakerTokenAmount: { - callAsync: (orderHash: string, defaultBlock?: Web3.BlockParam) => Promise<BigNumber>; - }; - isRoundingError: { - callAsync: (takerTokenFillAmount: BigNumber, takerTokenAmount: BigNumber, - makerTokenAmount: BigNumber, txOpts?: TxOpts) => Promise<boolean>; - }; - fillOrder: { - sendTransactionAsync: (orderAddresses: OrderAddresses, orderValues: OrderValues, - fillTakerTokenAmount: BigNumber, - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - v: number, r: string, s: string, txOpts?: TxOpts) => Promise<string>; - estimateGasAsync: (orderAddresses: OrderAddresses, orderValues: OrderValues, - fillTakerTokenAmount: BigNumber, - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - v: number, r: string, s: string, txOpts?: TxOpts) => Promise<number>; - }; - batchFillOrders: { - sendTransactionAsync: (orderAddresses: OrderAddresses[], orderValues: OrderValues[], - fillTakerTokenAmounts: BigNumber[], - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - v: number[], r: string[], s: string[], txOpts?: TxOpts) => Promise<string>; - estimateGasAsync: (orderAddresses: OrderAddresses[], orderValues: OrderValues[], - fillTakerTokenAmounts: BigNumber[], - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - v: number[], r: string[], s: string[], txOpts?: TxOpts) => Promise<number>; - }; - fillOrdersUpTo: { - sendTransactionAsync: (orderAddresses: OrderAddresses[], orderValues: OrderValues[], - fillTakerTokenAmount: BigNumber, - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - v: number[], r: string[], s: string[], txOpts?: TxOpts) => Promise<string>; - estimateGasAsync: (orderAddresses: OrderAddresses[], orderValues: OrderValues[], - fillTakerTokenAmount: BigNumber, - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - v: number[], r: string[], s: string[], txOpts?: TxOpts) => Promise<number>; - }; - cancelOrder: { - sendTransactionAsync: (orderAddresses: OrderAddresses, orderValues: OrderValues, - cancelTakerTokenAmount: BigNumber, txOpts?: TxOpts) => Promise<string>; - estimateGasAsync: (orderAddresses: OrderAddresses, orderValues: OrderValues, - cancelTakerTokenAmount: BigNumber, - txOpts?: TxOpts) => Promise<number>; - }; - batchCancelOrders: { - sendTransactionAsync: (orderAddresses: OrderAddresses[], orderValues: OrderValues[], - cancelTakerTokenAmounts: BigNumber[], txOpts?: TxOpts) => Promise<string>; - estimateGasAsync: (orderAddresses: OrderAddresses[], orderValues: OrderValues[], - cancelTakerTokenAmounts: BigNumber[], - txOpts?: TxOpts) => Promise<number>; - }; - fillOrKillOrder: { - sendTransactionAsync: (orderAddresses: OrderAddresses, orderValues: OrderValues, - fillTakerTokenAmount: BigNumber, - v: number, r: string, s: string, txOpts?: TxOpts) => Promise<string>; - estimateGasAsync: (orderAddresses: OrderAddresses, orderValues: OrderValues, - fillTakerTokenAmount: BigNumber, - v: number, r: string, s: string, txOpts?: TxOpts) => Promise<number>; - }; - batchFillOrKillOrders: { - sendTransactionAsync: (orderAddresses: OrderAddresses[], orderValues: OrderValues[], - fillTakerTokenAmounts: BigNumber[], - v: number[], r: string[], s: string[], txOpts: TxOpts) => Promise<string>; - estimateGasAsync: (orderAddresses: OrderAddresses[], orderValues: OrderValues[], - fillTakerTokenAmounts: BigNumber[], - v: number[], r: string[], s: string[], txOpts?: TxOpts) => Promise<number>; - }; - filled: { - callAsync: (orderHash: string, defaultBlock?: Web3.BlockParam) => Promise<BigNumber>; - }; - cancelled: { - callAsync: (orderHash: string, defaultBlock?: Web3.BlockParam) => Promise<BigNumber>; - }; - getOrderHash: { - callAsync: (orderAddresses: OrderAddresses, orderValues: OrderValues) => Promise<string>; - }; -} - -export interface TokenContract extends Web3.ContractInstance { - balanceOf: { - callAsync: (address: string, defaultBlock?: Web3.BlockParam) => Promise<BigNumber>; - }; - allowance: { - callAsync: (ownerAddress: string, allowedAddress: string, - defaultBlock?: Web3.BlockParam) => Promise<BigNumber>; - }; - transfer: { - sendTransactionAsync: (toAddress: string, amountInBaseUnits: BigNumber, - txOpts?: TxOpts) => Promise<string>; - }; - transferFrom: { - sendTransactionAsync: (fromAddress: string, toAddress: string, amountInBaseUnits: BigNumber, - txOpts?: TxOpts) => Promise<string>; - }; - approve: { - sendTransactionAsync: (proxyAddress: string, amountInBaseUnits: BigNumber, - txOpts?: TxOpts) => Promise<string>; - }; -} - -export interface TokenRegistryContract extends Web3.ContractInstance { - getTokenMetaData: { - callAsync: (address: string) => Promise<TokenMetadata>; - }; - getTokenAddresses: { - callAsync: () => Promise<string[]>; - }; - getTokenAddressBySymbol: { - callAsync: (symbol: string) => Promise<string>; - }; - getTokenAddressByName: { - callAsync: (name: string) => Promise<string>; - }; - getTokenBySymbol: { - callAsync: (symbol: string) => Promise<TokenMetadata>; - }; - getTokenByName: { - callAsync: (name: string) => Promise<TokenMetadata>; - }; -} - -export interface EtherTokenContract extends Web3.ContractInstance { - deposit: { - sendTransactionAsync: (txOpts: TxOpts) => Promise<string>; - }; - withdraw: { - sendTransactionAsync: (amount: BigNumber, txOpts: TxOpts) => Promise<string>; - }; -} - -export interface TokenTransferProxyContract extends Web3.ContractInstance { - getAuthorizedAddresses: { - callAsync: () => Promise<string[]>; - }; - authorized: { - callAsync: (address: string) => Promise<boolean>; - }; -} - export enum SolidityTypes { Address = 'address', Uint256 = 'uint256', @@ -393,10 +243,6 @@ export type AsyncMethod = (...args: any[]) => Promise<any>; */ export type Web3Provider = Web3.Provider; -export interface ExchangeContractByAddress { - [address: string]: ExchangeContract; -} - export interface JSONRPCPayload { params: any[]; method: string; @@ -540,6 +386,17 @@ export type OrderState = OrderStateValid|OrderStateInvalid; export type OnOrderStateChangeCallback = (orderState: OrderState) => void; +export interface TxData { + from?: string; + gas?: number; + gasPrice?: BigNumber; + nonce?: number; +} + +export interface TxDataPayable extends TxData { + value?: BigNumber; +} + export interface TransactionReceipt { blockHash: string; blockNumber: number; diff --git a/packages/0x.js/src/utils/class_utils.ts b/packages/0x.js/src/utils/class_utils.ts new file mode 100644 index 000000000..04e60ee57 --- /dev/null +++ b/packages/0x.js/src/utils/class_utils.ts @@ -0,0 +1,18 @@ +import * as _ from 'lodash'; + +export const classUtils = { + // This is useful for classes that have nested methods. Nested methods don't get bound out of the box. + bindAll(self: any, exclude: string[] = ['contructor'], thisArg?: any): void { + for (const key of Object.getOwnPropertyNames(self)) { + const val = self[key]; + if (!_.includes(exclude, key)) { + if (_.isFunction(val)) { + self[key] = val.bind(thisArg || self); + } else if (_.isObject(val)) { + classUtils.bindAll(val, exclude, self); + } + } + } + return self; + }, +}; diff --git a/packages/0x.js/src/utils/promisify.ts b/packages/0x.js/src/utils/promisify.ts new file mode 100644 index 000000000..c114cf32f --- /dev/null +++ b/packages/0x.js/src/utils/promisify.ts @@ -0,0 +1,24 @@ +import * as _ from 'lodash'; + +/** + * Transforms callback-based function -- func(arg1, arg2 .. argN, callback) -- into an ES6-compatible Promise. + * Promisify provides a default callback of the form (error, result) and rejects when `error` is not null. You can also + * supply thisArg object as the second argument which will be passed to `apply`. + */ +export function promisify<T>( + originalFn: ( + ...args: any[], + // HACK: This can't be properly typed without variadic kinds https://github.com/Microsoft/TypeScript/issues/5453 + ) => void, + thisArg?: any, +): (...callArgs: any[]) => Promise<T> { + const promisifiedFunction = async (...callArgs: any[]): Promise<T> => { + return new Promise<T>((resolve, reject) => { + const callback = (err: Error|null, data?: T) => { + _.isNull(err) ? resolve(data) : reject(err); + }; + originalFn.apply(thisArg, [...callArgs, callback]); + }); + }; + return promisifiedFunction; +} diff --git a/packages/0x.js/src/web3_wrapper.ts b/packages/0x.js/src/web3_wrapper.ts index a031de486..6a6b4e760 100644 --- a/packages/0x.js/src/web3_wrapper.ts +++ b/packages/0x.js/src/web3_wrapper.ts @@ -1,10 +1,9 @@ import BigNumber from 'bignumber.js'; -import promisify = require('es6-promisify'); import * as _ from 'lodash'; import * as Web3 from 'web3'; -import {Contract} from './contract'; -import {Artifact, ArtifactContractName, TransactionReceipt, ZeroExError} from './types'; +import {Artifact, ArtifactContractName, TransactionReceipt, TxData, ZeroExError} from './types'; +import {promisify} from './utils/promisify'; interface RawLogEntry { logIndex: string|null; @@ -29,9 +28,9 @@ const CONTRACT_NAME_TO_NOT_FOUND_ERROR: {[contractName: string]: ZeroExError} = export class Web3Wrapper { private web3: Web3; private networkId: number; - private defaults: Partial<Web3.TxData>; + private defaults: Partial<TxData>; private jsonRpcRequestId: number; - constructor(provider: Web3.Provider, networkId: number, defaults?: Partial<Web3.TxData>) { + constructor(provider: Web3.Provider, networkId: number, defaults?: Partial<TxData>) { if (_.isUndefined((provider as any).sendAsync)) { // Web3@1.0 provider doesn't support synchronous http requests, // so it only has an async `send` method, instead of a `send` and `sendAsync` in web3@0.x.x` @@ -44,6 +43,9 @@ export class Web3Wrapper { this.defaults = defaults || {}; this.jsonRpcRequestId = 0; } + public getContractDefaults(): Partial<TxData> { + return this.defaults; + } public setProvider(provider: Web3.Provider, networkId: number) { this.networkId = networkId; this.web3.setProvider(provider); @@ -56,11 +58,11 @@ export class Web3Wrapper { return _.includes(addresses, senderAddress); } public async getNodeVersionAsync(): Promise<string> { - const nodeVersion = await promisify(this.web3.version.getNode)(); + const nodeVersion = await promisify<string>(this.web3.version.getNode)(); return nodeVersion; } public async getTransactionReceiptAsync(txHash: string): Promise<TransactionReceipt> { - const transactionReceipt = await promisify(this.web3.eth.getTransactionReceipt)(txHash); + const transactionReceipt = await promisify<TransactionReceipt>(this.web3.eth.getTransactionReceipt)(txHash); if (!_.isNull(transactionReceipt)) { transactionReceipt.status = this.normalizeTxReceiptStatus(transactionReceipt.status); } @@ -72,8 +74,9 @@ export class Web3Wrapper { public getNetworkId(): number { return this.networkId; } - public async getContractInstanceFromArtifactAsync<A extends Web3.ContractInstance>(artifact: Artifact, - address?: string): Promise<A> { + public async getContractInstanceFromArtifactAsync( + artifact: Artifact, address?: string, + ): Promise<Web3.ContractInstance> { let contractAddress: string; if (_.isUndefined(address)) { const networkId = this.getNetworkId(); @@ -88,7 +91,7 @@ export class Web3Wrapper { if (!doesContractExist) { throw new Error(CONTRACT_NAME_TO_NOT_FOUND_ERROR[artifact.contract_name]); } - const contractInstance = this.getContractInstance<A>( + const contractInstance = this.getContractInstance( artifact.abi, contractAddress, ); return contractInstance; @@ -98,26 +101,26 @@ export class Web3Wrapper { return balanceWei; } public async getBalanceInWeiAsync(owner: string): Promise<BigNumber> { - let balanceInWei = await promisify(this.web3.eth.getBalance)(owner); + let balanceInWei = await promisify<BigNumber>(this.web3.eth.getBalance)(owner); balanceInWei = new BigNumber(balanceInWei); return balanceInWei; } public async doesContractExistAtAddressAsync(address: string): Promise<boolean> { - const code = await promisify(this.web3.eth.getCode)(address); + const code = await promisify<string>(this.web3.eth.getCode)(address); // Regex matches 0x0, 0x00, 0x in order to accommodate poorly implemented clients const codeIsEmpty = /^0x0{0,40}$/i.test(code); return !codeIsEmpty; } public async signTransactionAsync(address: string, message: string): Promise<string> { - const signData = await promisify(this.web3.eth.sign)(address, message); + const signData = await promisify<string>(this.web3.eth.sign)(address, message); return signData; } public async getBlockNumberAsync(): Promise<number> { - const blockNumber = await promisify(this.web3.eth.getBlockNumber)(); + const blockNumber = await promisify<number>(this.web3.eth.getBlockNumber)(); return blockNumber; } public async getBlockAsync(blockParam: string|Web3.BlockParam): Promise<Web3.BlockWithoutTransactionData> { - const block = await promisify(this.web3.eth.getBlock)(blockParam); + const block = await promisify<Web3.BlockWithoutTransactionData>(this.web3.eth.getBlock)(blockParam); return block; } public async getBlockTimestampAsync(blockParam: string|Web3.BlockParam): Promise<number> { @@ -125,7 +128,7 @@ export class Web3Wrapper { return timestamp; } public async getAvailableAddressesAsync(): Promise<string[]> { - const addresses: string[] = await promisify(this.web3.eth.getAccounts)(); + const addresses = await promisify<string[]>(this.web3.eth.getAccounts)(); return addresses; } public async getLogsAsync(filter: Web3.FilterObject): Promise<Web3.LogEntry[]> { @@ -152,18 +155,17 @@ export class Web3Wrapper { const formattedLogs = _.map(rawLogs, this.formatLog.bind(this)); return formattedLogs; } - private getContractInstance<A extends Web3.ContractInstance>(abi: Web3.ContractAbi, address: string): A { + private getContractInstance(abi: Web3.ContractAbi, address: string): Web3.ContractInstance { const web3ContractInstance = this.web3.eth.contract(abi).at(address); - const contractInstance = new Contract(web3ContractInstance, this.defaults) as any as A; - return contractInstance; + return web3ContractInstance; } private async getNetworkAsync(): Promise<number> { - const networkId = await promisify(this.web3.version.getNetwork)(); + const networkId = await promisify<number>(this.web3.version.getNetwork)(); return networkId; } private async sendRawPayloadAsync<A>(payload: Web3.JSONRPCRequestPayload): Promise<A> { const sendAsync = this.web3.currentProvider.sendAsync.bind(this.web3.currentProvider); - const response = await promisify(sendAsync)(payload); + const response = await promisify<Web3.JSONRPCResponsePayload>(sendAsync)(payload); const result = response.result; return result; } diff --git a/packages/0x.js/test/subscription_test.ts b/packages/0x.js/test/subscription_test.ts index e3b15808b..3aeeaa109 100644 --- a/packages/0x.js/test/subscription_test.ts +++ b/packages/0x.js/test/subscription_test.ts @@ -1,6 +1,5 @@ import BigNumber from 'bignumber.js'; import * as chai from 'chai'; -import promisify = require('es6-promisify'); import * as _ from 'lodash'; import 'mocha'; import * as Sinon from 'sinon'; diff --git a/packages/0x.js/test/token_wrapper_test.ts b/packages/0x.js/test/token_wrapper_test.ts index c853fe0c2..421bd0a8c 100644 --- a/packages/0x.js/test/token_wrapper_test.ts +++ b/packages/0x.js/test/token_wrapper_test.ts @@ -1,6 +1,5 @@ import BigNumber from 'bignumber.js'; import * as chai from 'chai'; -import promisify = require('es6-promisify'); import 'mocha'; import * as Web3 from 'web3'; @@ -19,6 +18,8 @@ import { ZeroExError, } from '../src'; import {BlockParamLiteral, DoneCallback} from '../src/types'; +import {promisify} from '../src/utils/promisify'; +import {Web3Wrapper} from '../src/web3_wrapper'; import {BlockchainLifecycle} from './utils/blockchain_lifecycle'; import {chaiSetup} from './utils/chai_setup'; @@ -38,12 +39,14 @@ describe('TokenWrapper', () => { let tokenUtils: TokenUtils; let coinbase: string; let addressWithoutFunds: string; + let web3Wrapper: Web3Wrapper; const config = { networkId: constants.TESTRPC_NETWORK_ID, }; before(async () => { web3 = web3Factory.create(); zeroEx = new ZeroEx(web3.currentProvider, config); + web3Wrapper = new Web3Wrapper(web3.currentProvider, config.networkId); userAddresses = await zeroEx.getAvailableAddressesAsync(); tokens = await zeroEx.tokenRegistry.getTokensAsync(); tokenUtils = new TokenUtils(tokens); @@ -237,8 +240,10 @@ describe('TokenWrapper', () => { await zeroEx.token.setAllowanceAsync(zrx.address, coinbase, userWithNormalAllowance, transferAmount); await zeroEx.token.setUnlimitedAllowanceAsync(zrx.address, coinbase, userWithUnlimitedAllowance); - const initBalanceWithNormalAllowance = await promisify(web3.eth.getBalance)(userWithNormalAllowance); - const initBalanceWithUnlimitedAllowance = await promisify(web3.eth.getBalance)(userWithUnlimitedAllowance); + const initBalanceWithNormalAllowance = await web3Wrapper.getBalanceInWeiAsync(userWithNormalAllowance); + const initBalanceWithUnlimitedAllowance = await web3Wrapper.getBalanceInWeiAsync( + userWithUnlimitedAllowance, + ); await zeroEx.token.transferFromAsync( zrx.address, coinbase, userWithNormalAllowance, userWithNormalAllowance, transferAmount, @@ -247,8 +252,10 @@ describe('TokenWrapper', () => { zrx.address, coinbase, userWithUnlimitedAllowance, userWithUnlimitedAllowance, transferAmount, ); - const finalBalanceWithNormalAllowance = await promisify(web3.eth.getBalance)(userWithNormalAllowance); - const finalBalanceWithUnlimitedAllowance = await promisify(web3.eth.getBalance)(userWithUnlimitedAllowance); + const finalBalanceWithNormalAllowance = await web3Wrapper.getBalanceInWeiAsync(userWithNormalAllowance); + const finalBalanceWithUnlimitedAllowance = await web3Wrapper.getBalanceInWeiAsync( + userWithUnlimitedAllowance, + ); const normalGasCost = initBalanceWithNormalAllowance.minus(finalBalanceWithNormalAllowance); const unlimitedGasCost = initBalanceWithUnlimitedAllowance.minus(finalBalanceWithUnlimitedAllowance); diff --git a/packages/abi-gen-templates/contract.mustache b/packages/abi-gen-templates/contract.mustache new file mode 100644 index 000000000..27783fb6e --- /dev/null +++ b/packages/abi-gen-templates/contract.mustache @@ -0,0 +1,27 @@ +/** + * This file is auto-generated using abi-gen. Don't edit directly. + * Templates can be found at https://github.com/0xProject/0x.js/tree/development/packages/abi-gen-templates. + */ +import {BigNumber} from 'bignumber.js'; +import * as Web3 from 'web3'; + +import {TxData, TxDataPayable} from '../../types'; +import {classUtils} from '../../utils/class_utils'; +import {promisify} from '../../utils/promisify'; + +import {BaseContract} from './base_contract'; + +export class {{contractName}}Contract extends BaseContract { +{{#each methods}} + {{#this.constant}} + {{> call contractName=../contractName}} + {{/this.constant}} + {{^this.constant}} + {{> tx contractName=../contractName}} + {{/this.constant}} +{{/each}} + constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) { + super(web3ContractInstance, defaults); + classUtils.bindAll(this, ['web3ContractInstance', 'defaults']); + } +} // tslint:disable:max-file-line-count diff --git a/packages/abi-gen-templates/package.json b/packages/abi-gen-templates/package.json new file mode 100644 index 000000000..104013c05 --- /dev/null +++ b/packages/abi-gen-templates/package.json @@ -0,0 +1,15 @@ +{ + "name": "abi-gen-templates", + "private": true, + "version": "0.0.0", + "description": "Handlebars templates to generate TS contract wrappers", + "repository": { + "type": "git", + "url": "https://github.com/0xProject/0x.js.git" + }, + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/0xProject/0x.js/issues" + }, + "homepage": "https://github.com/0xProject/0x.js/packages/abi-gen-templates/README.md" +} diff --git a/packages/abi-gen-templates/partials/call.mustache b/packages/abi-gen-templates/partials/call.mustache new file mode 100644 index 000000000..ef4bda724 --- /dev/null +++ b/packages/abi-gen-templates/partials/call.mustache @@ -0,0 +1,15 @@ +public {{this.name}} = { + async callAsync( + {{> typed_params inputs=inputs}} + defaultBlock?: Web3.BlockParam, + ): Promise<{{> return_type outputs=outputs}}> { + const self = this as {{contractName}}Contract; + const result = await promisify<{{> return_type outputs=outputs}}>( + self.web3ContractInstance.{{this.name}}.call, + self.web3ContractInstance, + )( + {{> params inputs=inputs}} + ); + return result; + }, +}; diff --git a/packages/abi-gen-templates/partials/params.mustache b/packages/abi-gen-templates/partials/params.mustache new file mode 100644 index 000000000..ac5d4ae85 --- /dev/null +++ b/packages/abi-gen-templates/partials/params.mustache @@ -0,0 +1,3 @@ +{{#each inputs}} +{{name}}, +{{/each}} diff --git a/packages/abi-gen-templates/partials/return_type.mustache b/packages/abi-gen-templates/partials/return_type.mustache new file mode 100644 index 000000000..383961a40 --- /dev/null +++ b/packages/abi-gen-templates/partials/return_type.mustache @@ -0,0 +1,6 @@ +{{#singleReturnValue}} +{{#returnType outputs.0.type}}{{/returnType}} +{{/singleReturnValue}} +{{^singleReturnValue}} +[{{#each outputs}}{{#returnType type}}{{/returnType}}{{#unless @last}}, {{/unless}}{{/each}}] +{{/singleReturnValue}} diff --git a/packages/abi-gen-templates/partials/tx.mustache b/packages/abi-gen-templates/partials/tx.mustache new file mode 100644 index 000000000..8a43e5319 --- /dev/null +++ b/packages/abi-gen-templates/partials/tx.mustache @@ -0,0 +1,51 @@ +public {{this.name}} = { + async sendTransactionAsync( + {{> typed_params inputs=inputs}} + {{#this.payable}} + txData: TxDataPayable = {}, + {{/this.payable}} + {{^this.payable}} + txData: TxData = {}, + {{/this.payable}} + ): Promise<string> { + const self = this as {{contractName}}Contract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + self.{{this.name}}.estimateGasAsync.bind( + self, + {{> params inputs=inputs}} + ), + ); + const txHash = await promisify<string>( + self.web3ContractInstance.{{this.name}}, self.web3ContractInstance, + )( + {{> params inputs=inputs}} + txDataWithDefaults, + ); + return txHash; + }, + async estimateGasAsync( + {{> typed_params inputs=inputs}} + txData: TxData = {}, + ): Promise<number> { + const self = this as {{contractName}}Contract; + const txDataWithDefaults = await self.applyDefaultsToTxDataAsync( + txData, + ); + const gas = await promisify<number>( + self.web3ContractInstance.{{this.name}}.estimateGas, self.web3ContractInstance, + )( + {{> params inputs=inputs}} + txDataWithDefaults, + ); + return gas; + }, + getABIEncodedTransactionData( + {{> typed_params inputs=inputs}} + txData: TxData = {}, + ): string { + const self = this as {{contractName}}Contract; + const abiEncodedTransactionData = self.web3ContractInstance.{{this.name}}.getData(); + return abiEncodedTransactionData; + }, +}; diff --git a/packages/abi-gen-templates/partials/typed_params.mustache b/packages/abi-gen-templates/partials/typed_params.mustache new file mode 100644 index 000000000..3ea4b2e95 --- /dev/null +++ b/packages/abi-gen-templates/partials/typed_params.mustache @@ -0,0 +1,3 @@ +{{#each inputs}} + {{name}}: {{#parameterType type}}{{/parameterType}}, +{{/each}} diff --git a/packages/abi-gen/README.md b/packages/abi-gen/README.md new file mode 100644 index 000000000..f1f8bd08f --- /dev/null +++ b/packages/abi-gen/README.md @@ -0,0 +1,40 @@ +# ABI Gen + +This package allows you to generate contract wrappers in any language from ABI files. +It's heavily inspired by [Geth abigen](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts) but takes a different approach. +You can write your custom handlebars templates which will allow you to seamlessly integrate the generated code into your existing codebase with existing conventions. + +For an example of the generated [wrapper files](https://github.com/0xProject/0x.js/tree/development/packages/0x.js/src/contract_wrappers/generated) check out 0x.js. +[Here](https://github.com/0xProject/0x.js/tree/development/packages/abi-gen-templates) are the templates used to generate those files. + +## Instalation +`yarn add -g abi-gen` +## Usage +``` +abi-gen +Options: + --help Show help [boolean] + --version Show version number [boolean] + --abiGlob Glob pattern to search for ABI JSON files [string] [required] + --templates Folder where to search for templates [string] [required] + --output Folder where to put the output files [string] [required] + --fileExtension The extension of the output file [string] [required] +``` +## ABI files +You're required to pass a [glob](https://en.wikipedia.org/wiki/Glob_(programming) template where your abi files are located. +TL;DR - here is the example from 0x.js. + +`--abiGlob 'src/artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry).json` + +We could've just used `--abiGlob 'src/artifacts/*.json` but we wanted to exclude some of the abi files. + +The abi file should be either a [Truffle](http://truffleframework.com/) contract artifact (a JSON object with an abi key) or a JSON abi array. +## How to write custom templates? +The best way to get started is to copy [0x.js templates](https://github.com/0xProject/0x.js/tree/development/packages/abi-gen-templates) and start adjusting them for your needs. +We use [handlebars](handlebarsjs.com) template engine under the hood. +You need to have a master template called `contract.mustache`. it will be used to generate each contract wrapper. Although - you don't need and probably shouldn't write all your logic in a single template file. You can write [partial templates](http://handlebarsjs.com/partials.html) and as long as they are within a partials folder - they will be registered and available. +## Which data/context do I get in my templates? +For now you don't get much on top of methods abi and a contract name because it was enough for our use-case, but if you need something else - create a PR. +[Type definition](https://github.com/0xProject/0x.js/tree/development/packages/abi-gen/src/types.ts) of what we pass to a render method. +## Output files +Output files will be generated within an output folder with names converted to camel case and taken from abi file names. If you already have some files in that folder they will be overwritten. diff --git a/packages/abi-gen/package.json b/packages/abi-gen/package.json new file mode 100644 index 000000000..defe4a621 --- /dev/null +++ b/packages/abi-gen/package.json @@ -0,0 +1,48 @@ +{ + "name": "abi-gen", + "version": "0.0.0", + "description": "Generate contract wrappers from ABI and handlebars templates", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "scripts": { + "lint": "tslint --project . 'src/**/*.ts'", + "clean": "shx rm -rf lib", + "build": "tsc" + }, + "bin": { + "abi-gen": "lib/index.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/0xProject/0x.js.git" + }, + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/0xProject/0x.js/issues" + }, + "homepage": "https://github.com/0xProject/0x.js/packages/abi-gen/README.md", + "dependencies": { + "bignumber.js": "^5.0.0", + "chalk": "^2.3.0", + "glob": "^7.1.2", + "handlebars": "^4.0.11", + "lodash": "^4.17.4", + "mkdirp": "^0.5.1", + "to-snake-case": "^1.0.0", + "web3": "^0.20.0", + "yargs": "^10.0.3" + }, + "devDependencies": { + "@types/handlebars": "^4.0.36", + "@0xproject/tslint-config": "^0.2.0", + "@types/glob": "^5.0.33", + "@types/mkdirp": "^0.5.1", + "@types/node": "^8.0.53", + "@types/yargs": "^8.0.2", + "npm-run-all": "^4.1.1", + "shx": "^0.2.2", + "tslint": "5.8.0", + "typescript": "~2.6.1", + "web3-typescript-typings": "^0.7.2" + } +} diff --git a/packages/abi-gen/src/globals.d.ts b/packages/abi-gen/src/globals.d.ts new file mode 100644 index 000000000..39df3f852 --- /dev/null +++ b/packages/abi-gen/src/globals.d.ts @@ -0,0 +1,4 @@ +declare function toSnakeCase(str: string): string; +declare module 'to-snake-case' { + export = toSnakeCase; +} diff --git a/packages/abi-gen/src/index.ts b/packages/abi-gen/src/index.ts new file mode 100644 index 000000000..12b78f96f --- /dev/null +++ b/packages/abi-gen/src/index.ts @@ -0,0 +1,103 @@ +#!/usr/bin/env node + +import chalk from 'chalk'; +import * as fs from 'fs'; +import {sync as globSync} from 'glob'; +import * as Handlebars from 'handlebars'; +import * as _ from 'lodash'; +import * as mkdirp from 'mkdirp'; +import * as yargs from 'yargs'; + +import toSnakeCase = require('to-snake-case'); +import * as Web3 from 'web3'; + +import {ContextData, ParamKind} from './types'; +import {utils} from './utils'; + +const ABI_TYPE_METHOD = 'function'; +const MAIN_TEMPLATE_NAME = 'contract.mustache'; + +const args = yargs + .option('abiGlob', { + describe: 'Glob pattern to search for ABI JSON files', + type: 'string', + demand: true, + }) + .option('templates', { + describe: 'Folder where to search for templates', + type: 'string', + demand: true, + }) + .option('output', { + describe: 'Folder where to put the output files', + type: 'string', + demand: true, + }) + .option('fileExtension', { + describe: 'The extension of the output file', + type: 'string', + demand: true, + }) + .argv; + +function writeOutputFile(name: string, renderedTsCode: string): void { + const fileName = toSnakeCase(name); + const filePath = `${args.output}/${fileName}.${args.fileExtension}`; + fs.writeFileSync(filePath, renderedTsCode); + utils.log(`Created: ${chalk.bold(filePath)}`); +} + +Handlebars.registerHelper('parameterType', utils.solTypeToTsType.bind(utils, ParamKind.Input)); +Handlebars.registerHelper('returnType', utils.solTypeToTsType.bind(utils, ParamKind.Output)); +const partialTemplateFileNames = globSync(`${args.templates}/partials/**/*.mustache`); +for (const partialTemplateFileName of partialTemplateFileNames) { + const namedContent = utils.getNamedContent(partialTemplateFileName); + Handlebars.registerPartial(namedContent.name, namedContent.content); +} + +const mainTemplate = utils.getNamedContent(`${args.templates}/${MAIN_TEMPLATE_NAME}`); +const template = Handlebars.compile<ContextData>(mainTemplate.content); +const abiFileNames = globSync(args.abiGlob); +if (_.isEmpty(abiFileNames)) { + utils.log(`${chalk.red(`No ABI files found.`)}`); + utils.log(`Please make sure you've passed the correct folder name and that the files have + ${chalk.bold('*.json')} extensions`); + process.exit(1); +} else { + utils.log(`Found ${chalk.green(`${abiFileNames.length}`)} ${chalk.bold('ABI')} files`); + mkdirp.sync(args.output); +} +for (const abiFileName of abiFileNames) { + const namedContent = utils.getNamedContent(abiFileName); + utils.log(`Processing: ${chalk.bold(namedContent.name)}...`); + const parsedContent = JSON.parse(namedContent.content); + const ABI = _.isArray(parsedContent) ? + parsedContent : // ABI file + parsedContent.abi; // Truffle contracts file + if (_.isUndefined(ABI)) { + utils.log(`${chalk.red(`ABI not found in ${abiFileName}.`)}`); + utils.log(`Please make sure your ABI file is either an array with ABI entries or an object with the abi key`); + process.exit(1); + } + const methodAbis = ABI.filter((abi: Web3.AbiDefinition) => abi.type === ABI_TYPE_METHOD) as Web3.MethodAbi[]; + const methodsData = _.map(methodAbis, methodAbi => { + _.map(methodAbi.inputs, input => { + if (_.isEmpty(input.name)) { + // Auto-generated getters don't have parameter names + input.name = 'index'; + } + }); + // This will make templates simpler + const methodData = { + ...methodAbi, + singleReturnValue: methodAbi.outputs.length === 1, + }; + return methodData; + }); + const contextData = { + contractName: namedContent.name, + methods: methodsData, + }; + const renderedTsCode = template(contextData); + writeOutputFile(namedContent.name, renderedTsCode); +} diff --git a/packages/abi-gen/src/types.ts b/packages/abi-gen/src/types.ts new file mode 100644 index 000000000..1dc039c83 --- /dev/null +++ b/packages/abi-gen/src/types.ts @@ -0,0 +1,15 @@ +import * as Web3 from 'web3'; + +export enum ParamKind { + Input = 'input', + Output = 'output', +} + +export interface Method extends Web3.MethodAbi { + singleReturnValue: boolean; +} + +export interface ContextData { + contractName: string; + methods: Method[]; +} diff --git a/packages/abi-gen/src/utils.ts b/packages/abi-gen/src/utils.ts new file mode 100644 index 000000000..eaf5a30cc --- /dev/null +++ b/packages/abi-gen/src/utils.ts @@ -0,0 +1,56 @@ +import * as fs from 'fs'; +import * as _ from 'lodash'; +import * as path from 'path'; + +import {ParamKind} from './types'; + +export const utils = { + solTypeToTsType(paramKind: ParamKind, solType: string): string { + const trailingArrayRegex = /\[\d*\]$/; + if (solType.match(trailingArrayRegex)) { + const arrayItemSolType = solType.replace(trailingArrayRegex, ''); + const arrayItemTsType = utils.solTypeToTsType(paramKind, arrayItemSolType); + const arrayTsType = `${arrayItemTsType}[]`; + return arrayTsType; + } else { + const solTypeRegexToTsType = [ + {regex: '^string$', tsType: 'string'}, + {regex: '^address$', tsType: 'string'}, + {regex: '^bool$', tsType: 'boolean'}, + {regex: '^u?int\\d*$', tsType: 'BigNumber'}, + {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 + solTypeRegexToTsType.unshift({regex: '^u?int(8|16|32)?$', tsType: 'number|BigNumber'}); + } + for (const regexAndTxType of solTypeRegexToTsType) { + const {regex, tsType} = regexAndTxType; + if (solType.match(regex)) { + return tsType; + } + } + throw new Error(`Unknown Solidity type found: ${solType}`); + } + }, + log(...args: any[]): void { + console.log(...args); // tslint:disable-line:no-console + }, + getPartialNameFromFileName(filename: string): string { + const name = path.parse(filename).name; + return name; + }, + getNamedContent(filename: string): {name: string; content: string} { + const name = utils.getPartialNameFromFileName(filename); + try { + const content = fs.readFileSync(filename).toString(); + return { + name, + content, + }; + } catch (err) { + throw new Error(`Failed to read ${filename}: ${err}`); + } + }, +}; diff --git a/packages/abi-gen/tsconfig.json b/packages/abi-gen/tsconfig.json new file mode 100644 index 000000000..2a3667890 --- /dev/null +++ b/packages/abi-gen/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "lib": ["es2015", "dom"], + "outDir": "lib", + "sourceMap": true, + "declaration": true, + "noImplicitAny": true, + "strictNullChecks": true + }, + "include": [ + "./src/**/*", + "./test/**/*", + "../../node_modules/web3-typescript-typings/index.d.ts", + ] +} diff --git a/packages/abi-gen/tslint.json b/packages/abi-gen/tslint.json new file mode 100644 index 000000000..a07795151 --- /dev/null +++ b/packages/abi-gen/tslint.json @@ -0,0 +1,5 @@ +{ + "extends": [ + "@0xproject/tslint-config" + ] +} diff --git a/packages/contracts/test/ts/exchange/core.ts b/packages/contracts/test/ts/exchange/core.ts index 2e7fb8343..daf46ca37 100644 --- a/packages/contracts/test/ts/exchange/core.ts +++ b/packages/contracts/test/ts/exchange/core.ts @@ -763,4 +763,4 @@ contract('Exchange', (accounts: string[]) => { expect(errCode).to.be.equal(ExchangeContractErrs.ERROR_ORDER_EXPIRED); }); }); -}); +}); // tslint:disable-line:max-file-line-count @@ -83,14 +83,14 @@ dependencies: "@types/node" "*" -"@types/glob@*": +"@types/glob@*", "@types/glob@^5.0.33": version "5.0.33" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-5.0.33.tgz#3dff7c6ce09d65abe919c7961dc3dee016f36ad7" dependencies: "@types/minimatch" "*" "@types/node" "*" -"@types/handlebars@^4.0.31": +"@types/handlebars@^4.0.31", "@types/handlebars@^4.0.36": version "4.0.36" resolved "https://registry.yarnpkg.com/@types/handlebars/-/handlebars-4.0.36.tgz#ff57c77fa1ab6713bb446534ddc4d979707a3a79" @@ -143,6 +143,12 @@ version "2.0.29" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-2.0.29.tgz#5002e14f75e2d71e564281df0431c8c1b4a2a36a" +"@types/mkdirp@^0.5.1": + version "0.5.1" + resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-0.5.1.tgz#ea887cd024f691c1ca67cce20b7606b053e43b0f" + dependencies: + "@types/node" "*" + "@types/mocha@^2.2.41", "@types/mocha@^2.2.42": version "2.2.44" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.44.tgz#1d4a798e53f35212fd5ad4d04050620171cd5b5e" @@ -161,6 +167,10 @@ version "7.0.48" resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.48.tgz#24bfdc0aa82e8f6dbd017159c58094a2e06d0abb" +"@types/node@^8.0.53": + version "8.0.53" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.53.tgz#396b35af826fa66aad472c8cb7b8d5e277f4e6d8" + "@types/query-string@^5.0.0", "@types/query-string@^5.0.1": version "5.0.1" resolved "https://registry.yarnpkg.com/@types/query-string/-/query-string-5.0.1.tgz#6cb41c724cb1644d56c2d1dae7c7b204e706b39e" @@ -1267,6 +1277,10 @@ bignumber.js@^4.0.2, bignumber.js@^4.1.0, bignumber.js@~4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-4.1.0.tgz#db6f14067c140bd46624815a7916c92d9b6c24b1" +bignumber.js@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-5.0.0.tgz#fbce63f09776b3000a83185badcde525daf34833" + "bignumber.js@git+https://github.com/debris/bignumber.js#master": version "2.0.7" resolved "git+https://github.com/debris/bignumber.js#c7a38de919ed75e6fb6ba38051986e294b328df9" @@ -3760,7 +3774,7 @@ handle-thing@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4" -handlebars@^4.0.2, handlebars@^4.0.3, handlebars@^4.0.6: +handlebars@^4.0.11, handlebars@^4.0.2, handlebars@^4.0.3, handlebars@^4.0.6: version "4.0.11" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" dependencies: @@ -8160,6 +8174,10 @@ to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" +to-no-case@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/to-no-case/-/to-no-case-1.0.2.tgz#c722907164ef6b178132c8e69930212d1b4aa16a" + to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" @@ -8181,6 +8199,18 @@ to-regex@^3.0.1: extend-shallow "^2.0.1" regex-not "^1.0.0" +to-snake-case@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-snake-case/-/to-snake-case-1.0.0.tgz#ce746913897946019a87e62edfaeaea4c608ab8c" + dependencies: + to-space-case "^1.0.0" + +to-space-case@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-space-case/-/to-space-case-1.0.0.tgz#b052daafb1b2b29dc770cea0163e5ec0ebc9fc17" + dependencies: + to-no-case "^1.0.0" + toggle-selection@^1.0.3: version "1.0.6" resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32" |