github.com/ConsenSys/Quorum@v20.10.0+incompatible/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, 3=Ropsten, 4=Rinkeby, 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     --rpcaddr value         HTTP-RPC server listening interface (default: "localhost")
    37     --rpcvhosts 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     --rpc                   Enable the HTTP-RPC server
    41     --rpcport 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 `rpcaddr`:`rpcport` (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 (transaction manager hash if transaction is private)
   227       - `nonce` [number]: account nonce
   228       - `isPrivate` [boolean:optional]: whether the transaction is a Quorum private transaction 
   229    1. method signature [string:optional]
   230       - 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.
   231  
   232  
   233  #### Result
   234    - raw [data]: signed transaction in RLP encoded form
   235    - tx [json]: signed transaction in JSON form
   236  
   237  #### Sample call
   238  ```json
   239  {
   240    "id": 2,
   241    "jsonrpc": "2.0",
   242    "method": "account_signTransaction",
   243    "params": [
   244      {
   245        "from": "0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db",
   246        "gas": "0x55555",
   247        "gasPrice": "0x1234",
   248        "input": "0xabcd",
   249        "nonce": "0x0",
   250        "to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
   251        "value": "0x1234"
   252      }
   253    ]
   254  }
   255  ```
   256  Response
   257  
   258  ```json
   259  {
   260    "jsonrpc": "2.0",
   261    "id": 2,
   262    "result": {
   263      "raw": "0xf88380018203339407a565b7ed7d7a678680a4c162885bedbb695fe080a44401a6e4000000000000000000000000000000000000000000000000000000000000001226a0223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20ea02aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663",
   264      "tx": {
   265        "nonce": "0x0",
   266        "gasPrice": "0x1234",
   267        "gas": "0x55555",
   268        "to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
   269        "value": "0x1234",
   270        "input": "0xabcd",
   271        "v": "0x26",
   272        "r": "0x223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20e",
   273        "s": "0x2aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663",
   274        "hash": "0xeba2df809e7a612a0a0d444ccfa5c839624bdc00dd29e3340d46df3870f8a30e"
   275      }
   276    }
   277  }
   278  ```
   279  #### Sample call with ABI-data
   280  
   281  
   282  ```json
   283  {
   284    "id": 67,
   285    "jsonrpc": "2.0",
   286    "method": "account_signTransaction",
   287    "params": [
   288      {
   289        "from": "0x694267f14675d7e1b9494fd8d72fefe1755710fa",
   290        "gas": "0x333",
   291        "gasPrice": "0x1",
   292        "nonce": "0x0",
   293        "to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
   294        "value": "0x0",
   295        "data": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012"
   296      },
   297      "safeSend(address)"
   298    ]
   299  }
   300  ```
   301  Response
   302  
   303  ```json
   304  {
   305    "jsonrpc": "2.0",
   306    "id": 67,
   307    "result": {
   308      "raw": "0xf88380018203339407a565b7ed7d7a678680a4c162885bedbb695fe080a44401a6e4000000000000000000000000000000000000000000000000000000000000001226a0223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20ea02aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663",
   309      "tx": {
   310        "nonce": "0x0",
   311        "gasPrice": "0x1",
   312        "gas": "0x333",
   313        "to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
   314        "value": "0x0",
   315        "input": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012",
   316        "v": "0x26",
   317        "r": "0x223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20e",
   318        "s": "0x2aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663",
   319        "hash": "0xeba2df809e7a612a0a0d444ccfa5c839624bdc00dd29e3340d46df3870f8a30e"
   320      }
   321    }
   322  }
   323  ```
   324  
   325  Bash example:
   326  ```bash
   327  > 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/
   328  
   329  {"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"}}}
   330  ```
   331  
   332  ### account_signData
   333  
   334  #### Sign data
   335     Signs a chunk of data and returns the calculated signature.
   336  
   337  #### Arguments
   338    - content type [string]: type of signed data
   339       - `text/validator`: hex data with custom validator defined in a contract
   340       - `application/clique`: [clique](https://github.com/ethereum/EIPs/issues/225) headers
   341       - `text/plain`: simple hex data validated by `account_ecRecover`
   342    - account [address]: account to sign with
   343    - data [object]: data to sign
   344  
   345  #### Result
   346    - calculated signature [data]
   347  
   348  #### Sample call
   349  ```json
   350  {
   351    "id": 3,
   352    "jsonrpc": "2.0",
   353    "method": "account_signData",
   354    "params": [
   355      "data/plain",
   356      "0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db",
   357      "0xaabbccdd"
   358    ]
   359  }
   360  ```
   361  Response
   362  
   363  ```json
   364  {
   365    "id": 3,
   366    "jsonrpc": "2.0",
   367    "result": "0x5b6693f153b48ec1c706ba4169960386dbaa6903e249cc79a8e6ddc434451d417e1e57327872c7f538beeb323c300afa9999a3d4a5de6caf3be0d5ef832b67ef1c"
   368  }
   369  ```
   370  
   371  ### account_signTypedData
   372  
   373  #### Sign data
   374     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.
   375  
   376  #### Arguments
   377    - account [address]: account to sign with
   378    - data [object]: data to sign
   379  
   380  #### Result
   381    - calculated signature [data]
   382  
   383  #### Sample call
   384  ```json
   385  {
   386    "id": 68,
   387    "jsonrpc": "2.0",
   388    "method": "account_signTypedData",
   389    "params": [
   390      "0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826",
   391      {
   392        "types": {
   393          "EIP712Domain": [
   394            {
   395              "name": "name",
   396              "type": "string"
   397            },
   398            {
   399              "name": "version",
   400              "type": "string"
   401            },
   402            {
   403              "name": "chainId",
   404              "type": "uint256"
   405            },
   406            {
   407              "name": "verifyingContract",
   408              "type": "address"
   409            }
   410          ],
   411          "Person": [
   412            {
   413              "name": "name",
   414              "type": "string"
   415            },
   416            {
   417              "name": "wallet",
   418              "type": "address"
   419            }
   420          ],
   421          "Mail": [
   422            {
   423              "name": "from",
   424              "type": "Person"
   425            },
   426            {
   427              "name": "to",
   428              "type": "Person"
   429            },
   430            {
   431              "name": "contents",
   432              "type": "string"
   433            }
   434          ]
   435        },
   436        "primaryType": "Mail",
   437        "domain": {
   438          "name": "Ether Mail",
   439          "version": "1",
   440          "chainId": 1,
   441          "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
   442        },
   443        "message": {
   444          "from": {
   445            "name": "Cow",
   446            "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
   447          },
   448          "to": {
   449            "name": "Bob",
   450            "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"
   451          },
   452          "contents": "Hello, Bob!"
   453        }
   454      }
   455    ]
   456  }
   457  ```
   458  Response
   459  
   460  ```json
   461  {
   462      "id": 1,
   463      "jsonrpc": "2.0",
   464      "result": "0x4355c47d63924e8a72e509b65029052eb6c299d53a04e167c5775fd466751c9d07299936d304c153f6443dfa05f40ff007d72911b6f72307f996231605b915621c"
   465  }
   466  ```
   467  
   468  ### account_ecRecover
   469  
   470  #### Recover the signing address
   471  
   472  Derive the address from the account that was used to sign data with content type `text/plain` and the signature.
   473  
   474  #### Arguments
   475    - data [data]: data that was signed
   476    - signature [data]: the signature to verify
   477  
   478  #### Result
   479    - derived account [address]
   480  
   481  #### Sample call
   482  ```json
   483  {
   484    "id": 4,
   485    "jsonrpc": "2.0",
   486    "method": "account_ecRecover",
   487    "params": [
   488      "0xaabbccdd",
   489      "0x5b6693f153b48ec1c706ba4169960386dbaa6903e249cc79a8e6ddc434451d417e1e57327872c7f538beeb323c300afa9999a3d4a5de6caf3be0d5ef832b67ef1c"
   490    ]
   491  }
   492  ```
   493  Response
   494  
   495  ```json
   496  {
   497    "id": 4,
   498    "jsonrpc": "2.0",
   499    "result": "0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db"
   500  }
   501  ```
   502  
   503  ### account_version
   504  
   505  #### Get external API version
   506  
   507  Get the version of the external API used by Clef.
   508  
   509  #### Arguments
   510  
   511  None
   512  
   513  #### Result
   514  
   515  * external API version [string]
   516  
   517  #### Sample call
   518  ```json
   519  {
   520    "id": 0,
   521    "jsonrpc": "2.0",
   522    "method": "account_version",
   523    "params": []
   524  }
   525  ```
   526  
   527  Response
   528  ```json
   529  {
   530      "id": 0,
   531      "jsonrpc": "2.0",
   532      "result": "6.0.0"
   533  }
   534  ```
   535  
   536  ## UI API
   537  
   538  These methods needs to be implemented by a UI listener.
   539  
   540  By starting the signer with the switch `--stdio-ui-test`, the signer will invoke all known methods, and expect the UI to respond with
   541  denials. This can be used during development to ensure that the API is (at least somewhat) correctly implemented.
   542  See `pythonsigner`, which can be invoked via `python3 pythonsigner.py test` to perform the 'denial-handshake-test'.
   543  
   544  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.
   545  
   546  See the [ui API changelog](intapi_changelog.md) for information about changes to this API.
   547  
   548  OBS! A slight deviation from `json` standard is in place: every request and response should be confined to a single line.
   549  Whereas the `json` specification allows for linebreaks, linebreaks __should not__ be used in this communication channel, to make
   550  things simpler for both parties.
   551  
   552  ### ApproveTx / `ui_approveTx`
   553  
   554  Invoked when there's a transaction for approval.
   555  
   556  
   557  #### Sample call
   558  
   559  Here's a method invocation:
   560  ```bash
   561  
   562  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/
   563  ```
   564  Results in the following invocation on the UI:
   565  ```json
   566  
   567  {
   568    "jsonrpc": "2.0",
   569    "id": 1,
   570    "method": "ui_approveTx",
   571    "params": [
   572      {
   573        "transaction": {
   574          "from": "0x0x694267f14675d7e1b9494fd8d72fefe1755710fa",
   575          "to": "0x0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
   576          "gas": "0x333",
   577          "gasPrice": "0x1",
   578          "value": "0x0",
   579          "nonce": "0x0",
   580          "data": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012",
   581          "input": null
   582        },
   583        "call_info": [
   584            {
   585              "type": "WARNING",
   586              "message": "Invalid checksum on to-address"
   587            },
   588            {
   589              "type": "Info",
   590              "message": "safeSend(address: 0x0000000000000000000000000000000000000012)"
   591            }
   592          ],
   593        "meta": {
   594          "remote": "127.0.0.1:48486",
   595          "local": "localhost:8550",
   596          "scheme": "HTTP/1.1"
   597        }
   598      }
   599    ]
   600  }
   601  
   602  ```
   603  
   604  The same method invocation, but with invalid data:
   605  ```bash
   606  
   607  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/
   608  ```
   609  
   610  ```json
   611  
   612  {
   613    "jsonrpc": "2.0",
   614    "id": 1,
   615    "method": "ui_approveTx",
   616    "params": [
   617      {
   618        "transaction": {
   619          "from": "0x0x694267f14675d7e1b9494fd8d72fefe1755710fa",
   620          "to": "0x0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
   621          "gas": "0x333",
   622          "gasPrice": "0x1",
   623          "value": "0x0",
   624          "nonce": "0x0",
   625          "data": "0x4401a6e40000000000000002000000000000000000000000000000000000000000000012",
   626          "input": null
   627        },
   628        "call_info": [
   629            {
   630              "type": "WARNING",
   631              "message": "Invalid checksum on to-address"
   632            },
   633            {
   634              "type": "WARNING",
   635              "message": "Transaction data did not match ABI-interface: WARNING: Supplied data is stuffed with extra data. \nWant 0000000000000002000000000000000000000000000000000000000000000012\nHave 0000000000000000000000000000000000000000000000000000000000000012\nfor method safeSend(address)"
   636            }
   637          ],
   638        "meta": {
   639          "remote": "127.0.0.1:48492",
   640          "local": "localhost:8550",
   641          "scheme": "HTTP/1.1"
   642        }
   643      }
   644    ]
   645  }
   646  
   647  
   648  ```
   649  
   650  One which has missing `to`, but with no `data`:
   651  
   652  
   653  ```json
   654  
   655  {
   656    "jsonrpc": "2.0",
   657    "id": 3,
   658    "method": "ui_approveTx",
   659    "params": [
   660      {
   661        "transaction": {
   662          "from": "",
   663          "to": null,
   664          "gas": "0x0",
   665          "gasPrice": "0x0",
   666          "value": "0x0",
   667          "nonce": "0x0",
   668          "data": null,
   669          "input": null
   670        },
   671        "call_info": [
   672            {
   673              "type": "CRITICAL",
   674              "message": "Tx will create contract with empty code!"
   675            }
   676          ],
   677        "meta": {
   678          "remote": "signer binary",
   679          "local": "main",
   680          "scheme": "in-proc"
   681        }
   682      }
   683    ]
   684  }
   685  ```
   686  
   687  ### ApproveListing / `ui_approveListing`
   688  
   689  Invoked when a request for account listing has been made.
   690  
   691  #### Sample call
   692  
   693  ```json
   694  
   695  {
   696    "jsonrpc": "2.0",
   697    "id": 5,
   698    "method": "ui_approveListing",
   699    "params": [
   700      {
   701        "accounts": [
   702          {
   703            "url": "keystore:///home/bazonk/.ethereum/keystore/UTC--2017-11-20T14-44-54.089682944Z--123409812340981234098123409812deadbeef42",
   704            "address": "0x123409812340981234098123409812deadbeef42"
   705          },
   706          {
   707            "url": "keystore:///home/bazonk/.ethereum/keystore/UTC--2017-11-23T21-59-03.199240693Z--cafebabedeadbeef34098123409812deadbeef42",
   708            "address": "0xcafebabedeadbeef34098123409812deadbeef42"
   709          }
   710        ],
   711        "meta": {
   712          "remote": "signer binary",
   713          "local": "main",
   714          "scheme": "in-proc"
   715        }
   716      }
   717    ]
   718  }
   719  
   720  ```
   721  
   722  
   723  ### ApproveSignData / `ui_approveSignData`
   724  
   725  #### Sample call
   726  
   727  ```json
   728  {
   729    "jsonrpc": "2.0",
   730    "id": 4,
   731    "method": "ui_approveSignData",
   732    "params": [
   733      {
   734        "address": "0x123409812340981234098123409812deadbeef42",
   735        "raw_data": "0x01020304",
   736        "messages": [
   737          {
   738            "name": "message",
   739            "value": "\u0019Ethereum Signed Message:\n4\u0001\u0002\u0003\u0004",
   740            "type": "text/plain"
   741          }
   742        ],
   743        "hash": "0x7e3a4e7a9d1744bc5c675c25e1234ca8ed9162bd17f78b9085e48047c15ac310",
   744        "meta": {
   745          "remote": "signer binary",
   746          "local": "main",
   747          "scheme": "in-proc"
   748        }
   749      }
   750    ]
   751  }
   752  ```
   753  
   754  ### ApproveNewAccount / `ui_approveNewAccount`
   755  
   756  Invoked when a request for creating a new account has been made.
   757  
   758  #### Sample call
   759  
   760  ```json
   761  {
   762    "jsonrpc": "2.0",
   763    "id": 4,
   764    "method": "ui_approveNewAccount",
   765    "params": [
   766      {
   767        "meta": {
   768          "remote": "signer binary",
   769          "local": "main",
   770          "scheme": "in-proc"
   771        }
   772      }
   773    ]
   774  }
   775  ```
   776  
   777  ### ShowInfo / `ui_showInfo`
   778  
   779  The UI should show the info (a single message) to the user. Does not expect response.
   780  
   781  #### Sample call
   782  
   783  ```json
   784  {
   785    "jsonrpc": "2.0",
   786    "id": 9,
   787    "method": "ui_showInfo",
   788    "params": [
   789      "Tests completed"
   790    ]
   791  }
   792  
   793  ```
   794  
   795  ### ShowError / `ui_showError`
   796  
   797  The UI should show the error (a single message) to the user. Does not expect response.
   798  
   799  ```json
   800  
   801  {
   802    "jsonrpc": "2.0",
   803    "id": 2,
   804    "method": "ui_showError",
   805    "params": [
   806      "Something bad happened!"
   807    ]
   808  }
   809  
   810  ```
   811  
   812  ### OnApprovedTx / `ui_onApprovedTx`
   813  
   814  `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.
   815  
   816  When implementing rate-limited rules, this callback should be used.
   817  
   818  TLDR; Use this method to keep track of signed transactions, instead of using the data in `ApproveTx`.
   819  
   820  Example call:
   821  ```json
   822  
   823  {
   824    "jsonrpc": "2.0",
   825    "id": 1,
   826    "method": "ui_onApprovedTx",
   827    "params": [
   828      {
   829        "raw": "0xf88380018203339407a565b7ed7d7a678680a4c162885bedbb695fe080a44401a6e4000000000000000000000000000000000000000000000000000000000000001226a0223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20ea02aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663",
   830        "tx": {
   831          "nonce": "0x0",
   832          "gasPrice": "0x1",
   833          "gas": "0x333",
   834          "to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
   835          "value": "0x0",
   836          "input": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012",
   837          "v": "0x26",
   838          "r": "0x223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20e",
   839          "s": "0x2aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663",
   840          "hash": "0xeba2df809e7a612a0a0d444ccfa5c839624bdc00dd29e3340d46df3870f8a30e"
   841        }
   842      }
   843    ]
   844  }
   845  ```
   846  
   847  ### OnSignerStartup / `ui_onSignerStartup`
   848  
   849  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,
   850  in k/v-form.
   851  
   852  Example call:
   853  ```json
   854  
   855  {
   856    "jsonrpc": "2.0",
   857    "id": 1,
   858    "method": "ui_onSignerStartup",
   859    "params": [
   860      {
   861        "info": {
   862          "extapi_http": "http://localhost:8550",
   863          "extapi_ipc": null,
   864          "extapi_version": "2.0.0",
   865          "intapi_version": "1.2.0"
   866        }
   867      }
   868    ]
   869  }
   870  
   871  ```
   872  
   873  ### OnInputRequired / `ui_onInputRequired`
   874  
   875  Invoked when Clef requires user input (e.g. a password).
   876  
   877  Example call:
   878  ```json
   879  
   880  {
   881    "jsonrpc": "2.0",
   882    "id": 1,
   883    "method": "ui_onInputRequired",
   884    "params": [
   885      {
   886        "title": "Account password",
   887        "prompt": "Please enter the password for account 0x694267f14675d7e1b9494fd8d72fefe1755710fa",
   888        "isPassword": true
   889      }
   890    ]
   891  }
   892  ```
   893  
   894  
   895  ### Rules for UI apis
   896  
   897  A UI should conform to the following rules.
   898  
   899  * A UI MUST NOT load any external resources that were not embedded/part of the UI package.
   900    * For example, not load icons, stylesheets from the internet
   901    * Not load files from the filesystem, unless they reside in the same local directory (e.g. config files)
   902  * A Graphical UI MUST show the blocky-identicon for ethereum addresses.
   903  * A UI MUST warn display appropriate warning if the destination-account is formatted with invalid checksum.
   904  * A UI MUST NOT open any ports or services
   905    * The signer opens the public port
   906  * A UI SHOULD verify the permissions on the signer binary, and refuse to execute or warn if permissions allow non-user write.
   907  * A UI SHOULD inform the user about the `SHA256` or `MD5` hash of the binary being executed
   908  * A UI SHOULD NOT maintain a secondary storage of data, e.g. list of accounts
   909    * The signer provides accounts
   910  * A UI SHOULD, to the best extent possible, use static linking / bundling, so that required libraries are bundled
   911  along with the UI.
   912  
   913  
   914  ### UI Implementations
   915  
   916  There are a couple of implementation for a UI. We'll try to keep this list up to date.
   917  
   918  | Name | Repo | UI type| No external resources| Blocky support| Verifies permissions | Hash information | No secondary storage | Statically linked| Can modify parameters|
   919  | ---- | ---- | -------| ---- | ---- | ---- |---- | ---- | ---- | ---- |
   920  | QtSigner| https://github.com/holiman/qtsigner/| Python3/QT-based| :+1:| :+1:| :+1:| :+1:| :+1:| :x: |  :+1: (partially)|
   921  | GtkSigner| https://github.com/holiman/gtksigner| Python3/GTK-based| :+1:| :x:| :x:| :+1:| :+1:| :x: |  :x: |
   922  | Frame | https://github.com/floating/frame/commits/go-signer| Electron-based| :x:| :x:| :x:| :x:| ?| :x: |  :x: |
   923  | Clef UI| https://github.com/kyokan/clef-ui| Golang/QT-based| :+1:| :+1:| :x:| :+1:| :+1:| :x: |  :+1: (approve tx only)|