github.com/daeglee/go-ethereum@v0.0.0-20190504220456-cad3e8d18e9b/cmd/clef/README.md (about)

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