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