Giter Site home page Giter Site logo

miguelmota / ethereum-input-data-decoder Goto Github PK

View Code? Open in Web Editor NEW
591.0 11.0 184.0 1.52 MB

Ethereum smart contract transaction input data decoder

Home Page: https://lab.miguelmota.com/ethereum-input-data-decoder

License: MIT License

JavaScript 98.37% HTML 1.61% CSS 0.02%
ethereum decoder smart-contracts abi javascript solidity remix utility library

ethereum-input-data-decoder's Introduction


logo


ethereum-input-data-decoder

Ethereum smart contract transaction input data decoder

License Build Status dependencies Status NPM version PRs Welcome

Demo

https://lab.miguelmota.com/ethereum-input-data-decoder

Install

npm install ethereum-input-data-decoder

Getting started

Pass ABI file path to decoder constructor:

const InputDataDecoder = require('ethereum-input-data-decoder');
const decoder = new InputDataDecoder(`${__dirname}/abi.json`);

Alternatively, you can pass ABI array object to constructor;

const abi = [{ ... }]
const decoder = new InputDataDecoder(abi);

example abi

Then you can decode input data:

const data = `0x67043cae0000000000000000000000005a9dac9315fdd1c3d13ef8af7fdfeb522db08f020000000000000000000000000000000000000000000000000000000058a20230000000000000000000000000000000000000000000000000000000000040293400000000000000000000000000000000000000000000000000000000000000a0f3df64775a2dfb6bc9e09dced96d0816ff5055bf95da13ce5b6c3f53b97071c800000000000000000000000000000000000000000000000000000000000000034254430000000000000000000000000000000000000000000000000000000000`;

const result = decoder.decodeData(data);

console.log(result);
{
  "method": "registerOffChainDonation",
  "types": [
    "address",
    "uint256",
    "uint256",
    "string",
    "bytes32"
    ],
    "inputs": [
      <BN: 5a9dac9315fdd1c3d13ef8af7fdfeb522db08f02>,
      <BN: 58a20230>,
      <BN: 402934>,
      "BTC",
      <Buffer f3 df ... 71 c8>
    ],
    "names": [
      "addr",
      "timestamp",
      "chfCents",
      "currency",
      "memo"
    ]
}

Example using input response from web3.getTransaction:

web3.eth.getTransaction(txHash, (error, txResult) => {
  const result = decoder.decodeData(txResult.input);
  console.log(result);
});

Decoding tuple and tuple[] types

Where OrderData is

struct OrderData {
  uint256 amount;
  address buyer;
}

Decoding input to a method someMethod(address,OrderData,OrderData[]) returns data in format

{
  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

All numbers are returned in big number format to preserve precision.

Here's an example of how to convert the big number to a human readable format.

console.log(result.inputs[0].toString(10)) // "5"
console.log(result.inputs[0].toNumber()) // 55

Please keep in mind that JavaScript only supports numbers up to 64 bits. Solidity numbers can be up to 256 bits, so you run the risk of truncation when casting or having the big number library error out when trying to parse a large number to a JavaScript Number type.

const n = new BN("543534254523452352345234523455")
console.log(n.toString(10)) // "543534254523452352345234523455"
console.log(n.toNumber()) // ERROR!

CLI

Install

npm install -g ethereum-input-data-decoder

Usage

$ ethereum_input_data_decoder --help

  Ethereum smart contract transaction input data decoder

  Usage
    $ ethereum_input_data_decoder [flags] [input]

  Options
    --abi, -a  ABI file path
    --input, -i Input data file path

  Examples
    $ ethereum_input_data_decoder --abi token.abi --input data.txt
    $ ethereum_input_data_decoder --abi token.abi "0x23b872dd..."

Example

Pass ABI file and input data as file:

$ ethereum_input_data_decoder --abi abi.json --input data.tx

method   registerOffChainDonation

address  addr       0x5a9dac9315fdd1c3d13ef8af7fdfeb522db08f02
uint256  timestamp  1487012400
uint256  chfCents   4204852
string   currency   BTC
bytes32  memo       0xf3df64775a2dfb6bc9e09dced96d0816ff5055bf95da13ce5b6c3f53b97071c8

Pass ABI file and input data as string:

$ ethereum_input_data_decoder --abi abi.json 0x67043cae0...000000

method   registerOffChainDonation

address  addr       0x5a9dac9315fdd1c3d13ef8af7fdfeb522db08f02
uint256  timestamp  1487012400
uint256  chfCents   4204852
string   currency   BTC
bytes32  memo       0xf3df64775a2dfb6bc9e09dced96d0816ff5055bf95da13ce5b6c3f53b97071c8

You can also pipe the input data:

$ cat data.txt | ethereum_input_data_decoder --abi abi.json

method   registerOffChainDonation

address  addr       0x5a9dac9315fdd1c3d13ef8af7fdfeb522db08f02
uint256  timestamp  1487012400
uint256  chfCents   4204852
string   currency   BTC
bytes32  memo       0xf3df64775a2dfb6bc9e09dced96d0816ff5055bf95da13ce5b6c3f53b97071c8

Test

npm test

Development

  1. Clone repository:
git clone [email protected]:miguelmota/ethereum-input-data-decoder.git

cd ethereum-input-data-decoder/
  1. Install dependencies:
npm install
  1. Make changes.

  2. Run tests:

npm test
  1. Run linter:
npm run lint
  1. Build:
npm run build

Contributing

Pull requests are welcome!

For contributions please create a new branch and submit a pull request for review.

Many thanks to all the contributors for making this a better library for everyone 🙏

FAQ

  • Q: How can I retrieve the ABI?

    • A: You can generate the ABI from the solidity source files using the Solidity Compiler.

      solc --abi MyContract.sol -o build
  • Q: Can this library decode contract creation input data?

    • A: Yes, it can decode contract creation input data.
  • Q: Does this library support ABIEncoderV2?

    • A: Yes, but it's buggy. Please submit a bug report if you encounter issues.

License

MIT

ethereum-input-data-decoder's People

Contributors

alexcampbelling avatar cmeisl avatar liamaharon avatar mesqueeb avatar miguelmota avatar nunoalexandre avatar plutalov avatar roderik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ethereum-input-data-decoder's Issues

Fails to parse and returns null for method and empty arrays

The transaction

The call data is:

0x18cbafe5000000000000000000000000000000000000000000000001046e76ef3f36caaa0000000000000000000000000000000000000000000000002b47243a1169519100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000006896016d2404ac2d7032e2747ef3f52192e2cf72000000000000000000000000000000000000000000000000000000006045547600000000000000000000000000000000000000000000000000000000000000020000000000000000000000001cbb83ebcd552d5ebf8131ef8c9cd9d9bab342bc000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
[
  {
    "inputs": [
      {
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "symbol",
        "type": "string"
      },
      {
        "internalType": "uint256",
        "name": "_totalSupply",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "owner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Approval",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Transfer",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "address",
        "name": "_previous",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "_next",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "_time",
        "type": "uint256"
      }
    ],
    "name": "TransferredOwnership",
    "type": "event"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      }
    ],
    "name": "allowance",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "approve",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "balanceOf",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "cap",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "contractAddress",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "decimals",
    "outputs": [
      {
        "internalType": "uint8",
        "name": "",
        "type": "uint8"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "subtractedValue",
        "type": "uint256"
      }
    ],
    "name": "decreaseAllowance",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "addedValue",
        "type": "uint256"
      }
    ],
    "name": "increaseAllowance",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "name",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address payable",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "symbol",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalSupply",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "transfer",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "transferFrom",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address payable",
        "name": "_owner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  }
]

