diff --git a/js/src/api/util/decode.js b/js/src/api/util/decode.js index e1c901261..926a5a8a1 100644 --- a/js/src/api/util/decode.js +++ b/js/src/api/util/decode.js @@ -85,3 +85,11 @@ export function methodToAbi (method) { return { type: 'function', name, inputs }; } + +export function abiDecode (inputTypes, data) { + return decodeMethodInput({ + inputs: inputTypes.map((type) => { + return { type }; + }) + }, data); +} diff --git a/js/src/api/util/decode.spec.js b/js/src/api/util/decode.spec.js index c3b18807c..006c6a863 100644 --- a/js/src/api/util/decode.spec.js +++ b/js/src/api/util/decode.spec.js @@ -15,7 +15,7 @@ // along with Parity. If not, see . import BigNumber from 'bignumber.js'; -import { decodeCallData, decodeMethodInput, methodToAbi } from './decode'; +import { abiDecode, decodeCallData, decodeMethodInput, methodToAbi } from './decode'; describe('api/util/decode', () => { const METH = '0x70a08231'; @@ -49,12 +49,16 @@ describe('api/util/decode', () => { }); it('correctly decodes valid inputs', () => { - expect(decodeMethodInput({ - type: 'function', - inputs: [ - { type: 'uint' } - ] - }, DATA)).to.deep.equal([ new BigNumber('0x5a5eff38da95b0d58b6c616f2699168b480953c9') ]); + expect( + decodeMethodInput({ + type: 'function', + inputs: [ + { type: 'uint' } + ] + }, DATA) + ).to.deep.equal( + [ new BigNumber('0x5a5eff38da95b0d58b6c616f2699168b480953c9') ] + ); }); }); @@ -90,4 +94,12 @@ describe('api/util/decode', () => { }); }); }); + + describe('abiDecode', () => { + it('correctly decodes valid inputs', () => { + expect(abiDecode(['uint'], DATA)).to.deep.equal( + [ new BigNumber('0x5a5eff38da95b0d58b6c616f2699168b480953c9') ] + ); + }); + }); }); diff --git a/js/src/api/util/encode.js b/js/src/api/util/encode.js new file mode 100644 index 000000000..d727d1e63 --- /dev/null +++ b/js/src/api/util/encode.js @@ -0,0 +1,40 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import Abi from '~/abi'; +import Func from '~/abi/spec/function'; + +export function encodeMethodCallAbi (methodAbi = {}, values = []) { + const func = new Func(methodAbi); + const tokens = Abi.encodeTokens(func.inputParamTypes(), values); + const call = func.encodeCall(tokens); + + return `0x${call}`; +} + +export function abiEncode (methodName, inputTypes, data) { + const result = encodeMethodCallAbi({ + name: methodName || '', + type: 'function', + inputs: inputTypes.map((type) => { + return { type }; + }) + }, data); + + return methodName === null + ? `0x${result.substr(10)}` + : result; +} diff --git a/js/src/api/util/encode.spec.js b/js/src/api/util/encode.spec.js new file mode 100644 index 000000000..6fead2ed5 --- /dev/null +++ b/js/src/api/util/encode.spec.js @@ -0,0 +1,63 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import { abiEncode, encodeMethodCallAbi } from './encode'; + +const ABI = { + type: 'function', + name: 'valid', + inputs: [ + { type: 'uint256' }, + { type: 'bool' } + ] +}; + +const RESULT = [ + 'f87fa141', + '0000000000000000000000000000000000000000000000000000000000000123', + '0000000000000000000000000000000000000000000000000000000000000001' +].join(''); +const VARIABLE = [ + '5a6fbce0', + 'c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470', + '0000000000000000000000000000000000000000000000000000000000000040', + '000000000000000000000000000000000000000000000000000000000000000f', + '687474703a2f2f666f6f2e6261722f0000000000000000000000000000000000' +].join(''); + +describe('api/util/encode', () => { + describe('encodeMethodCallAbi', () => { + it('encodes calls with the correct result', () => { + expect(encodeMethodCallAbi(ABI, [0x123, true])).to.equal(`0x${RESULT}`); + }); + }); + + describe('abiEncode', () => { + it('encodes calls with the correct result', () => { + expect(abiEncode('valid', ['uint256', 'bool'], [0x123, true])).to.equal(`0x${RESULT}`); + }); + + it('encodes variable values', () => { + expect(abiEncode('hintUrl', ['bytes32', 'string'], ['0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470', 'http://foo.bar/'])).to.equal(`0x${VARIABLE}`); + }); + + it('encodes only the data with null name', () => { + expect( + abiEncode(null, ['uint256', 'bool'], [0x123, true]) + ).to.equal(`0x${RESULT.substr(8)}`); + }); + }); +}); diff --git a/js/src/api/util/index.js b/js/src/api/util/index.js index 521329d59..254b97c74 100644 --- a/js/src/api/util/index.js +++ b/js/src/api/util/index.js @@ -15,7 +15,8 @@ // along with Parity. If not, see . import { isAddress as isAddressValid, toChecksumAddress } from '../../abi/util/address'; -import { decodeCallData, decodeMethodInput, methodToAbi } from './decode'; +import { abiDecode, decodeCallData, decodeMethodInput, methodToAbi } from './decode'; +import { abiEncode, encodeMethodCallAbi } from './encode'; import { bytesToHex, hexToAscii, asciiToHex } from './format'; import { fromWei, toWei } from './wei'; import { sha3 } from './sha3'; @@ -23,6 +24,8 @@ import { isArray, isFunction, isHex, isInstanceOf, isString } from './types'; import { createIdentityImg } from './identity'; export default { + abiDecode, + abiEncode, isAddressValid, isArray, isFunction, @@ -35,6 +38,7 @@ export default { createIdentityImg, decodeCallData, decodeMethodInput, + encodeMethodCallAbi, methodToAbi, fromWei, toChecksumAddress,