From b7dbcd63dc26f9abb2b401d3324e325655574101 Mon Sep 17 00:00:00 2001 From: Ryan Ghods Date: Fri, 15 May 2020 13:42:39 -0700 Subject: [PATCH 1/2] handle more encoding rules to reduce any breaking changes for abicoder dep update --- packages/web3-eth-abi/src/index.js | 126 ++++++++++++++++------------- test/abi.encodeParameter.js | 15 ++++ 2 files changed, 85 insertions(+), 56 deletions(-) diff --git a/packages/web3-eth-abi/src/index.js b/packages/web3-eth-abi/src/index.js index 67f59198795..f208030acb7 100644 --- a/packages/web3-eth-abi/src/index.js +++ b/packages/web3-eth-abi/src/index.js @@ -99,74 +99,88 @@ ABICoder.prototype.encodeParameter = function (type, param) { * @return {String} encoded list of params */ ABICoder.prototype.encodeParameters = function (types, params) { - const bytesToEvenLength = (param) => { - if (Buffer.isBuffer(param)) { - param = utils.toHex(param) + const paramTypeBytes = new RegExp(/^bytes([0-9]*)$/); + const paramTypeBytesArray = new RegExp(/^bytes([0-9]*)\[\]$/); + const paramTypeNumber = new RegExp(/^(u?int)([0-9]*)$/); + const paramTypeNumberArray = new RegExp(/^(u?int)([0-9]*)\[\]$/); + + params = params.map(function (param, index) { + let type = types[index] + if (typeof type === 'object' && type.type) { + // We may get a named type of shape {name, type} + type = type.type } - // bitwise AND operator returns true if odd - if (param.length & 1) { - return '0x0' + param.substring(2) - } - return param - } - const bytes32ToFixedLength = (param) => { - if (Buffer.isBuffer(param)) { - param = utils.toHex(param) - } - if (param.length < 66) { // 66 includes `0x` - return utils.rightPad(param, 64) + + // Format BN to string + if (utils.isBN(param) || utils.isBigNumber(param)) { + return param.toString(10); } - return param - } - return ethersAbiCoder.encode( - this.mapTypes(types), - params.map(function (param, index) { - let type = types[index] - if (typeof type === 'object' && type.type) { - // We may get a named type of shape {name, type} - type = type.type + // Handle some formatting of params as to not break previous compatability + const formatParam = (type, param) => { + if (type.match(paramTypeBytesArray) || type.match(paramTypeNumberArray)) { + return param.map(p => formatParam(type.replace('[]', ''), p)) } - // Format BN to string - if (utils.isBN(param) || utils.isBigNumber(param)) { - return param.toString(10); + // Format correct width for u?int[0-9]* + let match = type.match(paramTypeNumber); + if (match) { + let size = parseInt(match[2] || "256"); + if (size / 8 < param.length) { + // pad to correct bit width + param = utils.leftPad(param, size); + } } - // Convert odd-length bytes to even - if (type === 'bytes') { - param = bytesToEvenLength(param) - } else if (type === 'bytes[]') { - param = param.map(p => bytesToEvenLength(p)) - } + // Format correct length for bytes[0-9]+ + match = type.match(paramTypeBytes); + if (match) { + if (Buffer.isBuffer(param)) { + param = utils.toHex(param); + } - // Convert bytes32 to fixed length - if (type === 'bytes32') { - param = bytes32ToFixedLength(param) - } else if (type === 'bytes32[]') { - param = param.map(p => bytes32ToFixedLength(p)) + // format to correct length + let size = parseInt(match[1]); + if (size) { + let maxSize = size * 2; + if (param.substring(0, 2) === '0x') { + maxSize += 2; + } + if (param.length < maxSize) { + // pad to correct length + param = utils.rightPad(param, size * 2) + } + } + + // format odd-length bytes to even-length + if (param.length % 2 === 1) { + param = '0x0' + param.substring(2) + } } - // Format tuples for above 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 + } + + param = formatParam(type, param) + + // Format tuples for above 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 === 'tuple') { + modifyParams(c, param[i]) + } else { + param[i] = formatParam(c.name, param[i]) + } + }) } + modifyParams(coder, param) + } - return param; - }) - ); + return param; + }) + return ethersAbiCoder.encode(this.mapTypes(types), params); }; /** diff --git a/test/abi.encodeParameter.js b/test/abi.encodeParameter.js index dae077e5567..a2d4f6ee65e 100644 --- a/test/abi.encodeParameter.js +++ b/test/abi.encodeParameter.js @@ -699,6 +699,21 @@ describe('lib/solidity/coder', function () { values: [Buffer.from('cool'), Buffer.from('beans')], expected: '00000000000000000000000000000000000000000000000000000000000000406265616e730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004636f6f6c00000000000000000000000000000000000000000000000000000000' }); + test({ + types: ['bytes6', 'bytes12'], + values: [Buffer.from('super'), Buffer.from('man')], + expected: '73757065720000000000000000000000000000000000000000000000000000006d616e0000000000000000000000000000000000000000000000000000000000' + }); + test({ + types: ['bytes12[]'], + values: [[Buffer.from('buff'), Buffer.from('man')]], + expected: '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000262756666000000000000000000000000000000000000000000000000000000006d616e0000000000000000000000000000000000000000000000000000000000' + }); + test({ + types: ['uint16', 'uint24'], + values: ['10000', '100000'], + expected: '000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000186a0' + }); }); }); From d13c468526257d9cf6b3e2b551175a59831de328 Mon Sep 17 00:00:00 2001 From: cgewecke Date: Mon, 18 May 2020 09:44:35 -0700 Subject: [PATCH 2/2] Add detail to compatibility comment --- packages/web3-eth-abi/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web3-eth-abi/src/index.js b/packages/web3-eth-abi/src/index.js index f208030acb7..382b461d2d4 100644 --- a/packages/web3-eth-abi/src/index.js +++ b/packages/web3-eth-abi/src/index.js @@ -116,7 +116,7 @@ ABICoder.prototype.encodeParameters = function (types, params) { return param.toString(10); } - // Handle some formatting of params as to not break previous compatability + // Handle some formatting of params for backwards compatability with Ethers V4 const formatParam = (type, param) => { if (type.match(paramTypeBytesArray) || type.match(paramTypeNumberArray)) { return param.map(p => formatParam(type.replace('[]', ''), p))