Merge pull request #413 from 0xProject/feature/ethers-contracts

abi-gen V2 abi and ethers-contracts
This commit is contained in:
Leonid Logvinov 2018-02-27 14:41:59 -08:00 committed by GitHub
commit 7aa070f9ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
79 changed files with 749 additions and 545 deletions

View File

@ -1,5 +1,4 @@
lib lib
generated
.nyc_output .nyc_output
/packages/contracts/src/artifacts /packages/contracts/src/artifacts
package.json package.json

View File

@ -4,6 +4,7 @@
* Validate and lowercase all addresses in public methods (#373) * Validate and lowercase all addresses in public methods (#373)
* Improve validation to force passing contract addresses on private networks (#385) * Improve validation to force passing contract addresses on private networks (#385)
* Change `LogErrorContractEventArgs.errorId` type from `BigNumber` to `number` (#413)
* Rename all public `_unsubscribeAll` methods to `unsubscribeAll` (#415) * Rename all public `_unsubscribeAll` methods to `unsubscribeAll` (#415)
## v0.32.2 - _February 9, 2018_ ## v0.32.2 - _February 9, 2018_

View File

@ -1,15 +0,0 @@
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;
},
};

View File

@ -1,6 +0,0 @@
{{#singleReturnValue}}
{{#returnType outputs.0.type}}{{/returnType}}
{{/singleReturnValue}}
{{^singleReturnValue}}
[{{#each outputs}}{{#returnType type}}{{/returnType}}{{#unless @last}}, {{/unless}}{{/each}}]
{{/singleReturnValue}}

View File

@ -1,3 +0,0 @@
{{#each inputs}}
{{name}}: {{#parameterType type}}{{/parameterType}},
{{/each}}

View File

@ -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 --backend ethers && 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",
@ -77,6 +77,7 @@
"types-bn": "^0.0.1", "types-bn": "^0.0.1",
"typescript": "2.7.1", "typescript": "2.7.1",
"web3-provider-engine": "^13.0.1", "web3-provider-engine": "^13.0.1",
"ethers-typescript-typings": "^0.0.1",
"web3-typescript-typings": "^0.9.11", "web3-typescript-typings": "^0.9.11",
"webpack": "^3.1.0" "webpack": "^3.1.0"
}, },
@ -88,6 +89,7 @@
"@0xproject/web3-wrapper": "^0.1.14", "@0xproject/web3-wrapper": "^0.1.14",
"bintrees": "^1.0.2", "bintrees": "^1.0.2",
"bn.js": "^4.11.8", "bn.js": "^4.11.8",
"ethers-contracts": "^2.2.1",
"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",

View File

@ -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)) {

View File

@ -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;

View File

@ -108,8 +108,10 @@ export class ExchangeWrapper extends ContractWrapper {
const exchangeContract = await this._getExchangeContractAsync(); const exchangeContract = await this._getExchangeContractAsync();
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock; const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
const txData = {};
let unavailableTakerTokenAmount = await exchangeContract.getUnavailableTakerTokenAmount.callAsync( let unavailableTakerTokenAmount = await exchangeContract.getUnavailableTakerTokenAmount.callAsync(
orderHash, orderHash,
txData,
defaultBlock, defaultBlock,
); );
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
@ -127,7 +129,8 @@ export class ExchangeWrapper extends ContractWrapper {
const exchangeContract = await this._getExchangeContractAsync(); const exchangeContract = await this._getExchangeContractAsync();
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock; const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
let fillAmountInBaseUnits = await exchangeContract.filled.callAsync(orderHash, defaultBlock); const txData = {};
let fillAmountInBaseUnits = await exchangeContract.filled.callAsync(orderHash, txData, defaultBlock);
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
fillAmountInBaseUnits = new BigNumber(fillAmountInBaseUnits); fillAmountInBaseUnits = new BigNumber(fillAmountInBaseUnits);
return fillAmountInBaseUnits; return fillAmountInBaseUnits;
@ -144,7 +147,8 @@ export class ExchangeWrapper extends ContractWrapper {
const exchangeContract = await this._getExchangeContractAsync(); const exchangeContract = await this._getExchangeContractAsync();
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock; const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
let cancelledAmountInBaseUnits = await exchangeContract.cancelled.callAsync(orderHash, defaultBlock); const txData = {};
let cancelledAmountInBaseUnits = await exchangeContract.cancelled.callAsync(orderHash, txData, defaultBlock);
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
cancelledAmountInBaseUnits = new BigNumber(cancelledAmountInBaseUnits); cancelledAmountInBaseUnits = new BigNumber(cancelledAmountInBaseUnits);
return cancelledAmountInBaseUnits; return cancelledAmountInBaseUnits;
@ -858,7 +862,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 +910,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;
} }

View File

@ -1,6 +1 @@
dummy_token.ts *
ether_token.ts
exchange.ts
token_registry.ts
token_transfer_proxy.ts
token.ts

View File

@ -1,33 +0,0 @@
import {TxData, TxDataPayable} from '@0xproject/types';
import * as _ from 'lodash';
import * as Web3 from 'web3';
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;
}
}

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -51,7 +51,8 @@ export class TokenWrapper extends ContractWrapper {
const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock; const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
let balance = await tokenContract.balanceOf.callAsync(normalizedOwnerAddress, defaultBlock); const txData = {};
let balance = await tokenContract.balanceOf.callAsync(normalizedOwnerAddress, txData, defaultBlock);
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
balance = new BigNumber(balance); balance = new BigNumber(balance);
return balance; return balance;
@ -146,9 +147,11 @@ export class TokenWrapper extends ContractWrapper {
const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock; const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
const txData = {};
let allowanceInBaseUnits = await tokenContract.allowance.callAsync( let allowanceInBaseUnits = await tokenContract.allowance.callAsync(
normalizedOwnerAddress, normalizedOwnerAddress,
normalizedSpenderAddress, normalizedSpenderAddress,
txData,
defaultBlock, defaultBlock,
); );
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
@ -419,11 +422,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;

View File

@ -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;

View File

@ -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,

View File

@ -9,6 +9,7 @@
"./test/**/*", "./test/**/*",
"../../node_modules/types-bn/index.d.ts", "../../node_modules/types-bn/index.d.ts",
"../../node_modules/types-ethereumjs-util/index.d.ts", "../../node_modules/types-ethereumjs-util/index.d.ts",
"../../node_modules/ethers-typescript-typings/index.d.ts",
"../../node_modules/web3-typescript-typings/index.d.ts", "../../node_modules/web3-typescript-typings/index.d.ts",
"../../node_modules/chai-typescript-typings/index.d.ts", "../../node_modules/chai-typescript-typings/index.d.ts",
"../../node_modules/chai-as-promised-typescript-typings/index.d.ts" "../../node_modules/chai-as-promised-typescript-typings/index.d.ts"

View File

@ -1,5 +1,11 @@
# CHANGELOG # CHANGELOG
## v0.2.3 - _TBD, 2018_
* Add a `backend` parameter that allows you to specify the Ethereum library you use in your templates (`web3` or `ethers`). Ethers auto-converts small ints to numbers whereas Web3 doesn't. Defaults to `web3` (#413)
* Add support for [tuple types](https://solidity.readthedocs.io/en/develop/abi-spec.html#handling-tuple-types) (#413)
* Add `hasReturnValue` to context data (#413)
## v0.2.1 - _February 9, 2018_ ## 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)

View File

@ -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: `The backing Ethereum library your app uses. Either 'web3' or 'ethers'. Ethers auto-converts small ints to numbers whereas Web3 doesn't.`,
type: 'string',
choices: [ContractsBackend.Web3, ContractsBackend.Ethers],
default: DEFAULT_BACKEND,
})
.option('network-id', { .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);
@ -129,6 +136,7 @@ for (const abiFileName of abiFileNames) {
const methodData = { const methodData = {
...methodAbi, ...methodAbi,
singleReturnValue: methodAbi.outputs.length === 1, singleReturnValue: methodAbi.outputs.length === 1,
hasReturnValue: methodAbi.outputs.length !== 0,
}; };
return methodData; return methodData;
}); });

View File

@ -12,8 +12,14 @@ 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;
hasReturnValue: boolean;
} }
export interface ContextData { export interface ContextData {

View File

@ -3,15 +3,21 @@ 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,
components?: Web3.DataItem[],
): 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, components);
const arrayTsType = utils.isUnionType(arrayItemTsType) const arrayTsType =
utils.isUnionType(arrayItemTsType) || utils.isObjectType(arrayItemTsType)
? `Array<${arrayItemTsType}>` ? `Array<${arrayItemTsType}>`
: `${arrayItemTsType}[]`; : `${arrayItemTsType}[]`;
return arrayTsType; return arrayTsType;
@ -24,25 +30,49 @@ 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 && 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)) {
return tsType; return tsType;
} }
} }
const TUPLE_TYPE_REGEX = '^tuple$';
if (solType.match(TUPLE_TYPE_REGEX)) {
const componentsType = _.map(components, component => {
const componentValueType = utils.solTypeToTsType(
paramKind,
backend,
component.type,
component.components,
);
const componentType = `${component.name}: ${componentValueType}`;
return componentType;
});
const tsType = `{${componentsType}}`;
return tsType;
}
throw new Error(`Unknown Solidity type found: ${solType}`); throw new Error(`Unknown Solidity type found: ${solType}`);
} }
}, },
isUnionType(tsType: string): boolean { isUnionType(tsType: string): boolean {
return tsType === 'number|BigNumber'; return tsType === 'number|BigNumber';
}, },
isObjectType(tsType: string): boolean {
return /^{.*}$/.test(tsType);
},
log(...args: any[]): void { log(...args: any[]): void {
console.log(...args); // tslint:disable-line:no-console console.log(...args); // tslint:disable-line:no-console
}, },

View File

