github.com/theQRL/go-zond@v0.1.1/cmd/clef/README.md (about)

     1  # Clef
     2  
     3  Clef can be used to sign transactions and data and is meant as a(n eventual) replacement for Geth's account management. This allows DApps to not depend on Geth's account management. When a DApp wants to sign data (or a transaction), it can send the content to Clef, which will then provide the user with context and asks for permission to sign the content. If the users grants the signing request, Clef will send the signature back to the DApp.
     4  
     5  This setup allows a DApp to connect to a remote Ethereum node and send transactions that are locally signed. This can help in situations when a DApp is connected to an untrusted remote Ethereum node, because a local one is not available, not synchronised with the chain, or is a node that has no built-in (or limited) account management.
     6  
     7  Clef can run as a daemon on the same machine, off a usb-stick like [USB armory](https://inversepath.com/usbarmory), or even a separate VM in a [QubesOS](https://www.qubes-os.org/) type setup.
     8  
     9  Check out the
    10  
    11  * [CLI tutorial](tutorial.md) for some concrete examples on how Clef works.
    12  * [Setup docs](docs/setup.md) for information on how to configure Clef on QubesOS or USB Armory.
    13  * [Data types](datatypes.md) for details on the communication messages between Clef and an external UI.
    14  
    15  ## Command line flags
    16  
    17  Clef accepts the following command line options:
    18  
    19  ```
    20  COMMANDS:
    21     init    Initialize the signer, generate secret storage
    22     attest  Attest that a js-file is to be used
    23     setpw   Store a credential for a keystore file
    24     delpw   Remove a credential for a keystore file
    25     gendoc  Generate documentation about json-rpc format
    26     help    Shows a list of commands or help for one command
    27  
    28  GLOBAL OPTIONS:
    29     --loglevel value        log level to emit to the screen (default: 4)
    30     --keystore value        Directory for the keystore (default: "$HOME/.ethereum/keystore")
    31     --configdir value       Directory for Clef configuration (default: "$HOME/.clef")
    32     --chainid value         Chain id to use for signing (1=mainnet, 5=Goerli) (default: 1)
    33     --lightkdf              Reduce key-derivation RAM & CPU usage at some expense of KDF strength
    34     --nousb                 Disables monitoring for and managing USB hardware wallets
    35     --pcscdpath value       Path to the smartcard daemon (pcscd) socket file (default: "/run/pcscd/pcscd.comm")
    36     --http.addr value       HTTP-RPC server listening interface (default: "localhost")
    37     --http.vhosts value     Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard. (default: "localhost")
    38     --ipcdisable            Disable the IPC-RPC server
    39     --ipcpath               Filename for IPC socket/pipe within the datadir (explicit paths escape it)
    40     --http                  Enable the HTTP-RPC server
    41     --http.port value       HTTP-RPC server listening port (default: 8550)
    42     --signersecret value    A file containing the (encrypted) master seed to encrypt Clef data, e.g. keystore credentials and ruleset hash
    43     --4bytedb-custom value  File used for writing new 4byte-identifiers submitted via API (default: "./4byte-custom.json")
    44     --auditlog value        File used to emit audit logs. Set to "" to disable (default: "audit.log")
    45     --rules value           Path to the rule file to auto-authorize requests with
    46     --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 Clef is started by an external process.
    47     --stdio-ui-test         Mechanism to test interface between Clef and UI. Requires 'stdio-ui'.
    48     --advanced              If enabled, issues warnings instead of rejections for suspicious requests. Default off
    49     --suppress-bootwarn     If set, does not show the warning during boot
    50     --help, -h              show help
    51     --version, -v           print the version
    52  ```
    53  
    54  Example:
    55  
    56  ```
    57  $ clef -keystore /my/keystore -chainid 4
    58  ```
    59  
    60  ## Security model
    61  
    62  The security model of Clef is as follows:
    63  
    64  * One critical component (the Clef binary / daemon) is responsible for handling cryptographic operations: signing, private keys, encryption/decryption of keystore files.
    65  * Clef has a well-defined 'external' API.
    66  * The 'external' API is considered UNTRUSTED.
    67  * Clef also communicates with whatever process that invoked the binary, via stdin/stdout.
    68    * This channel is considered 'trusted'. Over this channel, approvals and passwords are communicated.
    69  
    70  The general flow for signing a transaction using e.g. Geth is as follows:
    71  ![image](sign_flow.png)
    72  
    73  In this case, `geth` would be started with `--signer http://localhost:8550` and would relay requests to `eth.sendTransaction`.
    74  
    75  ## TODOs
    76  
    77  Some snags and todos
    78  
    79  * [ ] Clef should take a startup param "--no-change", for UIs that do not contain the capability to perform changes to things, only approve/deny. Such a UI should be able to start the signer in a more secure mode by telling it that it only wants approve/deny capabilities.
    80  * [x] It would be nice if Clef could collect new 4byte-id:s/method selectors, and have a secondary database for those (`4byte_custom.json`). Users could then (optionally) submit their collections for inclusion upstream.
    81  * [ ] It should be possible to configure Clef to check if an account is indeed known to it, before passing on to the UI. The reason it currently does not, is that it would make it possible to enumerate accounts if it immediately returned "unknown account" (side channel attack).
    82  * [x] It should be possible to configure Clef to auto-allow listing (certain) accounts, instead of asking every time.
    83  * [x] Done Upon startup, Clef should spit out some info to the caller (particularly important when executed in `stdio-ui`-mode), invoking methods with the following info:
    84    * [x] Version info about the signer
    85    * [x] Address of API (HTTP/IPC)
    86    * [ ] List of known accounts
    87  * [ ] Have a default timeout on signing operations, so that if the user has not answered within e.g. 60 seconds, the request is rejected.
    88  * [ ] `account_signRawTransaction`
    89  * [ ] `account_bulkSignTransactions([] transactions)` should
    90     * only exist if enabled via config/flag
    91     * only allow non-data-sending transactions
    92     * all txs must use the same `from`-account
    93     * let the user confirm, showing
    94        * the total amount
    95        * the number of unique recipients
    96  
    97  * Geth todos
    98      - 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 put together is a bit of a hack into the HTTP server. This could probably be greatly improved.
    99      - Relay: Geth should be started in `geth --signer localhost:8550`.
   100      - Currently, the Geth APIs use `common.Address` in the arguments to transaction submission (e.g `to` field). This type is 20 `bytes`, and is incapable of carrying checksum information. The signer uses `common.MixedcaseAddress`, which retains the original input.
   101      - The Geth API should switch to use the same type, and relay `to`-account verbatim to the external API.
   102  * [x] Storage
   103      * [x] An encrypted key-value storage should be implemented.
   104      * See [rules.md](rules.md) for more info about this.
   105  * Another potential thing to introduce is pairing.
   106    * To prevent spurious requests which users just accept, implement a way to "pair" the caller with the signer (external API).
   107    * Thus Geth/cpp would cryptographically handshake and afterwards the caller would be allowed to make signing requests.
   108    * This feature would make the addition of rules less dangerous.
   109  
   110  * Wallets / accounts. Add API methods for wallets.
   111  
   112  ## Communication
   113  
   114  ### External API
   115  
   116  Clef listens to HTTP requests on `http.addr`:`http.port` (or to IPC on `ipcpath`), with the same JSON-RPC standard as Geth. The messages are expected to be [JSON-RPC 2.0 standard](https://www.jsonrpc.org/specification).
   117  
   118  Some of these calls can require user interaction. Clients must be aware that responses may be delayed significantly or may never be received if a user decides to ignore the confirmation request.
   119  
   120  The External API is **untrusted**: it does not accept credentials, nor does it expect that requests have any authority.
   121  
   122  ### Internal UI API
   123  
   124  Clef has one native console-based UI, for operation without any standalone tools. However, there is also an API to communicate with an external UI. To enable that UI, the signer needs to be executed with the `--stdio-ui` option, which allocates `stdin` / `stdout` for the UI API.
   125  
   126  An example (insecure) proof-of-concept of has been implemented in `pythonsigner.py`.
   127  
   128  The model is as follows:
   129  
   130  * The user starts the UI app (`pythonsigner.py`).
   131  * The UI app starts `clef` with `--stdio-ui`, and listens to the
   132  process output for confirmation-requests.
   133  * `clef` opens the external HTTP API.
   134  * When the `signer` receives requests, it sends a JSON-RPC request via `stdout`.
   135  * The UI app prompts the user accordingly, and responds to `clef`.
   136  * `clef` signs (or not), and responds to the original request.
   137  
   138  ## External API
   139  
   140  See the [external API changelog](extapi_changelog.md) for information about changes to this API.
   141  
   142  ### Encoding
   143  - number: positive integers that are hex encoded
   144  - data: hex encoded data
   145  - string: ASCII string
   146  
   147  All hex encoded values must be prefixed with `0x`.
   148  
   149  ### account_new
   150  
   151  #### Create new password protected account
   152  
   153  The signer will generate a new private key, encrypt it according to [web3 keystore spec](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) and store it in the keystore directory.  
   154  The client is responsible for creating a backup of the keystore. If the keystore is lost there is no method of retrieving lost accounts.
   155  
   156  #### Arguments
   157  
   158  None
   159  
   160  #### Result
   161    - address [string]: account address that is derived from the generated key
   162  
   163  #### Sample call
   164  ```json
   165  {
   166    "id": 0,
   167    "jsonrpc": "2.0",
   168    "method": "account_new",
   169    "params": []
   170  }
   171  ```
   172  Response
   173  ```json
   174  {
   175    "id": 0,
   176    "jsonrpc": "2.0",
   177    "result": "0xbea9183f8f4f03d427f6bcea17388bdff1cab133"
   178  }
   179  ```
   180  
   181  ### account_list
   182  
   183  #### List available accounts
   184     List all accounts that this signer currently manages
   185  
   186  #### Arguments
   187  
   188  None
   189  
   190  #### Result
   191    - array with account records:
   192       - account.address [string]: account address that is derived from the generated key
   193  
   194  #### Sample call
   195  ```json
   196  {
   197    "id": 1,
   198    "jsonrpc": "2.0",
   199    "method": "account_list"
   200  }
   201  ```
   202  Response
   203  ```json
   204  {
   205    "id": 1,
   206    "jsonrpc": "2.0",
   207    "result": [
   208      "0xafb2f771f58513609765698f65d3f2f0224a956f",
   209      "0xbea9183f8f4f03d427f6bcea17388bdff1cab133"
   210    ]
   211  }
   212  ```
   213  
   214  ### account_signTransaction
   215  
   216  #### Sign transactions
   217     Signs a transaction and responds with the signed transaction in RLP-encoded and JSON forms.
   218  
   219  #### Arguments
   220    1. transaction object:
   221       - `from` [address]: account to send the transaction from
   222       - `to` [address]: receiver account. If omitted or `0x`, will cause contract creation.
   223       - `gas` [number]: maximum amount of gas to burn
   224       - `gasPrice` [number]: gas price
   225       - `value` [number:optional]: amount of Wei to send with the transaction
   226       - `data` [data:optional]:  input data
   227       - `nonce` [number]: account nonce
   228    1. method signature [string:optional]
   229       - 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.
   230  
   231  
   232  #### Result
   233    - raw [data]: signed transaction in RLP encoded form
   234    - tx [json]: signed transaction in JSON form
   235  
   236  #### Sample call
   237  ```json
   238  {
   239    "id": 2,
   240    "jsonrpc": "2.0",
   241    "method": "account_signTransaction",
   242    "params": [
   243      {
   244        "from": "0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db",
   245        "gas": "0x55555",
   246        "gasPrice": "0x1234",
   247        "input": "0xabcd",
   248        "nonce": "0x0",
   249        "to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
   250        "value": "0x1234"
   251      }
   252    ]
   253  }
   254  ```
   255  Response
   256  
   257  ```json
   258  {
   259    "jsonrpc": "2.0",
   260    "id": 2,
   261    "result": {
   262      "raw": "0xf88380018203339407a565b7ed7d7a678680a4c162885bedbb695fe080a44401a6e4000000000000000000000000000000000000000000000000000000000000001226a0223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20ea02aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663",
   263      "tx": {
   264        "nonce": "0x0",
   265        "gasPrice": "0x1234",
   266        "gas": "0x55555",
   267        "to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
   268        "value": "0x1234",
   269        "input": "0xabcd",
   270        "v": "0x26",
   271        "r": "0x223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20e",
   272        "s": "0x2aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663",
   273        "hash": "0xeba2df809e7a612a0a0d444ccfa5c839624bdc00dd29e3340d46df3870f8a30e"
   274      }
   275    }
   276  }
   277  ```
   278  #### Sample call with ABI-data
   279  
   280  
   281  ```json
   282  {
   283    "id": 67,
   284    "jsonrpc": "2.0",
   285    "method": "account_signTransaction",
   286    "params": [
   287      {
   288        "from": "0x694267f14675d7e1b9494fd8d72fefe1755710fa",
   289        "gas": "0x333",
   290        "gasPrice": "0x1",
   291        "nonce": "0x0",
   292        "to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
   293        "value": "0x0",
   294        "data": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012"
   295      },
   296      "safeSend(address)"
   297    ]
   298  }
   299  ```
   300  Response
   301  
   302  ```json
   303  {
   304    "jsonrpc": "2.0",
   305    "id": 67,
   306    "result": {
   307      "raw": "0xf88380018203339407a565b7ed7d7a678680a4c162885bedbb695fe080a44401a6e4000000000000000000000000000000000000000000000000000000000000001226a0223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20ea02aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663",
   308      "tx": {
   309        "nonce": "0x0",
   310        "gasPrice": "0x1",
   311        "gas": "0x333",
   312        "to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
   313        "value": "0x0",
   314        "input": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012",
   315        "v": "0x26",
   316        "r": "0x223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20e",
   317        "s": "0x2aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663",
   318        "hash": "0xeba2df809e7a612a0a0d444ccfa5c839624bdc00dd29e3340d46df3870f8a30e"
   319      }
   320    }
   321  }
   322  ```
   323  
   324  Bash example:
   325  ```bash
   326  > 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/
   327  
   328  {"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"}}}
   329  ```
   330  
   331  ### account_signData
   332  
   333  #### Sign data
   334     Signs a chunk of data and returns the calculated signature.
   335  
   336  #### Arguments
   337    - content type [string]: type of signed data
   338       - `text/validator`: hex data with custom validator defined in a contract
   339       - `application/clique`: [clique](https://github.com/ethereum/EIPs/issues/225) headers
   340       - `text/plain`: simple hex data validated by `account_ecRecover`
   341    - account [address]: account to sign with
   342    - data [object]: data to sign
   343  
   344  #### Result
   345    - calculated signature [data]
   346  
   347  #### Sample call
   348  ```json
   349  {
   350    "id": 3,
   351    "jsonrpc": "2.0",
   352    "method": "account_signData",
   353    "params": [
   354      "data/plain",
   355      "0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db",
   356      "0xaabbccdd"
   357    ]
   358  }
   359  ```
   360  Response
   361  
   362  ```json
   363  {
   364    "id": 3,
   365    "jsonrpc": "2.0",
   366    "result": "0x5b6693f153b48ec1c706ba4169960386dbaa6903e249cc79a8e6ddc434451d417e1e57327872c7f538beeb323c300afa9999a3d4a5de6caf3be0d5ef832b67ef1c"
   367  }
   368  ```
   369  
   370  ### account_signTypedData
   371  
   372  #### Sign data
   373     Signs a chunk of structured data conformant to [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md) and returns the calculated signature.
   374  
   375  #### Arguments
   376    - account [address]: account to sign with
   377    - data [object]: data to sign
   378  
   379  #### Result
   380    - calculated signature [data]
   381  
   382  #### Sample call
   383  ```json
   384  {
   385    "id": 68,
   386    "jsonrpc": "2.0",
   387    "method": "account_signTypedData",
   388    "params": [
   389      "0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826",
   390      {
   391        "types": {
   392          "EIP712Domain": [
   393            {
   394              "name": "name",
   395              "type": "string"
   396            },
   397            {
   398              "name": "version",
   399              "type": "string"
   400            },
   401            {
   402              "name": "chainId",
   403              "type": "uint256"
   404            },
   405            {
   406              "name": "verifyingContract",
   407              "type": "address"
   408            }
   409          ],
   410          "Person": [
   411            {
   412              "name": "name",
   413              "type": "string"
   414            },
   415            {
   416              "name": "wallet",
   417              "type": "address"
   418            }
   419          ],
   420          "Mail": [
   421            {
   422              "name": "from",
   423              "type": "Person"
   424            },
   425            {
   426              "name": "to",
   427              "type": "Person"
   428            },
   429            {
   430              "name": "contents",
   431              "type": "string"
   432            }
   433          ]
   434        },
   435        "primaryType": "Mail",
   436        "domain": {
   437          "name": "Ether Mail",
   438          "version": "1",
   439          "chainId": 1,
   440          "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
   441        },
   442        "message": {
   443          "from": {
   444            "name": "Cow",
   445            "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
   446          },
   447          "to": {
   448            "name": "Bob",
   449            "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"
   450          },
   451          "contents": "Hello, Bob!"
   452        }
   453      }
   454    ]
   455  }
   456  ```
   457  Response
   458  
   459  ```json
   460  {
   461      "id": 1,
   462      "jsonrpc": "2.0",
   463      "result": "0x4355c47d63924e8a72e509b65029052eb6c299d53a04e167c5775fd466751c9d07299936d304c153f6443dfa05f40ff007d72911b6f72307f996231605b915621c"
   464  }
   465  ```
   466  
   467  ### account_ecRecover
   468  
   469  #### Recover the signing address
   470  
   471  Derive the address from the account that was used to sign data with content type `text/plain` and the signature.
   472  
   473  #### Arguments
   474    - data [data]: data that was signed
   475    - signature [data]: the signature to verify
   476  
   477  #### Result
   478    - derived account [address]
   479  
   480  #### Sample call
   481  ```json
   482  {
   483    "id": 4,
   484    "jsonrpc": "2.0",
   485    "method": "account_ecRecover",
   486    "params": [
   487      "0xaabbccdd",
   488      "0x5b6693f153b48ec1c706ba4169960386dbaa6903e249cc79a8e6ddc434451d417e1e57327872c7f538beeb323c300afa9999a3d4a5de6caf3be0d5ef832b67ef1c"
   489    ]
   490  }
   491  ```
   492  Response
   493  
   494  ```json
   495  {
   496    "id": 4,
   497    "jsonrpc": "2.0",
   498    "result": "0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db"
   499  }
   500  ```
   501  
   502  ### account_version
   503  
   504  #### Get external API version
   505  
   506  Get the version of the external API used by Clef.
   507  
   508  #### Arguments
   509  
   510  None
   511  
   512  #### Result
   513  
   514  * external API version [string]
   515  
   516  #### Sample call
   517  ```json
   518  {
   519    "id": 0,
   520    "jsonrpc": "2.0",
   521    "method": "account_version",
   522    "params": []
   523  }
   524  ```
   525  
   526  Response
   527  ```json
   528  {
   529      "id": 0,
   530      "jsonrpc": "2.0",
   531      "result": "6.0.0"
   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 use object-based parameters, so that there can be no mixup 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 / `ui_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  Results in the following invocation on the UI:
   564  ```json
   565  
   566  {
   567    "jsonrpc": "2.0",
   568    "id": 1,
   569    "method": "ui_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": "ui_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": "ui_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  ### ApproveListing / `ui_approveListing`
   687  
   688  Invoked when a request for account listing has been made.
   689  
   690  #### Sample call
   691  
   692  ```json
   693  
   694  {
   695    "jsonrpc": "2.0",
   696    "id": 5,
   697    "method": "ui_approveListing",
   698    "params": [
   699      {
   700        "accounts": [
   701          {
   702            "url": "keystore:///home/bazonk/.ethereum/keystore/UTC--2017-11-20T14-44-54.089682944Z--123409812340981234098123409812deadbeef42",
   703            "address": "0x123409812340981234098123409812deadbeef42"
   704          },
   705          {
   706            "url": "keystore:///home/bazonk/.ethereum/keystore/UTC--2017-11-23T21-59-03.199240693Z--cafebabedeadbeef34098123409812deadbeef42",
   707            "address": "0xcafebabedeadbeef34098123409812deadbeef42"
   708          }
   709        ],
   710        "meta": {
   711          "remote": "signer binary",
   712          "local": "main",
   713          "scheme": "in-proc"
   714        }
   715      }
   716    ]
   717  }
   718  
   719  ```
   720  
   721  
   722  ### ApproveSignData / `ui_approveSignData`
   723  
   724  #### Sample call
   725  
   726  ```json
   727  {
   728    "jsonrpc": "2.0",
   729    "id": 4,
   730    "method": "ui_approveSignData",
   731    "params": [
   732      {
   733        "address": "0x123409812340981234098123409812deadbeef42",
   734        "raw_data": "0x01020304",
   735        "messages": [
   736          {
   737            "name": "message",
   738            "value": "\u0019Ethereum Signed Message:\n4\u0001\u0002\u0003\u0004",
   739            "type": "text/plain"
   740          }
   741        ],
   742        "hash": "0x7e3a4e7a9d1744bc5c675c25e1234ca8ed9162bd17f78b9085e48047c15ac310",
   743        "meta": {
   744          "remote": "signer binary",
   745          "local": "main",
   746          "scheme": "in-proc"
   747        }
   748      }
   749    ]
   750  }
   751  ```
   752  
   753  ### ApproveNewAccount / `ui_approveNewAccount`
   754  
   755  Invoked when a request for creating a new account has been made.
   756  
   757  #### Sample call
   758  
   759  ```json
   760  {
   761    "jsonrpc": "2.0",
   762    "id": 4,
   763    "method": "ui_approveNewAccount",
   764    "params": [
   765      {
   766        "meta": {
   767          "remote": "signer binary",
   768          "local": "main",
   769          "scheme": "in-proc"
   770        }
   771      }
   772    ]
   773  }
   774  ```
   775  
   776  ### ShowInfo / `ui_showInfo`
   777  
   778  The UI should show the info (a single message) to the user. Does not expect response.
   779  
   780  #### Sample call
   781  
   782  ```json
   783  {
   784    "jsonrpc": "2.0",
   785    "id": 9,
   786    "method": "ui_showInfo",
   787    "params": [
   788      "Tests completed"
   789    ]
   790  }
   791  
   792  ```
   793  
   794  ### ShowError / `ui_showError`
   795  
   796  The UI should show the error (a single message) to the user. Does not expect response.
   797  
   798  ```json
   799  
   800  {
   801    "jsonrpc": "2.0",
   802    "id": 2,
   803    "method": "ui_showError",
   804    "params": [
   805      "Something bad happened!"
   806    ]
   807  }
   808  
   809  ```
   810  
   811  ### OnApprovedTx / `ui_onApprovedTx`
   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  Example call:
   820  ```json
   821  
   822  {
   823    "jsonrpc": "2.0",
   824    "id": 1,
   825    "method": "ui_onApprovedTx",
   826    "params": [
   827      {
   828        "raw": "0xf88380018203339407a565b7ed7d7a678680a4c162885bedbb695fe080a44401a6e4000000000000000000000000000000000000000000000000000000000000001226a0223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20ea02aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663",
   829        "tx": {
   830          "nonce": "0x0",
   831          "gasPrice": "0x1",
   832          "gas": "0x333",
   833          "to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
   834          "value": "0x0",
   835          "input": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012",
   836          "v": "0x26",
   837          "r": "0x223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20e",
   838          "s": "0x2aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663",
   839          "hash": "0xeba2df809e7a612a0a0d444ccfa5c839624bdc00dd29e3340d46df3870f8a30e"
   840        }
   841      }
   842    ]
   843  }
   844  ```
   845  
   846  ### OnSignerStartup / `ui_onSignerStartup`
   847  
   848  This method provides the UI with information about what API version the signer uses (both internal and external) as well as build-info and external API,
   849  in k/v-form.
   850  
   851  Example call:
   852  ```json
   853  
   854  {
   855    "jsonrpc": "2.0",
   856    "id": 1,
   857    "method": "ui_onSignerStartup",
   858    "params": [
   859      {
   860        "info": {
   861          "extapi_http": "http://localhost:8550",
   862          "extapi_ipc": null,
   863          "extapi_version": "2.0.0",
   864          "intapi_version": "1.2.0"
   865        }
   866      }
   867    ]
   868  }
   869  
   870  ```
   871  
   872  ### OnInputRequired / `ui_onInputRequired`
   873  
   874  Invoked when Clef requires user input (e.g. a password).
   875  
   876  Example call:
   877  ```json
   878  
   879  {
   880    "jsonrpc": "2.0",
   881    "id": 1,
   882    "method": "ui_onInputRequired",
   883    "params": [
   884      {
   885        "title": "Account password",
   886        "prompt": "Please enter the password for account 0x694267f14675d7e1b9494fd8d72fefe1755710fa",
   887        "isPassword": true
   888      }
   889    ]
   890  }
   891  ```
   892  
   893  
   894  ### Rules for UI apis
   895  
   896  A UI should conform to the following rules.
   897  
   898  * A UI MUST NOT load any external resources that were not embedded/part of the UI package.
   899    * For example, not load icons, stylesheets from the internet
   900    * Not load files from the filesystem, unless they reside in the same local directory (e.g. config files)
   901  * A Graphical UI MUST show the blocky-identicon for ethereum addresses.
   902  * A UI MUST warn display appropriate warning if the destination-account is formatted with invalid checksum.
   903  * A UI MUST NOT open any ports or services
   904    * The signer opens the public port
   905  * A UI SHOULD verify the permissions on the signer binary, and refuse to execute or warn if permissions allow non-user write.
   906  * A UI SHOULD inform the user about the `SHA256` or `MD5` hash of the binary being executed
   907  * A UI SHOULD NOT maintain a secondary storage of data, e.g. list of accounts
   908    * The signer provides accounts
   909  * A UI SHOULD, to the best extent possible, use static linking / bundling, so that required libraries are bundled
   910  along with the UI.
   911  
   912  
   913  ### UI Implementations
   914  
   915  There are a couple of implementation for a UI. We'll try to keep this list up to date.
   916  
   917  | Name | Repo | UI type| No external resources| Blocky support| Verifies permissions | Hash information | No secondary storage | Statically linked| Can modify parameters|
   918  | ---- | ---- | -------| ---- | ---- | ---- |---- | ---- | ---- | ---- |
   919  | QtSigner| https://github.com/holiman/qtsigner/| Python3/QT-based| :+1:| :+1:| :+1:| :+1:| :+1:| :x: |  :+1: (partially)|
   920  | GtkSigner| https://github.com/holiman/gtksigner| Python3/GTK-based| :+1:| :x:| :x:| :+1:| :+1:| :x: |  :x: |
   921  | Frame | https://github.com/floating/frame/commits/go-signer| Electron-based| :x:| :x:| :x:| :x:| ?| :x: |  :x: |
   922  | Clef UI| https://github.com/ethereum/clef-ui| Golang/QT-based| :+1:| :+1:| :x:| :+1:| :+1:| :x: |  :+1: (approve tx only)|