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