ethereum-input-data-decoder
Advanced tools
Comparing version 0.2.1 to 0.3.0
@@ -5,2 +5,4 @@ 'use strict'; | ||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
@@ -102,3 +104,3 @@ | ||
var types = obj.inputs ? obj.inputs.map(function (x) { | ||
if (x.type === 'tuple[]') { | ||
if (x.type.includes('tuple')) { | ||
return x; | ||
@@ -111,4 +113,6 @@ } else { | ||
var names = obj.inputs ? obj.inputs.map(function (x) { | ||
if (x.type === 'tuple[]') { | ||
return ''; | ||
if (x.type.includes('tuple')) { | ||
return [x.name, x.components.map(function (a) { | ||
return a.name; | ||
})]; | ||
} else { | ||
@@ -128,11 +132,40 @@ return x.name; | ||
} catch (err) { | ||
// TODO: normalize addresses for tuples | ||
inputs = ethers.utils.defaultAbiCoder.decode(types, inputsBuf); | ||
// defaultAbiCoder attaches some unwanted properties to the list object | ||
inputs = deepRemoveUnwantedArrayProperties(inputs); | ||
inputs = inputs[0]; | ||
// TODO: do this normalization into normalizeAddresses | ||
inputs = inputs.map(function (input, i) { | ||
if (types[i].components) { | ||
var tupleTypes = types[i].components; | ||
return deepStripTupleAddresses(input, tupleTypes); | ||
} | ||
if (types[i] === 'address') { | ||
return input.split('0x')[1]; | ||
} | ||
if (types[i] === 'address[]') { | ||
return input.map(function (address) { | ||
return address.split('0x')[1]; | ||
}); | ||
} | ||
return input; | ||
}); | ||
} | ||
// Map any tuple types into arrays | ||
var typesToReturn = types.map(function (t) { | ||
if (t.components) { | ||
var arr = t.components.reduce(function (acc, cur) { | ||
return [].concat(_toConsumableArray(acc), [cur.type]); | ||
}, []); | ||
var tupleStr = '(' + arr.join(',') + ')'; | ||
if (t.type === 'tuple[]') return tupleStr + '[]'; | ||
return tupleStr; | ||
} | ||
return t; | ||
}); | ||
return { | ||
method: method, | ||
types: types, | ||
types: typesToReturn, | ||
inputs: inputs, | ||
@@ -162,2 +195,27 @@ names: names | ||
// remove 0x from addresses | ||
function deepStripTupleAddresses(input, tupleTypes) { | ||
return input.map(function (item, i) { | ||
var type = tupleTypes[i].type; | ||
if (type === 'address' && typeof item === 'string') { | ||
return item.split('0x')[1]; | ||
} | ||
if (type === 'address[]' || Array.isArray()) { | ||
return item.map(function (a) { | ||
return a.split('0x')[1]; | ||
}); | ||
} | ||
return item; | ||
}); | ||
} | ||
function deepRemoveUnwantedArrayProperties(arr) { | ||
return [].concat(_toConsumableArray(arr.map(function (item) { | ||
if (Array.isArray(item)) return deepRemoveUnwantedArrayProperties(item); | ||
return item; | ||
}))); | ||
} | ||
function normalizeAddresses(types, input) { | ||
@@ -198,7 +256,5 @@ var offset = 0; | ||
function handleInputs(input) { | ||
var tupleArray = false; | ||
function handleInputs(input, tupleArray) { | ||
if (input instanceof Object && input.components) { | ||
input = input.components; | ||
tupleArray = true; | ||
} | ||
@@ -228,2 +284,4 @@ | ||
} | ||
return ret; | ||
} | ||
@@ -233,3 +291,3 @@ | ||
var input = methodName + '(' + types.reduce(function (acc, x) { | ||
acc.push(handleInputs(x)); | ||
acc.push(handleInputs(x, x.type === 'tuple[]')); | ||
return acc; | ||
@@ -236,0 +294,0 @@ }, []).join(',') + ')'; |
66
index.js
@@ -86,3 +86,3 @@ const fs = require('fs') | ||
let types = obj.inputs ? obj.inputs.map(x => { | ||
if (x.type === 'tuple[]') { | ||
if (x.type.includes('tuple')) { | ||
return x | ||
@@ -95,4 +95,4 @@ } else { | ||
let names = obj.inputs ? obj.inputs.map(x => { | ||
if (x.type === 'tuple[]') { | ||
return '' | ||
if (x.type.includes('tuple')) { | ||
return [x.name, x.components.map(a => a.name)] | ||
} else { | ||
@@ -112,11 +112,36 @@ return x.name | ||
} catch (err) { | ||
// TODO: normalize addresses for tuples | ||
inputs = ethers.utils.defaultAbiCoder.decode(types, inputsBuf) | ||
// defaultAbiCoder attaches some unwanted properties to the list object | ||
inputs = deepRemoveUnwantedArrayProperties(inputs) | ||
inputs = inputs[0] | ||
// TODO: do this normalization into normalizeAddresses | ||
inputs = inputs.map((input, i) => { | ||
if (types[i].components) { | ||
const tupleTypes = types[i].components | ||
return deepStripTupleAddresses(input, tupleTypes) | ||
} | ||
if (types[i] === 'address') { | ||
return input.split('0x')[1] | ||
} | ||
if (types[i] === 'address[]') { | ||
return input.map(address => address.split('0x')[1]) | ||
} | ||
return input | ||
}) | ||
} | ||
// Map any tuple types into arrays | ||
const typesToReturn = types.map(t => { | ||
if (t.components) { | ||
const arr = t.components.reduce((acc, cur) => [...acc, cur.type], []) | ||
const tupleStr = `(${arr.join(',')})` | ||
if (t.type === 'tuple[]') return tupleStr + '[]' | ||
return tupleStr | ||
} | ||
return t | ||
}) | ||
return { | ||
method, | ||
types, | ||
types: typesToReturn, | ||
inputs, | ||
@@ -143,2 +168,23 @@ names | ||
// remove 0x from addresses | ||
function deepStripTupleAddresses (input, tupleTypes) { | ||
return input.map((item, i) => { | ||
const type = tupleTypes[i].type | ||
if (type === 'address' && typeof item === 'string') { | ||
return item.split('0x')[1] | ||
} | ||
if (type === 'address[]' || Array.isArray()) { | ||
return item.map(a => a.split('0x')[1]) | ||
} | ||
return item | ||
}) | ||
} | ||
function deepRemoveUnwantedArrayProperties (arr) { | ||
return [...arr.map(item => { | ||
if (Array.isArray(item)) return deepRemoveUnwantedArrayProperties(item) | ||
return item | ||
})] | ||
} | ||
function normalizeAddresses (types, input) { | ||
@@ -179,7 +225,5 @@ let offset = 0 | ||
function handleInputs (input) { | ||
let tupleArray = false | ||
function handleInputs (input, tupleArray) { | ||
if (input instanceof Object && input.components) { | ||
input = input.components | ||
tupleArray = true | ||
} | ||
@@ -209,2 +253,4 @@ | ||
} | ||
return ret | ||
} | ||
@@ -214,3 +260,3 @@ | ||
const input = methodName + '(' + (types.reduce((acc, x) => { | ||
acc.push(handleInputs(x)) | ||
acc.push(handleInputs(x, x.type === 'tuple[]')) | ||
return acc | ||
@@ -217,0 +263,0 @@ }, []).join(',')) + ')' |
{ | ||
"name": "ethereum-input-data-decoder", | ||
"version": "0.2.1", | ||
"version": "0.3.0", | ||
"description": "Ethereum smart contract transaction input data decoder", | ||
@@ -10,5 +10,4 @@ "main": "dist/index.js", | ||
"build": "babel index.js --presets babel-preset-es2015 --out-dir dist/", | ||
"lint": "standard index.js test/*.js", | ||
"lint:fix": "standard --fix index.js test/*.js", | ||
"prepublishOnly": "npm run lint:fix && npm run build" | ||
"lint": "standard --fix index.js test/*.js", | ||
"prepare": "npm run lint && npm run build" | ||
}, | ||
@@ -15,0 +14,0 @@ "bin": { |
@@ -93,2 +93,32 @@ <h3 align="center"> | ||
### Decoding tuple and tuple[] types | ||
Where `OrderData` is | ||
```solidity | ||
struct OrderData { | ||
uint256 amount; | ||
address buyer; | ||
} | ||
``` | ||
decoding input to a method `someMethod(address,OrderData,OrderData[])` returns data in format | ||
```js | ||
{ | ||
method: 'someMethod', | ||
types: ['address', '(uint256,address)', '(uint256,address)[]'], | ||
inputs: [ | ||
'0x81c55017F7Ce6E72451cEd49FF7bAB1e3DF64d0C', | ||
[100, '0xA37dE6790861B5541b0dAa7d0C0e651F44c6f4D9'] | ||
[[274, '0xea674fdde714fd979de3edf0f56aa9716b898ec8']] | ||
], | ||
names: ['sender', ['order', ['amount', 'buyer']], ['allOrders', ['amount', 'buyer']]] | ||
} | ||
``` | ||
- In the `types` field, tuples are represented as a string containing types contained in the tuple | ||
- In the `inputs` field, tuples are represented as an array containing values contained in the tuple | ||
- In the `names` field, tuples are represented as an array with 2 items. Item 1 is the name of the tuple, item 2 is an array containing the names of the values contained in the tuple. | ||
### Decoding Big Numbers | ||
@@ -217,3 +247,3 @@ | ||
```bash | ||
npm run lint:fix | ||
npm run lint | ||
``` | ||
@@ -223,4 +253,6 @@ | ||
Pull requests are welcome! Fork, branch, and submit PR. | ||
Pull requests are welcome! | ||
For contributions please create a new branch and submit a pull request for review. | ||
## FAQ | ||
@@ -227,0 +259,0 @@ |
@@ -81,18 +81,137 @@ const fs = require('fs') | ||
t.test('abiv2', t => { | ||
t.plan(5) | ||
// marketSellOrders call | ||
// https://etherscan.io/tx/0xc79ee30142e935453eabd57f45e01bb394bff78d05cdf8df97631b03ad6cc0cd | ||
t.test('0x exchange sell (abiv2 tuple[])', t => { | ||
t.plan(4) | ||
const abi = JSON.parse(fs.readFileSync(`${__dirname}/data/abiv2.json`)) | ||
const abi = JSON.parse(fs.readFileSync(`${__dirname}/data/0x_exchange.json`)) | ||
const decoder = new InputDataDecoder(abi) | ||
const data = fs.readFileSync(`${__dirname}/data/abiv2_input_data.txt`) | ||
const data = fs.readFileSync(`${__dirname}/data/0x_exchange_data.txt`) | ||
const result = decoder.decodeData(data) | ||
t.equal(result.inputs[0].id.toString(10), '2') | ||
t.equal(result.inputs[0].state.toString(10), '2') | ||
t.equal(result.inputs[0].valuation.toString(10), '50') | ||
t.equal(result.inputs[0].fingerprint.toString(), '0xabcd000000000000000000000000000000000000000000000000000000000000') | ||
t.equal(result.inputs[0].countdown.toString(10), '1549925124') | ||
t.deepEqual(result.method, 'marketSellOrders') | ||
const expectedInputs = [ | ||
[ | ||
[ | ||
'0x6f02E6d47147B4448Fe2f2eb25B4f534cf110c23', | ||
'0x0000000000000000000000000000000000000000', | ||
'0xA258b39954ceF5cB142fd567A46cDdB31a670124', | ||
'0x0000000000000000000000000000000000000000', | ||
{ '_hex': '0x410d586a20a4bffff5' }, | ||
{ '_hex': '0x5e05647aedbbd450' }, | ||
{ '_hex': '0x00' }, | ||
{ '_hex': '0x00' }, | ||
{ '_hex': '0x5d787202' }, | ||
{ '_hex': '0x016d1e79ae50' }, | ||
'0xf47261b000000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359', | ||
'0xf47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' | ||
] | ||
], | ||
{ '_hex': '0x2386f26fc10000' }, | ||
[ '0x1b82e97aa18170e6b81ce3a829d77b7067cf3644c8706e97e7c96d5a92de61eb0c5c5aeb4fbfadca6b9fbc5adff91bfb32964aa9e1bf8309dad7e1bd3e45f0b44c03' ] | ||
] | ||
t.deepEqual(result.inputs, expectedInputs) | ||
const expectedTypes = [ | ||
'(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[]', | ||
'uint256', | ||
'bytes[]' | ||
] | ||
t.deepEqual(result.types, expectedTypes) | ||
const expectedNames = [ | ||
[ | ||
'orders', | ||
[ | ||
'makerAddress', | ||
'takerAddress', | ||
'feeRecipientAddress', | ||
'senderAddress', | ||
'makerAssetAmount', | ||
'takerAssetAmount', | ||
'makerFee', | ||
'takerFee', | ||
'expirationTimeSeconds', | ||
'salt', | ||
'makerAssetData', | ||
'takerAssetData' | ||
] | ||
], | ||
'takerAssetFillAmount', | ||
'signatures' | ||
] | ||
t.deepEqual(result.names, expectedNames) | ||
}) | ||
// https://etherscan.io/tx/0xcb0c447659123c5faa2f1e5bc8ac69697688f437c92a8abb4b882bb33cbc661a | ||
t.test('set issuance (abiv2 tuple)', t => { | ||
t.plan(4) | ||
const abi = JSON.parse(fs.readFileSync(`${__dirname}/data/set_exchange_issuance_lib.json`)) | ||
const decoder = new InputDataDecoder(abi) | ||
const data = fs.readFileSync(`${__dirname}/data/set_issuance.txt`) | ||
const result = decoder.decodeData(data) | ||
t.equal(result.method, 'issueRebalancingSetWithEther') | ||
const expectedInputs = [ | ||
'81c55017F7Ce6E72451cEd49FF7bAB1e3DF64d0C', | ||
{ '_hex': '0x27019ab6af611240' }, | ||
[ | ||
'A37dE6790861B5541b0dAa7d0C0e651F44c6f4D9', | ||
{ '_hex': '0x3bf6ab7ba24000' }, | ||
[ 1 ], | ||
[ 'C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' ], | ||
[{ '_hex': '0x1a04a045412d3457' }], | ||
[ | ||
'89d24A6b4CcB1B6fAA2625fE562bDD9a23260359', | ||
'2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599' | ||
], | ||
[ | ||
{ '_hex': '0x06989640c83ea4a200' }, | ||
{ '_hex': '0x19c110' } | ||
] | ||
], | ||
'0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000d5a4cdef78c36901bc9ab7c3108c7d7b06f183e7d71c591bb6c677e3fa2958310a2520b916b792c6538b8e43ccb9a1773e94daa441307827c377f3b197d6549f9de54794a806b697a0300000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf90000000000000000000000000acd0b5cf881cd8398ac563872209de1ce15df0f00000000000000000000000055662e225a3376759c24331a9aed764f8f0c9fbb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b70202a2f0d520000000000000000000000000000000000000000000000000000d97e20f757ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005dfa648800000000000000000000000000000000000000000000000015e187ad8bbe980000000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000caa536649a0fdc71bd88fc3a7ecf72f2082e39783296db7a0236b404ca968873f51ce89b4237ecdcf0da1d3cee4306348664629deacaca7f7961ada746036229c5b161612cdb96bad0300000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf90000000000000000000000000acd0b5cf881cd8398ac563872209de1ce15df0f00000000000000000000000055662e225a3376759c24331a9aed764f8f0c9fbb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a38050000000000000000000000000000000000000000000000000ce4d38704d0c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005dfa648800000000000000000000000000000000000000000000000015e187ad8bbe98000000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', | ||
true | ||
] | ||
t.deepEqual(result.inputs, expectedInputs) | ||
const expectedNames = [ | ||
'_rebalancingSetAddress', | ||
'_rebalancingSetQuantity', | ||
[ | ||
'_exchangeIssuanceParams', | ||
[ | ||
'setAddress', | ||
'quantity', | ||
'sendTokenExchangeIds', | ||
'sendTokens', | ||
'sendTokenAmounts', | ||
'receiveTokens', | ||
'receiveTokenAmounts' | ||
] | ||
], | ||
'_orderData', | ||
'_keepChangeInVault' | ||
] | ||
t.deepEqual(result.names, expectedNames) | ||
const expectedTypes = [ | ||
'address', | ||
'uint256', | ||
'(address,uint256,uint8[],address[],uint256[],address[],uint256[])', | ||
'bytes', | ||
'bool' | ||
] | ||
t.deepEqual(result.types, expectedTypes) | ||
}) | ||
// https://github.com/miguelmota/ethereum-input-data-decoder/issues/8 | ||
@@ -99,0 +218,0 @@ t.test('256 address', t => { |
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
1043832
28
22006
276
13