The result is:

result : {
  "method": null,
  "types": [],
  "inputs": [],
  "names": []
}

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module

Hi,

I am getting the following error when running from command line :

internal/modules/cjs/loader.js:1102
      throw new ERR_REQUIRE_ESM(filename, parentPath, packageJsonPath);
      ^

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: C:\Users\User\AppData\Roaming\npm\node_modules\ethereum-input-data-decoder\node_modules\meow\index.js
require() of ES modules is not supported.
require() of C:\Users\User\AppData\Roaming\npm\node_modules\ethereum-input-data-decoder\node_modules\meow\index.js from C:\Users\User\AppData\Roaming\npm\node_modules\ethereum-input-data-decoder\cli.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from C:\Users\User\AppData\Roaming\npm\node_modules\ethereum-input-data-decoder\node_modules\meow\package.json.

    at new NodeError (internal/errors.js:322:7)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1102:13)
    at Module.load (internal/modules/cjs/loader.js:950:32)
    at Function.Module._load (internal/modules/cjs/loader.js:790:12)
    at Module.require (internal/modules/cjs/loader.js:974:19)
    at require (internal/modules/cjs/helpers.js:93:18)
    at Object.<anonymous> (C:\Users\User\AppData\Roaming\npm\node_modules\ethereum-input-data-decoder\cli.js:3:14)
    at Module._compile (internal/modules/cjs/loader.js:1085:14)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
    at Module.load (internal/modules/cjs/loader.js:950:32) {
  code: 'ERR_REQUIRE_ESM'
}

Am i missing something ?

Regards,

David

null function name

question

hi, I got a ethereum tx decode like this

image

I don't know why there's a function named "null", I don't know which function is been executed, because there's no function name is "null", it seems only constructor function have the same signature, but I think it can't be constructor been executed, because it can only execute once.

so I am confused.

tx & contract detail

transaction : https://etherscan.io/tx/0x13389268ed1cae395a94cc111528ef8e5b929221af4ecc2a0c7e977dd7dbc38d

smart contract: https://etherscan.io/address/0x3e66b66fd1d0b02fda6c811da9e0547970db2f21#code

abi