@ -1,15 +1,16 @@
/** /**
* This file is auto-generated using abi-gen. Don't edit directly. * 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/0x.js/contract_templates. * Templates can be found at https://github.com/0xProject/0x.js/tree/development/packages/contract_templates.
*/ */
// tslint:disable:no-consecutive-blank-lines // tslint:disable:no-consecutive-blank-lines
// 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 { BaseContract, 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';
{{#if events}} {{#if events}}
export type {{contractName}}ContractEventArgs = export type {{contractName}}ContractEventArgs =
{{#each events}} {{#each events}}
@ -28,6 +29,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 +39,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

View File

@ -0,0 +1,3 @@
public {{this.name}} = {
{{> callAsync}}
};

View File

@ -0,0 +1,30 @@
{{#hasReturnValue}}
async callAsync(
{{> typed_params inputs=inputs}}
{{#this.payable}}
txData: TxDataPayable = {},
{{/this.payable}}
{{^this.payable}}
txData: TxData = {},
{{/this.payable}}
defaultBlock?: Web3.BlockParam,
): Promise<{{> return_type outputs=outputs}}> {
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 encodedData = self._ethersInterface.functions.{{this.name}}(
{{> params inputs=inputs}}
).data;
const callData = await self._applyDefaultsToTxDataAsync(
{
data: encodedData,
}
)
const rawCallResult = await self._web3Wrapper.callAsync(callData, defaultBlock);
const outputAbi = _.find(this.abi, {name: '{{this.name}}'}).outputs as Web3.DataItem[];
const outputParamsTypes = _.map(outputAbi, 'type');
let resultArray = ethersContracts.Interface.decodeParams(outputParamsTypes, rawCallResult) as any;
resultArray = BaseContract._transformABIData(outputAbi, resultArray, BaseContract._lowercaseAddress.bind(this));
return resultArray{{#singleReturnValue}}[0]{{/singleReturnValue}};
},
{{/hasReturnValue}}

View File

@ -1,5 +1,5 @@
export interface {{name}}ContractEventArgs { export interface {{name}}ContractEventArgs {
{{#each inputs}} {{#each inputs}}
{{name}}: {{#returnType type}}{{/returnType}}; {{name}}: {{#returnType type components}}{{/returnType}};
{{/each}} {{/each}}
} }

View File

@ -0,0 +1,10 @@
{{#if outputs.length}}
{{#singleReturnValue}}
{{#returnType outputs.0.type components}}{{/returnType}}
{{/singleReturnValue}}
{{^singleReturnValue}}
[{{#each outputs}}{{#returnType type components}}{{/returnType}}{{#unless @last}}, {{/unless}}{{/each}}]
{{/singleReturnValue}}
{{else}}
void
{{/if}}

View File

@ -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 encodedData = this._ethersInterface.functions.{{this.name}}(
{{> params inputs=inputs}}
).data
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( const txDataWithDefaults = await self._applyDefaultsToTxDataAsync(
txData, {
...txData,
data: encodedData,
},
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 encodedData = 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: encodedData,
}
); );
const gas = await this._web3Wrapper.estimateGasAsync(txDataWithDefaults);
return gas; return gas;
}, },
getABIEncodedTransactionData( getABIEncodedTransactionData(
@ -45,7 +49,10 @@ 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;
}, },
{{> callAsync}}
}; };

View File

@ -0,0 +1,3 @@
{{#each inputs}}
{{name}}: {{#parameterType type components}}{{/parameterType}},
{{/each}}

View File

@ -1,26 +0,0 @@
/**
* 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.
*/
// tslint:disable:async-suffix member-ordering no-consecutive-blank-lines
// tslint:disable-next-line:no-unused-variable
import { TxData, TxDataPayable } from '@0xproject/types';
import { BigNumber, classUtils, promisify } from '@0xproject/utils';
import * as Web3 from 'web3';
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

View File

@ -1,10 +0,0 @@
public async {{this.name}}(
{{> typed_params inputs=inputs}}
defaultBlock?: Web3.BlockParam,
): Promise<{{> return_type outputs=outputs}}> {
const self = this as {{contractName}}Contract;
const result = await self._web3ContractInstance.{{this.name}}.call(
{{> params inputs=inputs}}
);
return result;
}

View File

@ -1,3 +0,0 @@
{{#each inputs}}
{{name}},
{{/each}}

View File

@ -1,10 +0,0 @@
{{#if outputs.length}}
{{#singleReturnValue}}
{{#returnType outputs.0.type}}{{/returnType}}
{{/singleReturnValue}}
{{^singleReturnValue}}
[{{#each outputs}}{{#returnType type}}{{/returnType}}{{#unless @last}}, {{/unless}}{{/each}}]
{{/singleReturnValue}}
{{else}}
void
{{/if}}

View File

@ -1,36 +0,0 @@
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);
const txHash = await self._web3ContractInstance.{{this.name}}(
{{> params inputs=inputs}}
txDataWithDefaults,
);
return txHash;
},
async callAsync(
{{> typed_params inputs=inputs}}
{{#this.payable}}
txData: TxDataPayable = {},
{{/this.payable}}
{{^this.payable}}
txData: TxData = {},
{{/this.payable}}
): Promise<{{> return_type outputs=outputs}}> {
const self = this as {{contractName}}Contract;
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync(txData);
const returnValue = await self._web3ContractInstance.{{this.name}}.call(
{{> params inputs=inputs}}
txDataWithDefaults,
);
return returnValue;
},
};

View File

@ -1,3 +0,0 @@
{{#each inputs}}
{{name}}: {{#parameterType type}}{{/parameterType}},
{{/each}}

View File

@ -17,7 +17,7 @@
"compile:comment": "Yarn workspaces do not link binaries correctly so we need to reference them directly https://github.com/yarnpkg/yarn/issues/3846", "compile:comment": "Yarn workspaces do not link binaries correctly so we need to reference them directly https://github.com/yarnpkg/yarn/issues/3846",
"compile": "node ../deployer/lib/src/cli.js compile --contracts ${npm_package_config_contracts} --contracts-dir src/contracts --artifacts-dir src/artifacts", "compile": "node ../deployer/lib/src/cli.js compile --contracts ${npm_package_config_contracts} --contracts-dir src/contracts --artifacts-dir src/artifacts",
"clean": "shx rm -rf ./lib", "clean": "shx rm -rf ./lib",
"generate_contract_wrappers": "node ../abi-gen/lib/index.js --abis 'src/artifacts/@(DummyToken|TokenTransferProxy|Exchange|TokenRegistry|MultiSigWallet|MultiSigWalletWithTimeLock|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|TokenRegistry|ZRXToken).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/@(DummyToken|TokenTransferProxy|Exchange|TokenRegistry|MultiSigWallet|MultiSigWalletWithTimeLock|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|TokenRegistry|ZRXToken).json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated --backend ethers && prettier --write 'src/contract_wrappers/generated/**.ts'",
"migrate": "node ../deployer/lib/src/cli.js migrate", "migrate": "node ../deployer/lib/src/cli.js migrate",
"lint": "tslint --project . 'migrations/**/*.ts' 'test/**/*.ts' 'util/**/*.ts' 'deploy/**/*.ts'", "lint": "tslint --project . 'migrations/**/*.ts' 'test/**/*.ts' 'util/**/*.ts' 'deploy/**/*.ts'",
"test:circleci": "yarn test" "test:circleci": "yarn test"
@ -58,6 +58,7 @@
"types-bn": "^0.0.1", "types-bn": "^0.0.1",
"types-ethereumjs-util": "0xProject/types-ethereumjs-util", "types-ethereumjs-util": "0xProject/types-ethereumjs-util",
"typescript": "2.7.1", "typescript": "2.7.1",
"ethers-typescript-typings": "^0.0.1",
"web3-typescript-typings": "^0.9.11", "web3-typescript-typings": "^0.9.11",
"yargs": "^10.0.3" "yargs": "^10.0.3"
}, },
@ -72,6 +73,7 @@
"bn.js": "^4.11.8", "bn.js": "^4.11.8",
"ethereumjs-abi": "^0.6.4", "ethereumjs-abi": "^0.6.4",
"ethereumjs-util": "^5.1.1", "ethereumjs-util": "^5.1.1",
"ethers-contracts": "^2.2.1",
"isomorphic-fetch": "^2.2.1", "isomorphic-fetch": "^2.2.1",
"lodash": "^4.17.4", "lodash": "^4.17.4",
"request": "^2.81.0", "request": "^2.81.0",

View File

@ -1,8 +1 @@
dummy_token.ts *
exchange.ts
multi_sig_wallet_with_time_lock_except_remove_authorized_address.ts
multi_sig_wallet_with_time_lock.ts
multi_sig_wallet.ts
token_registry.ts
token_transfer_proxy.ts
zrx_token.ts

View File

@ -1,35 +0,0 @@
import {TxData, TxDataPayable} from '@0xproject/types';
import * as _ from 'lodash';
import * as Web3 from 'web3';
export class BaseContract {
public address: string;
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.address = web3ContractInstance.address;
this._web3ContractInstance = web3ContractInstance;
this._defaults = defaults || {};
}
}

View File

@ -1,12 +1,4 @@
import { import { LogWithDecodedArgs, SignedOrder, TransactionReceiptWithDecodedLogs, ZeroEx } from '0x.js';
LogCancelContractEventArgs,
LogErrorContractEventArgs,
LogFillContractEventArgs,
LogWithDecodedArgs,
SignedOrder,
TransactionReceiptWithDecodedLogs,
ZeroEx,
} from '0x.js';
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils'; import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
import { BigNumber } from '@0xproject/utils'; import { BigNumber } from '@0xproject/utils';
import { Web3Wrapper } from '@0xproject/web3-wrapper'; import { Web3Wrapper } from '@0xproject/web3-wrapper';
@ -15,7 +7,12 @@ import ethUtil = require('ethereumjs-util');
import * as Web3 from 'web3'; import * as Web3 from 'web3';
import { DummyTokenContract } from '../../src/contract_wrappers/generated/dummy_token'; import { DummyTokenContract } from '../../src/contract_wrappers/generated/dummy_token';
import { ExchangeContract } from '../../src/contract_wrappers/generated/exchange'; import {
ExchangeContract,
LogCancelContractEventArgs,
LogErrorContractEventArgs,
LogFillContractEventArgs,
} from '../../src/contract_wrappers/generated/exchange';
import { TokenTransferProxyContract } from '../../src/contract_wrappers/generated/token_transfer_proxy'; import { TokenTransferProxyContract } from '../../src/contract_wrappers/generated/token_transfer_proxy';
import { Balances } from '../../util/balances'; import { Balances } from '../../util/balances';
import { constants } from '../../util/constants'; import { constants } from '../../util/constants';
@ -63,16 +60,20 @@ describe('Exchange', () => {
deployer.deployAsync(ContractName.DummyToken), deployer.deployAsync(ContractName.DummyToken),
deployer.deployAsync(ContractName.DummyToken), deployer.deployAsync(ContractName.DummyToken),
]); ]);
rep = new DummyTokenContract(repInstance); rep = new DummyTokenContract(web3Wrapper, repInstance.abi, repInstance.address);
dgd = new DummyTokenContract(dgdInstance); dgd = new DummyTokenContract(web3Wrapper, dgdInstance.abi, dgdInstance.address);
zrx = new DummyTokenContract(zrxInstance); zrx = new DummyTokenContract(web3Wrapper, zrxInstance.abi, zrxInstance.address);
const tokenTransferProxyInstance = await deployer.deployAsync(ContractName.TokenTransferProxy); const tokenTransferProxyInstance = await deployer.deployAsync(ContractName.TokenTransferProxy);
tokenTransferProxy = new TokenTransferProxyContract(tokenTransferProxyInstance); tokenTransferProxy = new TokenTransferProxyContract(
web3Wrapper,
tokenTransferProxyInstance.abi,
tokenTransferProxyInstance.address,
);
const exchangeInstance = await deployer.deployAsync(ContractName.Exchange, [ const exchangeInstance = await deployer.deployAsync(ContractName.Exchange, [
zrx.address, zrx.address,
tokenTransferProxy.address, tokenTransferProxy.address,
]); ]);
exchange = new ExchangeContract(exchangeInstance); exchange = new ExchangeContract(web3Wrapper, exchangeInstance.abi, exchangeInstance.address);
await tokenTransferProxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: accounts[0] }); await tokenTransferProxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: accounts[0] });
zeroEx = new ZeroEx(web3.currentProvider, { zeroEx = new ZeroEx(web3.currentProvider, {
exchangeContractAddress: exchange.address, exchangeContractAddress: exchange.address,
@ -650,7 +651,7 @@ describe('Exchange', () => {
it('should not change balances if makerTokenAddress is ZRX, makerTokenAmount + makerFee > maker allowance, \ it('should not change balances if makerTokenAddress is ZRX, makerTokenAmount + makerFee > maker allowance, \
and shouldThrowOnInsufficientBalanceOrAllowance = false', async () => { and shouldThrowOnInsufficientBalanceOrAllowance = false', async () => {
const makerZRXAllowance = await zrx.allowance(maker, tokenTransferProxy.address); const makerZRXAllowance = await zrx.allowance.callAsync(maker, tokenTransferProxy.address);
signedOrder = await orderFactory.newSignedOrderAsync({ signedOrder = await orderFactory.newSignedOrderAsync({
makerTokenAddress: zrx.address, makerTokenAddress: zrx.address,
makerTokenAmount: new BigNumber(makerZRXAllowance), makerTokenAmount: new BigNumber(makerZRXAllowance),
@ -676,7 +677,7 @@ describe('Exchange', () => {
it('should not change balances if takerTokenAddress is ZRX, takerTokenAmount + takerFee > taker allowance, \ it('should not change balances if takerTokenAddress is ZRX, takerTokenAmount + takerFee > taker allowance, \
and shouldThrowOnInsufficientBalanceOrAllowance = false', async () => { and shouldThrowOnInsufficientBalanceOrAllowance = false', async () => {
const takerZRXAllowance = await zrx.allowance(taker, tokenTransferProxy.address); const takerZRXAllowance = await zrx.allowance.callAsync(taker, tokenTransferProxy.address);
signedOrder = await orderFactory.newSignedOrderAsync({ signedOrder = await orderFactory.newSignedOrderAsync({
takerTokenAddress: zrx.address, takerTokenAddress: zrx.address,
takerTokenAmount: new BigNumber(takerZRXAllowance), takerTokenAmount: new BigNumber(takerZRXAllowance),
@ -723,7 +724,7 @@ describe('Exchange', () => {
const res = await exWrapper.fillOrderAsync(signedOrder, taker); const res = await exWrapper.fillOrderAsync(signedOrder, taker);
expect(res.logs).to.have.length(1); expect(res.logs).to.have.length(1);
const log = res.logs[0] as LogWithDecodedArgs<LogErrorContractEventArgs>; const log = res.logs[0] as LogWithDecodedArgs<LogErrorContractEventArgs>;
const errCode = log.args.errorId.toNumber(); const errCode = log.args.errorId;
expect(errCode).to.be.equal(ExchangeContractErrs.ERROR_ORDER_EXPIRED); expect(errCode).to.be.equal(ExchangeContractErrs.ERROR_ORDER_EXPIRED);
}); });
@ -734,7 +735,7 @@ describe('Exchange', () => {
const res = await exWrapper.fillOrderAsync(signedOrder, taker); const res = await exWrapper.fillOrderAsync(signedOrder, taker);
expect(res.logs).to.have.length(1); expect(res.logs).to.have.length(1);
const log = res.logs[0] as LogWithDecodedArgs<LogErrorContractEventArgs>; const log = res.logs[0] as LogWithDecodedArgs<LogErrorContractEventArgs>;
const errCode = log.args.errorId.toNumber(); const errCode = log.args.errorId;
expect(errCode).to.be.equal(ExchangeContractErrs.ERROR_ORDER_FULLY_FILLED_OR_CANCELLED); expect(errCode).to.be.equal(ExchangeContractErrs.ERROR_ORDER_FULLY_FILLED_OR_CANCELLED);
}); });
}); });
@ -862,7 +863,7 @@ describe('Exchange', () => {
const res = await exWrapper.cancelOrderAsync(signedOrder, maker); const res = await exWrapper.cancelOrderAsync(signedOrder, maker);
expect(res.logs).to.have.length(1); expect(res.logs).to.have.length(1);
const log = res.logs[0] as LogWithDecodedArgs<LogErrorContractEventArgs>; const log = res.logs[0] as LogWithDecodedArgs<LogErrorContractEventArgs>;
const errCode = log.args.errorId.toNumber(); const errCode = log.args.errorId;
expect(errCode).to.be.equal(ExchangeContractErrs.ERROR_ORDER_FULLY_FILLED_OR_CANCELLED); expect(errCode).to.be.equal(ExchangeContractErrs.ERROR_ORDER_FULLY_FILLED_OR_CANCELLED);
}); });
@ -874,7 +875,7 @@ describe('Exchange', () => {
const res = await exWrapper.cancelOrderAsync(signedOrder, maker); const res = await exWrapper.cancelOrderAsync(signedOrder, maker);
expect(res.logs).to.have.length(1); expect(res.logs).to.have.length(1);
const log = res.logs[0] as LogWithDecodedArgs<LogErrorContractEventArgs>; const log = res.logs[0] as LogWithDecodedArgs<LogErrorContractEventArgs>;
const errCode = log.args.errorId.toNumber(); const errCode = log.args.errorId;
expect(errCode).to.be.equal(ExchangeContractErrs.ERROR_ORDER_EXPIRED); expect(errCode).to.be.equal(ExchangeContractErrs.ERROR_ORDER_EXPIRED);
}); });
}); });

View File

@ -5,7 +5,12 @@ import { Web3Wrapper } from '@0xproject/web3-wrapper';
import * as chai from 'chai'; import * as chai from 'chai';
import ethUtil = require('ethereumjs-util'); import ethUtil = require('ethereumjs-util');
import { ExchangeContract } from '../../src/contract_wrappers/generated/exchange'; import {
ExchangeContract,
LogCancelContractEventArgs,
LogErrorContractEventArgs,
LogFillContractEventArgs,
} from '../../src/contract_wrappers/generated/exchange';
import { constants } from '../../util/constants'; import { constants } from '../../util/constants';
import { ExchangeWrapper } from '../../util/exchange_wrapper'; import { ExchangeWrapper } from '../../util/exchange_wrapper';
import { OrderFactory } from '../../util/order_factory'; import { OrderFactory } from '../../util/order_factory';
@ -42,7 +47,7 @@ describe('Exchange', () => {
zrx.address, zrx.address,
tokenTransferProxy.address, tokenTransferProxy.address,
]); ]);
const exchange = new ExchangeContract(exchangeInstance); const exchange = new ExchangeContract(web3Wrapper, exchangeInstance.abi, exchangeInstance.address);
await tokenTransferProxy.addAuthorizedAddress(exchange.address, { from: accounts[0] }); await tokenTransferProxy.addAuthorizedAddress(exchange.address, { from: accounts[0] });
const zeroEx = new ZeroEx(web3.currentProvider, { networkId: constants.TESTRPC_NETWORK_ID }); const zeroEx = new ZeroEx(web3.currentProvider, { networkId: constants.TESTRPC_NETWORK_ID });
exchangeWrapper = new ExchangeWrapper(exchange, zeroEx); exchangeWrapper = new ExchangeWrapper(exchange, zeroEx);
@ -50,8 +55,8 @@ describe('Exchange', () => {
exchangeContractAddress: exchange.address, exchangeContractAddress: exchange.address,
maker, maker,
feeRecipient, feeRecipient,
makerToken: rep.address, makerTokenAddress: rep.address,
takerToken: dgd.address, takerTokenAddress: dgd.address,
makerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100), 18), makerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100), 18),
takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(200), 18), takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(200), 18),
makerFee: ZeroEx.toBaseUnitAmount(new BigNumber(1), 18), makerFee: ZeroEx.toBaseUnitAmount(new BigNumber(1), 18),

View File

@ -7,7 +7,12 @@ import * as _ from 'lodash';
import * as Web3 from 'web3'; import * as Web3 from 'web3';
import { DummyTokenContract } from '../../src/contract_wrappers/generated/dummy_token'; import { DummyTokenContract } from '../../src/contract_wrappers/generated/dummy_token';
import { ExchangeContract } from '../../src/contract_wrappers/generated/exchange'; import {
ExchangeContract,
LogCancelContractEventArgs,
LogErrorContractEventArgs,
LogFillContractEventArgs,
} from '../../src/contract_wrappers/generated/exchange';
import { TokenRegistryContract } from '../../src/contract_wrappers/generated/token_registry'; import { TokenRegistryContract } from '../../src/contract_wrappers/generated/token_registry';
import { TokenTransferProxyContract } from '../../src/contract_wrappers/generated/token_transfer_proxy'; import { TokenTransferProxyContract } from '../../src/contract_wrappers/generated/token_transfer_proxy';
import { Balances } from '../../util/balances'; import { Balances } from '../../util/balances';
@ -55,18 +60,26 @@ describe('Exchange', () => {
deployer.deployAsync(ContractName.DummyToken), deployer.deployAsync(ContractName.DummyToken),
deployer.deployAsync(ContractName.DummyToken), deployer.deployAsync(ContractName.DummyToken),
]); ]);
rep = new DummyTokenContract(repInstance); rep = new DummyTokenContract(web3Wrapper, repInstance.abi, repInstance.address);
dgd = new DummyTokenContract(dgdInstance); dgd = new DummyTokenContract(web3Wrapper, dgdInstance.abi, dgdInstance.address);
zrx = new DummyTokenContract(zrxInstance); zrx = new DummyTokenContract(web3Wrapper, zrxInstance.abi, zrxInstance.address);
const tokenRegistryInstance = await deployer.deployAsync(ContractName.TokenRegistry); const tokenRegistryInstance = await deployer.deployAsync(ContractName.TokenRegistry);
tokenRegistry = new TokenRegistryContract(tokenRegistryInstance); tokenRegistry = new TokenRegistryContract(
web3Wrapper,
tokenRegistryInstance.abi,
tokenRegistryInstance.address,
);
const tokenTransferProxyInstance = await deployer.deployAsync(ContractName.TokenTransferProxy); const tokenTransferProxyInstance = await deployer.deployAsync(ContractName.TokenTransferProxy);
tokenTransferProxy = new TokenTransferProxyContract(tokenTransferProxyInstance); tokenTransferProxy = new TokenTransferProxyContract(
web3Wrapper,
tokenTransferProxyInstance.abi,
tokenTransferProxyInstance.address,
);
const exchangeInstance = await deployer.deployAsync(ContractName.Exchange, [ const exchangeInstance = await deployer.deployAsync(ContractName.Exchange, [
zrx.address, zrx.address,
tokenTransferProxy.address, tokenTransferProxy.address,
]); ]);
exchange = new ExchangeContract(exchangeInstance); exchange = new ExchangeContract(web3Wrapper, exchangeInstance.abi, exchangeInstance.address);
await tokenTransferProxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: accounts[0] }); await tokenTransferProxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: accounts[0] });
const zeroEx = new ZeroEx(web3.currentProvider, { networkId: constants.TESTRPC_NETWORK_ID }); const zeroEx = new ZeroEx(web3.currentProvider, { networkId: constants.TESTRPC_NETWORK_ID });
exWrapper = new ExchangeWrapper(exchange, zeroEx); exWrapper = new ExchangeWrapper(exchange, zeroEx);

View File

@ -59,10 +59,14 @@ describe('MultiSigWalletWithTimeLock', () => {
SIGNATURES_REQUIRED, SIGNATURES_REQUIRED,
0, 0,
]); ]);
multiSig = new MultiSigWalletWithTimeLockContract(multiSigInstance); multiSig = new MultiSigWalletWithTimeLockContract(
web3Wrapper,
multiSigInstance.abi,
multiSigInstance.address,
);
multiSigWrapper = new MultiSigWrapper((multiSig as any) as MultiSigWalletContract); multiSigWrapper = new MultiSigWrapper((multiSig as any) as MultiSigWalletContract);
const secondsTimeLocked = await multiSig.secondsTimeLocked(); const secondsTimeLocked = await multiSig.secondsTimeLocked.callAsync();
initialSecondsTimeLocked = secondsTimeLocked.toNumber(); initialSecondsTimeLocked = secondsTimeLocked.toNumber();
}); });
it('should throw when not called by wallet', async () => { it('should throw when not called by wallet', async () => {
@ -113,7 +117,7 @@ describe('MultiSigWalletWithTimeLock', () => {
const blockNum = await web3Wrapper.getBlockNumberAsync(); const blockNum = await web3Wrapper.getBlockNumberAsync();
const blockInfo = await web3Wrapper.getBlockAsync(blockNum); const blockInfo = await web3Wrapper.getBlockAsync(blockNum);
const timestamp = new BigNumber(blockInfo.timestamp); const timestamp = new BigNumber(blockInfo.timestamp);
const confirmationTimeBigNum = new BigNumber(await multiSig.confirmationTimes(txId)); const confirmationTimeBigNum = new BigNumber(await multiSig.confirmationTimes.callAsync(txId));
expect(timestamp).to.be.bignumber.equal(confirmationTimeBigNum); expect(timestamp).to.be.bignumber.equal(confirmationTimeBigNum);
}); });
@ -141,7 +145,7 @@ describe('MultiSigWalletWithTimeLock', () => {
const res = await zeroEx.awaitTransactionMinedAsync(txHash); const res = await zeroEx.awaitTransactionMinedAsync(txHash);
expect(res.logs).to.have.length(2); expect(res.logs).to.have.length(2);
const secondsTimeLocked = new BigNumber(await multiSig.secondsTimeLocked()); const secondsTimeLocked = new BigNumber(await multiSig.secondsTimeLocked.callAsync());
expect(secondsTimeLocked).to.be.bignumber.equal(SECONDS_TIME_LOCKED); expect(secondsTimeLocked).to.be.bignumber.equal(SECONDS_TIME_LOCKED);
}); });
}); });
@ -152,10 +156,14 @@ describe('MultiSigWalletWithTimeLock', () => {
SIGNATURES_REQUIRED, SIGNATURES_REQUIRED,
SECONDS_TIME_LOCKED, SECONDS_TIME_LOCKED,
]); ]);
multiSig = new MultiSigWalletWithTimeLockContract(multiSigInstance); multiSig = new MultiSigWalletWithTimeLockContract(
web3Wrapper,
multiSigInstance.abi,
multiSigInstance.address,
);
multiSigWrapper = new MultiSigWrapper((multiSig as any) as MultiSigWalletContract); multiSigWrapper = new MultiSigWrapper((multiSig as any) as MultiSigWalletContract);
const secondsTimeLocked = await multiSig.secondsTimeLocked(); const secondsTimeLocked = await multiSig.secondsTimeLocked.callAsync();
initialSecondsTimeLocked = secondsTimeLocked.toNumber(); initialSecondsTimeLocked = secondsTimeLocked.toNumber();
const destination = multiSig.address; const destination = multiSig.address;
const from = owners[0]; const from = owners[0];
@ -187,7 +195,7 @@ describe('MultiSigWalletWithTimeLock', () => {
await rpc.increaseTimeAsync(SECONDS_TIME_LOCKED.toNumber()); await rpc.increaseTimeAsync(SECONDS_TIME_LOCKED.toNumber());
await multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }); await multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] });
const secondsTimeLocked = new BigNumber(await multiSig.secondsTimeLocked()); const secondsTimeLocked = new BigNumber(await multiSig.secondsTimeLocked.callAsync());
expect(secondsTimeLocked).to.be.bignumber.equal(newSecondsTimeLocked); expect(secondsTimeLocked).to.be.bignumber.equal(newSecondsTimeLocked);
}); });
}); });

