From f6f45a3f2045355f2a37b05abf5061ec07039073 Mon Sep 17 00:00:00 2001 From: Ryan Ghods Date: Tue, 28 Apr 2020 14:40:00 -0700 Subject: [PATCH] Updates --- packages/web3-eth-abi/src/index.js | 85 +++++++++++++++++++++++++----- test/abi.encodeParameter.js | 16 ++++++ 2 files changed, 89 insertions(+), 12 deletions(-) diff --git a/packages/web3-eth-abi/src/index.js b/packages/web3-eth-abi/src/index.js index cb37a867c44..39339e80342 100644 --- a/packages/web3-eth-abi/src/index.js +++ b/packages/web3-eth-abi/src/index.js @@ -25,6 +25,7 @@ var _ = require('underscore'); var utils = require('web3-utils'); var EthersAbiCoder = require('@ethersproject/abi').AbiCoder; +var ParamType = require('@ethersproject/abi').ParamType; var ethersAbiCoder = new EthersAbiCoder(function (type, value) { if (type.match(/^u?int/) && !_.isArray(value) && (!_.isObject(value) || value.constructor.name !== 'BN')) { return value.toString(); @@ -86,6 +87,34 @@ ABICoder.prototype.encodeParameter = function (type, param) { return this.encodeParameters([type], [param]); }; +function splitNesting(value) { + value = value.trim(); + + let result = []; + let accum = ""; + let depth = 0; + for (let offset = 0; offset < value.length; offset++) { + let c = value[offset]; + if (c === "," && depth === 0) { + result.push(accum); + accum = ""; + } else { + accum += c; + if (c === "(") { + depth++; + } else if (c === ")") { + depth--; + if (depth === -1) { + logger.throwArgumentError("unbalanced parenthesis", "value", value); + } + } + } + } + if (accum) { result.push(accum); } + + return result; +} + /** * Should be used to encode list of params * @@ -97,29 +126,61 @@ ABICoder.prototype.encodeParameter = function (type, param) { * @return {String} encoded list of params */ ABICoder.prototype.encodeParameters = function (types, params) { + const bytesToEvenLength = (param) => { + // bitwise AND operator returns true if odd + if (param.length & 1) { + return '0x0' + param.substring(2) + } + return param + } + const bytes32ToFixedLength = (param) => { + if (param.length < 66) { // 66 includes `0x` + return utils.rightPad(param, 64) + } + return param + } + return ethersAbiCoder.encode( this.mapTypes(types), params.map(function (param, index) { + let type = types[index] + if (typeof type === 'object') { + // We may get a named type of shape {name, type} + type = type.type + } + // Format BN to string if (utils.isBN(param) || utils.isBigNumber(param)) { return param.toString(10); } - // Format bytes to even-length - if (types[index] === 'bytes') { - if (param.length & 1) { // bitwise AND operator returns true if odd - return param + '0' - } + if (type === 'bytes') { + param = bytesToEvenLength(param) + } else if (type === 'bytes[]') { + param = param.map(p => bytesToEvenLength(p)) } - // Format bytes32 to fixed length - if (types[index] === 'bytes32') { - if (param.substring(2) === '0x') { - param = param.substring(2) - } - if (param.length < 64) { - return utils.rightPad(param, 64) + if (type === 'bytes32') { + param = bytes32ToFixedLength(param) + } else if (type === 'bytes32[]') { + param = param.map(p => bytes32ToFixedLength(p)) + } + + // Format tuples for above bytes and bytes32 rules + if (typeof type === 'string' && type.includes('tuple')) { + const coder = ethersAbiCoder._getCoder(ParamType.from(type)); + const modifyParams = (coder, param) => { + coder.coders.forEach((c, i) => { + if (c.name === 'bytes') { + param[i] = bytesToEvenLength(param[i]) + } else if (c.name === 'bytes32') { + param[i] = bytes32ToFixedLength(param[i]) + } else if (c.name === 'tuple') { + modifyParams(c, param[i]) + } + }) } + modifyParams(coder, param) } return param; diff --git a/test/abi.encodeParameter.js b/test/abi.encodeParameter.js index 1a64049fe6b..8eeeeb9b001 100644 --- a/test/abi.encodeParameter.js +++ b/test/abi.encodeParameter.js @@ -308,6 +308,22 @@ describe('lib/solidity/coder', function () { '0000000000000000000000000000000000000000000000000000000000000120' + '000000000000000000000000000000000000000000000000000000000000000f' + '74657374696e672074657374696e670000000000000000000000000000000000' }); + test({ + type: 'tuple(bool,tuple(bytes32,int256,tuple(bytes24,bytes8)),tuple(bool,bool,bool),string)', + value: [true, ["0xabdef", -18291849, ["0xabdef18710a18a18abdef18710a18a18abdef18710a18a18","0xabdef18710a18a18"]], [false, true, false], "testing testing"], + expected: + '0000000000000000000000000000000000000000000000000000000000000020' + + '0000000000000000000000000000000000000000000000000000000000000001' + + 'abdef00000000000000000000000000000000000000000000000000000000000' + + 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffee8e377' + + 'abdef18710a18a18abdef18710a18a18abdef18710a18a180000000000000000' + + 'abdef18710a18a18000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000001' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000120' + + '000000000000000000000000000000000000000000000000000000000000000f' + + '74657374696e672074657374696e670000000000000000000000000000000000' }); test({ type: 'uint256', value: new BN(42),