[{"inputs":[{"internalType":"address","name":"_weth","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"limitReturnAmount","type":"uint256"},{"internalType":"uint256","name":"maxPrice","type":"uint256"}],"internalType":"struct ExchangeProxy.Swap[]","name":"swaps","type":"tuple[]"},{"internalType":"contract TokenInterface","name":"tokenIn","type":"address"},{"internalType":"contract TokenInterface","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"totalAmountIn","type":"uint256"},{"internalType":"uint256","name":"minTotalAmountOut","type":"uint256"}],"name":"batchSwapExactIn","outputs":[{"internalType":"uint256","name":"totalAmountOut","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"limitReturnAmount","type":"uint256"},{"internalType":"uint256","name":"maxPrice","type":"uint256"}],"internalType":"struct ExchangeProxy.Swap[]","name":"swaps","type":"tuple[]"},{"internalType":"contract TokenInterface","name":"tokenIn","type":"address"},{"internalType":"contract TokenInterface","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"maxTotalAmountIn","type":"uint256"}],"name":"batchSwapExactOut","outputs":[{"internalType":"uint256","name":"totalAmountIn","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"limitReturnAmount","type":"uint256"},{"internalType":"uint256","name":"maxPrice","type":"uint256"}],"internalType":"struct ExchangeProxy.Swap[][]","name":"swapSequences","type":"tuple[][]"},{"internalType":"contract TokenInterface","name":"tokenIn","type":"address"},{"internalType":"contract TokenInterface","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"totalAmountIn","type":"uint256"},{"internalType":"uint256","name":"minTotalAmountOut","type":"uint256"}],"name":"multihopBatchSwapExactIn","outputs":[{"internalType":"uint256","name":"totalAmountOut","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"limitReturnAmount","type":"uint256"},{"internalType":"uint256","name":"maxPrice","type":"uint256"}],"internalType":"struct ExchangeProxy.Swap[][]","name":"swapSequences","type":"tuple[][]"},{"internalType":"contract TokenInterface","name":"tokenIn","type":"address"},{"internalType":"contract TokenInterface","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"maxTotalAmountIn","type":"uint256"}],"name":"multihopBatchSwapExactOut","outputs":[{"internalType":"uint256","name":"totalAmountIn","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_registry","type":"address"}],"name":"setRegistry","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract TokenInterface","name":"tokenIn","type":"address"},{"internalType":"contract TokenInterface","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"totalAmountIn","type":"uint256"},{"internalType":"uint256","name":"minTotalAmountOut","type":"uint256"},{"internalType":"uint256","name":"nPools","type":"uint256"}],"name":"smartSwapExactIn","outputs":[{"internalType":"uint256","name":"totalAmountOut","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract TokenInterface","name":"tokenIn","type":"address"},{"internalType":"contract TokenInterface","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"totalAmountOut","type":"uint256"},{"internalType":"uint256","name":"maxTotalAmountIn","type":"uint256"},{"internalType":"uint256","name":"nPools","type":"uint256"}],"name":"smartSwapExactOut","outputs":[{"internalType":"uint256","name":"totalAmountIn","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"nPools","type":"uint256"}],"name":"viewSplitExactIn","outputs":[{"components":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"limitReturnAmount","type":"uint256"},{"internalType":"uint256","name":"maxPrice","type":"uint256"}],"internalType":"struct ExchangeProxy.Swap[]","name":"swaps","type":"tuple[]"},{"internalType":"uint256","name":"totalOutput","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"nPools","type":"uint256"}],"name":"viewSplitExactOut","outputs":[{"components":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"limitReturnAmount","type":"uint256"},{"internalType":"uint256","name":"maxPrice","type":"uint256"}],"internalType":"struct ExchangeProxy.Swap[]","name":"swaps","type":"tuple[]"},{"internalType":"uint256","name":"totalOutput","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]

input data

0xe2b3974600000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000000000000000000000000000001b1bd5bfc01a36880000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000007842792a8471d0f5ae645f513cc5999b1bb6b182000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b785a0322126826d8226d77e173d75dafb84d11000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000005d87eb9ac9c107424734f2a95f11649206ccfea80000000000000000000000006b785a0322126826d8226d77e173d75dafb84d110000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984000000000000000000000000000000000000000000000001ee30107c0827ea7d0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff

decode ouput

{
  "method": null,
  "types": [
    "address"
  ],
  "inputs": [
    "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"
  ],
  "names": [
    "_weth"
  ]
}

decoding not working correctly when functions have arrays as parameters

this is an example to reproduce this issue:

pragma solidity >=0.8.0 <0.9.0;
contract Example  {
    
    function foo(string[2] calldata a, uint[2] calldata b) external returns (address) {
        return msg.sender;
    }
}

if you compile this Smart Contract, deploy it to a network and call the foo function, then pasting the abi and the transaction's input data in https://lab.miguelmota.com/ethereum-input-data-decoder/example/
will produce unexpected results,
as shown in the image
image

if it may be helpful the input data I passed to the transaction were:

a: [  "92bf076a-2b42-4df3-a74b-ee9f457225b8","7ee5645d-bd02-4526-ab69-039a1a54731f"]
b: [   "9",   "70" ]

'fs' package not included as dependency

Thanks a lot for this script. I imported it through yarn / webpack in a Rails app but get an error message because fs was undefined. Would it make sense to include fs as a dependency?

golang implementation

Hi Miguel, this is nodejs implementation, is there a golang implementation or any suggestion?

Decoding Complex Tuples

Hi there,

I would like to try to decode the input data for dydx PayableProxyForSoloMargin contract (see the one in mainnet at https://etherscan.io/address/0xa8b39829cE2246f89B31C013b8Cde15506Fb9A76). Using the abi (or see below)

[{"constant":true,"inputs":[],"name":"SOLO_MARGIN","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"WETH","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"components":[{"name":"owner","type":"address"},{"name":"number","type":"uint256"}],"name":"accounts","type":"tuple[]"},{"components":[{"name":"actionType","type":"uint8"},{"name":"accountId","type":"uint256"},{"components":[{"name":"sign","type":"bool"},{"name":"denomination","type":"uint8"},{"name":"ref","type":"uint8"},{"name":"value","type":"uint256"}],"name":"amount","type":"tuple"},{"name":"primaryMarketId","type":"uint256"},{"name":"secondaryMarketId","type":"uint256"},{"name":"otherAddress","type":"address"},{"name":"otherAccountId","type":"uint256"},{"name":"data","type":"bytes"}],"name":"actions","type":"tuple[]"},{"name":"sendEthTo","type":"address"}],"name":"operate","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"inputs":[{"name":"soloMargin","type":"address"},{"name":"weth","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"}]

I tried to decode it using a random transaction (say https://etherscan.io/tx/0x45a3c960ced0ed51562936e50e1a7473eb31c9a85f72d0aa4783aa271677eb44) but unfortunately it's not able to give me all input parameters in operate() function:

{ "method": null, "types": [ "address", "address" ], "inputs": [ "0xa8b39829cE2246f89B31C013b8Cde15506Fb9A76", "0x0000000000000000000000000000000000000000" ], "names": [ "soloMargin", "weth" ] }

The online tool (https://lab.miguelmota.com/ethereum-input-data-decoder/example/) yielded the same.

I believe it's related to the complex tuple hierarchies at the 1st and 2nd arguments (i.e. Account.Info[] memory accounts and Actions.ActionArgs[] memory actions).

I used python's web3py function (decode_function_input()) to do the same and it worked correctly:

(<Function operate(tuple[],tuple[],address)>, {'accounts': [('0xb929044aF6a7B7AE12EF0e653ACC59f73cf9577B', 0)], 'actions': [(0, 0, (True, 0, 0, 487620457500000000), 0, 0, '0xa8b39829cE2246f89B31C013b8Cde15506Fb9A76', 0, b'')], 'sendEthTo': '0xb929044aF6a7B7AE12EF0e653ACC59f73cf9577B'})

Just wonder if this needs to be fixed.

decode contract input data

Hi, how would i decode the input data for a contract creation. Since the ABI isnt known unless I am the contract creator or know the contract address

Implement support for ABIEncoderV2

In its current state the this decoder will not work with ABIEncoderV2. I suggest it be upgraded to also support the new ABI types allowed under this (currently experimental) feature.
However, due to arbitrary levels of nesting of dynamic types allowed under ABIEncoderV2, it would probably make more sense to change the data structure of the output from the decoder so it's easier to work out the name, type and value of each parameter.
For instance of the following function is defined in Solidity.

struct User {
    uint256 id;
    string name;
    address userAddr;
    Token[] tokensOwned;
}
struct Token {
    address tokenAddress;
    uint256 tokensOwned;
}
function addUser(User user) { ... }

The output could use a recursively structured object, such as:

{
  "inputs": [
    {
      "name": "user",
      "type": "tuple",
      "value": [
        {
          "name": "id",
          "type": "uint256",
          "value": "424242"
        },
        {
          "name": "name",
          "type": "string",
          "value": "Ford Prefect"
        },
        {
          "name": "userAddr",
          "type": "address",
          "value": "0x863DF6BFa4469f3ead0bE8f9F2AAE51c91A907b4"
        },
        {
          "name": "tokensOwned",
          "type": "tuple[]",
          "value": [
            {
              "type": "tuple",
              "value": [
                {
                  "name": "tokenAddress",
                  "type": "address",
                  "value": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF"
                },
                {
                  "name": "tokensOwned",
                  "type": "uint256",
                  "value": "100"
                }
              ]
            },
            {
              "type": "tuple",
              "value": [
                {
                  "name": "tokenAddress",
                  "type": "address",
                  "value": "0x10B0882603c24AF9f1c07cde9f5a06B1300A8c00"
                },
                {
                  "name": "tokensOwned",
                  "type": "uint256",
                  "value": "123123123"
                }
              ]
            }
          ]
        }
      ]
    }
  ],
  "name": "addUser"
}

Error happens when constructor doesn't have "string" type input

Hi. Thank you for providing this useful library.
Unfortunately, I've noticed there was a small problem.

If a constructor doesn't have a string type input parameter, it affects decoding other parameters in functions. I used your given example and just changed constructor part as follow.

  • ABI
    ...
    {
    "inputs": [
    { "name": "_masterAuth", "type": "address" },
    { "name": "_name", "type": "uint256"} // changed from "string" to "uint256"
    ],
    "payable": false,
    "type": "constroctor"
    },
    ...

  • Decoding Result after ABI change
    {
    "types": [
    "address",
    "uint256"
    ],
    "inputs": [
    "0x00000000000000000000000000000000000000a0",
    {
    "_bn": "f3df64775a2dfb6bc9e09dced96d0816ff5055bf95da13ce5b6c3f53b97071c8"
    }
    ]
    }

  • Expected Result
    {
    "name": "registerOffChainDonation",
    "types": [
    "address",
    "uint256",
    "uint256",
    "string",
    "bytes32"
    ],
    ...

I think this happens at line 49 "ethers.Interface.decodeParams(types, data)" in https://github.com/miguelmota/ethereum-input-data-decoder/blob/master/index.js
I wrapped this part with try-catch, it seems to work well but I don't convince this is a right way to avoid the error.
Could you please take a look?
Thanks,

Question: How to decode Buffer that comes back as bytes32 value

Hello!

Thank you for this really helpful library!

I have a question, I used the ABI and decoder to decode a transaction input and it worked great! However, one of the input properties was a bytes32 Buffer. I would like to know how I further decode that value so I can see it as a string or a human-readable blob of data.

Is this something that I can recursively decode using this library somehow?

Getting ABI issue

I tried to get abi by the following code:

const InputDataDecoder = require('ethereum-input-data-decoder');
let contractABI = "http://api.bscscan.com/api?module=contract&action=getabi&address=" + contract + "&format=raw&" + myAPI;
contractABI = await fetch(contractABI);
contractABI = await contractABI.text();
let abi = [contractABI];
console.log(abi);
const decoder = new InputDataDecoder(abi);

And I get the abi value before decoder: (bsc cake token)
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"address","name":"fromDelegate","type":"address"},{"indexed":true,"internalType":"address","name":"toDelegate","type":"address"}],"name":"DelegateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBalance","type":"uint256"}],"name":"DelegateVotesChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DELEGATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint32","name":"","type":"uint32"}],"name":"checkpoints","outputs":[{"internalType":"uint32","name":"fromBlock","type":"uint32"},{"internalType":"uint256","name":"votes","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"delegateBySig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegator","type":"address"}],"name":"delegates","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getCurrentVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getPriorVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"numCheckpoints","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

Then input data:

const data = '0xa9059cbb000000000000000000000000e84279f943429b4be5a2345fbd6ff8402059ae91000000000000000000000000000000000000000000000001152023b31fc68000';
const result = decoder.decodeData(data);
console.log("result: " + result);

The result I got:
[object Object]
It seems it is not the right way to get it or something is wrong?

Result doesn't render address field properly

Thanks for this script.

I used it on a Truffle sample contract MetaCoin. Specifically I called this method meta.sendCoin('0xf27c14a83851210c6e26502433fd8193733ace90', 2) and got the following input back: 0x90b98a11000000000000000000000000f27c14a83851210c6e26502433fd8193733ace900000000000000000000000000000000000000000000000000000000000000002

The result I got back correctly returns the second argument (2) and the types, but the first argument (address) doesn't make sense and it's split up into different words.

screen shot 2017-03-12 at 9 28 10 pm

screen shot 2017-03-12 at 9 28 36 pm

This is the ABI:

[
    {
      "constant": false,
      "inputs": [],
      "name": "testLog",
      "outputs": [],
      "payable": false,
      "type": "function"
    },
    {
      "constant": false,
      "inputs": [
        {
          "name": "addr",
          "type": "address"
        }
      ],
      "name": "getBalanceInEth",
      "outputs": [
        {
          "name": "",
          "type": "uint256"
        }
      ],
      "payable": false,
      "type": "function"
    },
    {
      "constant": false,
      "inputs": [
        {
          "name": "receiver",
          "type": "address"
        },
        {
          "name": "amount",
          "type": "uint256"
        }
      ],
      "name": "sendCoin",
      "outputs": [
        {
          "name": "sufficient",
          "type": "bool"
        }
      ],
      "payable": false,
      "type": "function"
    },
    {
      "constant": true,
      "inputs": [
        {
          "name": "addr",
          "type": "address"
        }
      ],
      "name": "getBalanceWithConstant",
      "outputs": [
        {
          "name": "",
          "type": "uint256"
        }
      ],
      "payable": false,
      "type": "function"
    },
    {
      "constant": false,
      "inputs": [
        {
          "name": "addr",
          "type": "address"
        }
      ],
      "name": "getBalance",
      "outputs": [
        {
          "name": "",
          "type": "uint256"
        }
      ],
      "payable": false,
      "type": "function"
    },
    {
      "inputs": [],
      "payable": false,
      "type": "constructor"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "name": "_from",
          "type": "address"
        },
        {
          "indexed": true,
          "name": "_to",
          "type": "address"
        },
        {
          "indexed": false,
          "name": "_value",
          "type": "uint256"
        }
      ],
      "name": "Transfer",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": false,
          "name": "eventName",
          "type": "bytes32"
        },
        {
          "indexed": false,
          "name": "eventValue",
          "type": "bytes32"
        }
      ],
      "name": "Test",
      "type": "event"
    }
  ]