View File

@ -49,7 +49,11 @@ describe('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', () => {
[authorizedAddress, unauthorizedAddress] = accounts; [authorizedAddress, unauthorizedAddress] = accounts;
const initialOwner = accounts[0]; const initialOwner = accounts[0];
const tokenTransferProxyInstance = await deployer.deployAsync(ContractName.TokenTransferProxy); const tokenTransferProxyInstance = await deployer.deployAsync(ContractName.TokenTransferProxy);
tokenTransferProxy = new TokenTransferProxyContract(tokenTransferProxyInstance); tokenTransferProxy = new TokenTransferProxyContract(
web3Wrapper,
tokenTransferProxyInstance.abi,
tokenTransferProxyInstance.address,
);
await tokenTransferProxy.addAuthorizedAddress.sendTransactionAsync(authorizedAddress, { await tokenTransferProxy.addAuthorizedAddress.sendTransactionAsync(authorizedAddress, {
from: initialOwner, from: initialOwner,
}); });
@ -57,7 +61,11 @@ describe('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', () => {
ContractName.MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress, ContractName.MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress,
[owners, requiredApprovals, SECONDS_TIME_LOCKED, tokenTransferProxy.address], [owners, requiredApprovals, SECONDS_TIME_LOCKED, tokenTransferProxy.address],
); );
multiSig = new MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddressContract(multiSigInstance); multiSig = new MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddressContract(
web3Wrapper,
multiSigInstance.abi,
multiSigInstance.address,
);
await tokenTransferProxy.transferOwnership.sendTransactionAsync(multiSig.address, { await tokenTransferProxy.transferOwnership.sendTransactionAsync(multiSig.address, {
from: initialOwner, from: initialOwner,
}); });
@ -74,12 +82,14 @@ describe('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', () => {
describe('isFunctionRemoveAuthorizedAddress', () => { describe('isFunctionRemoveAuthorizedAddress', () => {
it('should throw if data is not for removeAuthorizedAddress', async () => { it('should throw if data is not for removeAuthorizedAddress', async () => {
const data = MultiSigWrapper.encodeFnArgs('addAuthorizedAddress', PROXY_ABI, [owners[0]]); const data = MultiSigWrapper.encodeFnArgs('addAuthorizedAddress', PROXY_ABI, [owners[0]]);
return expect(multiSig.isFunctionRemoveAuthorizedAddress(data)).to.be.rejectedWith(constants.REVERT); return expect(multiSig.isFunctionRemoveAuthorizedAddress.callAsync(data)).to.be.rejectedWith(
constants.REVERT,
);
}); });
it('should return true if data is for removeAuthorizedAddress', async () => { it('should return true if data is for removeAuthorizedAddress', async () => {
const data = MultiSigWrapper.encodeFnArgs('removeAuthorizedAddress', PROXY_ABI, [owners[0]]); const data = MultiSigWrapper.encodeFnArgs('removeAuthorizedAddress', PROXY_ABI, [owners[0]]);
const isFunctionRemoveAuthorizedAddress = await multiSig.isFunctionRemoveAuthorizedAddress(data); const isFunctionRemoveAuthorizedAddress = await multiSig.isFunctionRemoveAuthorizedAddress.callAsync(data);
expect(isFunctionRemoveAuthorizedAddress).to.be.true(); expect(isFunctionRemoveAuthorizedAddress).to.be.true();
}); });
}); });
@ -114,7 +124,7 @@ describe('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', () => {
const log = abiDecoder.tryToDecodeLogOrNoop(res.logs[0]) as LogWithDecodedArgs<SubmissionContractEventArgs>; const log = abiDecoder.tryToDecodeLogOrNoop(res.logs[0]) as LogWithDecodedArgs<SubmissionContractEventArgs>;
const txId = log.args.transactionId; const txId = log.args.transactionId;
await multiSig.confirmTransaction.sendTransactionAsync(txId, { from: owners[1] }); await multiSig.confirmTransaction.sendTransactionAsync(txId, { from: owners[1] });
const isConfirmed = await multiSig.isConfirmed(txId); const isConfirmed = await multiSig.isConfirmed.callAsync(txId);
expect(isConfirmed).to.be.true(); expect(isConfirmed).to.be.true();
return expect( return expect(
@ -133,7 +143,7 @@ describe('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', () => {
const log = abiDecoder.tryToDecodeLogOrNoop(res.logs[0]) as LogWithDecodedArgs<SubmissionContractEventArgs>; const log = abiDecoder.tryToDecodeLogOrNoop(res.logs[0]) as LogWithDecodedArgs<SubmissionContractEventArgs>;
const txId = log.args.transactionId; const txId = log.args.transactionId;
await multiSig.confirmTransaction.sendTransactionAsync(txId, { from: owners[1] }); await multiSig.confirmTransaction.sendTransactionAsync(txId, { from: owners[1] });
const isConfirmed = await multiSig.isConfirmed(txId); const isConfirmed = await multiSig.isConfirmed.callAsync(txId);
expect(isConfirmed).to.be.true(); expect(isConfirmed).to.be.true();
return expect( return expect(
@ -152,10 +162,10 @@ describe('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', () => {
const log = abiDecoder.tryToDecodeLogOrNoop(res.logs[0]) as LogWithDecodedArgs<SubmissionContractEventArgs>; const log = abiDecoder.tryToDecodeLogOrNoop(res.logs[0]) as LogWithDecodedArgs<SubmissionContractEventArgs>;
const txId = log.args.transactionId; const txId = log.args.transactionId;
await multiSig.confirmTransaction.sendTransactionAsync(txId, { from: owners[1] }); await multiSig.confirmTransaction.sendTransactionAsync(txId, { from: owners[1] });
const isConfirmed = await multiSig.isConfirmed(txId); const isConfirmed = await multiSig.isConfirmed.callAsync(txId);
expect(isConfirmed).to.be.true(); expect(isConfirmed).to.be.true();
await multiSig.executeRemoveAuthorizedAddress.sendTransactionAsync(txId, { from: owners[1] }); await multiSig.executeRemoveAuthorizedAddress.sendTransactionAsync(txId, { from: owners[1] });
const isAuthorized = await tokenTransferProxy.authorized(authorizedAddress); const isAuthorized = await tokenTransferProxy.authorized.callAsync(authorizedAddress);
expect(isAuthorized).to.be.false(); expect(isAuthorized).to.be.false();
}); });
@ -170,10 +180,10 @@ describe('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', () => {
const log = abiDecoder.tryToDecodeLogOrNoop(res.logs[0]) as LogWithDecodedArgs<SubmissionContractEventArgs>; const log = abiDecoder.tryToDecodeLogOrNoop(res.logs[0]) as LogWithDecodedArgs<SubmissionContractEventArgs>;
const txId = log.args.transactionId; const txId = log.args.transactionId;
await multiSig.confirmTransaction.sendTransactionAsync(txId, { from: owners[1] }); await multiSig.confirmTransaction.sendTransactionAsync(txId, { from: owners[1] });
const isConfirmed = await multiSig.isConfirmed(txId); const isConfirmed = await multiSig.isConfirmed.callAsync(txId);
expect(isConfirmed).to.be.true(); expect(isConfirmed).to.be.true();
await multiSig.executeRemoveAuthorizedAddress.sendTransactionAsync(txId, { from: owners[1] }); await multiSig.executeRemoveAuthorizedAddress.sendTransactionAsync(txId, { from: owners[1] });
const tx = await multiSig.transactions(txId); const tx = await multiSig.transactions.callAsync(txId);
const isExecuted = tx[3]; const isExecuted = tx[3];
expect(isExecuted).to.be.true(); expect(isExecuted).to.be.true();
return expect( return expect(

View File

@ -31,7 +31,7 @@ describe('TokenRegistry', () => {
owner = accounts[0]; owner = accounts[0];
notOwner = accounts[1]; notOwner = accounts[1];
const tokenRegInstance = await deployer.deployAsync(ContractName.TokenRegistry); const tokenRegInstance = await deployer.deployAsync(ContractName.TokenRegistry);
tokenReg = new TokenRegistryContract(tokenRegInstance); tokenReg = new TokenRegistryContract(web3Wrapper, tokenRegInstance.abi, tokenRegInstance.address);
tokenRegWrapper = new TokenRegWrapper(tokenReg); tokenRegWrapper = new TokenRegWrapper(tokenReg);
}); });
beforeEach(async () => { beforeEach(async () => {

View File

@ -25,7 +25,11 @@ describe('TokenTransferProxy', () => {
owner = address = accounts[0]; owner = address = accounts[0];
notOwner = accounts[1]; notOwner = accounts[1];
const tokenTransferProxyInstance = await deployer.deployAsync(ContractName.TokenTransferProxy); const tokenTransferProxyInstance = await deployer.deployAsync(ContractName.TokenTransferProxy);
tokenTransferProxy = new TokenTransferProxyContract(tokenTransferProxyInstance); tokenTransferProxy = new TokenTransferProxyContract(
web3Wrapper,
tokenTransferProxyInstance.abi,
tokenTransferProxyInstance.address,
);
}); });
beforeEach(async () => { beforeEach(async () => {
await blockchainLifecycle.startAsync(); await blockchainLifecycle.startAsync();
@ -41,7 +45,7 @@ describe('TokenTransferProxy', () => {
}); });
it('should allow owner to add an authorized address', async () => { it('should allow owner to add an authorized address', async () => {
await tokenTransferProxy.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }); await tokenTransferProxy.addAuthorizedAddress.sendTransactionAsync(address, { from: owner });
const isAuthorized = await tokenTransferProxy.authorized(address); const isAuthorized = await tokenTransferProxy.authorized.callAsync(address);
expect(isAuthorized).to.be.true(); expect(isAuthorized).to.be.true();
}); });
it('should throw if owner attempts to authorize a duplicate address', async () => { it('should throw if owner attempts to authorize a duplicate address', async () => {
@ -67,7 +71,7 @@ describe('TokenTransferProxy', () => {
await tokenTransferProxy.removeAuthorizedAddress.sendTransactionAsync(address, { await tokenTransferProxy.removeAuthorizedAddress.sendTransactionAsync(address, {
from: owner, from: owner,
}); });
const isAuthorized = await tokenTransferProxy.authorized(address); const isAuthorized = await tokenTransferProxy.authorized.callAsync(address);
expect(isAuthorized).to.be.false(); expect(isAuthorized).to.be.false();
}); });
@ -82,19 +86,19 @@ describe('TokenTransferProxy', () => {
describe('getAuthorizedAddresses', () => { describe('getAuthorizedAddresses', () => {
it('should return all authorized addresses', async () => { it('should return all authorized addresses', async () => {
const initial = await tokenTransferProxy.getAuthorizedAddresses(); const initial = await tokenTransferProxy.getAuthorizedAddresses.callAsync();
expect(initial).to.have.length(0); expect(initial).to.have.length(0);
await tokenTransferProxy.addAuthorizedAddress.sendTransactionAsync(address, { await tokenTransferProxy.addAuthorizedAddress.sendTransactionAsync(address, {
from: owner, from: owner,
}); });
const afterAdd = await tokenTransferProxy.getAuthorizedAddresses(); const afterAdd = await tokenTransferProxy.getAuthorizedAddresses.callAsync();
expect(afterAdd).to.have.length(1); expect(afterAdd).to.have.length(1);
expect(afterAdd).to.include(address); expect(afterAdd).to.include(address);
await tokenTransferProxy.removeAuthorizedAddress.sendTransactionAsync(address, { await tokenTransferProxy.removeAuthorizedAddress.sendTransactionAsync(address, {
from: owner, from: owner,
}); });
const afterRemove = await tokenTransferProxy.getAuthorizedAddresses(); const afterRemove = await tokenTransferProxy.getAuthorizedAddresses.callAsync();
expect(afterRemove).to.have.length(0); expect(afterRemove).to.have.length(0);
}); });
}); });

View File

@ -33,9 +33,13 @@ describe('TokenTransferProxy', () => {
accounts = await web3Wrapper.getAvailableAddressesAsync(); accounts = await web3Wrapper.getAvailableAddressesAsync();
owner = notAuthorized = accounts[0]; owner = notAuthorized = accounts[0];
const tokenTransferProxyInstance = await deployer.deployAsync(ContractName.TokenTransferProxy); const tokenTransferProxyInstance = await deployer.deployAsync(ContractName.TokenTransferProxy);
tokenTransferProxy = new TokenTransferProxyContract(tokenTransferProxyInstance); tokenTransferProxy = new TokenTransferProxyContract(
web3Wrapper,
tokenTransferProxyInstance.abi,
tokenTransferProxyInstance.address,
);
const repInstance = await deployer.deployAsync(ContractName.DummyToken); const repInstance = await deployer.deployAsync(ContractName.DummyToken);
rep = new DummyTokenContract(repInstance); rep = new DummyTokenContract(web3Wrapper, repInstance.abi, repInstance.address);
dmyBalances = new Balances([rep], [accounts[0], accounts[1]]); dmyBalances = new Balances([rep], [accounts[0], accounts[1]]);
await Promise.all([ await Promise.all([

View File

@ -35,7 +35,7 @@ describe('UnlimitedAllowanceToken', () => {
owner = accounts[0]; owner = accounts[0];
spender = accounts[1]; spender = accounts[1];
const tokenInstance = await deployer.deployAsync(ContractName.DummyToken); const tokenInstance = await deployer.deployAsync(ContractName.DummyToken);
token = new DummyTokenContract(tokenInstance); token = new DummyTokenContract(web3Wrapper, tokenInstance.abi, tokenInstance.address);
await token.mint.sendTransactionAsync(MAX_MINT_VALUE, { from: owner }); await token.mint.sendTransactionAsync(MAX_MINT_VALUE, { from: owner });
tokenAddress = token.address; tokenAddress = token.address;
}); });

View File

@ -36,7 +36,7 @@ describe('ZRXToken', () => {
networkId: constants.TESTRPC_NETWORK_ID, networkId: constants.TESTRPC_NETWORK_ID,
}); });
const zrxInstance = await deployer.deployAsync(ContractName.ZRXToken); const zrxInstance = await deployer.deployAsync(ContractName.ZRXToken);
zrx = new ZRXTokenContract(zrxInstance); zrx = new ZRXTokenContract(web3Wrapper, zrxInstance.abi, zrxInstance.address);
zrxAddress = zrx.address; zrxAddress = zrx.address;
MAX_UINT = zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; MAX_UINT = zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
}); });
@ -48,25 +48,25 @@ describe('ZRXToken', () => {
}); });
describe('constants', () => { describe('constants', () => {
it('should have 18 decimals', async () => { it('should have 18 decimals', async () => {
const decimals = new BigNumber(await zrx.decimals()); const decimals = new BigNumber(await zrx.decimals.callAsync());
const expectedDecimals = 18; const expectedDecimals = 18;
expect(decimals).to.be.bignumber.equal(expectedDecimals); expect(decimals).to.be.bignumber.equal(expectedDecimals);
}); });
it('should have a total supply of 1 billion tokens', async () => { it('should have a total supply of 1 billion tokens', async () => {
const totalSupply = new BigNumber(await zrx.totalSupply()); const totalSupply = new BigNumber(await zrx.totalSupply.callAsync());
const expectedTotalSupply = 1000000000; const expectedTotalSupply = 1000000000;
expect(ZeroEx.toUnitAmount(totalSupply, 18)).to.be.bignumber.equal(expectedTotalSupply); expect(ZeroEx.toUnitAmount(totalSupply, 18)).to.be.bignumber.equal(expectedTotalSupply);
}); });
it('should be named 0x Protocol Token', async () => { it('should be named 0x Protocol Token', async () => {
const name = await zrx.name(); const name = await zrx.name.callAsync();
const expectedName = '0x Protocol Token'; const expectedName = '0x Protocol Token';
expect(name).to.be.equal(expectedName); expect(name).to.be.equal(expectedName);
}); });
it('should have the symbol ZRX', async () => { it('should have the symbol ZRX', async () => {
const symbol = await zrx.symbol(); const symbol = await zrx.symbol.callAsync();
const expectedSymbol = 'ZRX'; const expectedSymbol = 'ZRX';
expect(symbol).to.be.equal(expectedSymbol); expect(symbol).to.be.equal(expectedSymbol);
}); });
@ -75,7 +75,7 @@ describe('ZRXToken', () => {
describe('constructor', () => { describe('constructor', () => {
it('should initialize owner balance to totalSupply', async () => { it('should initialize owner balance to totalSupply', async () => {
const ownerBalance = await zeroEx.token.getBalanceAsync(zrxAddress, owner); const ownerBalance = await zeroEx.token.getBalanceAsync(zrxAddress, owner);
const totalSupply = new BigNumber(await zrx.totalSupply()); const totalSupply = new BigNumber(await zrx.totalSupply.callAsync());
expect(totalSupply).to.be.bignumber.equal(ownerBalance); expect(totalSupply).to.be.bignumber.equal(ownerBalance);
}); });
}); });

View File

@ -11,6 +11,7 @@
"../../node_modules/types-ethereumjs-util/index.d.ts", "../../node_modules/types-ethereumjs-util/index.d.ts",
"../../node_modules/chai-typescript-typings/index.d.ts", "../../node_modules/chai-typescript-typings/index.d.ts",
"../../node_modules/web3-typescript-typings/index.d.ts", "../../node_modules/web3-typescript-typings/index.d.ts",
"../../node_modules/ethers-typescript-typings/index.d.ts",
"../../node_modules/chai-as-promised-typescript-typings/index.d.ts", "../../node_modules/chai-as-promised-typescript-typings/index.d.ts",
"../../node_modules/types-ethereumjs-util/index.d.ts", "../../node_modules/types-ethereumjs-util/index.d.ts",
"../../node_modules/types-bn/index.d.ts", "../../node_modules/types-bn/index.d.ts",

View File

@ -17,7 +17,7 @@ export class Balances {
const balancesByOwner: BalancesByOwner = {}; const balancesByOwner: BalancesByOwner = {};
for (const tokenContractInstance of this._tokenContractInstances) { for (const tokenContractInstance of this._tokenContractInstances) {
for (const ownerAddress of this._ownerAddresses) { for (const ownerAddress of this._ownerAddresses) {
let balance = await tokenContractInstance.balanceOf(ownerAddress); let balance = await tokenContractInstance.balanceOf.callAsync(ownerAddress);
balance = new BigNumber(balance); balance = new BigNumber(balance);
if (_.isUndefined(balancesByOwner[ownerAddress])) { if (_.isUndefined(balancesByOwner[ownerAddress])) {
balancesByOwner[ownerAddress] = {}; balancesByOwner[ownerAddress] = {};

View File

@ -186,11 +186,11 @@ export class ExchangeWrapper {
public async getOrderHashAsync(signedOrder: SignedOrder): Promise<string> { public async getOrderHashAsync(signedOrder: SignedOrder): Promise<string> {
const shouldThrowOnInsufficientBalanceOrAllowance = false; const shouldThrowOnInsufficientBalanceOrAllowance = false;
const params = signedOrderUtils.getOrderAddressesAndValues(signedOrder); const params = signedOrderUtils.getOrderAddressesAndValues(signedOrder);
const orderHash = await this._exchange.getOrderHash(params.orderAddresses, params.orderValues); const orderHash = await this._exchange.getOrderHash.callAsync(params.orderAddresses, params.orderValues);
return orderHash; return orderHash;
} }
public async isValidSignatureAsync(signedOrder: SignedOrder): Promise<boolean> { public async isValidSignatureAsync(signedOrder: SignedOrder): Promise<boolean> {
const isValidSignature = await this._exchange.isValidSignature( const isValidSignature = await this._exchange.isValidSignature.callAsync(
signedOrder.maker, signedOrder.maker,
ZeroEx.getOrderHashHex(signedOrder), ZeroEx.getOrderHashHex(signedOrder),
signedOrder.ecSignature.v, signedOrder.ecSignature.v,
@ -204,7 +204,7 @@ export class ExchangeWrapper {
denominator: BigNumber, denominator: BigNumber,
target: BigNumber, target: BigNumber,
): Promise<boolean> { ): Promise<boolean> {
const isRoundingError = await this._exchange.isRoundingError(numerator, denominator, target); const isRoundingError = await this._exchange.isRoundingError.callAsync(numerator, denominator, target);
return isRoundingError; return isRoundingError;
} }
public async getPartialAmountAsync( public async getPartialAmountAsync(
@ -212,7 +212,9 @@ export class ExchangeWrapper {
denominator: BigNumber, denominator: BigNumber,
target: BigNumber, target: BigNumber,
): Promise<BigNumber> { ): Promise<BigNumber> {
const partialAmount = new BigNumber(await this._exchange.getPartialAmount(numerator, denominator, target)); const partialAmount = new BigNumber(
await this._exchange.getPartialAmount.callAsync(numerator, denominator, target),
);
return partialAmount; return partialAmount;
} }
} }

View File

@ -22,36 +22,36 @@ export class TokenRegWrapper {
return tx; return tx;
} }
public async getTokenMetaDataAsync(tokenAddress: string) { public async getTokenMetaDataAsync(tokenAddress: string) {
const data = await this._tokenReg.getTokenMetaData(tokenAddress); const data = await this._tokenReg.getTokenMetaData.callAsync(tokenAddress);
const token: Token = { const token: Token = {
address: data[0], address: data[0],
name: data[1], name: data[1],
symbol: data[2], symbol: data[2],
decimals: data[3].toNumber(), decimals: data[3],
ipfsHash: data[4], ipfsHash: data[4],
swarmHash: data[5], swarmHash: data[5],
}; };
return token; return token;
} }
public async getTokenByNameAsync(tokenName: string) { public async getTokenByNameAsync(tokenName: string) {
const data = await this._tokenReg.getTokenByName(tokenName); const data = await this._tokenReg.getTokenByName.callAsync(tokenName);
const token: Token = { const token: Token = {
address: data[0], address: data[0],
name: data[1], name: data[1],
symbol: data[2], symbol: data[2],
decimals: data[3].toNumber(), decimals: data[3],
ipfsHash: data[4], ipfsHash: data[4],
swarmHash: data[5], swarmHash: data[5],
}; };
return token; return token;
} }
public async getTokenBySymbolAsync(tokenSymbol: string) { public async getTokenBySymbolAsync(tokenSymbol: string) {
const data = await this._tokenReg.getTokenBySymbol(tokenSymbol); const data = await this._tokenReg.getTokenBySymbol.callAsync(tokenSymbol);
const token: Token = { const token: Token = {
address: data[0], address: data[0],
name: data[1], name: data[1],
symbol: data[2], symbol: data[2],
decimals: data[3].toNumber(), decimals: data[3],
ipfsHash: data[4], ipfsHash: data[4],
swarmHash: data[5], swarmHash: data[5],
}; };

View File

@ -41,8 +41,8 @@ export interface DefaultOrderParams {
exchangeContractAddress: string; exchangeContractAddress: string;
maker: string; maker: string;
feeRecipient: string; feeRecipient: string;
makerToken: string; makerTokenAddress: string;
takerToken: string; takerTokenAddress: string;
makerTokenAmount: BigNumber; makerTokenAmount: BigNumber;
takerTokenAmount: BigNumber; takerTokenAmount: BigNumber;
makerFee: BigNumber; makerFee: BigNumber;

View File

@ -36,6 +36,7 @@
"tslint": "5.8.0", "tslint": "5.8.0",
"types-bn": "^0.0.1", "types-bn": "^0.0.1",
"typescript": "2.7.1", "typescript": "2.7.1",
"ethers-typescript-typings": "^0.0.1",
"web3-typescript-typings": "^0.9.11" "web3-typescript-typings": "^0.9.11"
}, },
"dependencies": { "dependencies": {

View File

@ -10,8 +10,8 @@ import { constants } from './utils/constants';
import { CliOptions, CompilerOptions, DeployerOptions } from './utils/types'; import { CliOptions, CompilerOptions, DeployerOptions } from './utils/types';
const DEFAULT_OPTIMIZER_ENABLED = false; const DEFAULT_OPTIMIZER_ENABLED = false;
const DEFAULT_CONTRACTS_DIR = path.resolve('src'); const DEFAULT_CONTRACTS_DIR = path.resolve('src/contracts');
const DEFAULT_ARTIFACTS_DIR = path.resolve('artifacts'); const DEFAULT_ARTIFACTS_DIR = path.resolve('src/artifacts');
const DEFAULT_NETWORK_ID = 50; const DEFAULT_NETWORK_ID = 50;
const DEFAULT_JSONRPC_PORT = 8545; const DEFAULT_JSONRPC_PORT = 8545;
const DEFAULT_GAS_PRICE = (10 ** 9 * 2).toString(); const DEFAULT_GAS_PRICE = (10 ** 9 * 2).toString();
@ -100,6 +100,9 @@ async function onDeployCommand(argv: CliOptions): Promise<void> {
*/ */
function getContractsSetFromList(contracts: string): Set<string> { function getContractsSetFromList(contracts: string): Set<string> {
const specifiedContracts = new Set(); const specifiedContracts = new Set();
if (contracts === '*') {
return new Set(['*']);
}
const contractsArray = contracts.split(','); const contractsArray = contracts.split(',');
_.forEach(contractsArray, contractName => { _.forEach(contractsArray, contractName => {
const fileName = `${contractName}${constants.SOLIDITY_FILE_EXTENSION}`; const fileName = `${contractName}${constants.SOLIDITY_FILE_EXTENSION}`;

View File

@ -174,7 +174,7 @@ export class Deployer {
const block = await this.web3Wrapper.getBlockAsync('latest'); const block = await this.web3Wrapper.getBlockAsync('latest');
let gas: number; let gas: number;
try { try {
const gasEstimate: number = await this.web3Wrapper.estimateGasAsync(data); const gasEstimate: number = await this.web3Wrapper.estimateGasAsync({ data });
gas = Math.min(gasEstimate + EXTRA_GAS, block.gasLimit); gas = Math.min(gasEstimate + EXTRA_GAS, block.gasLimit);
} catch (err) { } catch (err) {
gas = block.gasLimit; gas = block.gasLimit;

View File

@ -11,6 +11,7 @@
"../../node_modules/types-bn/index.d.ts", "../../node_modules/types-bn/index.d.ts",
"../../node_modules/types-ethereumjs-util/index.d.ts", "../../node_modules/types-ethereumjs-util/index.d.ts",
"../../node_modules/chai-typescript-typings/index.d.ts", "../../node_modules/chai-typescript-typings/index.d.ts",
"../../node_modules/ethers-typescript-typings/index.d.ts",
"../../node_modules/web3-typescript-typings/index.d.ts" "../../node_modules/web3-typescript-typings/index.d.ts"
] ]
} }

View File

@ -8,6 +8,7 @@
"./test/**/*", "./test/**/*",
"../../node_modules/types-bn/index.d.ts", "../../node_modules/types-bn/index.d.ts",
"../../node_modules/chai-typescript-typings/index.d.ts", "../../node_modules/chai-typescript-typings/index.d.ts",
"../../node_modules/ethers-typescript-typings/index.d.ts",
"../../node_modules/web3-typescript-typings/index.d.ts", "../../node_modules/web3-typescript-typings/index.d.ts",
"../../node_modules/types-ethereumjs-util/index.d.ts" "../../node_modules/types-ethereumjs-util/index.d.ts"
] ]

View File

@ -0,0 +1,3 @@
.*
yarn-error.log
/scripts/

View File

@ -0,0 +1,5 @@
# CHANGELOG
## v0.0.1 - _TBD, 2018_
* Initial types (#413)

View File

@ -0,0 +1,49 @@
## ethers-typescript-typings
There currently isn't an official [Ethers][ethers]
type definition included in the [DefinitelyTyped][definitelytyped] project.
Until that happens, we will continue to improve our own type definition.
If it get's close to comprehensive, we'll add it to [DefinitelyTyped][definitelytyped].
[ethers]: https://github.com/ethers-io/ethers.js
[definitelytyped]: https://github.com/DefinitelyTyped/DefinitelyTyped
## Installation
```bash
yarn add -D ethers-typescript-typings
```
## Usage
Add the following line within an `include` section of your `tsconfig.json`
```json
"./node_modules/ethers-typescript-typings/index.d.ts"
```
## Contributing
We strongly encourage that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
```bash
yarn config set workspaces-experimental true
```
Then install dependencies
```bash
yarn install
```
### Lint
```bash
yarn lint
```

View File

@ -0,0 +1,28 @@
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 {
parse: (...args: any[]) => any;
inputs: { names: string[]; types: string[] };
signature: string;
topic: string;
}
export class Interface {
public functions: { [functionName: string]: FunctionDescription };
public events: { [eventName: string]: EventDescription };
public static decodeParams(types: string[], data: string): any[];
constructor(abi: any);
}
}

View File

@ -0,0 +1,28 @@
{
"name": "ethers-typescript-typings",
"version": "0.0.1",
"description": "Typescript type definitions for ethers.js",
"main": "index.d.ts",
"types": "index.d.ts",
"scripts": {
"lint": "tslint index.d.ts"
},
"repository": {
"type": "git",
"url": "git+https://github.com/0xProject/0x.js.git"
},
"author": "Fabio Berger",
"contributors": [
"Leonid Logvinov <logvinov.leon@gmail.com>"
],
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/0xProject/0x.js/issues"
},
"homepage": "https://github.com/0xProject/0x.js/packages/ethers-typescript-typings#readme",
"devDependencies": {
"tslint": "5.8.0",
"tslint-config-0xproject": "^0.0.2",
"typescript": "2.7.1"
}
}

View File

@ -0,0 +1,5 @@
const postpublish_utils = require('../../../scripts/postpublish_utils');
const packageJSON = require('../package.json');
const subPackageName = packageJSON.name;
postpublish_utils.standardPostPublishAsync(subPackageName);

View File

@ -0,0 +1,3 @@
{
"extends": ["tslint-config-0xproject"]
}

View File

@ -1,5 +1,10 @@
# CHANGELOG # CHANGELOG
## v0.2.4 - _TBD, 2018_
* Add `data` to `TxData` (#413)
* Add `number` as an option to `ContractEventArg` (#413)
## 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)

View File

@ -2,6 +2,7 @@ import { BigNumber } from 'bignumber.js';
import * as Web3 from 'web3'; import * as Web3 from 'web3';
export interface TxData { export interface TxData {
data?: string;
from?: string; from?: string;
gas?: number; gas?: number;
gasPrice?: BigNumber; gasPrice?: BigNumber;
@ -38,7 +39,7 @@ export enum AbiType {
Fallback = 'fallback', Fallback = 'fallback',
} }
export type ContractEventArg = string | BigNumber; export type ContractEventArg = string | BigNumber | number;
export interface DecodedLogArgs { export interface DecodedLogArgs {
[argName: string]: ContractEventArg; [argName: string]: ContractEventArg;

View File

@ -1,5 +1,9 @@
# CHANGELOG # CHANGELOG
## v0.4.0 - _TBD, 2018_
* Use `ethers-contracts` as a backend to decode event args (#413)
## v0.3.2 - _February 9, 2018_ ## v0.3.2 - _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)

View File

@ -26,11 +26,13 @@
"shx": "^0.2.2", "shx": "^0.2.2",
"tslint": "5.8.0", "tslint": "5.8.0",
"typescript": "2.7.1", "typescript": "2.7.1",
"ethers-typescript-typings": "^0.0.1",
"web3-typescript-typings": "^0.9.11" "web3-typescript-typings": "^0.9.11"
}, },
"dependencies": { "dependencies": {
"@0xproject/types": "^0.2.3", "@0xproject/types": "^0.2.3",
"bignumber.js": "~4.1.0", "bignumber.js": "~4.1.0",
"ethers-contracts": "^2.2.1",
"js-sha3": "^0.7.0", "js-sha3": "^0.7.0",
"lodash": "^4.17.4", "lodash": "^4.17.4",
"web3": "^0.20.0" "web3": "^0.20.0"

View File

@ -1,7 +1,7 @@
import { AbiType, DecodedLogArgs, LogWithDecodedArgs, RawLog, SolidityTypes } from '@0xproject/types'; import { AbiType, DecodedLogArgs, LogWithDecodedArgs, RawLog, SolidityTypes } from '@0xproject/types';
import * as ethersContracts from 'ethers-contracts';
import * as _ from 'lodash'; import * as _ from 'lodash';
import * as Web3 from 'web3'; import * as Web3 from 'web3';
import * as SolidityCoder from 'web3/lib/solidity/coder';
import { BigNumber } from './configured_bignumber'; import { BigNumber } from './configured_bignumber';
@ -27,31 +27,29 @@ export class AbiDecoder {
if (_.isUndefined(event)) { if (_.isUndefined(event)) {
return log; return log;
} }
const ethersInterface = new ethersContracts.Interface([event]);
const logData = log.data; const logData = log.data;
const decodedParams: DecodedLogArgs = {}; const decodedParams: DecodedLogArgs = {};
let dataIndex = 0;
let topicsIndex = 1; let topicsIndex = 1;
const nonIndexedInputs = _.filter(event.inputs, input => !input.indexed); const nonIndexedInputs = _.filter(event.inputs, input => !input.indexed);
const dataTypes = _.map(nonIndexedInputs, input => input.type); const dataTypes = _.map(nonIndexedInputs, input => input.type);
const decodedData = SolidityCoder.decodeParams(dataTypes, logData.slice('0x'.length)); const decodedData = ethersInterface.events[event.name].parse(log.data);
let failedToDecode = false; let failedToDecode = false;
_.forEach(event.inputs, (param: Web3.EventParameter) => { _.forEach(event.inputs, (param: Web3.EventParameter, i: number) => {
// Indexed parameters are stored in topics. Non-indexed ones in decodedData // Indexed parameters are stored in topics. Non-indexed ones in decodedData
let value: BigNumber | string = param.indexed ? log.topics[topicsIndex++] : decodedData[dataIndex++]; let value: BigNumber | string | number = param.indexed ? log.topics[topicsIndex++] : decodedData[i];
if (_.isUndefined(value)) { if (_.isUndefined(value)) {
failedToDecode = true; failedToDecode = true;
return; return;
} }
if (param.type === SolidityTypes.Address) { if (param.type === SolidityTypes.Address) {
value = AbiDecoder._padZeros(new BigNumber(value).toString(16)); value = AbiDecoder._padZeros(new BigNumber(value).toString(16));
} else if ( } else if (param.type === SolidityTypes.Uint256 || param.type === SolidityTypes.Uint) {
param.type === SolidityTypes.Uint256 ||
param.type === SolidityTypes.Uint8 ||
param.type === SolidityTypes.Uint
) {
value = new BigNumber(value); value = new BigNumber(value);
} else if (param.type === SolidityTypes.Uint8) {
value = new BigNumber(value).toNumber();
} }
decodedParams[param.name] = value; decodedParams[param.name] = value;
}); });
@ -67,11 +65,14 @@ export class AbiDecoder {
} }
} }
private _addABI(abiArray: Web3.AbiDefinition[]): void { private _addABI(abiArray: Web3.AbiDefinition[]): void {
if (_.isUndefined(abiArray)) {
return;
}
const ethersInterface = new ethersContracts.Interface(abiArray);
_.map(abiArray, (abi: Web3.AbiDefinition) => { _.map(abiArray, (abi: Web3.AbiDefinition) => {
if (abi.type === AbiType.Event) { if (abi.type === AbiType.Event) {
const signature = `${abi.name}(${_.map(abi.inputs, input => input.type).join(',')})`; const topic = ethersInterface.events[abi.name].topic;
const signatureHash = new Web3().sha3(signature); this._methodIds[topic] = abi;
this._methodIds[signatureHash] = abi;
} }
}); });
this._savedABIs = this._savedABIs.concat(abiArray); this._savedABIs = this._savedABIs.concat(abiArray);

View File

@ -1,3 +0,0 @@
declare module 'web3/lib/solidity/coder' {
const decodeParams: (types: string[], data: string) => any[];
}

View File

@ -3,5 +3,9 @@
"compilerOptions": { "compilerOptions": {
"outDir": "lib" "outDir": "lib"
}, },
"include": ["./src/**/*", "../../node_modules/web3-typescript-typings/index.d.ts"] "include": [
"./src/**/*",
"../../node_modules/web3-typescript-typings/index.d.ts",
"../../node_modules/ethers-typescript-typings/index.d.ts"
]
} }

View File

@ -1,9 +1,12 @@
# CHANGELOG # CHANGELOG
## v0.2.XX - _TBD_ 2018 ## v0.2.0 _TBD, 2018_
* Ensure all returned user addresses are lowercase (#373) * Ensure all returned user addresses are lowercase (#373)
* Add `web3Wrapper.callAsync` (#413)
* Make `web3Wrapper.estimateGas` accept whole `txData` instead of `data` (#413)
* Remove `web3Wrapper.getContractInstance` (#413)
## v0.1.12 - _February 9, 2018_ ## v0.1.12 _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)

View File

@ -26,11 +26,13 @@
"shx": "^0.2.2", "shx": "^0.2.2",
"tslint": "5.8.0", "tslint": "5.8.0",
"typescript": "2.7.1", "typescript": "2.7.1",
"ethers-typescript-typings": "^0.0.1",
"web3-typescript-typings": "^0.9.11" "web3-typescript-typings": "^0.9.11"
}, },
"dependencies": { "dependencies": {
"@0xproject/types": "^0.2.3", "@0xproject/types": "^0.2.3",
"@0xproject/utils": "^0.3.4", "@0xproject/utils": "^0.3.4",
"ethers-contracts": "^2.2.1",
"lodash": "^4.17.4", "lodash": "^4.17.4",
"web3": "^0.20.0" "web3": "^0.20.0"
} }

View File

@ -0,0 +1,69 @@
import { TxData, TxDataPayable } from '@0xproject/types';
import * as ethersContracts from 'ethers-contracts';
import * as _ from 'lodash';
import * as Web3 from 'web3';
import { Web3Wrapper } from './web3_wrapper';
export class BaseContract {
protected _ethersInterface: ethersContracts.Interface;
protected _web3Wrapper: Web3Wrapper;
public abi: Web3.ContractAbi;
public 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 => this._transformTypedData(arrayItemType, value, transformation));
} else {
return transformation(type, values);
}
}
protected async _applyDefaultsToTxDataAsync<T extends Partial<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 = {
to: this.address,
...removeUndefinedProperties(this._web3Wrapper.getContractDefaults()),
...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(web3Wrapper: Web3Wrapper, abi: Web3.ContractAbi, address: string) {
this._web3Wrapper = web3Wrapper;
this.abi = abi;
this.address = address;
this._ethersInterface = new ethersContracts.Interface(abi);
}
}

View File

@ -1,179 +1,2 @@
import { TransactionReceipt, TxData } from '@0xproject/types'; export { Web3Wrapper } from './web3_wrapper';
import { BigNumber, promisify } from '@0xproject/utils'; export { BaseContract } from './base_contract';
import * as _ from 'lodash';
import * as Web3 from 'web3';
interface RawLogEntry {
logIndex: string | null;
transactionIndex: string | null;
transactionHash: string;
blockHash: string | null;
blockNumber: string | null;
address: string;
data: string;
topics: string[];
}
export class Web3Wrapper {
private _web3: Web3;
private _defaults: Partial<TxData>;
private _jsonRpcRequestId: number;
constructor(provider: Web3.Provider, 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`
// We re-assign the send method so that Web3@1.0 providers work with 0x.js
(provider as any).sendAsync = (provider as any).send;
}
this._web3 = new Web3();
this._web3.setProvider(provider);
this._defaults = defaults || {};
this._jsonRpcRequestId = 0;
}
public getContractDefaults(): Partial<TxData> {
return this._defaults;
}
public setProvider(provider: Web3.Provider) {
this._web3.setProvider(provider);
}
public isAddress(address: string): boolean {
return this._web3.isAddress(address);
}
public async isSenderAddressAvailableAsync(senderAddress: string): Promise<boolean> {
const addresses = await this.getAvailableAddressesAsync();
const normalizedAddress = senderAddress.toLowerCase();
return _.includes(addresses, normalizedAddress);
}
public async getNodeVersionAsync(): Promise<string> {
const nodeVersion = await promisify<string>(this._web3.version.getNode)();
return nodeVersion;
}
public async getNetworkIdAsync(): Promise<number> {
const networkIdStr = await promisify<string>(this._web3.version.getNetwork)();
const networkId = _.parseInt(networkIdStr);
return networkId;
}
public async getTransactionReceiptAsync(txHash: string): Promise<TransactionReceipt> {
const transactionReceipt = await promisify<TransactionReceipt>(this._web3.eth.getTransactionReceipt)(txHash);
if (!_.isNull(transactionReceipt)) {
transactionReceipt.status = this._normalizeTxReceiptStatus(transactionReceipt.status);
}
return transactionReceipt;
}
public getCurrentProvider(): Web3.Provider {
return this._web3.currentProvider;
}
public toWei(ethAmount: BigNumber): BigNumber {
const balanceWei = this._web3.toWei(ethAmount, 'ether');
return balanceWei;
}
public async getBalanceInWeiAsync(owner: string): Promise<BigNumber> {
let balanceInWei = await promisify<BigNumber>(this._web3.eth.getBalance)(owner);
// Rewrap in a new BigNumber
balanceInWei = new BigNumber(balanceInWei);
return balanceInWei;
}
public async doesContractExistAtAddressAsync(address: string): Promise<boolean> {
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<string>(this._web3.eth.sign)(address, message);
return signData;
}
public async getBlockNumberAsync(): Promise<number> {
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<Web3.BlockWithoutTransactionData>(this._web3.eth.getBlock)(blockParam);
return block;
}
public async getBlockTimestampAsync(blockParam: string | Web3.BlockParam): Promise<number> {
const { timestamp } = await this.getBlockAsync(blockParam);
return timestamp;
}
public async getAvailableAddressesAsync(): Promise<string[]> {
const addresses = await promisify<string[]>(this._web3.eth.getAccounts)();
const normalizedAddresses = _.map(addresses, address => address.toLowerCase());
return normalizedAddresses;
}
public async getLogsAsync(filter: Web3.FilterObject): Promise<Web3.LogEntry[]> {
let fromBlock = filter.fromBlock;
if (_.isNumber(fromBlock)) {
fromBlock = this._web3.toHex(fromBlock);
}
let toBlock = filter.toBlock;
if (_.isNumber(toBlock)) {
toBlock = this._web3.toHex(toBlock);
}
const serializedFilter = {
...filter,
fromBlock,
toBlock,
};
const payload = {
jsonrpc: '2.0',
id: this._jsonRpcRequestId++,
method: 'eth_getLogs',
params: [serializedFilter],
};
const rawLogs = await this._sendRawPayloadAsync<RawLogEntry[]>(payload);
const formattedLogs = _.map(rawLogs, this._formatLog.bind(this));
return formattedLogs;
}
public getContractFromAbi(abi: Web3.ContractAbi): Web3.Contract<any> {
const web3Contract = this._web3.eth.contract(abi);
return web3Contract;
}
public getContractInstance(abi: Web3.ContractAbi, address: string): Web3.ContractInstance {
const web3ContractInstance = this.getContractFromAbi(abi).at(address);
return web3ContractInstance;
}
public async estimateGasAsync(data: string): Promise<number> {
const gas = await promisify<number>(this._web3.eth.estimateGas)({ data });
return gas;
}
public async sendTransactionAsync(txData: Web3.TxData): Promise<string> {
const txHash = await promisify<string>(this._web3.eth.sendTransaction)(txData);
return txHash;
}
private async _sendRawPayloadAsync<A>(payload: Web3.JSONRPCRequestPayload): Promise<A> {
const sendAsync = this._web3.currentProvider.sendAsync.bind(this._web3.currentProvider);
const response = await promisify<Web3.JSONRPCResponsePayload>(sendAsync)(payload);
const result = response.result;
return result;
}
private _normalizeTxReceiptStatus(status: undefined | null | string | 0 | 1): null | 0 | 1 {
// Transaction status might have four values
// undefined - Testrpc and other old clients
// null - New clients on old transactions
// number - Parity
// hex - Geth
if (_.isString(status)) {
return this._web3.toDecimal(status) as 0 | 1;
} else if (_.isUndefined(status)) {
return null;
} else {
return status;
}
}
private _formatLog(rawLog: RawLogEntry): Web3.LogEntry {
const formattedLog = {
...rawLog,
logIndex: this._hexToDecimal(rawLog.logIndex),
blockNumber: this._hexToDecimal(rawLog.blockNumber),
transactionIndex: this._hexToDecimal(rawLog.transactionIndex),
};
return formattedLog;
}
private _hexToDecimal(hex: string | null): number | null {
if (_.isNull(hex)) {
return null;
}
const decimal = this._web3.toDecimal(hex);
return decimal;
}
}

View File

@ -0,0 +1,179 @@
import { TransactionReceipt, TxData } from '@0xproject/types';
import { BigNumber, promisify } from '@0xproject/utils';
import * as _ from 'lodash';
import * as Web3 from 'web3';
interface RawLogEntry {
logIndex: string | null;
transactionIndex: string | null;
transactionHash: string;
blockHash: string | null;
blockNumber: string | null;
address: string;
data: string;
topics: string[];
}
export class Web3Wrapper {
private _web3: Web3;
private _defaults: Partial<TxData>;
private _jsonRpcRequestId: number;
constructor(provider: Web3.Provider, 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`
// We re-assign the send method so that Web3@1.0 providers work with 0x.js
(provider as any).sendAsync = (provider as any).send;
}
this._web3 = new Web3();
this._web3.setProvider(provider);
this._defaults = defaults || {};
this._jsonRpcRequestId = 0;
}
public getContractDefaults(): Partial<TxData> {
return this._defaults;
}
public setProvider(provider: Web3.Provider) {
this._web3.setProvider(provider);
}
public isAddress(address: string): boolean {
return this._web3.isAddress(address);
}
public async isSenderAddressAvailableAsync(senderAddress: string): Promise<boolean> {
const addresses = await this.getAvailableAddressesAsync();
const normalizedAddress = senderAddress.toLowerCase();
return _.includes(addresses, normalizedAddress);
}
public async getNodeVersionAsync(): Promise<string> {
const nodeVersion = await promisify<string>(this._web3.version.getNode)();
return nodeVersion;
}
public async getNetworkIdAsync(): Promise<number> {
const networkIdStr = await promisify<string>(this._web3.version.getNetwork)();
const networkId = _.parseInt(networkIdStr);
return networkId;
}
public async getTransactionReceiptAsync(txHash: string): Promise<TransactionReceipt> {
const transactionReceipt = await promisify<TransactionReceipt>(this._web3.eth.getTransactionReceipt)(txHash);
if (!_.isNull(transactionReceipt)) {
transactionReceipt.status = this._normalizeTxReceiptStatus(transactionReceipt.status);
}
return transactionReceipt;
}
public getCurrentProvider(): Web3.Provider {
return this._web3.currentProvider;
}
public toWei(ethAmount: BigNumber): BigNumber {
const balanceWei = this._web3.toWei(ethAmount, 'ether');
return balanceWei;
}
public async getBalanceInWeiAsync(owner: string): Promise<BigNumber> {
let balanceInWei = await promisify<BigNumber>(this._web3.eth.getBalance)(owner);
// Rewrap in a new BigNumber
balanceInWei = new BigNumber(balanceInWei);
return balanceInWei;
}
public async doesContractExistAtAddressAsync(address: string): Promise<boolean> {
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<string>(this._web3.eth.sign)(address, message);
return signData;
}
public async getBlockNumberAsync(): Promise<number> {
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<Web3.BlockWithoutTransactionData>(this._web3.eth.getBlock)(blockParam);
return block;
}
public async getBlockTimestampAsync(blockParam: string | Web3.BlockParam): Promise<number> {
const { timestamp } = await this.getBlockAsync(blockParam);
return timestamp;
}
public async getAvailableAddressesAsync(): Promise<string[]> {
const addresses = await promisify<string[]>(this._web3.eth.getAccounts)();
const normalizedAddresses = _.map(addresses, address => address.toLowerCase());
return normalizedAddresses;
}
public async getLogsAsync(filter: Web3.FilterObject): Promise<Web3.LogEntry[]> {
let fromBlock = filter.fromBlock;
if (_.isNumber(fromBlock)) {
fromBlock = this._web3.toHex(fromBlock);
}
let toBlock = filter.toBlock;
if (_.isNumber(toBlock)) {
toBlock = this._web3.toHex(toBlock);
}
const serializedFilter = {
...filter,
fromBlock,
toBlock,
};
const payload = {
jsonrpc: '2.0',
id: this._jsonRpcRequestId++,
method: 'eth_getLogs',
params: [serializedFilter],
};
const rawLogs = await this._sendRawPayloadAsync<RawLogEntry[]>(payload);
const formattedLogs = _.map(rawLogs, this._formatLog.bind(this));
return formattedLogs;
}
public getContractFromAbi(abi: Web3.ContractAbi): Web3.Contract<any> {
const web3Contract = this._web3.eth.contract(abi);
return web3Contract;
}
public async estimateGasAsync(txData: Partial<Web3.TxData>): Promise<number> {
const gas = await promisify<number>(this._web3.eth.estimateGas)(txData);
return gas;
}
public async callAsync(callData: Web3.CallData, defaultBlock?: Web3.BlockParam): Promise<string> {
const rawCalllResult = await promisify<string>(this._web3.eth.call)(callData, defaultBlock);
return rawCalllResult;
}
public async sendTransactionAsync(txData: Web3.TxData): Promise<string> {
const txHash = await promisify<string>(this._web3.eth.sendTransaction)(txData);
return txHash;
}
private async _sendRawPayloadAsync<A>(payload: Web3.JSONRPCRequestPayload): Promise<A> {
const sendAsync = this._web3.currentProvider.sendAsync.bind(this._web3.currentProvider);
const response = await promisify<Web3.JSONRPCResponsePayload>(sendAsync)(payload);
const result = response.result;
return result;
}
private _normalizeTxReceiptStatus(status: undefined | null | string | 0 | 1): null | 0 | 1 {
// Transaction status might have four values
// undefined - Testrpc and other old clients
// null - New clients on old transactions
// number - Parity
// hex - Geth
if (_.isString(status)) {
return this._web3.toDecimal(status) as 0 | 1;
} else if (_.isUndefined(status)) {
return null;
} else {
return status;
}
}
private _formatLog(rawLog: RawLogEntry): Web3.LogEntry {
const formattedLog = {
...rawLog,
logIndex: this._hexToDecimal(rawLog.logIndex),
blockNumber: this._hexToDecimal(rawLog.blockNumber),
transactionIndex: this._hexToDecimal(rawLog.transactionIndex),
};
return formattedLog;
}
private _hexToDecimal(hex: string | null): number | null {
if (_.isNull(hex)) {
return null;
}
const decimal = this._web3.toDecimal(hex);
return decimal;
}
}

View File

@ -3,5 +3,9 @@
"compilerOptions": { "compilerOptions": {
"outDir": "lib" "outDir": "lib"
}, },
"include": ["./src/**/*", "../../node_modules/web3-typescript-typings/index.d.ts"] "include": [
"./src/**/*",
"../../node_modules/ethers-typescript-typings/index.d.ts",
"../../node_modules/web3-typescript-typings/index.d.ts"
]
} }

View File

@ -3227,6 +3227,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 +4985,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 +9830,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"