diff options
author | Leonid Logvinov <logvinov.leon@gmail.com> | 2018-09-26 20:55:52 +0800 |
---|---|---|
committer | Leonid Logvinov <logvinov.leon@gmail.com> | 2018-09-26 20:55:52 +0800 |
commit | 5d73eebf6abe52763ea6984f85102157abea5b6c (patch) | |
tree | 8cec1c58fe22ba62d979dbc1c6ff366e81985b8d /packages/web3-wrapper | |
parent | f3deabccf4e6caec57351a09f82b3f786122b5ea (diff) | |
parent | 13aa98f0f3431e4ea4db07794a06304c237e8d45 (diff) | |
download | dexon-0x-contracts-5d73eebf6abe52763ea6984f85102157abea5b6c.tar.gz dexon-0x-contracts-5d73eebf6abe52763ea6984f85102157abea5b6c.tar.zst dexon-0x-contracts-5d73eebf6abe52763ea6984f85102157abea5b6c.zip |
Merge branch 'development' into feature/ts-ethers
Diffstat (limited to 'packages/web3-wrapper')
-rw-r--r-- | packages/web3-wrapper/CHANGELOG.json | 36 | ||||
-rw-r--r-- | packages/web3-wrapper/CHANGELOG.md | 13 | ||||
-rw-r--r-- | packages/web3-wrapper/package.json | 12 | ||||
-rw-r--r-- | packages/web3-wrapper/src/web3_wrapper.ts | 106 | ||||
-rw-r--r-- | packages/web3-wrapper/test/web3_wrapper_test.ts | 34 |
5 files changed, 141 insertions, 60 deletions
diff --git a/packages/web3-wrapper/CHANGELOG.json b/packages/web3-wrapper/CHANGELOG.json index 57e6f7689..1ab2acafc 100644 --- a/packages/web3-wrapper/CHANGELOG.json +++ b/packages/web3-wrapper/CHANGELOG.json @@ -1,5 +1,41 @@ [ { + "timestamp": 1537907159, + "version": "3.0.1", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "version": "3.0.0", + "changes": [ + { + "note": + "Rename `getBlockAsync` to `getBlockIfExistsAsync` and rather then throw if the requested block wasn't found, return undefined.", + "pr": 1082 + }, + { + "note": + "Expose `sendRawPayloadAsync` so one can easily extend `Web3Wrapper` with their own custom JSON RPC calls", + "pr": 1080 + } + ], + "timestamp": 1537875740 + }, + { + "version": "2.0.3", + "changes": [ + { + "note": + "Fixes issue #1076 where Parity now returns a placeholder transactionReceipt before the transaction is mined.", + "pr": 1079 + } + ], + "timestamp": 1537541580 + }, + { "timestamp": 1536142250, "version": "2.0.2", "changes": [ diff --git a/packages/web3-wrapper/CHANGELOG.md b/packages/web3-wrapper/CHANGELOG.md index 17f2b9f48..1c592d22e 100644 --- a/packages/web3-wrapper/CHANGELOG.md +++ b/packages/web3-wrapper/CHANGELOG.md @@ -5,6 +5,19 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.0.1 - _September 25, 2018_ + + * Dependencies updated + +## v3.0.0 - _September 25, 2018_ + + * Rename `getBlockAsync` to `getBlockIfExistsAsync` and rather then throw if the requested block wasn't found, return undefined. (#1082) + * Expose `sendRawPayloadAsync` so one can easily extend `Web3Wrapper` with their own custom JSON RPC calls (#1080) + +## v2.0.3 - _September 21, 2018_ + + * Fixes issue #1076 where Parity now returns a placeholder transactionReceipt before the transaction is mined. (#1079) + ## v2.0.2 - _September 5, 2018_ * Dependencies updated diff --git a/packages/web3-wrapper/package.json b/packages/web3-wrapper/package.json index cad814d8d..319360409 100644 --- a/packages/web3-wrapper/package.json +++ b/packages/web3-wrapper/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/web3-wrapper", - "version": "2.0.2", + "version": "3.0.1", "engines": { "node": ">=6.12" }, @@ -53,11 +53,11 @@ "typescript": "3.0.1" }, "dependencies": { - "@0xproject/assert": "^1.0.8", - "@0xproject/json-schemas": "^1.0.1", - "@0xproject/typescript-typings": "^2.0.0", - "@0xproject/utils": "^1.0.8", - "ethereum-types": "^1.0.6", + "@0xproject/assert": "^1.0.11", + "@0xproject/json-schemas": "^1.0.4", + "@0xproject/typescript-typings": "^2.0.2", + "@0xproject/utils": "^1.0.11", + "ethereum-types": "^1.0.8", "ethereumjs-util": "^5.1.1", "ethers": "^4.0.0-beta.14", "lodash": "^4.17.5" diff --git a/packages/web3-wrapper/src/web3_wrapper.ts b/packages/web3-wrapper/src/web3_wrapper.ts index ea78f8801..d52c1cb6e 100644 --- a/packages/web3-wrapper/src/web3_wrapper.ts +++ b/packages/web3-wrapper/src/web3_wrapper.ts @@ -193,7 +193,7 @@ export class Web3Wrapper { * @returns Ethereum node's version string */ public async getNodeVersionAsync(): Promise<string> { - const nodeVersion = await this._sendRawPayloadAsync<string>({ method: 'web3_clientVersion' }); + const nodeVersion = await this.sendRawPayloadAsync<string>({ method: 'web3_clientVersion' }); return nodeVersion; } /** @@ -201,7 +201,7 @@ export class Web3Wrapper { * @returns The network id */ public async getNetworkIdAsync(): Promise<number> { - const networkIdStr = await this._sendRawPayloadAsync<string>({ method: 'net_version' }); + const networkIdStr = await this.sendRawPayloadAsync<string>({ method: 'net_version' }); const networkId = _.parseInt(networkIdStr); return networkId; } @@ -212,7 +212,7 @@ export class Web3Wrapper { */ public async getTransactionReceiptAsync(txHash: string): Promise<TransactionReceipt> { assert.isHexString('txHash', txHash); - const transactionReceipt = await this._sendRawPayloadAsync<TransactionReceipt>({ + const transactionReceipt = await this.sendRawPayloadAsync<TransactionReceipt>({ method: 'eth_getTransactionReceipt', params: [txHash], }); @@ -228,7 +228,7 @@ export class Web3Wrapper { */ public async getTransactionByHashAsync(txHash: string): Promise<Transaction> { assert.isHexString('txHash', txHash); - const transaction = await this._sendRawPayloadAsync<Transaction>({ + const transaction = await this.sendRawPayloadAsync<Transaction>({ method: 'eth_getTransactionByHash', params: [txHash], }); @@ -247,7 +247,7 @@ export class Web3Wrapper { } const marshalledDefaultBlock = marshaller.marshalBlockParam(defaultBlock); const encodedOwner = marshaller.marshalAddress(owner); - const balanceInWei = await this._sendRawPayloadAsync<string>({ + const balanceInWei = await this.sendRawPayloadAsync<string>({ method: 'eth_getBalance', params: [encodedOwner, marshalledDefaultBlock], }); @@ -279,7 +279,7 @@ export class Web3Wrapper { } const marshalledDefaultBlock = marshaller.marshalBlockParam(defaultBlock); const encodedAddress = marshaller.marshalAddress(address); - const code = await this._sendRawPayloadAsync<string>({ + const code = await this.sendRawPayloadAsync<string>({ method: 'eth_getCode', params: [encodedAddress, marshalledDefaultBlock], }); @@ -293,7 +293,7 @@ export class Web3Wrapper { */ public async getTransactionTraceAsync(txHash: string, traceParams: TraceParams): Promise<TransactionTrace> { assert.isHexString('txHash', txHash); - const trace = await this._sendRawPayloadAsync<TransactionTrace>({ + const trace = await this.sendRawPayloadAsync<TransactionTrace>({ method: 'debug_traceTransaction', params: [txHash, traceParams], }); @@ -308,7 +308,7 @@ export class Web3Wrapper { public async signMessageAsync(address: string, message: string): Promise<string> { assert.isETHAddressHex('address', address); assert.isString('message', message); // TODO: Should this be stricter? Hex string? - const signData = await this._sendRawPayloadAsync<string>({ + const signData = await this.sendRawPayloadAsync<string>({ method: 'eth_sign', params: [address, message], }); @@ -319,7 +319,7 @@ export class Web3Wrapper { * @returns Block number */ public async getBlockNumberAsync(): Promise<number> { - const blockNumberHex = await this._sendRawPayloadAsync<string>({ + const blockNumberHex = await this.sendRawPayloadAsync<string>({ method: 'eth_blockNumber', params: [], }); @@ -329,23 +329,29 @@ export class Web3Wrapper { /** * Fetch a specific Ethereum block without transaction data * @param blockParam The block you wish to fetch (blockHash, blockNumber or blockLiteral) - * @returns The requested block without transaction data + * @returns The requested block without transaction data, or undefined if block was not found + * (e.g the node isn't fully synced, there was a block re-org and the requested block was uncles, etc...) */ - public async getBlockAsync(blockParam: string | BlockParam): Promise<BlockWithoutTransactionData> { + public async getBlockIfExistsAsync( + blockParam: string | BlockParam, + ): Promise<BlockWithoutTransactionData | undefined> { Web3Wrapper._assertBlockParamOrString(blockParam); const encodedBlockParam = marshaller.marshalBlockParam(blockParam); const method = utils.isHexStrict(blockParam) ? 'eth_getBlockByHash' : 'eth_getBlockByNumber'; const shouldIncludeTransactionData = false; - const blockWithoutTransactionDataWithHexValues = await this._sendRawPayloadAsync< + const blockWithoutTransactionDataWithHexValuesOrNull = await this.sendRawPayloadAsync< BlockWithoutTransactionDataRPC >({ method, params: [encodedBlockParam, shouldIncludeTransactionData], }); - const blockWithoutTransactionData = marshaller.unmarshalIntoBlockWithoutTransactionData( - blockWithoutTransactionDataWithHexValues, - ); - return blockWithoutTransactionData; + let blockWithoutTransactionDataIfExists; + if (!_.isNull(blockWithoutTransactionDataWithHexValuesOrNull)) { + blockWithoutTransactionDataIfExists = marshaller.unmarshalIntoBlockWithoutTransactionData( + blockWithoutTransactionDataWithHexValuesOrNull, + ); + } + return blockWithoutTransactionDataIfExists; } /** * Fetch a specific Ethereum block with transaction data @@ -360,7 +366,7 @@ export class Web3Wrapper { } const method = utils.isHexStrict(blockParam) ? 'eth_getBlockByHash' : 'eth_getBlockByNumber'; const shouldIncludeTransactionData = true; - const blockWithTransactionDataWithHexValues = await this._sendRawPayloadAsync<BlockWithTransactionDataRPC>({ + const blockWithTransactionDataWithHexValues = await this.sendRawPayloadAsync<BlockWithTransactionDataRPC>({ method, params: [encodedBlockParam, shouldIncludeTransactionData], }); @@ -376,15 +382,18 @@ export class Web3Wrapper { */ public async getBlockTimestampAsync(blockParam: string | BlockParam): Promise<number> { Web3Wrapper._assertBlockParamOrString(blockParam); - const { timestamp } = await this.getBlockAsync(blockParam); - return timestamp; + const blockIfExists = await this.getBlockIfExistsAsync(blockParam); + if (_.isUndefined(blockIfExists)) { + throw new Error(`Failed to fetch block with blockParam: ${JSON.stringify(blockParam)}`); + } + return blockIfExists.timestamp; } /** * Retrieve the user addresses available through the backing provider * @returns Available user addresses */ public async getAvailableAddressesAsync(): Promise<string[]> { - const addresses = await this._sendRawPayloadAsync<string>({ + const addresses = await this.sendRawPayloadAsync<string>({ method: 'eth_accounts', params: [], }); @@ -396,7 +405,7 @@ export class Web3Wrapper { * @returns The snapshot id. This can be used to revert to this snapshot */ public async takeSnapshotAsync(): Promise<number> { - const snapshotId = Number(await this._sendRawPayloadAsync<string>({ method: 'evm_snapshot', params: [] })); + const snapshotId = Number(await this.sendRawPayloadAsync<string>({ method: 'evm_snapshot', params: [] })); return snapshotId; } /** @@ -406,14 +415,14 @@ export class Web3Wrapper { */ public async revertSnapshotAsync(snapshotId: number): Promise<boolean> { assert.isNumber('snapshotId', snapshotId); - const didRevert = await this._sendRawPayloadAsync<boolean>({ method: 'evm_revert', params: [snapshotId] }); + const didRevert = await this.sendRawPayloadAsync<boolean>({ method: 'evm_revert', params: [snapshotId] }); return didRevert; } /** * Mine a block on a TestRPC/Ganache local node */ public async mineBlockAsync(): Promise<void> { - await this._sendRawPayloadAsync<string>({ method: 'evm_mine', params: [] }); + await this.sendRawPayloadAsync<string>({ method: 'evm_mine', params: [] }); } /** * Increase the next blocks timestamp on TestRPC/Ganache or Geth local node. @@ -425,9 +434,9 @@ export class Web3Wrapper { // Detect Geth vs. Ganache and use appropriate endpoint. const version = await this.getNodeVersionAsync(); if (_.includes(version, uniqueVersionIds.geth)) { - return this._sendRawPayloadAsync<number>({ method: 'debug_increaseTime', params: [timeDelta] }); + return this.sendRawPayloadAsync<number>({ method: 'debug_increaseTime', params: [timeDelta] }); } else if (_.includes(version, uniqueVersionIds.ganache)) { - return this._sendRawPayloadAsync<number>({ method: 'evm_increaseTime', params: [timeDelta] }); + return this.sendRawPayloadAsync<number>({ method: 'evm_increaseTime', params: [timeDelta] }); } else { throw new Error(`Unknown client version: ${version}`); } @@ -438,6 +447,12 @@ export class Web3Wrapper { * @returns The corresponding log entries */ public async getLogsAsync(filter: FilterObject): Promise<LogEntry[]> { + if (!_.isUndefined(filter.blockHash) && (!_.isUndefined(filter.fromBlock) || !_.isUndefined(filter.toBlock))) { + throw new Error( + `Cannot specify 'blockHash' as well as 'fromBlock'/'toBlock' in the filter supplied to 'getLogsAsync'`, + ); + } + let fromBlock = filter.fromBlock; if (_.isNumber(fromBlock)) { fromBlock = utils.numberToHex(fromBlock); @@ -455,7 +470,7 @@ export class Web3Wrapper { method: 'eth_getLogs', params: [serializedFilter], }; - const rawLogs = await this._sendRawPayloadAsync<RawLogEntry[]>(payload); + const rawLogs = await this.sendRawPayloadAsync<RawLogEntry[]>(payload); const formattedLogs = _.map(rawLogs, marshaller.unmarshalLog.bind(marshaller)); return formattedLogs; } @@ -471,7 +486,7 @@ export class Web3Wrapper { schemas.jsNumber, ]); const txDataHex = marshaller.marshalTxData(txData); - const gasHex = await this._sendRawPayloadAsync<string>({ method: 'eth_estimateGas', params: [txDataHex] }); + const gasHex = await this.sendRawPayloadAsync<string>({ method: 'eth_estimateGas', params: [txDataHex] }); const gas = utils.convertHexToNumber(gasHex); return gas; } @@ -492,7 +507,7 @@ export class Web3Wrapper { } const marshalledDefaultBlock = marshaller.marshalBlockParam(defaultBlock); const callDataHex = marshaller.marshalCallData(callData); - const rawCallResult = await this._sendRawPayloadAsync<string>({ + const rawCallResult = await this.sendRawPayloadAsync<string>({ method: 'eth_call', params: [callDataHex, marshalledDefaultBlock], }); @@ -513,7 +528,7 @@ export class Web3Wrapper { schemas.jsNumber, ]); const txDataHex = marshaller.marshalTxData(txData); - const txHash = await this._sendRawPayloadAsync<string>({ method: 'eth_sendTransaction', params: [txDataHex] }); + const txHash = await this.sendRawPayloadAsync<string>({ method: 'eth_sendTransaction', params: [txDataHex] }); return txHash; } /** @@ -539,7 +554,7 @@ export class Web3Wrapper { } // Immediately check if the transaction has already been mined. let transactionReceipt = await this.getTransactionReceiptAsync(txHash); - if (!_.isNull(transactionReceipt)) { + if (!_.isNull(transactionReceipt) && !_.isNull(transactionReceipt.blockNumber)) { const logsWithDecodedArgs = _.map( transactionReceipt.logs, this.abiDecoder.tryToDecodeLogOrNoop.bind(this.abiDecoder), @@ -623,7 +638,24 @@ export class Web3Wrapper { */ public async setHeadAsync(blockNumber: number): Promise<void> { assert.isNumber('blockNumber', blockNumber); - await this._sendRawPayloadAsync<void>({ method: 'debug_setHead', params: [utils.numberToHex(blockNumber)] }); + await this.sendRawPayloadAsync<void>({ method: 'debug_setHead', params: [utils.numberToHex(blockNumber)] }); + } + /** + * Sends a raw Ethereum JSON RPC payload and returns the response's `result` key + * @param payload A partial JSON RPC payload. No need to include version, id, params (if none needed) + * @return The contents nested under the result key of the response body + */ + public async sendRawPayloadAsync<A>(payload: Partial<JSONRPCRequestPayload>): Promise<A> { + const sendAsync = this._provider.sendAsync.bind(this._provider); + const payloadWithDefaults = { + id: this._jsonRpcRequestId++, + params: [], + jsonrpc: '2.0', + ...payload, + }; + const response = await promisify<JSONRPCResponsePayload>(sendAsync)(payloadWithDefaults); + const result = response.result; + return result; } /** * Returns either NodeType.Geth or NodeType.Ganache depending on the type of @@ -639,16 +671,4 @@ export class Web3Wrapper { throw new Error(`Unknown client version: ${version}`); } } - private async _sendRawPayloadAsync<A>(payload: Partial<JSONRPCRequestPayload>): Promise<A> { - const sendAsync = this._provider.sendAsync.bind(this._provider); - const payloadWithDefaults = { - id: this._jsonRpcRequestId++, - params: [], - jsonrpc: '2.0', - ...payload, - }; - const response = await promisify<JSONRPCResponsePayload>(sendAsync)(payloadWithDefaults); - const result = response.result; - return result; - } } // tslint:disable-line:max-file-line-count diff --git a/packages/web3-wrapper/test/web3_wrapper_test.ts b/packages/web3-wrapper/test/web3_wrapper_test.ts index b4fd8bb44..385c469bf 100644 --- a/packages/web3-wrapper/test/web3_wrapper_test.ts +++ b/packages/web3-wrapper/test/web3_wrapper_test.ts @@ -85,28 +85,40 @@ describe('Web3Wrapper tests', () => { expect(typeof blockNumber).to.be.equal('number'); }); }); - describe('#getBlockAsync', () => { + describe('#getBlockIfExistsAsync', () => { it('gets block when supplied a valid BlockParamLiteral value', async () => { const blockParamLiteral = BlockParamLiteral.Earliest; - const block = await web3Wrapper.getBlockAsync(blockParamLiteral); - expect(block.number).to.be.equal(0); - expect(utils.isBigNumber(block.difficulty)).to.equal(true); - expect(_.isNumber(block.gasLimit)).to.equal(true); + const blockIfExists = await web3Wrapper.getBlockIfExistsAsync(blockParamLiteral); + if (_.isUndefined(blockIfExists)) { + throw new Error('Expected block to exist'); + } + expect(blockIfExists.number).to.be.equal(0); + expect(utils.isBigNumber(blockIfExists.difficulty)).to.equal(true); + expect(_.isNumber(blockIfExists.gasLimit)).to.equal(true); }); it('gets block when supplied a block number', async () => { const blockParamLiteral = 0; - const block = await web3Wrapper.getBlockAsync(blockParamLiteral); - expect(block.number).to.be.equal(0); + const blockIfExists = await web3Wrapper.getBlockIfExistsAsync(blockParamLiteral); + if (_.isUndefined(blockIfExists)) { + throw new Error('Expected block to exist'); + } + expect(blockIfExists.number).to.be.equal(0); }); it('gets block when supplied a block hash', async () => { const blockParamLiteral = 0; - const block = await web3Wrapper.getBlockAsync(blockParamLiteral); - const sameBlock = await web3Wrapper.getBlockAsync(block.hash as string); - expect(sameBlock.number).to.be.equal(0); + const blockIfExists = await web3Wrapper.getBlockIfExistsAsync(blockParamLiteral); + if (_.isUndefined(blockIfExists)) { + throw new Error('Expected block to exist'); + } + const sameBlockIfExists = await web3Wrapper.getBlockIfExistsAsync(blockIfExists.hash as string); + if (_.isUndefined(sameBlockIfExists)) { + throw new Error('Expected block to exist'); + } + expect(sameBlockIfExists.number).to.be.equal(0); }); it('should throw if supplied invalid blockParam value', async () => { const invalidBlockParam = 'deadbeef'; - expect(web3Wrapper.getBlockAsync(invalidBlockParam)).to.eventually.to.be.rejected(); + expect(web3Wrapper.getBlockIfExistsAsync(invalidBlockParam)).to.eventually.to.be.rejected(); }); }); describe('#getBlockWithTransactionDataAsync', () => { |