Unexpected data returned when decoding input with a tuple[] type

Hi. Huge fan of this tool, saves me tons of time fiddling with transaction input data. Thanks to all the maintainers for their work.

I've encountered behaviour I think may be incorrect when decoding inputs with the tuple[] type.

Specifically, calls to 0x Exchange contract methods like marketSellOrders which takes 3 params:

  1. orders: tuple[]
  2. takerAssetFillAmount: uint256
  3. signatures: bytes[]
marketSellOrders ABI (click to expand)
  {
    constant: false,
    inputs: [
      {
        components: [
          { name: 'makerAddress', type: 'address' },
          { name: 'takerAddress', type: 'address' },
          { name: 'feeRecipientAddress', type: 'address' },
          { name: 'senderAddress', type: 'address' },
          { name: 'makerAssetAmount', type: 'uint256' },
          { name: 'takerAssetAmount', type: 'uint256' },
          { name: 'makerFee', type: 'uint256' },
          { name: 'takerFee', type: 'uint256' },
          { name: 'expirationTimeSeconds', type: 'uint256' },
          { name: 'salt', type: 'uint256' },
          { name: 'makerAssetData', type: 'bytes' },
          { name: 'takerAssetData', type: 'bytes' },
        ],
        name: 'orders',
        type: 'tuple[]',
      },
      { name: 'takerAssetFillAmount', type: 'uint256' },
      { name: 'signatures', type: 'bytes[]' },
    ],
    name: 'marketSellOrders',
    outputs: [
      {
        components: [
          { name: 'makerAssetFilledAmount', type: 'uint256' },
          { name: 'takerAssetFilledAmount', type: 'uint256' },
          { name: 'makerFeePaid', type: 'uint256' },
          { name: 'takerFeePaid', type: 'uint256' },
        ],
        name: 'totalFillResults',
        type: 'tuple',
      },
    ],
    payable: false,
    stateMutability: 'nonpayable',
    type: 'function',
  },

