Allow users to specify the contracts backend in abi-gen
This commit is contained in:
parent
f5275d3ad7
commit
2d561bc8a0
@ -6,6 +6,9 @@
|
|||||||
// tslint:disable-next-line:no-unused-variable
|
// tslint:disable-next-line:no-unused-variable
|
||||||
import { TxData, TxDataPayable } from '@0xproject/types';
|
import { TxData, TxDataPayable } from '@0xproject/types';
|
||||||
import { BigNumber, classUtils, promisify } from '@0xproject/utils';
|
import { BigNumber, classUtils, promisify } from '@0xproject/utils';
|
||||||
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
|
import * as ethersContracts from 'ethers-contracts';
|
||||||
|
import * as _ from 'lodash';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {BaseContract} from './base_contract';
|
import {BaseContract} from './base_contract';
|
||||||
@ -28,6 +31,7 @@ export enum {{contractName}}Events {
|
|||||||
{{/each}}
|
{{/each}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
// tslint:disable:no-parameter-reassignment
|
||||||
export class {{contractName}}Contract extends BaseContract {
|
export class {{contractName}}Contract extends BaseContract {
|
||||||
{{#each methods}}
|
{{#each methods}}
|
||||||
{{#this.constant}}
|
{{#this.constant}}
|
||||||
@ -37,8 +41,8 @@ export class {{contractName}}Contract extends BaseContract {
|
|||||||
{{> tx contractName=../contractName}}
|
{{> tx contractName=../contractName}}
|
||||||
{{/this.constant}}
|
{{/this.constant}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) {
|
constructor(web3Wrapper: Web3Wrapper, abi: Web3.ContractAbi, address: string) {
|
||||||
super(web3ContractInstance, defaults);
|
super(web3Wrapper, abi, address);
|
||||||
classUtils.bindAll(this, ['_web3ContractInstance', '_defaults']);
|
classUtils.bindAll(this, ['_ethersInterface', '_address', '_abi', '_web3Wrapper']);
|
||||||
}
|
}
|
||||||
} // tslint:disable:max-file-line-count
|
} // tslint:disable:max-file-line-count
|
||||||
|
@ -4,12 +4,20 @@ public {{this.name}} = {
|
|||||||
defaultBlock?: Web3.BlockParam,
|
defaultBlock?: Web3.BlockParam,
|
||||||
): Promise<{{> return_type outputs=outputs}}> {
|
): Promise<{{> return_type outputs=outputs}}> {
|
||||||
const self = this as {{contractName}}Contract;
|
const self = this as {{contractName}}Contract;
|
||||||
const result = await promisify<{{> return_type outputs=outputs}}>(
|
const inputAbi = _.find(this._abi, {name: '{{this.name}}'}).inputs;
|
||||||
self._web3ContractInstance.{{this.name}}.call,
|
[{{> params inputs=inputs}}] = BaseContract._transformABIData(inputAbi, [{{> params inputs=inputs}}], BaseContract._bigNumberToString.bind(this));
|
||||||
self._web3ContractInstance,
|
const callDescription = self._ethersInterface.functions.{{this.name}}(
|
||||||
)(
|
|
||||||
{{> params inputs=inputs}}
|
{{> params inputs=inputs}}
|
||||||
);
|
) as ethersContracts.CallDescription;
|
||||||
return result;
|
const callData = await self._applyDefaultsToTxDataAsync(
|
||||||
|
{
|
||||||
|
data: callDescription.data,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const rawCallResult = await self._web3Wrapper.callAsync(callData);
|
||||||
|
let resultArray = callDescription.parse(rawCallResult);
|
||||||
|
const outputAbi = _.find(this._abi, {name: '{{this.name}}'}).outputs;
|
||||||
|
resultArray = BaseContract._transformABIData(outputAbi, resultArray, BaseContract._lowercaseAddress.bind(this));
|
||||||
|
return resultArray{{#singleReturnValue}}[0]{{/singleReturnValue}};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -9,19 +9,22 @@ public {{this.name}} = {
|
|||||||
{{/this.payable}}
|
{{/this.payable}}
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const self = this as {{contractName}}Contract;
|
const self = this as {{contractName}}Contract;
|
||||||
|
const inputAbi = _.find(this._abi, {name: '{{this.name}}'}).inputs;
|
||||||
|
[{{> params inputs=inputs}}] = BaseContract._transformABIData(inputAbi, [{{> params inputs=inputs}}], BaseContract._bigNumberToString.bind(this));
|
||||||
|
const data = this._ethersInterface.functions.{{this.name}}(
|
||||||
|
{{> params inputs=inputs}}
|
||||||
|
).data
|
||||||
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync(
|
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync(
|
||||||
txData,
|
{
|
||||||
|
...txData,
|
||||||
|
data,
|
||||||
|
},
|
||||||
self.{{this.name}}.estimateGasAsync.bind(
|
self.{{this.name}}.estimateGasAsync.bind(
|
||||||
self,
|
self,
|
||||||
{{> params inputs=inputs}}
|
{{> params inputs=inputs}}
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
const txHash = await promisify<string>(
|
const txHash = await this._web3Wrapper.sendTransactionAsync(txDataWithDefaults);
|
||||||
self._web3ContractInstance.{{this.name}}, self._web3ContractInstance,
|
|
||||||
)(
|
|
||||||
{{> params inputs=inputs}}
|
|
||||||
txDataWithDefaults,
|
|
||||||
);
|
|
||||||
return txHash;
|
return txHash;
|
||||||
},
|
},
|
||||||
async estimateGasAsync(
|
async estimateGasAsync(
|
||||||
@ -29,15 +32,16 @@ public {{this.name}} = {
|
|||||||
txData: TxData = {},
|
txData: TxData = {},
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
const self = this as {{contractName}}Contract;
|
const self = this as {{contractName}}Contract;
|
||||||
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync(
|
const data = this._ethersInterface.functions.{{this.name}}(
|
||||||
txData,
|
|
||||||
);
|
|
||||||
const gas = await promisify<number>(
|
|
||||||
self._web3ContractInstance.{{this.name}}.estimateGas, self._web3ContractInstance,
|
|
||||||
)(
|
|
||||||
{{> params inputs=inputs}}
|
{{> params inputs=inputs}}
|
||||||
txDataWithDefaults,
|
).data
|
||||||
|
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync(
|
||||||
|
{
|
||||||
|
...txData,
|
||||||
|
data,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
const gas = await this._web3Wrapper.estimateGasAsync(txDataWithDefaults);
|
||||||
return gas;
|
return gas;
|
||||||
},
|
},
|
||||||
getABIEncodedTransactionData(
|
getABIEncodedTransactionData(
|
||||||
@ -45,7 +49,9 @@ public {{this.name}} = {
|
|||||||
txData: TxData = {},
|
txData: TxData = {},
|
||||||
): string {
|
): string {
|
||||||
const self = this as {{contractName}}Contract;
|
const self = this as {{contractName}}Contract;
|
||||||
const abiEncodedTransactionData = self._web3ContractInstance.{{this.name}}.getData();
|
const abiEncodedTransactionData = this._ethersInterface.functions.{{this.name}}(
|
||||||
|
{{> params inputs=inputs}}
|
||||||
|
).data
|
||||||
return abiEncodedTransactionData;
|
return abiEncodedTransactionData;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
"build": "run-p build:umd:prod build:commonjs; exit 0;",
|
"build": "run-p build:umd:prod build:commonjs; exit 0;",
|
||||||
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_DIR",
|
"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",
|
"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": "node ../abi-gen/lib/index.js --abis 'src/artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry|DummyToken).json' --template contract_templates/contract.handlebars --partials 'contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated",
|
"generate_contract_wrappers": "node ../abi-gen/lib/index.js --abis 'src/artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry|DummyToken).json' --template contract_templates/contract.handlebars --partials 'contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated && prettier --write 'src/contract_wrappers/generated/**.ts'",
|
||||||
"lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'",
|
"lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'",
|
||||||
"test:circleci": "run-s test:coverage report_test_coverage",
|
"test:circleci": "run-s test:coverage report_test_coverage",
|
||||||
"test": "run-s clean test:commonjs",
|
"test": "run-s clean test:commonjs",
|
||||||
@ -91,6 +91,7 @@
|
|||||||
"ethereumjs-abi": "^0.6.4",
|
"ethereumjs-abi": "^0.6.4",
|
||||||
"ethereumjs-blockstream": "^2.0.6",
|
"ethereumjs-blockstream": "^2.0.6",
|
||||||
"ethereumjs-util": "^5.1.1",
|
"ethereumjs-util": "^5.1.1",
|
||||||
|
"ethers-contracts": "^2.2.1",
|
||||||
"js-sha3": "^0.7.0",
|
"js-sha3": "^0.7.0",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"uuid": "^3.1.0",
|
"uuid": "^3.1.0",
|
||||||
|
@ -108,10 +108,10 @@ export class ContractWrapper {
|
|||||||
const logWithDecodedArgs = this._abiDecoder.tryToDecodeLogOrNoop(log);
|
const logWithDecodedArgs = this._abiDecoder.tryToDecodeLogOrNoop(log);
|
||||||
return logWithDecodedArgs;
|
return logWithDecodedArgs;
|
||||||
}
|
}
|
||||||
protected async _instantiateContractIfExistsAsync(
|
protected async _getContractAbiAndAddressFromArtifactsAsync(
|
||||||
artifact: Artifact,
|
artifact: Artifact,
|
||||||
addressIfExists?: string,
|
addressIfExists?: string,
|
||||||
): Promise<Web3.ContractInstance> {
|
): Promise<[Web3.ContractAbi, string]> {
|
||||||
let contractAddress: string;
|
let contractAddress: string;
|
||||||
if (_.isUndefined(addressIfExists)) {
|
if (_.isUndefined(addressIfExists)) {
|
||||||
if (_.isUndefined(artifact.networks[this._networkId])) {
|
if (_.isUndefined(artifact.networks[this._networkId])) {
|
||||||
@ -125,8 +125,8 @@ export class ContractWrapper {
|
|||||||
if (!doesContractExist) {
|
if (!doesContractExist) {
|
||||||
throw new Error(CONTRACT_NAME_TO_NOT_FOUND_ERROR[artifact.contract_name]);
|
throw new Error(CONTRACT_NAME_TO_NOT_FOUND_ERROR[artifact.contract_name]);
|
||||||
}
|
}
|
||||||
const contractInstance = this._web3Wrapper.getContractInstance(artifact.abi, contractAddress);
|
const abiAndAddress: [Web3.ContractAbi, string] = [artifact.abi, contractAddress];
|
||||||
return contractInstance;
|
return abiAndAddress;
|
||||||
}
|
}
|
||||||
protected _getContractAddress(artifact: Artifact, addressIfExists?: string): string {
|
protected _getContractAddress(artifact: Artifact, addressIfExists?: string): string {
|
||||||
if (_.isUndefined(addressIfExists)) {
|
if (_.isUndefined(addressIfExists)) {
|
||||||
|
@ -187,11 +187,11 @@ export class EtherTokenWrapper extends ContractWrapper {
|
|||||||
if (!_.isUndefined(etherTokenContract)) {
|
if (!_.isUndefined(etherTokenContract)) {
|
||||||
return etherTokenContract;
|
return etherTokenContract;
|
||||||
}
|
}
|
||||||
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
|
||||||
artifacts.EtherTokenArtifact,
|
artifacts.EtherTokenArtifact,
|
||||||
etherTokenAddress,
|
etherTokenAddress,
|
||||||
);
|
);
|
||||||
const contractInstance = new EtherTokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
|
const contractInstance = new EtherTokenContract(this._web3Wrapper, abi, address);
|
||||||
etherTokenContract = contractInstance;
|
etherTokenContract = contractInstance;
|
||||||
this._etherTokenContractsByAddress[etherTokenAddress] = etherTokenContract;
|
this._etherTokenContractsByAddress[etherTokenAddress] = etherTokenContract;
|
||||||
return etherTokenContract;
|
return etherTokenContract;
|
||||||
|
@ -858,7 +858,7 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
});
|
});
|
||||||
if (!_.isUndefined(errLog)) {
|
if (!_.isUndefined(errLog)) {
|
||||||
const logArgs = (errLog as LogWithDecodedArgs<LogErrorContractEventArgs>).args;
|
const logArgs = (errLog as LogWithDecodedArgs<LogErrorContractEventArgs>).args;
|
||||||
const errCode = logArgs.errorId.toNumber();
|
const errCode = logArgs.errorId;
|
||||||
const errMessage = this._exchangeContractErrCodesToMsg[errCode];
|
const errMessage = this._exchangeContractErrCodesToMsg[errCode];
|
||||||
throw new Error(errMessage);
|
throw new Error(errMessage);
|
||||||
}
|
}
|
||||||
@ -906,11 +906,11 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
if (!_.isUndefined(this._exchangeContractIfExists)) {
|
if (!_.isUndefined(this._exchangeContractIfExists)) {
|
||||||
return this._exchangeContractIfExists;
|
return this._exchangeContractIfExists;
|
||||||
}
|
}
|
||||||
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
|
||||||
artifacts.ExchangeArtifact,
|
artifacts.ExchangeArtifact,
|
||||||
this._contractAddressIfExists,
|
this._contractAddressIfExists,
|
||||||
);
|
);
|
||||||
const contractInstance = new ExchangeContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
|
const contractInstance = new ExchangeContract(this._web3Wrapper, abi, address);
|
||||||
this._exchangeContractIfExists = contractInstance;
|
this._exchangeContractIfExists = contractInstance;
|
||||||
return this._exchangeContractIfExists;
|
return this._exchangeContractIfExists;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,45 @@
|
|||||||
import {TxData, TxDataPayable} from '@0xproject/types';
|
import { TxData, TxDataPayable } from '@0xproject/types';
|
||||||
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
|
import * as ethersContracts from 'ethers-contracts';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
export class BaseContract {
|
export class BaseContract {
|
||||||
protected _web3ContractInstance: Web3.ContractInstance;
|
protected _ethersInterface: ethersContracts.Interface;
|
||||||
protected _defaults: Partial<TxData>;
|
protected _web3Wrapper: Web3Wrapper;
|
||||||
protected async _applyDefaultsToTxDataAsync<T extends TxData|TxDataPayable>(
|
protected _abi: Web3.ContractAbi;
|
||||||
|
protected _address: string;
|
||||||
|
protected static _transformABIData(
|
||||||
|
abis: Web3.DataItem[],
|
||||||
|
values: any[],
|
||||||
|
transformation: (type: string, value: any) => any,
|
||||||
|
): any {
|
||||||
|
return _.map(values, (value: any, i: number) =>
|
||||||
|
BaseContract._transformTypedData(abis[i].type, value, transformation),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
protected static _lowercaseAddress(type: string, value: string): string {
|
||||||
|
return type === 'address' ? value.toLowerCase() : value;
|
||||||
|
}
|
||||||
|
protected static _bigNumberToString(type: string, value: string): string {
|
||||||
|
return _.isObject(value) && (value as any).isBigNumber ? value.toString() : value;
|
||||||
|
}
|
||||||
|
private static _transformTypedData(
|
||||||
|
type: string,
|
||||||
|
values: any,
|
||||||
|
transformation: (type: string, value: any) => any,
|
||||||
|
): any {
|
||||||
|
const trailingArrayRegex = /\[\d*\]$/;
|
||||||
|
if (type.match(trailingArrayRegex)) {
|
||||||
|
const arrayItemType = type.replace(trailingArrayRegex, '');
|
||||||
|
return _.map(values, (value: any, i: number) =>
|
||||||
|
this._transformTypedData(arrayItemType, value, transformation),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return transformation(type, values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected async _applyDefaultsToTxDataAsync<T extends Partial<TxData | TxDataPayable>>(
|
||||||
txData: T,
|
txData: T,
|
||||||
estimateGasAsync?: (txData: T) => Promise<number>,
|
estimateGasAsync?: (txData: T) => Promise<number>,
|
||||||
): Promise<TxData> {
|
): Promise<TxData> {
|
||||||
@ -15,7 +49,8 @@ export class BaseContract {
|
|||||||
// 3. Gas estimate calculation + safety margin
|
// 3. Gas estimate calculation + safety margin
|
||||||
const removeUndefinedProperties = _.pickBy;
|
const removeUndefinedProperties = _.pickBy;
|
||||||
const txDataWithDefaults = {
|
const txDataWithDefaults = {
|
||||||
...removeUndefinedProperties(this._defaults),
|
to: this._address,
|
||||||
|
...removeUndefinedProperties(this._web3Wrapper.getContractDefaults()),
|
||||||
...removeUndefinedProperties(txData as any),
|
...removeUndefinedProperties(txData as any),
|
||||||
// HACK: TS can't prove that T is spreadable.
|
// HACK: TS can't prove that T is spreadable.
|
||||||
// Awaiting https://github.com/Microsoft/TypeScript/pull/13288 to be merged
|
// Awaiting https://github.com/Microsoft/TypeScript/pull/13288 to be merged
|
||||||
@ -26,8 +61,10 @@ export class BaseContract {
|
|||||||
}
|
}
|
||||||
return txDataWithDefaults;
|
return txDataWithDefaults;
|
||||||
}
|
}
|
||||||
constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) {
|
constructor(web3Wrapper: Web3Wrapper, abi: Web3.ContractAbi, address: string) {
|
||||||
this._web3ContractInstance = web3ContractInstance;
|
this._web3Wrapper = web3Wrapper;
|
||||||
this._defaults = defaults;
|
this._abi = abi;
|
||||||
|
this._address = address;
|
||||||
|
this._ethersInterface = new ethersContracts.Interface(abi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
|||||||
address: metadata[0],
|
address: metadata[0],
|
||||||
name: metadata[1],
|
name: metadata[1],
|
||||||
symbol: metadata[2],
|
symbol: metadata[2],
|
||||||
decimals: metadata[3].toNumber(),
|
decimals: metadata[3],
|
||||||
};
|
};
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
@ -50,7 +50,8 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
|||||||
public async getTokenAddressesAsync(): Promise<string[]> {
|
public async getTokenAddressesAsync(): Promise<string[]> {
|
||||||
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
||||||
const addresses = await tokenRegistryContract.getTokenAddresses.callAsync();
|
const addresses = await tokenRegistryContract.getTokenAddresses.callAsync();
|
||||||
return addresses;
|
const lowerCaseAddresses = _.map(addresses, address => address.toLowerCase());
|
||||||
|
return lowerCaseAddresses;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Retrieves a token by address currently listed in the Token Registry smart contract
|
* Retrieves a token by address currently listed in the Token Registry smart contract
|
||||||
@ -116,14 +117,11 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
|||||||
if (!_.isUndefined(this._tokenRegistryContractIfExists)) {
|
if (!_.isUndefined(this._tokenRegistryContractIfExists)) {
|
||||||
return this._tokenRegistryContractIfExists;
|
return this._tokenRegistryContractIfExists;
|
||||||
}
|
}
|
||||||
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
|
||||||
artifacts.TokenRegistryArtifact,
|
artifacts.TokenRegistryArtifact,
|
||||||
this._contractAddressIfExists,
|
this._contractAddressIfExists,
|
||||||
);
|
);
|
||||||
const contractInstance = new TokenRegistryContract(
|
const contractInstance = new TokenRegistryContract(this._web3Wrapper, abi, address);
|
||||||
web3ContractInstance,
|
|
||||||
this._web3Wrapper.getContractDefaults(),
|
|
||||||
);
|
|
||||||
this._tokenRegistryContractIfExists = contractInstance;
|
this._tokenRegistryContractIfExists = contractInstance;
|
||||||
return this._tokenRegistryContractIfExists;
|
return this._tokenRegistryContractIfExists;
|
||||||
}
|
}
|
||||||
|
@ -59,14 +59,11 @@ export class TokenTransferProxyWrapper extends ContractWrapper {
|
|||||||
if (!_.isUndefined(this._tokenTransferProxyContractIfExists)) {
|
if (!_.isUndefined(this._tokenTransferProxyContractIfExists)) {
|
||||||
return this._tokenTransferProxyContractIfExists;
|
return this._tokenTransferProxyContractIfExists;
|
||||||
}
|
}
|
||||||
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
|
||||||
artifacts.TokenTransferProxyArtifact,
|
artifacts.TokenTransferProxyArtifact,
|
||||||
this._contractAddressIfExists,
|
this._contractAddressIfExists,
|
||||||
);
|
);
|
||||||
const contractInstance = new TokenTransferProxyContract(
|
const contractInstance = new TokenTransferProxyContract(this._web3Wrapper, abi, address);
|
||||||
web3ContractInstance,
|
|
||||||
this._web3Wrapper.getContractDefaults(),
|
|
||||||
);
|
|
||||||
this._tokenTransferProxyContractIfExists = contractInstance;
|
this._tokenTransferProxyContractIfExists = contractInstance;
|
||||||
return this._tokenTransferProxyContractIfExists;
|
return this._tokenTransferProxyContractIfExists;
|
||||||
}
|
}
|
||||||
|
@ -419,11 +419,11 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
if (!_.isUndefined(tokenContract)) {
|
if (!_.isUndefined(tokenContract)) {
|
||||||
return tokenContract;
|
return tokenContract;
|
||||||
}
|
}
|
||||||
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
|
||||||
artifacts.TokenArtifact,
|
artifacts.TokenArtifact,
|
||||||
normalizedTokenAddress,
|
normalizedTokenAddress,
|
||||||
);
|
);
|
||||||
const contractInstance = new TokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
|
const contractInstance = new TokenContract(this._web3Wrapper, abi, address);
|
||||||
tokenContract = contractInstance;
|
tokenContract = contractInstance;
|
||||||
this._tokenContractsByAddress[normalizedTokenAddress] = tokenContract;
|
this._tokenContractsByAddress[normalizedTokenAddress] = tokenContract;
|
||||||
return tokenContract;
|
return tokenContract;
|
||||||
|
28
packages/0x.js/src/globals.d.ts
vendored
28
packages/0x.js/src/globals.d.ts
vendored
@ -41,3 +41,31 @@ declare module 'truffle-hdwallet-provider' {
|
|||||||
}
|
}
|
||||||
export = HDWalletProvider;
|
export = HDWalletProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare module 'ethers-contracts' {
|
||||||
|
export interface TransactionDescription {
|
||||||
|
name: string;
|
||||||
|
signature: string;
|
||||||
|
sighash: string;
|
||||||
|
data: string;
|
||||||
|
}
|
||||||
|
export interface CallDescription extends TransactionDescription {
|
||||||
|
parse: (...args: any[]) => any;
|
||||||
|
}
|
||||||
|
export interface FunctionDescription {
|
||||||
|
(...params: any[]): TransactionDescription | CallDescription;
|
||||||
|
inputs: { names: string[]; types: string[] };
|
||||||
|
outputs: { names: string[]; types: string[] };
|
||||||
|
}
|
||||||
|
export interface EventDescription {
|
||||||
|
inputs: { names: string[]; types: string[] };
|
||||||
|
signature: string;
|
||||||
|
topic: string;
|
||||||
|
}
|
||||||
|
// tslint:disable-next-line:max-classes-per-file
|
||||||
|
export class Interface {
|
||||||
|
public functions: { [functionName: string]: FunctionDescription };
|
||||||
|
public events: { [eventName: string]: EventDescription };
|
||||||
|
constructor(abi: any);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -127,7 +127,7 @@ export interface SignedOrder extends Order {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// [address, name, symbol, decimals, ipfsHash, swarmHash]
|
// [address, name, symbol, decimals, ipfsHash, swarmHash]
|
||||||
export type TokenMetadata = [string, string, string, BigNumber, string, string];
|
export type TokenMetadata = [string, string, string, number, string, string];
|
||||||
|
|
||||||
export interface Token {
|
export interface Token {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -35,12 +35,8 @@ export class FillScenarios {
|
|||||||
const web3Wrapper = (this._zeroEx as any)._web3Wrapper as Web3Wrapper;
|
const web3Wrapper = (this._zeroEx as any)._web3Wrapper as Web3Wrapper;
|
||||||
for (const token of this._tokens) {
|
for (const token of this._tokens) {
|
||||||
if (token.symbol !== 'ZRX' && token.symbol !== 'WETH') {
|
if (token.symbol !== 'ZRX' && token.symbol !== 'WETH') {
|
||||||
const contractInstance = web3Wrapper.getContractInstance(
|
|
||||||
artifacts.DummyTokenArtifact.abi,
|
|
||||||
token.address,
|
|
||||||
);
|
|
||||||
const defaults = {};
|
const defaults = {};
|
||||||
const dummyToken = new DummyTokenContract(contractInstance, defaults);
|
const dummyToken = new DummyTokenContract(web3Wrapper, artifacts.DummyTokenArtifact.abi, token.address);
|
||||||
const tokenSupply = ZeroEx.toBaseUnitAmount(INITIAL_COINBASE_TOKEN_SUPPLY_IN_UNITS, token.decimals);
|
const tokenSupply = ZeroEx.toBaseUnitAmount(INITIAL_COINBASE_TOKEN_SUPPLY_IN_UNITS, token.decimals);
|
||||||
const txHash = await dummyToken.setBalance.sendTransactionAsync(this._coinbase, tokenSupply, {
|
const txHash = await dummyToken.setBalance.sendTransactionAsync(this._coinbase, tokenSupply, {
|
||||||
from: this._coinbase,
|
from: this._coinbase,
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
|
## v0.2.3 - _TBD, 2018_
|
||||||
|
|
||||||
|
* Add a `backend` parameter that allows you to specify your backend (web3 or ethers). Ethers auto-converts small ints to numbers (#TBD)
|
||||||
|
|
||||||
## v0.2.1 - _February 9, 2018_
|
## v0.2.1 - _February 9, 2018_
|
||||||
|
|
||||||
* Fix publishing issue where .npmignore was not properly excluding undesired content (#389)
|
* Fix publishing issue where .npmignore was not properly excluding undesired content (#389)
|
||||||
|
@ -11,13 +11,14 @@ import * as yargs from 'yargs';
|
|||||||
import toSnakeCase = require('to-snake-case');
|
import toSnakeCase = require('to-snake-case');
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import { ContextData, ParamKind } from './types';
|
import { ContextData, ContractsBackend, ParamKind } from './types';
|
||||||
import { utils } from './utils';
|
import { utils } from './utils';
|
||||||
|
|
||||||
const ABI_TYPE_CONSTRUCTOR = 'constructor';
|
const ABI_TYPE_CONSTRUCTOR = 'constructor';
|
||||||
const ABI_TYPE_METHOD = 'function';
|
const ABI_TYPE_METHOD = 'function';
|
||||||
const ABI_TYPE_EVENT = 'event';
|
const ABI_TYPE_EVENT = 'event';
|
||||||
const DEFAULT_NETWORK_ID = 50;
|
const DEFAULT_NETWORK_ID = 50;
|
||||||
|
const DEFAULT_BACKEND = 'web3';
|
||||||
|
|
||||||
const args = yargs
|
const args = yargs
|
||||||
.option('abis', {
|
.option('abis', {
|
||||||
@ -43,6 +44,12 @@ const args = yargs
|
|||||||
demandOption: true,
|
demandOption: true,
|
||||||
normalize: true,
|
normalize: true,
|
||||||
})
|
})
|
||||||
|
.option('backend', {
|
||||||
|
describe: 'Which backend do you plan to use. Either web3 or ethers',
|
||||||
|
type: 'string',
|
||||||
|
choices: [ContractsBackend.Web3, ContractsBackend.Ethers],
|
||||||
|
default: DEFAULT_BACKEND,
|
||||||
|
})
|
||||||
.option('network-id', {
|
.option('network-id', {
|
||||||
describe: 'ID of the network where contract ABIs are nested in artifacts',
|
describe: 'ID of the network where contract ABIs are nested in artifacts',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
@ -73,8 +80,8 @@ function writeOutputFile(name: string, renderedTsCode: string): void {
|
|||||||
utils.log(`Created: ${chalk.bold(filePath)}`);
|
utils.log(`Created: ${chalk.bold(filePath)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
Handlebars.registerHelper('parameterType', utils.solTypeToTsType.bind(utils, ParamKind.Input));
|
Handlebars.registerHelper('parameterType', utils.solTypeToTsType.bind(utils, ParamKind.Input, args.backend));
|
||||||
Handlebars.registerHelper('returnType', utils.solTypeToTsType.bind(utils, ParamKind.Output));
|
Handlebars.registerHelper('returnType', utils.solTypeToTsType.bind(utils, ParamKind.Output, args.backend));
|
||||||
|
|
||||||
if (args.partials) {
|
if (args.partials) {
|
||||||
registerPartials(args.partials);
|
registerPartials(args.partials);
|
||||||
|
@ -12,6 +12,11 @@ export enum AbiType {
|
|||||||
Fallback = 'fallback',
|
Fallback = 'fallback',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ContractsBackend {
|
||||||
|
Web3 = 'web3',
|
||||||
|
Ethers = 'ethers',
|
||||||
|
}
|
||||||
|
|
||||||
export interface Method extends Web3.MethodAbi {
|
export interface Method extends Web3.MethodAbi {
|
||||||
singleReturnValue: boolean;
|
singleReturnValue: boolean;
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,14 @@ import * as _ from 'lodash';
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import { AbiType, ParamKind } from './types';
|
import { AbiType, ContractsBackend, ParamKind } from './types';
|
||||||
|
|
||||||
export const utils = {
|
export const utils = {
|
||||||
solTypeToTsType(paramKind: ParamKind, solType: string): string {
|
solTypeToTsType(paramKind: ParamKind, backend: ContractsBackend, solType: string): string {
|
||||||
const trailingArrayRegex = /\[\d*\]$/;
|
const trailingArrayRegex = /\[\d*\]$/;
|
||||||
if (solType.match(trailingArrayRegex)) {
|
if (solType.match(trailingArrayRegex)) {
|
||||||
const arrayItemSolType = solType.replace(trailingArrayRegex, '');
|
const arrayItemSolType = solType.replace(trailingArrayRegex, '');
|
||||||
const arrayItemTsType = utils.solTypeToTsType(paramKind, arrayItemSolType);
|
const arrayItemTsType = utils.solTypeToTsType(paramKind, backend, arrayItemSolType);
|
||||||
const arrayTsType = utils.isUnionType(arrayItemTsType)
|
const arrayTsType = utils.isUnionType(arrayItemTsType)
|
||||||
? `Array<${arrayItemTsType}>`
|
? `Array<${arrayItemTsType}>`
|
||||||
: `${arrayItemTsType}[]`;
|
: `${arrayItemTsType}[]`;
|
||||||
@ -24,13 +24,21 @@ export const utils = {
|
|||||||
{ regex: '^bytes\\d*$', tsType: 'string' },
|
{ regex: '^bytes\\d*$', tsType: 'string' },
|
||||||
];
|
];
|
||||||
if (paramKind === ParamKind.Input) {
|
if (paramKind === ParamKind.Input) {
|
||||||
// web3 allows to pass those an non-bignumbers and that's nice
|
// web3 and ethers allow to pass those as numbers instead of bignumbers
|
||||||
// but it always returns stuff as BigNumbers
|
|
||||||
solTypeRegexToTsType.unshift({
|
solTypeRegexToTsType.unshift({
|
||||||
regex: '^u?int(8|16|32)?$',
|
regex: '^u?int(8|16|32)?$',
|
||||||
tsType: 'number|BigNumber',
|
tsType: 'number|BigNumber',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (backend === ContractsBackend.Ethers) {
|
||||||
|
if (paramKind === ParamKind.Output) {
|
||||||
|
// ethers-contracts automatically converts small BigNumbers to numbers
|
||||||
|
solTypeRegexToTsType.unshift({
|
||||||
|
regex: '^u?int(8|16|32|48)?$',
|
||||||
|
tsType: 'number',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
for (const regexAndTxType of solTypeRegexToTsType) {
|
for (const regexAndTxType of solTypeRegexToTsType) {
|
||||||
const { regex, tsType } = regexAndTxType;
|
const { regex, tsType } = regexAndTxType;
|
||||||
if (solType.match(regex)) {
|
if (solType.match(regex)) {
|
||||||
|
31
yarn.lock
31
yarn.lock
@ -10,6 +10,12 @@
|
|||||||
version "4.0.3"
|
version "4.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@types/bignumber.js/-/bignumber.js-4.0.3.tgz#e8ce5f28c3025a01c6af7fc6d944494903a9e348"
|
resolved "https://registry.yarnpkg.com/@types/bignumber.js/-/bignumber.js-4.0.3.tgz#e8ce5f28c3025a01c6af7fc6d944494903a9e348"
|
||||||
|
|
||||||
|
"@types/bignumber.js@^5.0.0":
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/bignumber.js/-/bignumber.js-5.0.0.tgz#d9f1a378509f3010a3255e9cc822ad0eeb4ab969"
|
||||||
|
dependencies:
|
||||||
|
bignumber.js "*"
|
||||||
|
|
||||||
"@types/bintrees@^1.0.2":
|
"@types/bintrees@^1.0.2":
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@types/bintrees/-/bintrees-1.0.2.tgz#0dfdce4eeebdf90427bd35b0e79dc248b3d157a6"
|
resolved "https://registry.yarnpkg.com/@types/bintrees/-/bintrees-1.0.2.tgz#0dfdce4eeebdf90427bd35b0e79dc248b3d157a6"
|
||||||
@ -1283,6 +1289,10 @@ big.js@^3.1.3:
|
|||||||
version "3.2.0"
|
version "3.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e"
|
resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e"
|
||||||
|
|
||||||
|
bignumber.js@*, bignumber.js@^6.0.0:
|
||||||
|
version "6.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-6.0.0.tgz#bbfa047644609a5af093e9cbd83b0461fa3f6002"
|
||||||
|
|
||||||
"bignumber.js@git+https://github.com/debris/bignumber.js#master":
|
"bignumber.js@git+https://github.com/debris/bignumber.js#master":
|
||||||
version "2.0.7"
|
version "2.0.7"
|
||||||
resolved "git+https://github.com/debris/bignumber.js#c7a38de919ed75e6fb6ba38051986e294b328df9"
|
resolved "git+https://github.com/debris/bignumber.js#c7a38de919ed75e6fb6ba38051986e294b328df9"
|
||||||
@ -3227,6 +3237,21 @@ ethereumjs-wallet@^0.6.0:
|
|||||||
utf8 "^2.1.1"
|
utf8 "^2.1.1"
|
||||||
uuid "^2.0.1"
|
uuid "^2.0.1"
|
||||||
|
|
||||||
|
ethers-contracts@^2.2.1:
|
||||||
|
version "2.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/ethers-contracts/-/ethers-contracts-2.2.1.tgz#e2bf5dd5e157313ba454b50c646c8472fcd0a8b3"
|
||||||
|
dependencies:
|
||||||
|
ethers-utils "^2.1.0"
|
||||||
|
|
||||||
|
ethers-utils@^2.1.0:
|
||||||
|
version "2.1.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/ethers-utils/-/ethers-utils-2.1.11.tgz#b27535ca3226118be300211c39c896b1e5e21641"
|
||||||
|
dependencies:
|
||||||
|
bn.js "^4.4.0"
|
||||||
|
hash.js "^1.0.0"
|
||||||
|
js-sha3 "0.5.7"
|
||||||
|
xmlhttprequest "1.8.0"
|
||||||
|
|
||||||
ethjs-abi@0.1.8:
|
ethjs-abi@0.1.8:
|
||||||
version "0.1.8"
|
version "0.1.8"
|
||||||
resolved "https://registry.yarnpkg.com/ethjs-abi/-/ethjs-abi-0.1.8.tgz#cd288583ed628cdfadaf8adefa3ba1dbcbca6c18"
|
resolved "https://registry.yarnpkg.com/ethjs-abi/-/ethjs-abi-0.1.8.tgz#cd288583ed628cdfadaf8adefa3ba1dbcbca6c18"
|
||||||
@ -4970,6 +4995,10 @@ js-sha3@0.5.5:
|
|||||||
version "0.5.5"
|
version "0.5.5"
|
||||||
resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.5.tgz#baf0c0e8c54ad5903447df96ade7a4a1bca79a4a"
|
resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.5.tgz#baf0c0e8c54ad5903447df96ade7a4a1bca79a4a"
|
||||||
|
|
||||||
|
js-sha3@0.5.7:
|
||||||
|
version "0.5.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7"
|
||||||
|
|
||||||
js-sha3@^0.3.1:
|
js-sha3@^0.3.1:
|
||||||
version "0.3.1"
|
version "0.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.3.1.tgz#86122802142f0828502a0d1dee1d95e253bb0243"
|
resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.3.1.tgz#86122802142f0828502a0d1dee1d95e253bb0243"
|
||||||
@ -9811,7 +9840,7 @@ xml-js@^1.3.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
sax "^1.2.4"
|
sax "^1.2.4"
|
||||||
|
|
||||||
xmlhttprequest@*:
|
xmlhttprequest@*, xmlhttprequest@1.8.0:
|
||||||
version "1.8.0"
|
version "1.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc"
|
resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user