github.com/niluplatform/go-nilu@v1.7.4-0.20200912082737-a0cb0776d52c/cmd/clef/README.md (about)

     1  Clef
     2  ----
     3  Clef can be used to sign transactions and data and is meant as a replacement for geth's account management.
     4  This allows DApps not to depend on geth's account management. When a DApp wants to sign data it can send the data to
     5  the signer, the signer will then provide the user with context and asks the user for permission to sign the data. If
     6  the users grants the signing request the signer will send the signature back to the DApp.
     7    
     8  This setup allows a DApp to connect to a remote Ethereum node and send transactions that are locally signed. This can
     9  help in situations when a DApp is connected to a remote node because a local Ethereum node is not available, not
    10  synchronised with the chain or a particular Ethereum node that has no built-in (or limited) account management.
    11    
    12  Clef can run as a daemon on the same machine, or off a usb-stick like [usb armory](https://inversepath.com/usbarmory),
    13  or a separate VM in a [QubesOS](https://www.qubes-os.org/) type os setup.
    14  
    15  Check out 
    16  
    17  * the [tutorial](tutorial.md) for some concrete examples on how the signer works.
    18  * the [setup docs](docs/setup.md) for some information on how to configure it to work on QubesOS or USBArmory. 
    19  
    20  
    21  ## Command line flags
    22  Clef accepts the following command line options:
    23  ```
    24  COMMANDS:
    25     init    Initialize the signer, generate secret storage
    26     attest  Attest that a js-file is to be used
    27     addpw   Store a credential for a keystore file
    28     help    Shows a list of commands or help for one command
    29  
    30  GLOBAL OPTIONS:
    31     --loglevel value        log level to emit to the screen (default: 4)
    32     --keystore value        Directory for the keystore (default: "$HOME/.ethereum/keystore")
    33     --configdir value       Directory for clef configuration (default: "$HOME/.clef")
    34     --networkid value       Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby) (default: 1)
    35     --lightkdf              Reduce key-derivation RAM & CPU usage at some expense of KDF strength
    36     --nousb                 Disables monitoring for and managing USB hardware wallets
    37     --rpcaddr value         HTTP-RPC server listening interface (default: "localhost")
    38     --rpcport value         HTTP-RPC server listening port (default: 8550)
    39     --signersecret value    A file containing the password used to encrypt signer credentials, e.g. keystore credentials and ruleset hash
    40     --4bytedb value         File containing 4byte-identifiers (default: "./4byte.json")
    41     --4bytedb-custom value  File used for writing new 4byte-identifiers submitted via API (default: "./4byte-custom.json")
    42     --auditlog value        File used to emit audit logs. Set to "" to disable (default: "audit.log")
    43     --rules value           Enable rule-engine (default: "rules.json")
    44     --stdio-ui              Use STDIN/STDOUT as a channel for an external UI. This means that an STDIN/STDOUT is used for RPC-communication with a e.g. a graphical user interface, and can be used when the signer is started by an external process.
    45     --stdio-ui-test         Mechanism to test interface between signer and UI. Requires 'stdio-ui'.
    46     --help, -h              show help
    47     --version, -v           print the version
    48  
    49  ```
    50  
    51  
    52  Example:
    53  ```
    54  signer -keystore /my/keystore -chainid 4
    55  ```
    56  
    57  
    58  ## Security model
    59  
    60  The security model of the signer is as follows:
    61  
    62  * One critical component (the signer binary / daemon) is responsible for handling cryptographic operations: signing, private keys, encryption/decryption of keystore files.
    63  * The signer binary has a well-defined 'external' API.
    64  * The 'external' API is considered UNTRUSTED.
    65  * The signer binary also communicates with whatever process that invoked the binary, via stdin/stdout.
    66    * This channel is considered 'trusted'. Over this channel, approvals and passwords are communicated.
    67  
    68  The general flow for signing a transaction using e.g. geth is as follows:
    69  ![image](sign_flow.png)
    70  
    71  In this case, `geth` would be started with `--externalsigner=http://localhost:8550` and would relay requests to `eth.sendTransaction`.
    72  
    73  ## TODOs
    74  
    75  Some snags and todos
    76  
    77  * [ ] The signer should take a startup param "--no-change", for UIs that do not contain the capability
    78     to perform changes to things, only approve/deny. Such a UI should be able to start the signer in
    79     a more secure mode by telling it that it only wants approve/deny capabilities.
    80  
    81  * [x] It would be nice if the signer could collect new 4byte-id:s/method selectors, and have a
    82  secondary database for those (`4byte_custom.json`). Users could then (optionally) submit their collections for
    83  inclusion upstream.
    84  
    85  * It should be possible to configure the signer to check if an account is indeed known to it, before
    86  passing on to the UI. The reason it currently does not, is that it would make it possible to enumerate
    87  accounts if it immediately returned "unknown account".
    88  * [x] It should be possible to configure the signer to auto-allow listing (certain) accounts, instead of asking every time.
    89  * [x] Done Upon startup, the signer should spit out some info to the caller (particularly important when executed in `stdio-ui`-mode),
    90  invoking methods with the following info:
    91    * [x] Version info about the signer
    92    * [x] Address of API (http/ipc)
    93    * [ ] List of known accounts
    94  * [ ] Have a default timeout on signing operations, so that if the user has not answered withing e.g. 60 seconds, the request is rejected.
    95  * [ ] `account_signRawTransaction`
    96  * [ ] `account_bulkSignTransactions([] transactions)` should
    97     * only exist if enabled via config/flag
    98     * only allow non-data-sending transactions
    99     * all txs must use the same `from`-account
   100     * let the user confirm, showing
   101        * the total amount
   102        * the number of unique recipients
   103  
   104  * Geth todos
   105      - The signer should pass the `Origin` header as call-info to the UI. As of right now, the way that info about the request is
   106  put together is a bit of a hack into the http server. This could probably be greatly improved
   107      - Relay: Geth should be started in `geth --external_signer localhost:8550`.
   108      - Currently, the Geth APIs use `common.Address` in the arguments to transaction submission (e.g `to` field). This
   109    type is 20 `bytes`, and is incapable of carrying checksum information. The signer uses `common.MixedcaseAddress`, which
   110    retains the original input.
   111      - The Geth api should switch to use the same type, and relay `to`-account verbatim to the external api.
   112  
   113  * [x] Storage
   114      * [x] An encrypted key-value storage should be implemented
   115      * See [rules.md](rules.md) for more info about this.
   116  
   117  * Another potential thing to introduce is pairing.
   118    * To prevent spurious requests which users just accept, implement a way to "pair" the caller with the signer (external API).
   119    * Thus geth/mist/cpp would cryptographically handshake and afterwards the caller would be allowed to make signing requests.
   120    * This feature would make the addition of rules less dangerous.
   121  
   122  * Wallets / accounts. Add API methods for wallets.
   123  
   124  ## Communication
   125  
   126  ### External API
   127  
   128  The signer listens to HTTP requests on `rpcaddr`:`rpcport`, with the same JSONRPC standard as Geth. The messages are
   129  expected to be JSON [jsonrpc 2.0 standard](http://www.jsonrpc.org/specification).
   130  
   131  Some of these call can require user interaction. Clients must be aware that responses
   132  may be delayed significanlty or may never be received if a users decides to ignore the confirmation request.
   133  
   134  The External API is **untrusted** : it does not accept credentials over this api, nor does it expect
   135  that requests have any authority.
   136  
   137  ### UI API
   138  
   139  The signer has one native console-based UI, for operation without any standalone tools.
   140  However, there is also an API to communicate with an external UI. To enable that UI,
   141  the signer needs to be executed with the `--stdio-ui` option, which allocates the
   142  `stdin`/`stdout` for the UI-api.
   143  
   144  An example (insecure) proof-of-concept of has been implemented in `pythonsigner.py`.
   145  
   146  The model is as follows:
   147  
   148  * The user starts the UI app (`pythonsigner.py`).
   149  * The UI app starts the `signer` with `--stdio-ui`, and listens to the
   150  process output for confirmation-requests.
   151  * The `signer` opens the external http api.
   152  * When the `signer` receives requests, it sends a `jsonrpc` request via `stdout`.
   153  * The UI app prompts the user accordingly, and responds to the `signer`
   154  * The `signer` signs (or not), and responds to the original request.
   155  
   156  ## External API
   157  
   158  See the [external api changelog](extapi_changelog.md) for information about changes to this API.
   159  
   160  ### Encoding
   161  - number: positive integers that are hex encoded
   162  - data: hex encoded data
   163  - string: ASCII string
   164  
   165  All hex encoded values must be prefixed with `0x`.
   166  
   167  ## Methods
   168  
   169  ### account_new
   170  
   171  #### Create new password protected account
   172  
   173  The signer will generate a new private key, encrypts it according to [web3 keystore spec](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) and stores it in the keystore directory.
   174  The client is responsible for creating a backup of the keystore. If the keystore is lost there is no method of retrieving lost accounts.
   175  
   176  #### Arguments
   177  
   178  None
   179  
   180  #### Result
   181    - address [string]: account address that is derived from the generated key
   182    - url [string]: location of the keyfile
   183    
   184  #### Sample call
   185  ```json
   186  {
   187    "id": 0,
   188    "jsonrpc": "2.0",
   189    "method": "account_new",
   190    "params": []
   191  }
   192  
   193  {
   194    "id": 0,
   195    "jsonrpc": "2.0",
   196    "result": {
   197      "address": "0xbea9183f8f4f03d427f6bcea17388bdff1cab133",
   198      "url": "keystore:///my/keystore/UTC--2017-08-24T08-40-15.419655028Z--bea9183f8f4f03d427f6bcea17388bdff1cab133"
   199    }
   200  }
   201  ```
   202  
   203  ### account_list
   204  
   205  #### List available accounts
   206     List all accounts that this signer currently manages
   207  
   208  #### Arguments
   209  
   210  None
   211  
   212  #### Result
   213    - array with account records:
   214       - account.address [string]: account address that is derived from the generated key
   215       - account.type [string]: type of the 
   216       - account.url [string]: location of the account
   217    
   218  #### Sample call
   219  ```json
   220  {
   221    "id": 1,
   222    "jsonrpc": "2.0",
   223    "method": "account_list"
   224  }
   225  
   226  {
   227    "id": 1,
   228    "jsonrpc": "2.0",
   229    "result": [
   230      {
   231        "address": "0xafb2f771f58513609765698f65d3f2f0224a956f",
   232        "type": "account",
   233        "url": "keystore:///tmp/keystore/UTC--2017-08-24T07-26-47.162109726Z--afb2f771f58513609765698f65d3f2f0224a956f"
   234      },
   235      {
   236        "address": "0xbea9183f8f4f03d427f6bcea17388bdff1cab133",
   237        "type": "account",
   238        "url": "keystore:///tmp/keystore/UTC--2017-08-24T08-40-15.419655028Z--bea9183f8f4f03d427f6bcea17388bdff1cab133"
   239      }
   240    ]
   241  }
   242  ```
   243  
   244  ### account_signTransaction
   245  
   246  #### Sign transactions
   247     Signs a transactions and responds with the signed transaction in RLP encoded form.
   248  
   249  #### Arguments
   250    2. transaction object:
   251       - `from` [address]: account to send the transaction from
   252       - `to` [address]: receiver account. If omitted or `0x`, will cause contract creation.
   253       - `gas` [number]: maximum amount of gas to burn
   254       - `gasPrice` [number]: gas price
   255       - `value` [number:optional]: amount of Wei to send with the transaction
   256       - `data` [data:optional]:  input data
   257       - `nonce` [number]: account nonce
   258    3. method signature [string:optional]
   259       - The method signature, if present, is to aid decoding the calldata. Should consist of `methodname(paramtype,...)`, e.g. `transfer(uint256,address)`. The signer may use this data to parse the supplied calldata, and show the user. The data, however, is considered totally untrusted, and reliability is not expected.
   260  
   261  
   262  #### Result
   263    - signed transaction in RLP encoded form [data]
   264    
   265  #### Sample call
   266  ```json
   267  {
   268    "id": 2,
   269    "jsonrpc": "2.0",
   270    "method": "account_signTransaction",
   271    "params": [
   272      {
   273        "from": "0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db",
   274        "gas": "0x55555",
   275        "gasPrice": "0x1234",
   276        "input": "0xabcd",
   277        "nonce": "0x0",
   278        "to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
   279        "value": "0x1234"
   280      }
   281    ]
   282  }
   283  ```
   284  Response
   285  
   286  ```json
   287  {
   288    "jsonrpc": "2.0",
   289    "id": 67,
   290    "error": {
   291      "code": -32000,
   292      "message": "Request denied"
   293    }
   294  }
   295  ```
   296  #### Sample call with ABI-data
   297  
   298  
   299  ```json
   300  {
   301    "jsonrpc": "2.0",
   302    "method": "account_signTransaction",
   303    "params": [
   304      {
   305        "from": "0x694267f14675d7e1b9494fd8d72fefe1755710fa",
   306        "gas": "0x333",
   307        "gasPrice": "0x1",
   308        "nonce": "0x0",
   309        "to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
   310        "value": "0x0",
   311        "data": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012"
   312      },
   313      "safeSend(address)"
   314    ],
   315    "id": 67
   316  }
   317  ```
   318  Response
   319  
   320  ```json
   321  {
   322    "jsonrpc": "2.0",
   323    "id": 67,
   324    "result": {
   325      "raw": "0xf88380018203339407a565b7ed7d7a678680a4c162885bedbb695fe080a44401a6e4000000000000000000000000000000000000000000000000000000000000001226a0223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20ea02aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663",
   326      "tx": {
   327        "nonce": "0x0",
   328        "gasPrice": "0x1",
   329        "gas": "0x333",
   330        "to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
   331        "value": "0x0",
   332        "input": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012",
   333        "v": "0x26",
   334        "r": "0x223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20e",
   335        "s": "0x2aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663",
   336        "hash": "0xeba2df809e7a612a0a0d444ccfa5c839624bdc00dd29e3340d46df3870f8a30e"
   337      }
   338    }
   339  }
   340  ```
   341  
   342  Bash example:
   343  ```bash
   344  #curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_signTransaction","params":[{"from":"0x694267f14675d7e1b9494fd8d72fefe1755710fa","gas":"0x333","gasPrice":"0x1","nonce":"0x0","to":"0x07a565b7ed7d7a678680a4c162885bedbb695fe0", "value":"0x0", "data":"0x4401a6e40000000000000000000000000000000000000000000000000000000000000012"},"safeSend(address)"],"id":67}' http://localhost:8550/
   345  
   346  {"jsonrpc":"2.0","id":67,"result":{"raw":"0xf88380018203339407a565b7ed7d7a678680a4c162885bedbb695fe080a44401a6e4000000000000000000000000000000000000000000000000000000000000001226a0223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20ea02aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663","tx":{"nonce":"0x0","gasPrice":"0x1","gas":"0x333","to":"0x07a565b7ed7d7a678680a4c162885bedbb695fe0","value":"0x0","input":"0x4401a6e40000000000000000000000000000000000000000000000000000000000000012","v":"0x26","r":"0x223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20e","s":"0x2aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663","hash":"0xeba2df809e7a612a0a0d444ccfa5c839624bdc00dd29e3340d46df3870f8a30e"}}}
   347  ```
   348  
   349  
   350  ### account_sign
   351  
   352  #### Sign data
   353     Signs a chunk of data and returns the calculated signature.
   354  
   355  #### Arguments
   356    - account [address]: account to sign with
   357    - data [data]: data to sign
   358  
   359  #### Result
   360    - calculated signature [data]
   361    
   362  #### Sample call
   363  ```json
   364  {
   365    "id": 3,
   366    "jsonrpc": "2.0",
   367    "method": "account_sign",
   368    "params": [
   369      "0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db",
   370      "0xaabbccdd"
   371    ]
   372  }
   373  ```
   374  Response
   375  
   376  ```json
   377  {
   378    "id": 3,
   379    "jsonrpc": "2.0",
   380    "result": "0x5b6693f153b48ec1c706ba4169960386dbaa6903e249cc79a8e6ddc434451d417e1e57327872c7f538beeb323c300afa9999a3d4a5de6caf3be0d5ef832b67ef1c"
   381  }
   382  ```
   383  
   384  ### account_ecRecover
   385  
   386  #### Recover address
   387     Derive the address from the account that was used to sign data from the data and signature.
   388     
   389  #### Arguments
   390    - data [data]: data that was signed
   391    - signature [data]: the signature to verify
   392  
   393  #### Result
   394    - derived account [address]
   395    
   396  #### Sample call
   397  ```json
   398  {
   399    "id": 4,
   400    "jsonrpc": "2.0",
   401    "method": "account_ecRecover",
   402    "params": [
   403      "0xaabbccdd",
   404      "0x5b6693f153b48ec1c706ba4169960386dbaa6903e249cc79a8e6ddc434451d417e1e57327872c7f538beeb323c300afa9999a3d4a5de6caf3be0d5ef832b67ef1c"
   405    ]
   406  }
   407  ```
   408  Response
   409  
   410  ```json
   411  {
   412    "id": 4,
   413    "jsonrpc": "2.0",
   414    "result": "0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db"
   415  }
   416  
   417  ```
   418  
   419  ### account_import
   420  
   421  #### Import account
   422     Import a private key into the keystore. The imported key is expected to be encrypted according to the web3 keystore
   423     format.
   424     
   425  #### Arguments
   426    - account [object]: key in [web3 keystore format](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) (retrieved with account_export) 
   427  
   428  #### Result
   429    - imported key [object]:
   430       - key.address [address]: address of the imported key
   431       - key.type [string]: type of the account
   432       - key.url [string]: key URL
   433    
   434  #### Sample call
   435  ```json
   436  {
   437    "id": 6,
   438    "jsonrpc": "2.0",
   439    "method": "account_import",
   440    "params": [
   441      {
   442        "address": "c7412fc59930fd90099c917a50e5f11d0934b2f5",
   443        "crypto": {
   444          "cipher": "aes-128-ctr",
   445          "cipherparams": {
   446            "iv": "401c39a7c7af0388491c3d3ecb39f532"
   447          },
   448          "ciphertext": "eb045260b18dd35cd0e6d99ead52f8fa1e63a6b0af2d52a8de198e59ad783204",
   449          "kdf": "scrypt",
   450          "kdfparams": {
   451            "dklen": 32,
   452            "n": 262144,
   453            "p": 1,
   454            "r": 8,
   455            "salt": "9a657e3618527c9b5580ded60c12092e5038922667b7b76b906496f021bb841a"
   456          },
   457          "mac": "880dc10bc06e9cec78eb9830aeb1e7a4a26b4c2c19615c94acb632992b952806"
   458        },
   459        "id": "09bccb61-b8d3-4e93-bf4f-205a8194f0b9",
   460        "version": 3
   461      },
   462    ]
   463  }
   464  ```
   465  Response
   466  
   467  ```json
   468  {
   469    "id": 6,
   470    "jsonrpc": "2.0",
   471    "result": {
   472      "address": "0xc7412fc59930fd90099c917a50e5f11d0934b2f5",
   473      "type": "account",
   474      "url": "keystore:///tmp/keystore/UTC--2017-08-24T11-00-42.032024108Z--c7412fc59930fd90099c917a50e5f11d0934b2f5"
   475    }
   476  }
   477  ```
   478  
   479  ### account_export
   480  
   481  #### Export account from keystore
   482     Export a private key from the keystore. The exported private key is encrypted with the original passphrase. When the
   483     key is imported later this passphrase is required.
   484     
   485  #### Arguments
   486    - account [address]: export private key that is associated with this account
   487  
   488  #### Result
   489    - exported key, see [web3 keystore format](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) for
   490    more information
   491    
   492  #### Sample call
   493  ```json
   494  {
   495    "id": 5,
   496    "jsonrpc": "2.0",
   497    "method": "account_export",
   498    "params": [
   499      "0xc7412fc59930fd90099c917a50e5f11d0934b2f5"
   500    ]
   501  }
   502  ```
   503  Response
   504  
   505  ```json
   506  {
   507    "id": 5,
   508    "jsonrpc": "2.0",
   509    "result": {
   510      "address": "c7412fc59930fd90099c917a50e5f11d0934b2f5",
   511      "crypto": {
   512        "cipher": "aes-128-ctr",
   513        "cipherparams": {
   514          "iv": "401c39a7c7af0388491c3d3ecb39f532"
   515        },
   516        "ciphertext": "eb045260b18dd35cd0e6d99ead52f8fa1e63a6b0af2d52a8de198e59ad783204",
   517        "kdf": "scrypt",
   518        "kdfparams": {
   519          "dklen": 32,
   520          "n": 262144,
   521          "p": 1,
   522          "r": 8,
   523          "salt": "9a657e3618527c9b5580ded60c12092e5038922667b7b76b906496f021bb841a"
   524        },
   525        "mac": "880dc10bc06e9cec78eb9830aeb1e7a4a26b4c2c19615c94acb632992b952806"
   526      },
   527      "id": "09bccb61-b8d3-4e93-bf4f-205a8194f0b9",
   528      "version": 3
   529    }
   530  }
   531  ```
   532  
   533  
   534  
   535  ## UI API
   536  
   537  These methods needs to be implemented by a UI listener.
   538  
   539  By starting the signer with the switch `--stdio-ui-test`, the signer will invoke all known methods, and expect the UI to respond with
   540  denials. This can be used during development to ensure that the API is (at least somewhat) correctly implemented.
   541  See `pythonsigner`, which can be invoked via `python3 pythonsigner.py test` to perform the 'denial-handshake-test'.
   542  
   543  All methods in this API uses object-based parameters, so that there can be no mixups of parameters: each piece of data is accessed by key.
   544  
   545  See the [ui api changelog](intapi_changelog.md) for information about changes to this API.
   546  
   547  OBS! A slight deviation from `json` standard is in place: every request and response should be confined to a single line.
   548  Whereas the `json` specification allows for linebreaks, linebreaks __should not__ be used in this communication channel, to make
   549  things simpler for both parties.
   550  
   551  ### ApproveTx
   552  
   553  Invoked when there's a transaction for approval.
   554  
   555  
   556  #### Sample call
   557  
   558  Here's a method invocation:
   559  ```bash
   560  
   561  curl -i -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_signTransaction","params":[{"from":"0x694267f14675d7e1b9494fd8d72fefe1755710fa","gas":"0x333","gasPrice":"0x1","nonce":"0x0","to":"0x07a565b7ed7d7a678680a4c162885bedbb695fe0", "value":"0x0", "data":"0x4401a6e40000000000000000000000000000000000000000000000000000000000000012"},"safeSend(address)"],"id":67}' http://localhost:8550/
   562  ```
   563  
   564  ```json
   565  
   566  {
   567    "jsonrpc": "2.0",
   568    "id": 1,
   569    "method": "ApproveTx",
   570    "params": [
   571      {
   572        "transaction": {
   573          "from": "0x0x694267f14675d7e1b9494fd8d72fefe1755710fa",
   574          "to": "0x0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
   575          "gas": "0x333",
   576          "gasPrice": "0x1",
   577          "value": "0x0",
   578          "nonce": "0x0",
   579          "data": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012",
   580          "input": null
   581        },
   582        "call_info": [
   583            {
   584              "type": "WARNING",
   585              "message": "Invalid checksum on to-address"
   586            },
   587            {
   588              "type": "Info",
   589              "message": "safeSend(address: 0x0000000000000000000000000000000000000012)"
   590            }
   591          ],
   592        "meta": {
   593          "remote": "127.0.0.1:48486",
   594          "local": "localhost:8550",
   595          "scheme": "HTTP/1.1"
   596        }
   597      }
   598    ]
   599  }
   600  
   601  ```
   602  
   603  The same method invocation, but with invalid data:
   604  ```bash
   605  
   606  curl -i -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_signTransaction","params":[{"from":"0x694267f14675d7e1b9494fd8d72fefe1755710fa","gas":"0x333","gasPrice":"0x1","nonce":"0x0","to":"0x07a565b7ed7d7a678680a4c162885bedbb695fe0", "value":"0x0", "data":"0x4401a6e40000000000000002000000000000000000000000000000000000000000000012"},"safeSend(address)"],"id":67}' http://localhost:8550/
   607  ```
   608  
   609  ```json
   610  
   611  {
   612    "jsonrpc": "2.0",
   613    "id": 1,
   614    "method": "ApproveTx",
   615    "params": [
   616      {
   617        "transaction": {
   618          "from": "0x0x694267f14675d7e1b9494fd8d72fefe1755710fa",
   619          "to": "0x0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
   620          "gas": "0x333",
   621          "gasPrice": "0x1",
   622          "value": "0x0",
   623          "nonce": "0x0",
   624          "data": "0x4401a6e40000000000000002000000000000000000000000000000000000000000000012",
   625          "input": null
   626        },
   627        "call_info": [
   628            {
   629              "type": "WARNING",
   630              "message": "Invalid checksum on to-address"
   631            },
   632            {
   633              "type": "WARNING",
   634              "message": "Transaction data did not match ABI-interface: WARNING: Supplied data is stuffed with extra data. \nWant 0000000000000002000000000000000000000000000000000000000000000012\nHave 0000000000000000000000000000000000000000000000000000000000000012\nfor method safeSend(address)"
   635            }
   636          ],
   637        "meta": {
   638          "remote": "127.0.0.1:48492",
   639          "local": "localhost:8550",
   640          "scheme": "HTTP/1.1"
   641        }
   642      }
   643    ]
   644  }
   645  
   646  
   647  ```
   648  
   649  One which has missing `to`, but with no `data`:
   650  
   651  
   652  ```json
   653  
   654  {
   655    "jsonrpc": "2.0",
   656    "id": 3,
   657    "method": "ApproveTx",
   658    "params": [
   659      {
   660        "transaction": {
   661          "from": "",
   662          "to": null,
   663          "gas": "0x0",
   664          "gasPrice": "0x0",
   665          "value": "0x0",
   666          "nonce": "0x0",
   667          "data": null,
   668          "input": null
   669        },
   670        "call_info": [
   671            {
   672              "type": "CRITICAL",
   673              "message": "Tx will create contract with empty code!"
   674            }
   675          ],
   676        "meta": {
   677          "remote": "signer binary",
   678          "local": "main",
   679          "scheme": "in-proc"
   680        }
   681      }
   682    ]
   683  }
   684  ```
   685  
   686  ### ApproveExport
   687  
   688  Invoked when a request to export an account has been made.
   689  
   690  #### Sample call
   691  
   692  ```json
   693  
   694  {
   695    "jsonrpc": "2.0",
   696    "id": 7,
   697    "method": "ApproveExport",
   698    "params": [
   699      {
   700        "address": "0x0000000000000000000000000000000000000000",
   701        "meta": {
   702          "remote": "signer binary",
   703          "local": "main",
   704          "scheme": "in-proc"
   705        }
   706      }
   707    ]
   708  }
   709  
   710  ```
   711  
   712  ### ApproveListing
   713  
   714  Invoked when a request for account listing has been made.
   715  
   716  #### Sample call
   717  
   718  ```json
   719  
   720  {
   721    "jsonrpc": "2.0",
   722    "id": 5,
   723    "method": "ApproveListing",
   724    "params": [
   725      {
   726        "accounts": [
   727          {
   728            "type": "Account",
   729            "url": "keystore:///home/bazonk/.ethereum/keystore/UTC--2017-11-20T14-44-54.089682944Z--123409812340981234098123409812deadbeef42",
   730            "address": "0x123409812340981234098123409812deadbeef42"
   731          },
   732          {
   733            "type": "Account",
   734            "url": "keystore:///home/bazonk/.ethereum/keystore/UTC--2017-11-23T21-59-03.199240693Z--cafebabedeadbeef34098123409812deadbeef42",
   735            "address": "0xcafebabedeadbeef34098123409812deadbeef42"
   736          }
   737        ],
   738        "meta": {
   739          "remote": "signer binary",
   740          "local": "main",
   741          "scheme": "in-proc"
   742        }
   743      }
   744    ]
   745  }
   746  
   747  ```
   748  
   749  
   750  ### ApproveSignData
   751  
   752  #### Sample call
   753  
   754  ```json
   755  {
   756    "jsonrpc": "2.0",
   757    "id": 4,
   758    "method": "ApproveSignData",
   759    "params": [
   760      {
   761        "address": "0x123409812340981234098123409812deadbeef42",
   762        "raw_data": "0x01020304",
   763        "message": "\u0019Ethereum Signed Message:\n4\u0001\u0002\u0003\u0004",
   764        "hash": "0x7e3a4e7a9d1744bc5c675c25e1234ca8ed9162bd17f78b9085e48047c15ac310",
   765        "meta": {
   766          "remote": "signer binary",
   767          "local": "main",
   768          "scheme": "in-proc"
   769        }
   770      }
   771    ]
   772  }
   773  
   774  ```
   775  
   776  ### ShowInfo
   777  
   778  The UI should show the info to the user. Does not expect response.
   779  
   780  #### Sample call
   781  
   782  ```json
   783  {
   784    "jsonrpc": "2.0",
   785    "id": 9,
   786    "method": "ShowInfo",
   787    "params": [
   788      {
   789        "text": "Tests completed"
   790      }
   791    ]
   792  }
   793  
   794  ```
   795  
   796  ### ShowError
   797  
   798  The UI should show the info to the user. Does not expect response.
   799  
   800  ```json
   801  
   802  {
   803    "jsonrpc": "2.0",
   804    "id": 2,
   805    "method": "ShowError",
   806    "params": [
   807      {
   808        "text": "Testing 'ShowError'"
   809      }
   810    ]
   811  }
   812  
   813  ```
   814  
   815  ### OnApproved
   816  
   817  `OnApprovedTx` is called when a transaction has been approved and signed. The call contains the return value that will be sent to the external caller.  The return value from this method is ignored - the reason for having this callback is to allow the ruleset to keep track of approved transactions.
   818  
   819  When implementing rate-limited rules, this callback should be used.
   820  
   821  TLDR; Use this method to keep track of signed transactions, instead of using the data in `ApproveTx`.
   822  
   823  ### OnSignerStartup
   824  
   825  This method provide the UI with information about what API version the signer uses (both internal and external) aswell as build-info and external api,
   826  in k/v-form.
   827  
   828  Example call:
   829  ```json
   830  
   831  {
   832    "jsonrpc": "2.0",
   833    "id": 1,
   834    "method": "OnSignerStartup",
   835    "params": [
   836      {
   837        "info": {
   838          "extapi_http": "http://localhost:8550",
   839          "extapi_ipc": null,
   840          "extapi_version": "2.0.0",
   841          "intapi_version": "1.2.0"
   842        }
   843      }
   844    ]
   845  }
   846  
   847  ```
   848  
   849  
   850  ### Rules for UI apis
   851  
   852  A UI should conform to the following rules.
   853  
   854  * A UI MUST NOT load any external resources that were not embedded/part of the UI package.
   855    * For example, not load icons, stylesheets from the internet
   856    * Not load files from the filesystem, unless they reside in the same local directory (e.g. config files)
   857  * A Graphical UI MUST show the blocky-identicon for ethereum addresses.
   858  * A UI MUST warn display approproate warning if the destination-account is formatted with invalid checksum.
   859  * A UI MUST NOT open any ports or services
   860    * The signer opens the public port
   861  * A UI SHOULD verify the permissions on the signer binary, and refuse to execute or warn if permissions allow non-user write.
   862  * A UI SHOULD inform the user about the `SHA256` or `MD5` hash of the binary being executed
   863  * A UI SHOULD NOT maintain a secondary storage of data, e.g. list of accounts
   864    * The signer provides accounts
   865  * A UI SHOULD, to the best extent possible, use static linking / bundling, so that requried libraries are bundled
   866  along with the UI.
   867  
   868  
   869  ### UI Implementations 
   870  
   871  There are a couple of implementation for a UI. We'll try to keep this list up to date. 
   872  
   873  | Name | Repo | UI type| No external resources| Blocky support| Verifies permissions | Hash information | No secondary storage | Statically linked| Can modify parameters|
   874  | ---- | ---- | -------| ---- | ---- | ---- |---- | ---- | ---- | ---- |
   875  | QtSigner| https://github.com/holiman/qtsigner/| Python3/QT-based| :+1:| :+1:| :+1:| :+1:| :+1:| :x: |  :+1: (partially)|
   876  | GtkSigner| https://github.com/holiman/gtksigner| Python3/GTK-based| :+1:| :x:| :x:| :+1:| :+1:| :x: |  :x: |
   877  | Frame | https://github.com/floating/frame/commits/go-signer| Electron-based| :x:| :x:| :x:| :x:| ?| :x: |  :x: |