Here's an example of what's returned when I decode a call to this method with ethereum-input-data-decoder (click to expand)
{                                                                                                                                                                                                                  
  "method": "marketSellOrders",                                                                                                                                                                                    
  "types": [                                                                                                                                                                                                       
    {                                                                                                                                                                                                              
      "components": [                                                                                                                                                                                              
        {                                                                                                                                                                                                          
          "name": "makerAddress",                                                                                                                                                                                  
          "type": "address"                                                                                                                                                                                        
        }, 
        {                                                                                                                                                                                                          
          "name": "takerAddress",                                                                                                                                                                                  
          "type": "address"                                                                                                                                                                                        
        },                                                                                                                                                                                                         
        {                                                                                                                                                                                                          
          "name": "feeRecipientAddress",                                                                                                                                                                           
          "type": "address"                                                                                                                                                                                        
        },                                                                                                                                                                                                         
        {                                                                                                                                                                                                          
          "name": "senderAddress",                                                                                                                                                                                 
          "type": "address"                                                                                                                                                                                        
        },                                                                                                                                                                                                         
        {                                                                                                                                                                                                          
          "name": "makerAssetAmount",                                                                                                                                                                              
          "type": "uint256"                                                                                                                                                                                        
        },                                                                                                                                                                                                         
        {                                                                                                                                                                                                          
          "name": "takerAssetAmount",                                                                                                                                                                              
          "type": "uint256"                                                                                                                                                                                        
        },                                                                                                                                                                                                         
        {                                                                                                                                                                                                          
          "name": "makerFee",                                                                                                                                                                                      
          "type": "uint256"                                                                                                                                                                                        
        },                                                                                                                                                                                                         
        {                                                                                                                                                                                                          
          "name": "takerFee",                                                                                                                                                                                      
          "type": "uint256"                                                                                                                                                                                        
        },                                                                                                                                                                                                         
        {                                                                                                                                                                                                          
          "name": "expirationTimeSeconds",                                                                                                                                                                         
          "type": "uint256"                                                                                                                                                                                        
        },                                                                                                                                                                                                         
        {                                                                                                                                                                                                          
          "name": "salt",                                                                                                                                                                                          
          "type": "uint256"                                                                                                                                                                                        
        },                                                                                                                                                                                                         
        {                                                                                                                                                                                                          
          "name": "makerAssetData",                                                                                                                                                                                
          "type": "bytes"                                                                                                                                                                                          
        },                                                                                                                                                                                                         
        {                                                                                                                                                                                                          
          "name": "takerAssetData",                                                                                                                                                                                
          "type": "bytes"                                                                                                                                                                                          
        }                                                                                                                                                                                                          
      ],                                                                                                                                                                                                           
      "name": "orders",                                                                                                                                                                                            
      "type": "tuple[]"                                                                                                                                                                                            
    },                                                                                                                                                                                                             
    "uint256",                                                                                                                                                                                                     
    "bytes[]"                                                                                                                                                                                                      
  ],                            
  "inputs": [                                                                                                                                                                                                      
    [                                                                                                                                                                                                              
      "0x6f02E6d47147B4448Fe2f2eb25B4f534cf110c23",                                                                                                                                                                
      "0x0000000000000000000000000000000000000000",                                                                                                                                                                
      "0xA258b39954ceF5cB142fd567A46cDdB31a670124",                                                                                                                                                                
      "0x0000000000000000000000000000000000000000",                                                                                                                                                                
      {                                                                                                                                                                                                            
        "_hex": "0x410d586a20a4bffff5"                                                                                                                                                                             
      },                                                                                                                                                                                                           
      {                                                                                                                                                                                                            
        "_hex": "0x5e05647aedbbd450"                                                                                                                                                                               
      },                                                                                                                                                                                                           
      {                                                                                                                                                                                                            
        "_hex": "0x00"                                                                                                                                                                                             
      },
      {
        "_hex": "0x00"
      },
      {
        "_hex": "0x5d787202"
      },
      {
        "_hex": "0x016d1e79ae50"
      },
      "0xf47261b000000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359",
      "0xf47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
    ]
  ],
  "names": [
    "",
    "takerAssetFillAmount",
    "signatures"
  ]
}

