diff options
author | Brandon Millman <brandon.millman@gmail.com> | 2018-03-02 05:04:55 +0800 |
---|---|---|
committer | Brandon Millman <brandon.millman@gmail.com> | 2018-03-02 05:04:55 +0800 |
commit | 0c16f0ea221d65e66942c27a69dda1c54f49e775 (patch) | |
tree | 5530d18fcd6e6c5e15272de3cb915fc2025c01bf /packages/0x.js | |
parent | 003d43b03ae373ca24d6d728ffa6b0f2dfcda79a (diff) | |
parent | 451a0dacbe85d7a0d16ef007c1eb945a4c1977cb (diff) | |
download | dexon-sol-tools-0c16f0ea221d65e66942c27a69dda1c54f49e775.tar dexon-sol-tools-0c16f0ea221d65e66942c27a69dda1c54f49e775.tar.gz dexon-sol-tools-0c16f0ea221d65e66942c27a69dda1c54f49e775.tar.bz2 dexon-sol-tools-0c16f0ea221d65e66942c27a69dda1c54f49e775.tar.lz dexon-sol-tools-0c16f0ea221d65e66942c27a69dda1c54f49e775.tar.xz dexon-sol-tools-0c16f0ea221d65e66942c27a69dda1c54f49e775.tar.zst dexon-sol-tools-0c16f0ea221d65e66942c27a69dda1c54f49e775.zip |
Merge branch 'development' into feature/sra-reporter
* development: (71 commits)
Set max to 2 ETH/2 ZRX
Add missing types from website
Add dependencies
Update the README
Move BaseContract to its own package
Upgrate prettier
remove unused import
Move more configs into docsInfo and remove logic that does not belong there elsewhere
Fix a bug with displaying solidity functions returning multiple return values
Add ethers-contracts as a dependency
Include types for ethers-contracts
Fix the version
Include types for ethers-contracts
Rename idx to i
Remove tslint disable
Move BaseContract to web3Wrapper
Merge ifs
Fix an option description
Add link to the docs
Improve CHANGELOG entry
...
Diffstat (limited to 'packages/0x.js')
29 files changed, 272 insertions, 302 deletions
diff --git a/packages/0x.js/CHANGELOG.md b/packages/0x.js/CHANGELOG.md index 0af474c74..b882a1b31 100644 --- a/packages/0x.js/CHANGELOG.md +++ b/packages/0x.js/CHANGELOG.md @@ -1,5 +1,12 @@ # CHANGELOG +## v0.33.0 - _TBD, 2018_ + + * Validate and lowercase all addresses in public methods (#373) + * 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) + ## v0.32.2 - _February 9, 2018_ * Fix publishing issue where .npmignore was not properly excluding undesired content (#389) diff --git a/packages/0x.js/contract_templates/contract.handlebars b/packages/0x.js/contract_templates/contract.handlebars deleted file mode 100644 index 33699b8a7..000000000 --- a/packages/0x.js/contract_templates/contract.handlebars +++ /dev/null @@ -1,44 +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/0x.js/contract_templates. - */ -// tslint:disable: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'; - -{{#if events}} -export type {{contractName}}ContractEventArgs = -{{#each events}} - | {{name}}ContractEventArgs{{#if @last}};{{/if}} -{{/each}} - -export enum {{contractName}}Events { - {{#each events}} - {{name}} = '{{name}}', - {{/each}} -} - -{{#each events}} -{{> event}} - -{{/each}} -{{/if}} - -export class {{contractName}}Contract extends BaseContract { -{{#each methods}} - {{#this.constant}} - {{> call contractName=../contractName}} - {{/this.constant}} - {{^this.constant}} - {{> tx contractName=../contractName}} - {{/this.constant}} -{{/each}} - constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) { - super(web3ContractInstance, defaults); - classUtils.bindAll(this, ['_web3ContractInstance', '_defaults']); - } -} // tslint:disable:max-file-line-count diff --git a/packages/0x.js/contract_templates/partials/call.handlebars b/packages/0x.js/contract_templates/partials/call.handlebars deleted file mode 100644 index 0475136f0..000000000 --- a/packages/0x.js/contract_templates/partials/call.handlebars +++ /dev/null @@ -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; - }, -}; diff --git a/packages/0x.js/contract_templates/partials/event.handlebars b/packages/0x.js/contract_templates/partials/event.handlebars deleted file mode 100644 index 6d68d4c0f..000000000 --- a/packages/0x.js/contract_templates/partials/event.handlebars +++ /dev/null @@ -1,5 +0,0 @@ -export interface {{name}}ContractEventArgs { - {{#each inputs}} - {{name}}: {{#returnType type}}{{/returnType}}; - {{/each}} -} diff --git a/packages/0x.js/contract_templates/partials/params.handlebars b/packages/0x.js/contract_templates/partials/params.handlebars deleted file mode 100644 index ac5d4ae85..000000000 --- a/packages/0x.js/contract_templates/partials/params.handlebars +++ /dev/null @@ -1,3 +0,0 @@ -{{#each inputs}} -{{name}}, -{{/each}} diff --git a/packages/0x.js/contract_templates/partials/return_type.handlebars b/packages/0x.js/contract_templates/partials/return_type.handlebars deleted file mode 100644 index 383961a40..000000000 --- a/packages/0x.js/contract_templates/partials/return_type.handlebars +++ /dev/null @@ -1,6 +0,0 @@ -{{#singleReturnValue}} -{{#returnType outputs.0.type}}{{/returnType}} -{{/singleReturnValue}} -{{^singleReturnValue}} -[{{#each outputs}}{{#returnType type}}{{/returnType}}{{#unless @last}}, {{/unless}}{{/each}}] -{{/singleReturnValue}} diff --git a/packages/0x.js/contract_templates/partials/tx.handlebars b/packages/0x.js/contract_templates/partials/tx.handlebars deleted file mode 100644 index 9df83266a..000000000 --- a/packages/0x.js/contract_templates/partials/tx.handlebars +++ /dev/null @@ -1,51 +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, - self.{{this.name}}.estimateGasAsync.bind( - self, - {{> params inputs=inputs}} - ), - ); - const txHash = await promisify<string>( - self._web3ContractInstance.{{this.name}}, self._web3ContractInstance, - )( - {{> params inputs=inputs}} - txDataWithDefaults, - ); - return txHash; - }, - async estimateGasAsync( - {{> typed_params inputs=inputs}} - txData: TxData = {}, - ): Promise<number> { - const self = this as {{contractName}}Contract; - const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( - txData, - ); - const gas = await promisify<number>( - self._web3ContractInstance.{{this.name}}.estimateGas, self._web3ContractInstance, - )( - {{> params inputs=inputs}} - txDataWithDefaults, - ); - return gas; - }, - getABIEncodedTransactionData( - {{> typed_params inputs=inputs}} - txData: TxData = {}, - ): string { - const self = this as {{contractName}}Contract; - const abiEncodedTransactionData = self._web3ContractInstance.{{this.name}}.getData(); - return abiEncodedTransactionData; - }, -}; diff --git a/packages/0x.js/contract_templates/partials/typed_params.handlebars b/packages/0x.js/contract_templates/partials/typed_params.handlebars deleted file mode 100644 index 3ea4b2e95..000000000 --- a/packages/0x.js/contract_templates/partials/typed_params.handlebars +++ /dev/null @@ -1,3 +0,0 @@ -{{#each inputs}} - {{name}}: {{#parameterType type}}{{/parameterType}}, -{{/each}} diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json index 4fb0eb6ac..20af430d6 100644 --- a/packages/0x.js/package.json +++ b/packages/0x.js/package.json @@ -17,7 +17,7 @@ "build": "run-p build:umd:prod build:commonjs; exit 0;", "docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_DIR", "upload_docs_json": "aws s3 cp generated_docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type application/json", - "generate_contract_wrappers": "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'", "test:circleci": "run-s test:coverage report_test_coverage", "test": "run-s clean test:commonjs", @@ -77,17 +77,20 @@ "types-bn": "^0.0.1", "typescript": "2.7.1", "web3-provider-engine": "^13.0.1", + "ethers-typescript-typings": "^0.0.1", "web3-typescript-typings": "^0.9.11", "webpack": "^3.1.0" }, "dependencies": { "@0xproject/assert": "^0.0.20", + "@0xproject/base-contract": "^0.0.1", "@0xproject/json-schemas": "^0.7.12", "@0xproject/types": "^0.2.3", "@0xproject/utils": "^0.3.4", "@0xproject/web3-wrapper": "^0.1.14", "bintrees": "^1.0.2", "bn.js": "^4.11.8", + "ethers-contracts": "^2.2.1", "ethereumjs-abi": "^0.6.4", "ethereumjs-blockstream": "^2.0.6", "ethereumjs-util": "^5.1.1", diff --git a/packages/0x.js/src/0x.ts b/packages/0x.js/src/0x.ts index 6cfa65cc2..22a5fee10 100644 --- a/packages/0x.js/src/0x.ts +++ b/packages/0x.js/src/0x.ts @@ -13,6 +13,8 @@ import { TokenTransferProxyWrapper } from './contract_wrappers/token_transfer_pr import { TokenWrapper } from './contract_wrappers/token_wrapper'; import { OrderStateWatcher } from './order_watcher/order_state_watcher'; import { zeroExConfigSchema } from './schemas/zero_ex_config_schema'; +import { zeroExPrivateNetworkConfigSchema } from './schemas/zero_ex_private_network_config_schema'; +import { zeroExPublicNetworkConfigSchema } from './schemas/zero_ex_public_network_config_schema'; import { ECSignature, Order, SignedOrder, Web3Provider, ZeroExConfig, ZeroExError } from './types'; import { assert } from './utils/assert'; import { constants } from './utils/constants'; @@ -74,8 +76,9 @@ export class ZeroEx { assert.isHexString('data', data); assert.doesConformToSchema('signature', signature, schemas.ecSignatureSchema); assert.isETHAddressHex('signerAddress', signerAddress); + const normalizedSignerAddress = signerAddress.toLowerCase(); - const isValidSignature = signatureUtils.isValidSignature(data, signature, signerAddress); + const isValidSignature = signatureUtils.isValidSignature(data, signature, normalizedSignerAddress); return isValidSignature; } /** @@ -163,7 +166,10 @@ export class ZeroEx { */ constructor(provider: Web3Provider, config: ZeroExConfig) { assert.isWeb3Provider('provider', provider); - assert.doesConformToSchema('config', config, zeroExConfigSchema); + assert.doesConformToSchema('config', config, zeroExConfigSchema, [ + zeroExPrivateNetworkConfigSchema, + zeroExPublicNetworkConfigSchema, + ]); const artifactJSONs = _.values(artifacts); const abiArrays = _.map(artifactJSONs, artifact => artifact.abi); this._abiDecoder = new AbiDecoder(abiArrays); @@ -245,6 +251,7 @@ export class ZeroEx { ): Promise<ECSignature> { assert.isHexString('orderHash', orderHash); await assert.isSenderAddressAsync('signerAddress', signerAddress, this._web3Wrapper); + const normalizedSignerAddress = signerAddress.toLowerCase(); let msgHashHex = orderHash; if (shouldAddPersonalMessagePrefix) { @@ -253,7 +260,7 @@ export class ZeroEx { msgHashHex = ethUtil.bufferToHex(msgHashBuff); } - const signature = await this._web3Wrapper.signTransactionAsync(signerAddress, msgHashHex); + const signature = await this._web3Wrapper.signTransactionAsync(normalizedSignerAddress, msgHashHex); // HACK: There is no consensus on whether the signatureHex string should be formatted as // v + r + s OR r + s + v, and different clients (even different versions of the same client) @@ -262,7 +269,7 @@ export class ZeroEx { const validVParamValues = [27, 28]; const ecSignatureVRS = signatureUtils.parseSignatureHexAsVRS(signature); if (_.includes(validVParamValues, ecSignatureVRS.v)) { - const isValidVRSSignature = ZeroEx.isValidSignature(orderHash, ecSignatureVRS, signerAddress); + const isValidVRSSignature = ZeroEx.isValidSignature(orderHash, ecSignatureVRS, normalizedSignerAddress); if (isValidVRSSignature) { return ecSignatureVRS; } @@ -270,7 +277,7 @@ export class ZeroEx { const ecSignatureRSV = signatureUtils.parseSignatureHexAsRSV(signature); if (_.includes(validVParamValues, ecSignatureRSV.v)) { - const isValidRSVSignature = ZeroEx.isValidSignature(orderHash, ecSignatureRSV, signerAddress); + const isValidRSVSignature = ZeroEx.isValidSignature(orderHash, ecSignatureRSV, normalizedSignerAddress); if (isValidRSVSignature) { return ecSignatureRSV; } diff --git a/packages/0x.js/src/contract_wrappers/contract_wrapper.ts b/packages/0x.js/src/contract_wrappers/contract_wrapper.ts index b313273b5..ad7727de5 100644 --- a/packages/0x.js/src/contract_wrappers/contract_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/contract_wrapper.ts @@ -108,10 +108,10 @@ export class ContractWrapper { const logWithDecodedArgs = this._abiDecoder.tryToDecodeLogOrNoop(log); return logWithDecodedArgs; } - protected async _instantiateContractIfExistsAsync( + protected async _getContractAbiAndAddressFromArtifactsAsync( artifact: Artifact, addressIfExists?: string, - ): Promise<Web3.ContractInstance> { + ): Promise<[Web3.ContractAbi, string]> { let contractAddress: string; if (_.isUndefined(addressIfExists)) { if (_.isUndefined(artifact.networks[this._networkId])) { @@ -125,8 +125,8 @@ export class ContractWrapper { if (!doesContractExist) { throw new Error(CONTRACT_NAME_TO_NOT_FOUND_ERROR[artifact.contract_name]); } - const contractInstance = this._web3Wrapper.getContractInstance(artifact.abi, contractAddress); - return contractInstance; + const abiAndAddress: [Web3.ContractAbi, string] = [artifact.abi, contractAddress]; + return abiAndAddress; } protected _getContractAddress(artifact: Artifact, addressIfExists?: string): string { if (_.isUndefined(addressIfExists)) { diff --git a/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts b/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts index db7cdee43..42f8213a2 100644 --- a/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts @@ -41,15 +41,18 @@ export class EtherTokenWrapper extends ContractWrapper { depositor: string, txOpts: TransactionOpts = {}, ): Promise<string> { + assert.isETHAddressHex('etherTokenAddress', etherTokenAddress); assert.isValidBaseUnitAmount('amountInWei', amountInWei); await assert.isSenderAddressAsync('depositor', depositor, this._web3Wrapper); + const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase(); + const normalizedDepositorAddress = depositor.toLowerCase(); - const ethBalanceInWei = await this._web3Wrapper.getBalanceInWeiAsync(depositor); + const ethBalanceInWei = await this._web3Wrapper.getBalanceInWeiAsync(normalizedDepositorAddress); assert.assert(ethBalanceInWei.gte(amountInWei), ZeroExError.InsufficientEthBalanceForDeposit); - const wethContract = await this._getEtherTokenContractAsync(etherTokenAddress); + const wethContract = await this._getEtherTokenContractAsync(normalizedEtherTokenAddress); const txHash = await wethContract.deposit.sendTransactionAsync({ - from: depositor, + from: normalizedDepositorAddress, value: amountInWei, gas: txOpts.gasLimit, gasPrice: txOpts.gasPrice, @@ -72,14 +75,20 @@ export class EtherTokenWrapper extends ContractWrapper { txOpts: TransactionOpts = {}, ): Promise<string> { assert.isValidBaseUnitAmount('amountInWei', amountInWei); + assert.isETHAddressHex('etherTokenAddress', etherTokenAddress); await assert.isSenderAddressAsync('withdrawer', withdrawer, this._web3Wrapper); + const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase(); + const normalizedWithdrawerAddress = withdrawer.toLowerCase(); - const WETHBalanceInBaseUnits = await this._tokenWrapper.getBalanceAsync(etherTokenAddress, withdrawer); + const WETHBalanceInBaseUnits = await this._tokenWrapper.getBalanceAsync( + normalizedEtherTokenAddress, + normalizedWithdrawerAddress, + ); assert.assert(WETHBalanceInBaseUnits.gte(amountInWei), ZeroExError.InsufficientWEthBalanceForWithdrawal); - const wethContract = await this._getEtherTokenContractAsync(etherTokenAddress); + const wethContract = await this._getEtherTokenContractAsync(normalizedEtherTokenAddress); const txHash = await wethContract.withdraw.sendTransactionAsync(amountInWei, { - from: withdrawer, + from: normalizedWithdrawerAddress, gas: txOpts.gasLimit, gasPrice: txOpts.gasPrice, }); @@ -101,11 +110,12 @@ export class EtherTokenWrapper extends ContractWrapper { indexFilterValues: IndexedFilterValues, ): Promise<Array<LogWithDecodedArgs<ArgsType>>> { assert.isETHAddressHex('etherTokenAddress', etherTokenAddress); + const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase(); assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents); assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); const logs = await this._getLogsAsync<ArgsType>( - etherTokenAddress, + normalizedEtherTokenAddress, eventName, blockRange, indexFilterValues, @@ -129,11 +139,12 @@ export class EtherTokenWrapper extends ContractWrapper { callback: EventCallback<ArgsType>, ): string { assert.isETHAddressHex('etherTokenAddress', etherTokenAddress); + const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase(); assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents); assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); assert.isFunction('callback', callback); const subscriptionToken = this._subscribe<ArgsType>( - etherTokenAddress, + normalizedEtherTokenAddress, eventName, indexFilterValues, artifacts.EtherTokenArtifact.abi, @@ -151,7 +162,7 @@ export class EtherTokenWrapper extends ContractWrapper { /** * Cancels all existing subscriptions */ - public _unsubscribeAll(): void { + public unsubscribeAll(): void { super._unsubscribeAll(); } /** @@ -168,7 +179,7 @@ export class EtherTokenWrapper extends ContractWrapper { return contractAddressIfExists; } private _invalidateContractInstance(): void { - this._unsubscribeAll(); + this.unsubscribeAll(); this._etherTokenContractsByAddress = {}; } private async _getEtherTokenContractAsync(etherTokenAddress: string): Promise<EtherTokenContract> { @@ -176,11 +187,11 @@ export class EtherTokenWrapper extends ContractWrapper { if (!_.isUndefined(etherTokenContract)) { return etherTokenContract; } - const web3ContractInstance = await this._instantiateContractIfExistsAsync( + const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync( artifacts.EtherTokenArtifact, etherTokenAddress, ); - const contractInstance = new EtherTokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults()); + const contractInstance = new EtherTokenContract(this._web3Wrapper, abi, address); etherTokenContract = contractInstance; this._etherTokenContractsByAddress[etherTokenAddress] = etherTokenContract; return etherTokenContract; diff --git a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts b/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts index c82b7ecf5..20b46c6bc 100644 --- a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts @@ -108,8 +108,10 @@ export class ExchangeWrapper extends ContractWrapper { const exchangeContract = await this._getExchangeContractAsync(); const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock; + const txData = {}; let unavailableTakerTokenAmount = await exchangeContract.getUnavailableTakerTokenAmount.callAsync( orderHash, + txData, defaultBlock, ); // 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 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 fillAmountInBaseUnits = new BigNumber(fillAmountInBaseUnits); return fillAmountInBaseUnits; @@ -144,7 +147,8 @@ export class ExchangeWrapper extends ContractWrapper { const exchangeContract = await this._getExchangeContractAsync(); 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 cancelledAmountInBaseUnits = new BigNumber(cancelledAmountInBaseUnits); return cancelledAmountInBaseUnits; @@ -180,6 +184,7 @@ export class ExchangeWrapper extends ContractWrapper { assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + const normalizedTakerAddress = takerAddress.toLowerCase(); const exchangeInstance = await this._getExchangeContractAsync(); const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) @@ -192,7 +197,7 @@ export class ExchangeWrapper extends ContractWrapper { exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, - takerAddress, + normalizedTakerAddress, zrxTokenAddress, ); } @@ -208,7 +213,7 @@ export class ExchangeWrapper extends ContractWrapper { signedOrder.ecSignature.r, signedOrder.ecSignature.s, { - from: takerAddress, + from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, }, @@ -254,6 +259,7 @@ export class ExchangeWrapper extends ContractWrapper { assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + const normalizedTakerAddress = takerAddress.toLowerCase(); const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? SHOULD_VALIDATE_BY_DEFAULT @@ -267,7 +273,7 @@ export class ExchangeWrapper extends ContractWrapper { exchangeTradeEmulator, signedOrder, fillTakerTokenAmount.minus(filledTakerTokenAmount), - takerAddress, + normalizedTakerAddress, zrxTokenAddress, ); filledTakerTokenAmount = filledTakerTokenAmount.plus(singleFilledTakerTokenAmount); @@ -301,7 +307,7 @@ export class ExchangeWrapper extends ContractWrapper { rArray, sArray, { - from: takerAddress, + from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, }, @@ -345,6 +351,7 @@ export class ExchangeWrapper extends ContractWrapper { ); assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + const normalizedTakerAddress = takerAddress.toLowerCase(); const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? SHOULD_VALIDATE_BY_DEFAULT : orderTransactionOpts.shouldValidate; @@ -356,7 +363,7 @@ export class ExchangeWrapper extends ContractWrapper { exchangeTradeEmulator, orderFillRequest.signedOrder, orderFillRequest.takerTokenFillAmount, - takerAddress, + normalizedTakerAddress, zrxTokenAddress, ); } @@ -389,7 +396,7 @@ export class ExchangeWrapper extends ContractWrapper { rArray, sArray, { - from: takerAddress, + from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, }, @@ -417,6 +424,7 @@ export class ExchangeWrapper extends ContractWrapper { assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + const normalizedTakerAddress = takerAddress.toLowerCase(); const exchangeInstance = await this._getExchangeContractAsync(); @@ -430,7 +438,7 @@ export class ExchangeWrapper extends ContractWrapper { exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, - takerAddress, + normalizedTakerAddress, zrxTokenAddress, ); } @@ -444,7 +452,7 @@ export class ExchangeWrapper extends ContractWrapper { signedOrder.ecSignature.r, signedOrder.ecSignature.s, { - from: takerAddress, + from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, }, @@ -476,6 +484,7 @@ export class ExchangeWrapper extends ContractWrapper { ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress, ); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + const normalizedTakerAddress = takerAddress.toLowerCase(); if (_.isEmpty(orderFillRequests)) { throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem); } @@ -492,7 +501,7 @@ export class ExchangeWrapper extends ContractWrapper { exchangeTradeEmulator, orderFillRequest.signedOrder, orderFillRequest.takerTokenFillAmount, - takerAddress, + normalizedTakerAddress, zrxTokenAddress, ); } @@ -520,7 +529,7 @@ export class ExchangeWrapper extends ContractWrapper { rParams, sParams, { - from: takerAddress, + from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, }, @@ -544,6 +553,7 @@ export class ExchangeWrapper extends ContractWrapper { assert.doesConformToSchema('order', order, schemas.orderSchema); assert.isValidBaseUnitAmount('takerTokenCancelAmount', cancelTakerTokenAmount); await assert.isSenderAddressAsync('order.maker', order.maker, this._web3Wrapper); + const normalizedMakerAddress = order.maker.toLowerCase(); const exchangeInstance = await this._getExchangeContractAsync(); @@ -566,7 +576,7 @@ export class ExchangeWrapper extends ContractWrapper { orderValues, cancelTakerTokenAmount, { - from: order.maker, + from: normalizedMakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, }, @@ -603,6 +613,8 @@ export class ExchangeWrapper extends ContractWrapper { assert.hasAtMostOneUniqueValue(makers, ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed); const maker = makers[0]; await assert.isSenderAddressAsync('maker', maker, this._web3Wrapper); + const normalizedMakerAddress = maker.toLowerCase(); + const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? SHOULD_VALIDATE_BY_DEFAULT : orderTransactionOpts.shouldValidate; @@ -636,7 +648,7 @@ export class ExchangeWrapper extends ContractWrapper { orderValues, cancelTakerTokenAmounts, { - from: maker, + from: normalizedMakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, }, @@ -679,7 +691,7 @@ export class ExchangeWrapper extends ContractWrapper { /** * Cancels all existing subscriptions */ - public _unsubscribeAll(): void { + public unsubscribeAll(): void { super._unsubscribeAll(); } /** @@ -757,13 +769,14 @@ export class ExchangeWrapper extends ContractWrapper { assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + const normalizedTakerAddress = takerAddress.toLowerCase(); const zrxTokenAddress = this.getZRXTokenAddress(); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync( exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, - takerAddress, + normalizedTakerAddress, zrxTokenAddress, ); } @@ -803,13 +816,14 @@ export class ExchangeWrapper extends ContractWrapper { assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + const normalizedTakerAddress = takerAddress.toLowerCase(); const zrxTokenAddress = this.getZRXTokenAddress(); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync( exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, - takerAddress, + normalizedTakerAddress, zrxTokenAddress, ); } @@ -848,7 +862,7 @@ export class ExchangeWrapper extends ContractWrapper { }); if (!_.isUndefined(errLog)) { const logArgs = (errLog as LogWithDecodedArgs<LogErrorContractEventArgs>).args; - const errCode = logArgs.errorId.toNumber(); + const errCode = logArgs.errorId; const errMessage = this._exchangeContractErrCodesToMsg[errCode]; throw new Error(errMessage); } @@ -862,7 +876,7 @@ export class ExchangeWrapper extends ContractWrapper { return contractAddress; } private _invalidateContractInstances(): void { - this._unsubscribeAll(); + this.unsubscribeAll(); delete this._exchangeContractIfExists; } private async _isValidSignatureUsingContractCallAsync( @@ -873,11 +887,12 @@ export class ExchangeWrapper extends ContractWrapper { assert.isHexString('dataHex', dataHex); assert.doesConformToSchema('ecSignature', ecSignature, schemas.ecSignatureSchema); assert.isETHAddressHex('signerAddressHex', signerAddressHex); + const normalizedSignerAddress = signerAddressHex.toLowerCase(); const exchangeInstance = await this._getExchangeContractAsync(); const isValidSignature = await exchangeInstance.isValidSignature.callAsync( - signerAddressHex, + normalizedSignerAddress, dataHex, ecSignature.v, ecSignature.r, @@ -895,11 +910,11 @@ export class ExchangeWrapper extends ContractWrapper { if (!_.isUndefined(this._exchangeContractIfExists)) { return this._exchangeContractIfExists; } - const web3ContractInstance = await this._instantiateContractIfExistsAsync( + const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync( artifacts.ExchangeArtifact, this._contractAddressIfExists, ); - const contractInstance = new ExchangeContract(web3ContractInstance, this._web3Wrapper.getContractDefaults()); + const contractInstance = new ExchangeContract(this._web3Wrapper, abi, address); this._exchangeContractIfExists = contractInstance; return this._exchangeContractIfExists; } diff --git a/packages/0x.js/src/contract_wrappers/generated/.gitignore b/packages/0x.js/src/contract_wrappers/generated/.gitignore index 834808b48..72e8ffc0d 100644 --- a/packages/0x.js/src/contract_wrappers/generated/.gitignore +++ b/packages/0x.js/src/contract_wrappers/generated/.gitignore @@ -1,6 +1 @@ -dummy_token.ts -ether_token.ts -exchange.ts -token_registry.ts -token_transfer_proxy.ts -token.ts +* diff --git a/packages/0x.js/src/contract_wrappers/generated/base_contract.ts b/packages/0x.js/src/contract_wrappers/generated/base_contract.ts deleted file mode 100644 index d8fac7eea..000000000 --- a/packages/0x.js/src/contract_wrappers/generated/base_contract.ts +++ /dev/null @@ -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; - } -} diff --git a/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts b/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts index f54aaf0f8..e1806c6f2 100644 --- a/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts @@ -23,7 +23,7 @@ export class TokenRegistryWrapper extends ContractWrapper { address: metadata[0], name: metadata[1], symbol: metadata[2], - decimals: metadata[3].toNumber(), + decimals: metadata[3], }; return token; } @@ -50,7 +50,8 @@ export class TokenRegistryWrapper extends ContractWrapper { public async getTokenAddressesAsync(): Promise<string[]> { const tokenRegistryContract = await this._getTokenRegistryContractAsync(); 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 @@ -58,9 +59,10 @@ export class TokenRegistryWrapper extends ContractWrapper { */ public async getTokenIfExistsAsync(address: string): Promise<Token | undefined> { assert.isETHAddressHex('address', address); + const normalizedAddress = address.toLowerCase(); const tokenRegistryContract = await this._getTokenRegistryContractAsync(); - const metadata = await tokenRegistryContract.getTokenMetaData.callAsync(address); + const metadata = await tokenRegistryContract.getTokenMetaData.callAsync(normalizedAddress); const token = TokenRegistryWrapper._createTokenFromMetadata(metadata); return token; } @@ -115,14 +117,11 @@ export class TokenRegistryWrapper extends ContractWrapper { if (!_.isUndefined(this._tokenRegistryContractIfExists)) { return this._tokenRegistryContractIfExists; } - const web3ContractInstance = await this._instantiateContractIfExistsAsync( + const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync( artifacts.TokenRegistryArtifact, this._contractAddressIfExists, ); - const contractInstance = new TokenRegistryContract( - web3ContractInstance, - this._web3Wrapper.getContractDefaults(), - ); + const contractInstance = new TokenRegistryContract(this._web3Wrapper, abi, address); this._tokenRegistryContractIfExists = contractInstance; return this._tokenRegistryContractIfExists; } diff --git a/packages/0x.js/src/contract_wrappers/token_transfer_proxy_wrapper.ts b/packages/0x.js/src/contract_wrappers/token_transfer_proxy_wrapper.ts index f5d9d108a..211c7dfb4 100644 --- a/packages/0x.js/src/contract_wrappers/token_transfer_proxy_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/token_transfer_proxy_wrapper.ts @@ -2,6 +2,7 @@ import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as _ from 'lodash'; import { artifacts } from '../artifacts'; +import { assert } from '../utils/assert'; import { ContractWrapper } from './contract_wrapper'; import { TokenTransferProxyContract } from './generated/token_transfer_proxy'; @@ -22,8 +23,12 @@ export class TokenTransferProxyWrapper extends ContractWrapper { * @return Whether the exchangeContractAddress is authorized. */ public async isAuthorizedAsync(exchangeContractAddress: string): Promise<boolean> { + assert.isETHAddressHex('exchangeContractAddress', exchangeContractAddress); + const normalizedExchangeContractAddress = exchangeContractAddress.toLowerCase(); const tokenTransferProxyContractInstance = await this._getTokenTransferProxyContractAsync(); - const isAuthorized = await tokenTransferProxyContractInstance.authorized.callAsync(exchangeContractAddress); + const isAuthorized = await tokenTransferProxyContractInstance.authorized.callAsync( + normalizedExchangeContractAddress, + ); return isAuthorized; } /** @@ -54,14 +59,11 @@ export class TokenTransferProxyWrapper extends ContractWrapper { if (!_.isUndefined(this._tokenTransferProxyContractIfExists)) { return this._tokenTransferProxyContractIfExists; } - const web3ContractInstance = await this._instantiateContractIfExistsAsync( + const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync( artifacts.TokenTransferProxyArtifact, this._contractAddressIfExists, ); - const contractInstance = new TokenTransferProxyContract( - web3ContractInstance, - this._web3Wrapper.getContractDefaults(), - ); + const contractInstance = new TokenTransferProxyContract(this._web3Wrapper, abi, address); this._tokenTransferProxyContractIfExists = contractInstance; return this._tokenTransferProxyContractIfExists; } diff --git a/packages/0x.js/src/contract_wrappers/token_wrapper.ts b/packages/0x.js/src/contract_wrappers/token_wrapper.ts index a018006b8..0f688cb71 100644 --- a/packages/0x.js/src/contract_wrappers/token_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/token_wrapper.ts @@ -46,10 +46,13 @@ export class TokenWrapper extends ContractWrapper { ): Promise<BigNumber> { assert.isETHAddressHex('ownerAddress', ownerAddress); assert.isETHAddressHex('tokenAddress', tokenAddress); + const normalizedTokenAddress = tokenAddress.toLowerCase(); + const normalizedOwnerAddress = ownerAddress.toLowerCase(); - const tokenContract = await this._getTokenContractAsync(tokenAddress); + const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock; - let balance = await tokenContract.balanceOf.callAsync(ownerAddress, defaultBlock); + const txData = {}; + let balance = await tokenContract.balanceOf.callAsync(normalizedOwnerAddress, txData, defaultBlock); // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber balance = new BigNumber(balance); return balance; @@ -72,14 +75,17 @@ export class TokenWrapper extends ContractWrapper { amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}, ): Promise<string> { - await assert.isSenderAddressAsync('ownerAddress', ownerAddress, this._web3Wrapper); assert.isETHAddressHex('spenderAddress', spenderAddress); assert.isETHAddressHex('tokenAddress', tokenAddress); + await assert.isSenderAddressAsync('ownerAddress', ownerAddress, this._web3Wrapper); + const normalizedTokenAddress = tokenAddress.toLowerCase(); + const normalizedSpenderAddress = spenderAddress.toLowerCase(); + const normalizedOwnerAddress = ownerAddress.toLowerCase(); assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits); - const tokenContract = await this._getTokenContractAsync(tokenAddress); - const txHash = await tokenContract.approve.sendTransactionAsync(spenderAddress, amountInBaseUnits, { - from: ownerAddress, + const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); + const txHash = await tokenContract.approve.sendTransactionAsync(normalizedSpenderAddress, amountInBaseUnits, { + from: normalizedOwnerAddress, gas: txOpts.gasLimit, gasPrice: txOpts.gasPrice, }); @@ -103,10 +109,16 @@ export class TokenWrapper extends ContractWrapper { spenderAddress: string, txOpts: TransactionOpts = {}, ): Promise<string> { + assert.isETHAddressHex('ownerAddress', ownerAddress); + assert.isETHAddressHex('tokenAddress', tokenAddress); + assert.isETHAddressHex('spenderAddress', spenderAddress); + const normalizedTokenAddress = tokenAddress.toLowerCase(); + const normalizedOwnerAddress = ownerAddress.toLowerCase(); + const normalizedSpenderAddress = spenderAddress.toLowerCase(); const txHash = await this.setAllowanceAsync( - tokenAddress, - ownerAddress, - spenderAddress, + normalizedTokenAddress, + normalizedOwnerAddress, + normalizedSpenderAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, txOpts, ); @@ -128,10 +140,20 @@ export class TokenWrapper extends ContractWrapper { ): Promise<BigNumber> { assert.isETHAddressHex('ownerAddress', ownerAddress); assert.isETHAddressHex('tokenAddress', tokenAddress); + assert.isETHAddressHex('spenderAddress', spenderAddress); + const normalizedTokenAddress = tokenAddress.toLowerCase(); + const normalizedOwnerAddress = ownerAddress.toLowerCase(); + const normalizedSpenderAddress = spenderAddress.toLowerCase(); - const tokenContract = await this._getTokenContractAsync(tokenAddress); + const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock; - let allowanceInBaseUnits = await tokenContract.allowance.callAsync(ownerAddress, spenderAddress, defaultBlock); + const txData = {}; + let allowanceInBaseUnits = await tokenContract.allowance.callAsync( + normalizedOwnerAddress, + normalizedSpenderAddress, + txData, + defaultBlock, + ); // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber allowanceInBaseUnits = new BigNumber(allowanceInBaseUnits); return allowanceInBaseUnits; @@ -149,9 +171,16 @@ export class TokenWrapper extends ContractWrapper { ): Promise<BigNumber> { assert.isETHAddressHex('ownerAddress', ownerAddress); assert.isETHAddressHex('tokenAddress', tokenAddress); + const normalizedTokenAddress = tokenAddress.toLowerCase(); + const normalizedOwnerAddress = ownerAddress.toLowerCase(); const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress(); - const allowanceInBaseUnits = await this.getAllowanceAsync(tokenAddress, ownerAddress, proxyAddress, methodOpts); + const allowanceInBaseUnits = await this.getAllowanceAsync( + normalizedTokenAddress, + normalizedOwnerAddress, + proxyAddress, + methodOpts, + ); return allowanceInBaseUnits; } /** @@ -172,12 +201,14 @@ export class TokenWrapper extends ContractWrapper { ): Promise<string> { assert.isETHAddressHex('ownerAddress', ownerAddress); assert.isETHAddressHex('tokenAddress', tokenAddress); + const normalizedTokenAddress = tokenAddress.toLowerCase(); + const normalizedOwnerAddress = ownerAddress.toLowerCase(); assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits); const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress(); const txHash = await this.setAllowanceAsync( - tokenAddress, - ownerAddress, + normalizedTokenAddress, + normalizedOwnerAddress, proxyAddress, amountInBaseUnits, txOpts, @@ -200,9 +231,13 @@ export class TokenWrapper extends ContractWrapper { ownerAddress: string, txOpts: TransactionOpts = {}, ): Promise<string> { + assert.isETHAddressHex('ownerAddress', ownerAddress); + assert.isETHAddressHex('tokenAddress', tokenAddress); + const normalizedTokenAddress = tokenAddress.toLowerCase(); + const normalizedOwnerAddress = ownerAddress.toLowerCase(); const txHash = await this.setProxyAllowanceAsync( - tokenAddress, - ownerAddress, + normalizedTokenAddress, + normalizedOwnerAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, txOpts, ); @@ -225,19 +260,22 @@ export class TokenWrapper extends ContractWrapper { txOpts: TransactionOpts = {}, ): Promise<string> { assert.isETHAddressHex('tokenAddress', tokenAddress); - await assert.isSenderAddressAsync('fromAddress', fromAddress, this._web3Wrapper); assert.isETHAddressHex('toAddress', toAddress); + await assert.isSenderAddressAsync('fromAddress', fromAddress, this._web3Wrapper); + const normalizedTokenAddress = tokenAddress.toLowerCase(); + const normalizedFromAddress = fromAddress.toLowerCase(); + const normalizedToAddress = toAddress.toLowerCase(); assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits); - const tokenContract = await this._getTokenContractAsync(tokenAddress); + const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); - const fromAddressBalance = await this.getBalanceAsync(tokenAddress, fromAddress); + const fromAddressBalance = await this.getBalanceAsync(normalizedTokenAddress, normalizedFromAddress); if (fromAddressBalance.lessThan(amountInBaseUnits)) { throw new Error(ZeroExError.InsufficientBalanceForTransfer); } - const txHash = await tokenContract.transfer.sendTransactionAsync(toAddress, amountInBaseUnits, { - from: fromAddress, + const txHash = await tokenContract.transfer.sendTransactionAsync(normalizedToAddress, amountInBaseUnits, { + from: normalizedFromAddress, gas: txOpts.gasLimit, gasPrice: txOpts.gasPrice, }); @@ -265,30 +303,38 @@ export class TokenWrapper extends ContractWrapper { amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}, ): Promise<string> { - assert.isETHAddressHex('tokenAddress', tokenAddress); - assert.isETHAddressHex('fromAddress', fromAddress); assert.isETHAddressHex('toAddress', toAddress); + assert.isETHAddressHex('fromAddress', fromAddress); + assert.isETHAddressHex('tokenAddress', tokenAddress); await assert.isSenderAddressAsync('senderAddress', senderAddress, this._web3Wrapper); + const normalizedToAddress = toAddress.toLowerCase(); + const normalizedFromAddress = fromAddress.toLowerCase(); + const normalizedTokenAddress = tokenAddress.toLowerCase(); + const normalizedSenderAddress = senderAddress.toLowerCase(); assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits); - const tokenContract = await this._getTokenContractAsync(tokenAddress); + const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); - const fromAddressAllowance = await this.getAllowanceAsync(tokenAddress, fromAddress, senderAddress); + const fromAddressAllowance = await this.getAllowanceAsync( + normalizedTokenAddress, + normalizedFromAddress, + normalizedSenderAddress, + ); if (fromAddressAllowance.lessThan(amountInBaseUnits)) { throw new Error(ZeroExError.InsufficientAllowanceForTransfer); } - const fromAddressBalance = await this.getBalanceAsync(tokenAddress, fromAddress); + const fromAddressBalance = await this.getBalanceAsync(normalizedTokenAddress, normalizedFromAddress); if (fromAddressBalance.lessThan(amountInBaseUnits)) { throw new Error(ZeroExError.InsufficientBalanceForTransfer); } const txHash = await tokenContract.transferFrom.sendTransactionAsync( - fromAddress, - toAddress, + normalizedFromAddress, + normalizedToAddress, amountInBaseUnits, { - from: senderAddress, + from: normalizedSenderAddress, gas: txOpts.gasLimit, gasPrice: txOpts.gasPrice, }, @@ -311,11 +357,12 @@ export class TokenWrapper extends ContractWrapper { callback: EventCallback<ArgsType>, ): string { assert.isETHAddressHex('tokenAddress', tokenAddress); + const normalizedTokenAddress = tokenAddress.toLowerCase(); assert.doesBelongToStringEnum('eventName', eventName, TokenEvents); assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); assert.isFunction('callback', callback); const subscriptionToken = this._subscribe<ArgsType>( - tokenAddress, + normalizedTokenAddress, eventName, indexFilterValues, artifacts.TokenArtifact.abi, @@ -333,7 +380,7 @@ export class TokenWrapper extends ContractWrapper { /** * Cancels all existing subscriptions */ - public _unsubscribeAll(): void { + public unsubscribeAll(): void { super._unsubscribeAll(); } /** @@ -352,11 +399,12 @@ export class TokenWrapper extends ContractWrapper { indexFilterValues: IndexedFilterValues, ): Promise<Array<LogWithDecodedArgs<ArgsType>>> { assert.isETHAddressHex('tokenAddress', tokenAddress); + const normalizedTokenAddress = tokenAddress.toLowerCase(); assert.doesBelongToStringEnum('eventName', eventName, TokenEvents); assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); const logs = await this._getLogsAsync<ArgsType>( - tokenAddress, + normalizedTokenAddress, eventName, blockRange, indexFilterValues, @@ -365,21 +413,22 @@ export class TokenWrapper extends ContractWrapper { return logs; } private _invalidateContractInstances(): void { - this._unsubscribeAll(); + this.unsubscribeAll(); this._tokenContractsByAddress = {}; } private async _getTokenContractAsync(tokenAddress: string): Promise<TokenContract> { - let tokenContract = this._tokenContractsByAddress[tokenAddress]; + const normalizedTokenAddress = tokenAddress.toLowerCase(); + let tokenContract = this._tokenContractsByAddress[normalizedTokenAddress]; if (!_.isUndefined(tokenContract)) { return tokenContract; } - const web3ContractInstance = await this._instantiateContractIfExistsAsync( + const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync( artifacts.TokenArtifact, - tokenAddress, + normalizedTokenAddress, ); - const contractInstance = new TokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults()); + const contractInstance = new TokenContract(this._web3Wrapper, abi, address); tokenContract = contractInstance; - this._tokenContractsByAddress[tokenAddress] = tokenContract; + this._tokenContractsByAddress[normalizedTokenAddress] = tokenContract; return tokenContract; } } diff --git a/packages/0x.js/src/schemas/zero_ex_config_schema.ts b/packages/0x.js/src/schemas/zero_ex_config_schema.ts index 546b1c2d0..a9c3c64fc 100644 --- a/packages/0x.js/src/schemas/zero_ex_config_schema.ts +++ b/packages/0x.js/src/schemas/zero_ex_config_schema.ts @@ -1,27 +1,5 @@ export const zeroExConfigSchema = { id: '/ZeroExConfig', - properties: { - networkId: { - type: 'number', - minimum: 0, - }, - gasPrice: { $ref: '/Number' }, - exchangeContractAddress: { $ref: '/Address' }, - tokenRegistryContractAddress: { $ref: '/Address' }, - orderWatcherConfig: { - type: 'object', - properties: { - pollingIntervalMs: { - type: 'number', - minimum: 0, - }, - numConfirmations: { - type: 'number', - minimum: 0, - }, - }, - }, - }, + oneOf: [{ $ref: '/ZeroExPrivateNetworkConfig' }, { $ref: '/ZeroExPublicNetworkConfig' }], type: 'object', - required: ['networkId'], }; diff --git a/packages/0x.js/src/schemas/zero_ex_private_network_config_schema.ts b/packages/0x.js/src/schemas/zero_ex_private_network_config_schema.ts new file mode 100644 index 000000000..f7f649a6d --- /dev/null +++ b/packages/0x.js/src/schemas/zero_ex_private_network_config_schema.ts @@ -0,0 +1,35 @@ +export const zeroExPrivateNetworkConfigSchema = { + id: '/ZeroExPrivateNetworkConfig', + properties: { + networkId: { + type: 'number', + minimum: 1, + }, + gasPrice: { $ref: '/Number' }, + zrxContractAddress: { $ref: '/Address' }, + exchangeContractAddress: { $ref: '/Address' }, + tokenRegistryContractAddress: { $ref: '/Address' }, + tokenTransferProxyContractAddress: { $ref: '/Address' }, + orderWatcherConfig: { + type: 'object', + properties: { + pollingIntervalMs: { + type: 'number', + minimum: 0, + }, + numConfirmations: { + type: 'number', + minimum: 0, + }, + }, + }, + }, + type: 'object', + required: [ + 'networkId', + 'zrxContractAddress', + 'exchangeContractAddress', + 'tokenRegistryContractAddress', + 'tokenTransferProxyContractAddress', + ], +}; diff --git a/packages/0x.js/src/schemas/zero_ex_public_network_config_schema.ts b/packages/0x.js/src/schemas/zero_ex_public_network_config_schema.ts new file mode 100644 index 000000000..9da31481a --- /dev/null +++ b/packages/0x.js/src/schemas/zero_ex_public_network_config_schema.ts @@ -0,0 +1,29 @@ +export const zeroExPublicNetworkConfigSchema = { + id: '/ZeroExPublicNetworkConfig', + properties: { + networkId: { + type: 'number', + enum: [1, 3, 4, 42, 50], + }, + gasPrice: { $ref: '/Number' }, + zrxContractAddress: { $ref: '/Address' }, + exchangeContractAddress: { $ref: '/Address' }, + tokenRegistryContractAddress: { $ref: '/Address' }, + tokenTransferProxyContractAddress: { $ref: '/Address' }, + orderWatcherConfig: { + type: 'object', + properties: { + pollingIntervalMs: { + type: 'number', + minimum: 0, + }, + numConfirmations: { + type: 'number', + minimum: 0, + }, + }, + }, + }, + type: 'object', + required: ['networkId'], +}; diff --git a/packages/0x.js/src/types.ts b/packages/0x.js/src/types.ts index ab97f7775..2f17e30c2 100644 --- a/packages/0x.js/src/types.ts +++ b/packages/0x.js/src/types.ts @@ -127,7 +127,7 @@ export interface SignedOrder extends Order { } // [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 { name: string; @@ -196,7 +196,7 @@ export interface OrderStateWatcherConfig { } /* - * networkId: The id of the underlying ethereum network your provider is connected to. (1-mainnet, 42-kovan, 50-testrpc) + * networkId: The id of the underlying ethereum network your provider is connected to. (1-mainnet, 3-ropsten, 4-rinkeby, 42-kovan, 50-testrpc) * gasPrice: Gas price to use with every transaction * exchangeContractAddress: The address of an exchange contract to use * zrxContractAddress: The address of the ZRX contract to use diff --git a/packages/0x.js/test/ether_token_wrapper_test.ts b/packages/0x.js/test/ether_token_wrapper_test.ts index da49ec467..68f2c6f66 100644 --- a/packages/0x.js/test/ether_token_wrapper_test.ts +++ b/packages/0x.js/test/ether_token_wrapper_test.ts @@ -75,11 +75,14 @@ describe('EtherTokenWrapper', () => { const contractAddressIfExists = zeroEx.etherToken.getContractAddressIfExists(); expect(contractAddressIfExists).to.not.be.undefined(); }); - it('should return undefined if connected to an unknown network', () => { + it('should throw if connected to a private network and contract addresses are not specified', () => { const UNKNOWN_NETWORK_NETWORK_ID = 10; - const unknownNetworkZeroEx = new ZeroEx(web3.currentProvider, { networkId: UNKNOWN_NETWORK_NETWORK_ID }); - const contractAddressIfExists = unknownNetworkZeroEx.etherToken.getContractAddressIfExists(); - expect(contractAddressIfExists).to.be.undefined(); + expect( + () => + new ZeroEx(web3.currentProvider, { + networkId: UNKNOWN_NETWORK_NETWORK_ID, + } as any), + ).to.throw(); }); }); describe('#depositAsync', () => { @@ -155,7 +158,7 @@ describe('EtherTokenWrapper', () => { etherTokenAddress = etherToken.address; }); afterEach(() => { - zeroEx.etherToken._unsubscribeAll(); + zeroEx.etherToken.unsubscribeAll(); }); // Hack: Mocha does not allow a test to be both async and have a `done` callback // Since we need to await the receipt of the event in the `subscribe` callback, diff --git a/packages/0x.js/test/exchange_wrapper_test.ts b/packages/0x.js/test/exchange_wrapper_test.ts index 325426438..688be628f 100644 --- a/packages/0x.js/test/exchange_wrapper_test.ts +++ b/packages/0x.js/test/exchange_wrapper_test.ts @@ -922,7 +922,7 @@ describe('ExchangeWrapper', () => { ); }); afterEach(async () => { - zeroEx.exchange._unsubscribeAll(); + zeroEx.exchange.unsubscribeAll(); }); // Hack: Mocha does not allow a test to be both async and have a `done` callback // Since we need to await the receipt of the event in the `subscribe` callback, diff --git a/packages/0x.js/test/expiration_watcher_test.ts b/packages/0x.js/test/expiration_watcher_test.ts index b49dee8e5..7f79e3802 100644 --- a/packages/0x.js/test/expiration_watcher_test.ts +++ b/packages/0x.js/test/expiration_watcher_test.ts @@ -9,10 +9,10 @@ import * as Web3 from 'web3'; import { ZeroEx } from '../src/0x'; import { ExpirationWatcher } from '../src/order_watcher/expiration_watcher'; import { DoneCallback, Token } from '../src/types'; -import { constants } from '../src/utils/constants'; import { utils } from '../src/utils/utils'; import { chaiSetup } from './utils/chai_setup'; +import { constants } from './utils/constants'; import { FillScenarios } from './utils/fill_scenarios'; import { reportNoErrorCallbackErrors } from './utils/report_callback_errors'; import { TokenUtils } from './utils/token_utils'; diff --git a/packages/0x.js/test/subscription_test.ts b/packages/0x.js/test/subscription_test.ts index 337e2effa..f485bf84b 100644 --- a/packages/0x.js/test/subscription_test.ts +++ b/packages/0x.js/test/subscription_test.ts @@ -49,7 +49,7 @@ describe('SubscriptionTest', () => { tokenAddress = token.address; }); afterEach(() => { - zeroEx.token._unsubscribeAll(); + zeroEx.token.unsubscribeAll(); _.each(stubs, s => s.restore()); stubs = []; }); @@ -76,7 +76,7 @@ describe('SubscriptionTest', () => { const callback = (err: Error | null, logEvent?: DecodedLogEvent<ApprovalContractEventArgs>) => _.noop; zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback); stubs = [Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync').throws(new Error('JSON RPC error'))]; - zeroEx.token._unsubscribeAll(); + zeroEx.token.unsubscribeAll(); done(); })().catch(done); }); diff --git a/packages/0x.js/test/token_wrapper_test.ts b/packages/0x.js/test/token_wrapper_test.ts index 34ebe30c2..070d6ec47 100644 --- a/packages/0x.js/test/token_wrapper_test.ts +++ b/packages/0x.js/test/token_wrapper_test.ts @@ -377,7 +377,7 @@ describe('TokenWrapper', () => { tokenAddress = token.address; }); afterEach(() => { - zeroEx.token._unsubscribeAll(); + zeroEx.token.unsubscribeAll(); }); // Hack: Mocha does not allow a test to be both async and have a `done` callback // Since we need to await the receipt of the event in the `subscribe` callback, diff --git a/packages/0x.js/test/utils/fill_scenarios.ts b/packages/0x.js/test/utils/fill_scenarios.ts index 1a61487f4..8b1308298 100644 --- a/packages/0x.js/test/utils/fill_scenarios.ts +++ b/packages/0x.js/test/utils/fill_scenarios.ts @@ -35,12 +35,8 @@ export class FillScenarios { const web3Wrapper = (this._zeroEx as any)._web3Wrapper as Web3Wrapper; for (const token of this._tokens) { if (token.symbol !== 'ZRX' && token.symbol !== 'WETH') { - const contractInstance = web3Wrapper.getContractInstance( - artifacts.DummyTokenArtifact.abi, - token.address, - ); 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 txHash = await dummyToken.setBalance.sendTransactionAsync(this._coinbase, tokenSupply, { from: this._coinbase, diff --git a/packages/0x.js/tsconfig.json b/packages/0x.js/tsconfig.json index 117f51e83..a6b5c71c2 100644 --- a/packages/0x.js/tsconfig.json +++ b/packages/0x.js/tsconfig.json @@ -9,6 +9,7 @@ "./test/**/*", "../../node_modules/types-bn/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/chai-typescript-typings/index.d.ts", "../../node_modules/chai-as-promised-typescript-typings/index.d.ts" |