diff --git a/packages/web3-utils/src/index.js b/packages/web3-utils/src/index.js
index d7693b7ce19..0c30545723a 100644
--- a/packages/web3-utils/src/index.js
+++ b/packages/web3-utils/src/index.js
@@ -390,6 +390,7 @@ module.exports = {
keccak256: utils.sha3,
soliditySha3: soliditySha3.soliditySha3,
soliditySha3Raw: soliditySha3.soliditySha3Raw,
+ encodePacked: soliditySha3.encodePacked,
isAddress: utils.isAddress,
checkAddressChecksum: utils.checkAddressChecksum,
toChecksumAddress: toChecksumAddress,
diff --git a/packages/web3-utils/src/soliditySha3.js b/packages/web3-utils/src/soliditySha3.js
index 6b8a0cf87c5..055f3e30f9e 100644
--- a/packages/web3-utils/src/soliditySha3.js
+++ b/packages/web3-utils/src/soliditySha3.js
@@ -169,7 +169,7 @@ var _solidityPack = function (type, value, arraySize) {
};
-var _processSoliditySha3Args = function (arg) {
+var _processSolidityEncodePackedArgs = function (arg) {
/*jshint maxcomplexity:false */
if(_.isArray(arg)) {
@@ -233,7 +233,7 @@ var soliditySha3 = function () {
var args = Array.prototype.slice.call(arguments);
- var hexArgs = _.map(args, _processSoliditySha3Args);
+ var hexArgs = _.map(args, _processSolidityEncodePackedArgs);
// console.log(args, hexArgs);
// console.log('0x'+ hexArgs.join(''));
@@ -248,11 +248,28 @@ var soliditySha3 = function () {
* @return {Object} the sha3
*/
var soliditySha3Raw = function () {
- return utils.sha3Raw('0x'+ _.map(Array.prototype.slice.call(arguments), _processSoliditySha3Args).join(''));
+ return utils.sha3Raw('0x'+ _.map(Array.prototype.slice.call(arguments), _processSolidityEncodePackedArgs).join(''));
+};
+
+/**
+ * Encode packed args to hex
+ *
+ * @method encodePacked
+ * @return {String} the hex encoded arguments
+ */
+var encodePacked = function () {
+ /*jshint maxcomplexity:false */
+
+ var args = Array.prototype.slice.call(arguments);
+
+ var hexArgs = _.map(args, _processSolidityEncodePackedArgs);
+
+ return '0x'+ hexArgs.join('').toLowerCase();
};
module.exports = {
soliditySha3: soliditySha3,
- soliditySha3Raw: soliditySha3Raw
+ soliditySha3Raw: soliditySha3Raw,
+ encodePacked: encodePacked
};
diff --git a/packages/web3-utils/types/index.d.ts b/packages/web3-utils/types/index.d.ts
index fad6c39db85..59606095e47 100644
--- a/packages/web3-utils/types/index.d.ts
+++ b/packages/web3-utils/types/index.d.ts
@@ -115,6 +115,7 @@ export function isTopic(topic: string): boolean;
export function jsonInterfaceMethodToString(abiItem: AbiItem): string;
export function soliditySha3(...val: Mixed[]): string | null;
export function soliditySha3Raw(...val: Mixed[]): string;
+export function encodePacked(...val: Mixed[]): string | null;
export function getUnitValue(unit: Unit): string;
export function unitMap(): Units;
export function testAddress(bloom: string, address: string): boolean;
@@ -170,6 +171,7 @@ export interface Utils {
jsonInterfaceMethodToString(abiItem: AbiItem): string;
soliditySha3(...val: Mixed[]): string | null;
soliditySha3Raw(...val: Mixed[]): string;
+ encodePacked(...val: Mixed[]): string | null;
getUnitValue(unit: Unit): string;
unitMap(): Units;
testAddress(bloom: string, address: string): boolean;
diff --git a/packages/web3-utils/types/tests/encode-packed.ts b/packages/web3-utils/types/tests/encode-packed.ts
new file mode 100644
index 00000000000..acfa7e7e52e
--- /dev/null
+++ b/packages/web3-utils/types/tests/encode-packed.ts
@@ -0,0 +1,52 @@
+/*
+ This file is part of web3.js.
+
+ web3.js is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ web3.js is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with web3.js. If not, see .
+*/
+/**
+ * @file solidity-sha3-test.ts
+ * @author Josh Stevens
+ * @date 2018
+ */
+
+import BN = require('bn.js');
+import {encodePacked} from 'web3-utils';
+
+// $ExpectType string | null
+encodePacked('234564535', '0xfff23243', true, -10);
+// $ExpectType string | null
+encodePacked('Hello!%');
+// $ExpectType string | null
+encodePacked('234');
+// $ExpectType string | null
+encodePacked(0xea);
+// $ExpectType string | null
+encodePacked(new BN(3));
+// $ExpectType string | null
+encodePacked({type: 'uint256', value: '234'});
+// $ExpectType string | null
+encodePacked({t: 'uint', v: new BN('234')});
+// $ExpectType string | null
+encodePacked({t: 'string', v: 'Hello!%'}, {t: 'int8', v: -23}, {t: 'address', v: '0x85F43D8a49eeB85d32Cf465507DD71d507100C1d'});
+// $ExpectType string | null
+encodePacked('0x407D73d8a49eeb85D32Cf465507dd71d507100c1');
+
+// $ExpectError
+encodePacked(['hey']);
+// $ExpectError
+encodePacked([34]);
+// $ExpectError
+encodePacked(null);
+// $ExpectError
+encodePacked(undefined);
diff --git a/test/utils.encodePacked.js b/test/utils.encodePacked.js
new file mode 100644
index 00000000000..a56f13d9609
--- /dev/null
+++ b/test/utils.encodePacked.js
@@ -0,0 +1,252 @@
+var _ = require('underscore');
+var BN = require('bn.js');
+var BigNumber = require('bignumber.js');
+var chai = require('chai');
+var assert = chai.assert;
+var utils = require('../packages/web3-utils');
+
+// each "values" is one kind of parameter of the same type
+var tests = [{
+ values: [
+ true,
+ {value: true, type: 'bool'},
+ {v: true, t: 'bool'},
+ {v: true, type: 'bool'},
+ {value: true, t: 'bool'}
+ ], expected: '0x01'
+},{
+ values: [
+ false,
+ {value: false, type: 'bool'},
+ {v: false, t: 'bool'},
+ {v: false, type: 'bool'},
+ {value: false, t: 'bool'}
+ ], expected: '0x00'
+},{
+ values: [
+ 'Hello!%',
+ {value: 'Hello!%', type: 'string'},
+ {value: 'Hello!%', type: 'string'},
+ {v: 'Hello!%', t: 'string'}
+ ], expected: '0x48656c6c6f2125'
+},{
+ values: [
+ 2345676856,
+ '2345676856',
+ new BN('2345676856'),
+ new BigNumber('2345676856', 10),
+ {v: '2345676856', t: 'uint256'},
+ {v: new BN('2345676856'), t: 'uint256'},
+ {v: '2345676856', t: 'uint'}
+ ], expected: '0x000000000000000000000000000000000000000000000000000000008bd03038'
+},{
+ values: [
+ '2342342342342342342345676856',
+ new BN('2342342342342342342345676856'),
+ new BigNumber('2342342342342342342345676856', 10),
+ {v: '2342342342342342342345676856', t: 'uint256'},
+ {v: '2342342342342342342345676856', t: 'uint'}
+ ], expected: '0x000000000000000000000000000000000000000007918a48d0493ed3da6ed838'
+// 5
+},{
+ values: [
+ {v: '56', t: 'uint8'}
+ ], expected: '0x38'
+},{
+ values: [
+ {v: '256', t: 'uint16'}
+ ], expected: '0x0100'
+},{
+ values: [
+ {v: '3256', t: 'uint32'}
+ ], expected: '0x00000cb8'
+},{
+ values: [
+ {v: '454256', t: 'uint64'}
+ ], expected: '0x000000000006ee70'
+},{
+ values: [
+ {v: '44454256', t: 'uint128'},
+ {v: '44454256', t: 'int128'} // should be the same
+ ], expected: '0x00000000000000000000000002a65170'
+},{
+ values: [
+ {v: '3435454256', t: 'uint160'}
+ ], expected: '0x00000000000000000000000000000000ccc4df30'
+// 11
+},{
+ values: [
+ '0x2345435675432144555ffffffffdd222222222222224444556553522',
+ {v: '0x2345435675432144555ffffffffdd222222222222224444556553522', t: 'bytes'},
+ {v: '2345435675432144555ffffffffdd222222222222224444556553522', t: 'bytes'},
+ {error: true, v: '0x2345435675432144555ffffffffdd22222222222222444455655352', t: 'bytes'}
+ ], expected: '0x2345435675432144555ffffffffdd222222222222224444556553522'
+},{
+ values: [
+ -3435454256,
+ new BN(-3435454256),
+ new BN('-3435454256'),
+ '-3435454256',
+ {v: '-3435454256', t: 'int'},
+ {v: '-3435454256', t: 'int256'}
+ ], expected: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff333b20d0'
+// 13
+},{
+ values: [
+ {v: '-36', t: 'int8'}
+ ], expected: '0xdc'
+},{
+ values: [
+ {v: '0x22', t: 'bytes2'},
+ {v: '22', t: 'bytes2'},
+ {error: true, v: '0x222222', t: 'bytes2'}
+ ], expected: '0x2200'
+},{
+ values: [
+ {v: '0x44222266', t: 'bytes4'},
+ {v: '44222266', t: 'bytes4'}
+ ], expected: '0x44222266'
+},{
+ values: [
+ {v: '0x44555ffffffffdd222222222222224444556553522', t: 'bytes32'},
+ {v: '44555ffffffffdd222222222222224444556553522', t: 'bytes32'}
+ ], expected: '0x44555ffffffffdd2222222222222244445565535220000000000000000000000'
+},{
+ values: [
+ '0x407D73d8a49eeb85D32Cf465507dd71d507100c1',
+ '0x407d73d8a49eeb85D32Cf465507dd71d507100c1', // invalid checksum, should work as it is interpreted as address
+ {v: '0x407D73d8a49eeb85D32Cf465507dd71d507100c1', t: 'address'},
+ {error: true, v: '0x407d73d8a49eeb85D32Cf465507dd71d507100c1', t: 'address'},
+ {v: '0x407D73d8a49eeb85D32Cf465507dd71d507100c1', t: 'bytes'},
+ {v: '0x407D73d8a49eeb85D32Cf465507dd71d507100c1', t: 'bytes20'}
+ ], expected: '0x407d73d8a49eeb85d32cf465507dd71d507100c1'
+// 18
+},{
+ values: [
+ {v: '36', t: 'int8'}
+ ], expected: '0x24'
+},{
+ values: [
+ {v: '36', t: 'int256'}
+ ], expected: '0x0000000000000000000000000000000000000000000000000000000000000024'
+},{
+ values: [
+ {v: [-12, 243], t: 'int[]'},
+ {v: [-12, 243], t: 'int256[]'},
+ {v: ['-12', '243'], t: 'int256[]'},
+ {v: [new BN('-12'), new BN('243')], t: 'int256[]'},
+ {v: ['-12', '243'], t: 'int256[2]'}
+ ], expected: '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff400000000000000000000000000000000000000000000000000000000000000f3'
+},{
+ values: [
+ {v: [12, 243], t: 'uint[]'},
+ {v: [12, 243], t: 'uint256[]'},
+ {v: ['12', '243'], t: 'uint256[]'},
+ {v: [new BN('12'), new BN('243')], t: 'uint256[]'},
+ {v: ['12', '243'], t: 'uint256[2]'},
+ {error: true, v: ['12', '243'], t: 'uint256[1]'}
+ ], expected: '0x000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000f3'
+},{
+ values: [
+ {v: ['0x234656', '0x23434234234ffff456'], t: 'bytes32[]'},
+ ], expected: '0x234656000000000000000000000000000000000000000000000000000000000023434234234ffff4560000000000000000000000000000000000000000000000'
+},{
+ values: [
+ {v: '0x234656', t: 'bytes16'},
+ {v: '234656', t: 'bytes16'}
+ ], expected: '0x23465600000000000000000000000000'
+},{
+ values: [
+ {v: ['0x234656', '0x23434234234ffff456'], t: 'bytes16[]'},
+ {v: ['234656', '23434234234ffff456'], t: 'bytes16[]'}
+ ], expected: '0x234656000000000000000000000000000000000000000000000000000000000023434234234ffff4560000000000000000000000000000000000000000000000'
+},{
+ values: [
+ {v: ['0x407D73d8a49eeb85D32Cf465507dd71d507100c1', '0x85F43D8a49eeB85d32Cf465507DD71d507100C1d'], t: 'address[]'},
+ {v: ['0x407D73d8a49eeb85D32Cf465507dd71d507100c1', '0x85F43D8a49eeB85d32Cf465507DD71d507100C1d'], t: 'address[2]'},
+ {error: true, v: ['0x407d73d8a49eeb85D32Cf465507dd71d507100c1', '0x85F43D8a49eeB85d32Cf465507DD71d507100C1d'], t: 'address[]'},
+ {error: true, v: ['0x407D73d8a49eeb85D32Cf465507dd71d507100c1', '0x85F43D8a49eeB85d32Cf465507DD71d507100C1d'], t: 'address[4]'}
+ ], expected: '0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c100000000000000000000000085f43d8a49eeb85d32cf465507dd71d507100c1d'
+},{
+ values: [
+ {v: 0, t: 'uint'}
+ ], expected: '0x0000000000000000000000000000000000000000000000000000000000000000'
+},{
+ values: [
+ ['someValue'] // should error
+ ], expected: ''
+}];
+
+
+describe('web3.encodePacked', function () {
+ tests.forEach(function (test) {
+ test.values.forEach(function (value) {
+ it('should hash "'+ JSON.stringify(value) +'" into "'+ test.expected +'"', function() {
+
+ if(value.error || _.isArray(value)) {
+ assert.throws(utils.encodePacked.bind(null, value));
+ } else {
+ assert.deepEqual(utils.encodePacked(value), test.expected);
+ }
+
+ });
+ });
+ });
+
+ it('should hash mixed boolean values in any order', function() {
+
+ assert.deepEqual(utils.encodePacked(
+ tests[0].values[1], // true
+ tests[1].values[0], // false
+ tests[1].values[2], // false
+ tests[0].values[3] // true
+ ), '0x01000001');
+ });
+
+ it('should hash mixed string and number values in any order', function() {
+
+ assert.deepEqual(utils.encodePacked(
+ tests[2].values[0], // 'Hello!%'
+ tests[3].values[2], // 2345676856
+ tests[4].values[2], // '2342342342342342342345676856'
+ tests[2].values[3], // 'Hello!%'
+ tests[1].values[2] // false
+ ), '0x48656c6c6f2125000000000000000000000000000000000000000000000000000000008bd03038000000000000000000000000000000000000000007918a48d0493ed3da6ed83848656c6c6f212500');
+ });
+
+ it('should hash mixed number types in any order', function() {
+
+ assert.deepEqual(utils.encodePacked(
+ tests[5].values[0], // v: '56', t: 'uint8'
+ tests[6].values[0], // v: '256', t: 'uint16'
+ tests[7].values[0], // v: '3256', t: 'uint32'
+ tests[8].values[0], // v: '454256', t: 'uint64'
+ tests[9].values[0], // v: '44454256', t: 'uint128'
+ tests[10].values[0] // v: '3435454256', t: 'uint160'
+ ), '0x38010000000cb8000000000006ee7000000000000000000000000002a6517000000000000000000000000000000000ccc4df30');
+ });
+
+ it('should hash mixed number types addresses and boolean in any order', function() {
+
+ assert.deepEqual(utils.encodePacked(
+ tests[5].values[0], // v: '56', t: 'uint8'
+ tests[13].values[0], // v: '-36', t: 'int8'
+ tests[15].values[0], // v: '0x44222266', t: 'bytes4'
+ tests[0].values[0], // true
+ tests[17].values[1] // v: '0x407D73d8a49eeb85D32Cf465507dd71d507100c1', t: 'address'
+ ), '0x38dc4422226601407d73d8a49eeb85d32cf465507dd71d507100c1');
+ });
+
+ it('should hash mixed number arrays addresses and boolean in any order', function() {
+
+ assert.deepEqual(utils.encodePacked(
+ tests[15].values[1], // v: '0x44222266', t: 'bytes4'
+ tests[25].values[0], // address array
+ tests[0].values[0], // true
+ tests[13].values[0], // v: '-36', t: 'int8'
+ tests[12].values[5], // v: '-3435454256', t: 'int256'
+ tests[17].values[0], // 0x407D73d8a49eeb85D32Cf465507dd71d507100c1
+ tests[17].values[1] // v: 0x407D73d8a49eeb85D32Cf465507dd71d507100c1 t: address
+ ), '0x44222266000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c100000000000000000000000085f43d8a49eeb85d32cf465507dd71d507100c1d01dcffffffffffffffffffffffffffffffffffffffffffffffffffffffff333b20d0407d73d8a49eeb85d32cf465507dd71d507100c1407d73d8a49eeb85d32cf465507dd71d507100c1');
+ });
+});
diff --git a/test/utils_methods.js b/test/utils_methods.js
index ca0450f4982..038cd24646a 100644
--- a/test/utils_methods.js
+++ b/test/utils_methods.js
@@ -12,6 +12,7 @@ describe('utils', function() {
u.methodExists(utils, 'toWei');
u.methodExists(utils, 'toBN');
u.methodExists(utils, 'isAddress');
+ u.methodExists(utils, 'soliditySha3');
+ u.methodExists(utils, 'encodePacked');
});
});
-