What makes sense to me ✔️

  • types provides all the information I need

What I'm unsure about ❓

  • inputs contains an array with a single entry in it, which appears to by a tuple not a tuple[]. I would have expected this first entry in inputs to be an array of tuples, so that information for multiple orders can be included
  • takerAssetFillAmount and signatures appear to be missing from the inputs array. I expected them to be at index 1 and 2 of inputs
  • names[0] is an empty string, I expected it to be "orders" (this is not as much of a blocker for me than the first two points)

Code example

I've pushed a code example and steps to replicate this behaviour to https://github.com/liamaharon/decode-tuple-arr-example

I'd appreciate any help figuring out if this is unexpected behaviour from ethereum-input-data-decoder, or if I'm simply misinterpreting the data returned to me. Thanks.

Decoder Only Returning Null Array With Null Output

Hi there,
Your tool looks super helpful and interesting and is explained really well. I managed to get it to work on my react website without any error. However, all the decoded output I get looks like this:

{
"method": null,
"types": [],
"inputs": [],
"names": []
}

I used my ABI and the input data that I want to decode on your demo website as well and still I get the same output. I double checked that I'm using the correct .json file from my artefacts folder. Any ideas what it could be? Can I maybe vary the input format of my txRequest.input? Any other ideas? Could it be a padding issue? Cheers :)

TypeError: this.abi.reduce is not a function

I'm getting the above error when I do in a javascript jupyter notebook:

const result = decoder.decodeData('0x........');
/path/to/myproject/node_modules/ethereum-input-data-decoder/dist/index.js:89
      var result = this.abi.reduce(function (acc, obj) {
                            ^

TypeError: this.abi.reduce is not a function
    at InputDataDecoder.decodeData (/path/to/myproject/node_modules/ethereum-input-data-decoder/dist/index.js:89:29)
    at evalmachine.<anonymous>:1:24
    at Script.runInThisContext (vm.js:91:20)
    at Object.runInThisContext (vm.js:298:38)
    at run ([eval]:1002:15)
    at onRunRequest ([eval]:829:18)
    at onMessage ([eval]:789:13)
    at process.emit (events.js:182:13)
    at emit (internal/child_process.js:807:12)
    at process._tickCallback (internal/process/next_tick.js:63:19)

I'm using version 0.0.12 of ethereum-input-data-decoder

Could this be because I'm using latest solc ?
One of the attributes of the decoder is listed as follows :

compiler: 
      { name: 'solc',
        version: '0.4.24+commit.e67f0147.Emscripten.clang' }

I'll try to see if I have ABI generated using older version of solc

Etherscan input data decode

What is ABI information? I have a structure that performs random transactions over etherscan. Which abi will I use?

Failed to minify

I'm having that problem when trying to build my react app:

> react-scripts build

Creating an optimized production build...
Failed to compile.

Failed to minify the code from this file: 

 	./node_modules/ethereum-input-data-decoder/index.js:5 

Read more here: http://bit.ly/2tRViJ9

The link says: "Some third-party packages don't compile their code to ES5 before publishing to npm. This often causes problems in the ecosystem because neither browsers (except for most modern versions) nor some tools currently support all ES6 features. We recommend to publish code on npm as ES5 at least for a few more years."

It's a good idea, to build the the code to ES5 too before publish.

Bower Package

I would really appreciate if you could provide a bower package as well.

Type 'typeof import(".../node_modules/ethereum-input-data-decoder/index")' has no construct signatures.

0.3.5 release broke something

Error: src/update.ts(55,30): error TS2351: This expression is not constructable.
  Type 'typeof import("/home/runner/work/lost-robbies/lost-robbies/node_modules/ethereum-input-data-decoder/index")' has no construct signatures.
Error: src/update.ts(93,30): error TS2351: This expression is not constructable.
  Type 'typeof import("/home/runner/work/lost-robbies/lost-robbies/node_modules/ethereum-input-data-decoder/index")' has no construct signatures.
Error: src/update.ts(178,34): error TS2351: This expression is not constructable.
  Type 'typeof import("/home/runner/work/lost-robbies/lost-robbies/node_modules/ethereum-input-data-decoder/index")' has no construct signatures.
var inputDataDecoder = new InputDataDecoder(await getAbi());

Not sure what the issue is, didn't debug. Probably eb5bc44. Locking back at 0.3.4 works.

To repro, check out https://github.com/dblock/lost-robbies, bump version in package.json, npm install and npm run sales.

TypeError: result.names[i].padEnd is not a function

This is the exception I run into when I want to decode input of uniswap v3 transaction

/usr/local/lib/node_modules/ethereum-input-data-decoder/cli.js:81
    output.push(`${result.types[i].padEnd(padType)}${result.names[i].padEnd(padName)}${value}`)
                                                                     ^

TypeError: result.names[i].padEnd is not a function
    at run (/usr/local/lib/node_modules/ethereum-input-data-decoder/cli.js:81:70)
    at Object.<anonymous> (/usr/local/lib/node_modules/ethereum-input-data-decoder/cli.js:38:3)
    at Module._compile (node:internal/modules/cjs/loader:1101:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:94:18)
    at Object.<anonymous> (/usr/local/lib/node_modules/ethereum-input-data-decoder/bin/ethereum_input_data_decoder:3:1)
    at Module._compile (node:internal/modules/cjs/loader:1101:14)

Abi:
[{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_WETH9","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH9","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"}],"internalType":"struct ISwapRouter.ExactInputParams","name":"params","type":"tuple"}],"name":"exactInput","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct ISwapRouter.ExactInputSingleParams","name":"params","type":"tuple"}],"name":"exactInputSingle","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"}],"internalType":"struct ISwapRouter.ExactOutputParams","name":"params","type":"tuple"}],"name":"exactOutput","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct ISwapRouter.ExactOutputSingleParams","name":"params","type":"tuple"}],"name":"exactOutputSingle","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"refundETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowed","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowedIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"sweepTokenWithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"uniswapV3SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"unwrapWETH9WithFee","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]
input: 0xc04b8d59000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000007a58b76ffd3989ddbce7bd632fdcf79b50530a690000000000000000000000000000000000000000000000000000000060ffb75c000000000000000000000000000000000000000000000000000000001dcd650000000000000000000000000000000000000000000000001f8587609e8c5bc3bf0000000000000000000000000000000000000000000000000000000000000042dac17f958d2ee523a2206206994597c13d831ec70001f4c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb8aa99199d1e9644b588796f3215089878440d58e0000000000000000000000000000000000000000000000000000000000000

SyntaxError: Unexpected token else

The following error occurred when I decoded:

`root@kali:~/node-v4.9.1-linux-x64/bin# ./ethereum_input_data_decoder --abi DaysBank.abi --input data.txt
/root/node-v4.9.1-linux-x64/lib/node_modules/ethereum-input-data-decoder/cli.js:55
} else {
^^^^

SyntaxError: Unexpected token else
at new Script (vm.js:79:7)
at createScript (vm.js:251:10)
at Object.runInThisContext (vm.js:303:10)
at Module._compile (internal/modules/cjs/loader.js:657:28)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
at Module.load (internal/modules/cjs/loader.js:599:32)
at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
at Function.Module._load (internal/modules/cjs/loader.js:530:3)
at Module.require (internal/modules/cjs/loader.js:637:17)
at require (internal/modules/cjs/helpers.js:22:18)
This is my file and data. What is wrong with it?[{"constant":false,"inputs":[{"name":"b64email","type":"string"}],"name":"payforflag","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"gift","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"flagnum","type":"uint256"},{"indexed":false,"name":"b64email","type":"string"}],"name":"SendFlag","type":"event"}]`

0x608060405234801561001057600080fd5b5060028054600160a060020a03191633179055610455806100326000396000f3006080604052600436106100825763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663652e9d91811461008757806366d16cc31461009e5780636bc344bc146100b357806370a082311461010c5780637ce7c9901461014c578063a9059cbb1461017d578063cbfc4bce146101ae575b600080fd5b34801561009357600080fd5b5061009c6101dc565b005b3480156100aa57600080fd5b5061009c61021a565b3480156100bf57600080fd5b506040805160206004803580820135601f810184900484028501840190955284845261009c9436949293602493928401919081908401838280828437509497506102789650505050505050565b34801561011857600080fd5b5061013a73ffffffffffffffffffffffffffffffffffffffff6004351661033b565b60408051918252519081900360200190f35b34801561015857600080fd5b5061009c73ffffffffffffffffffffffffffffffffffffffff6004351660243561034d565b34801561018957600080fd5b5061009c73ffffffffffffffffffffffffffffffffffffffff600435166024356103d2565b3480156101ba57600080fd5b5061013a73ffffffffffffffffffffffffffffffffffffffff60043516610417565b33600090815260016020526040902054156101f657600080fd5b33600090815260208181526040808320805460019081019091559182905290912055565b3360009081526020819052604090205460011461023657600080fd5b336000908152600160208190526040909120541461025357600080fd5b3360009081526020818152604080832080546001908101909155909152902060029055565b33600090815260208190526040902054612710111561029657600080fd5b7fb1bc9a9c599feac73a94c3ba415fa0b75cbe44496bfda818a9b4a689efb7adba6001826040518083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156102fd5781810151838201526020016102e5565b50505050905090810190601f16801561032a5780820380516001836020036101000a031916815260200191505b50935050505060405180910390a150565b60006020819052908152604090205481565b6002811161035a57600080fd5b3360009081526020819052604090205460021061037657600080fd5b336000908152602081905260408120548290031161039357600080fd5b336000908152602081905260408082208054849003905573ffffffffffffffffffffffffffffffffffffffff9390931681529190912080549091019055565b600181116103df57600080fd5b336000908152602081905260409020546001106103fb57600080fd5b3360009081526020819052604090205481111561039357600080fd5b600160205260009081526040902054815600a165627a7a7230582031248cecd3490d708a53c37a5b45e0b4401ff31020534cf7b2879aacf8ca10560029

smart contract creation input data not working

Hi, I am trying to decode a simplestorage contract i've deployed, but getting back blank when trying to decode the data string.

my smart contract

pragma solidity ^0.4.18;

contract simplestorage { 
    uint public storedData; 
    
    function simplestorage(uint initVal) public { 
        storedData = initVal; 
    } 
    
    function set(uint x) public { 
        storedData = x; 
    } 
    
    function get() public constant returns (uint retVal) { 
        return storedData; 
    } 
}

ABI (in abi.json file)
[{"constant":true,"inputs":[],"name":"storedData","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"initVal","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]

DATA:

"0x6060604052341561000f57600080fd5b60405160208061014b833981016040528080519060200190919050508060008190555050610109806100426000396000f3006060604052600436106053576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605857806360fe47b114607e5780636d4ce63c14609e575b600080fd5b3415606257600080fd5b606860c4565b6040518082815260200191505060405180910390f35b3415608857600080fd5b609c600480803590602001909190505060ca565b005b341560a857600080fd5b60ae60d4565b6040518082815260200191505060405180910390f35b60005481565b8060008190555050565b600080549050905600a165627a7a72305820533b4b05fd6a7ab04f015270e7710e56bab06315aafb2a8bd0f01789dc1290b30029000000000000000000000000000000000000000000000000000000000000022c"

commands executed:

d = new InputDataDecoder('//abi.json');
data="DATAFROMABOVE";
res = d.decodeData(data);
{} <-- THIS IS MY OUTPUT

What am i doing wrong here?

unable to decode

Hi,
Is this supposed to work with ABI generated from Truffle? See problem code below.

// tx =  https://rinkeby.etherscan.io/tx/0xdd387a53ac20c30a47689d79f1a1650623eb1c2afa590a1b3cbb6a30bf3abef9

const InputDataDecoder = require('ethereum-input-data-decoder')
// ABI  json from Truffle is here: https://gist.github.com/lakamsani/4ab20d3a60024303861568219c8ab121
const json = require('./build/contracts/PulseToken.json')
const decoder = new InputDataDecoder(json.abi)
// web3 is set to rinkeby
const tx = web3.eth.getTransaction('0xdd387a53ac20c30a47689d79f1a1650623eb1c2afa590a1b3cbb6a30bf3abef9')

// const data = tx.input 
const data = `0x23b872dd00000000000000000000000008aba4448bf7ee5ba13c5f4797ffe653d11c6c02000000000000000000000000d4f1a493787a29d38c216f592d4a1c84d89caad10000000000000000000000000000000000000000000000008ac7230489e80000`
const result = decoder.decodeData(data)
console.log(result)
{ name: null, types: [], inputs: [] }

High level explanation of decodeData()

This isn't really an issue but if you have 5 minutes, I'd be very keen to hear how the decodeData method works (high level explanation) and what the ethereumjs-abi library was created for. I'm new to Ethereum and I'm still struggling to wrap my head around the input field of transactions.

Decoded int exceeds width: 160 vs 256 on tranfersFrom() ERC721 contract

Hi, I have been using this library successfully and its works great but have hit a small problem when trying to decode a transactions on live.

This transaction in question is this: https://etherscan.io/tx/0x94fadf5f5c7805b8ceb8a13a0a7fbce06054ff08cdfdc2fd555a7902592aebe6

Interestingly enough etherscan also fails to decode the inputs and you can see the error in the browser console.

I actually noticed this in a backend service which we use this library to decode txs for specific addresses.

The error is Decoded int exceeds width: 160 vs 256

I guess the reason is that the data provided to args two _address is of the wrong type/length.

Got any ideas on how to check for this and order handle it?

Any help would be appreciated.

Thanks

James

ethereumjs-abi bug: "Decoded int exceeds width: 160 vs 256 "

I scanned the ethereum main chain, tx_hash = 0x0fc8f1cb5112c4679dfcbde54306cabecedfbfd115030252b2e3d77ed7b7da8c.
decode the input and there is a error msg "Decoded int exceeds width: 160 vs 256 "

const ether_decoder = require('ethereum-input-data-decoder');
const decoder = new ether_decoder(config.get('ERC20-abi'));
//...
const callObj = decoder.decodeData(transaction.input);
//...

ethereum-input-data-decoder version 0.0.6

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.