The two developers on this project are Craig Everett and Peter Harpending. Craig is an Erlang graybeard. Peter is a recovering @@ -201,6 +225,7 @@ manifestation of Satoshi's dream.
Please click the word "Documentation" in the sidebar
+Generated using TypeDoc
Generated using TypeDoc
This is the data that is sent from the aepp to the wallet through the Event +bus
+ +// layer 2: who is the message for
{type : "to_waellet",
// layer 3: json rpc
data : {jsonrpc : "2.0",
id : "ske-connect-1",
method : "connection.open",
// layer 4: AWCP-specific semantics
params : {name : "sidekick examples",
version : 1}}}
+
+Generated using TypeDoc
Actual aepp-to-waellet "address.subscribe" event data sent over the message bus
+(layer 2)
+ +{
"type": "to_waellet",
"data": {
"jsonrpc": "2.0",
"id": "ske-address-1",
"method": "address.subscribe",
"params": {
"type": "subscribe",
"value": "connected"
}
}
}
+
+Generated using TypeDoc
The actual aepp-to-waellet "connection.open" event data passed over the message bus
+(layer 2)
+ +{
"type": "to_waellet",
"data": {
"jsonrpc": "2.0",
"id": "ske-connect-1",
"method": "connection.open",
"params": {
"name": "sidekick examples",
"version": 1
}
}
}
+
+Generated using TypeDoc
Event data for aepp-to-waellet "message.sign"
+(layer 2)
+ +{
"type": "to_waellet",
"data": {
"jsonrpc": "2.0",
"id": "sk-msg-sign-1",
"method": "message.sign",
"params": {
"onAccount": "ak_2RT9RPbcX8RtjBpMWqsKtVRVKASAbj8V4c3f7cCdJfuVdihhyL",
"message": "MESSSSSSSSSSAGGGGGGGGGGGGGGGGGGGGGGGGGGGE"
}
}
}
+
+Generated using TypeDoc
Event data for aepp-to-waellet "transaction.sign" (do not propagate) message
+(layer 2)
+ +{
"type": "to_waellet",
"data": {
"jsonrpc": "2.0",
"id": "sk-tx-sign-1",
"method": "transaction.sign",
"params": {
"tx": "tx_+FgMAaEBuzbuuWjOzR7ecjOY8+u7HdNk0KoxTQcCDerZELEQ+UShAXtm5sMFBwg25Ol5IFI9w+pZy7/YbFi6BwPqi80KuKdsCoYPJvVhyAAAAYdoYWluYW5h9uAnNQ==",
"returnSigned": true,
"networkId": "ae_uat"
}
}
}
+
+Generated using TypeDoc
Event data for aepp-to-waellet "transaction.sign" (do propagate) message
+(layer 2)
+ +{
"type": "to_waellet",
"data": {
"jsonrpc": "2.0",
"id": "sk-tx-sign-1",
"method": "transaction.sign",
"params": {
"tx": "tx_+FgMAaEBuzbuuWjOzR7ecjOY8+u7HdNk0KoxTQcCDerZELEQ+UShAXtm5sMFBwg25Ol5IFI9w+pZy7/YbFi6BwPqi80KuKdsCoYPJvVhyAAAAYdoYWluYW5h9uAnNQ==",
"returnSigned": false,
"networkId": "ae_uat"
}
}
}
+
+Generated using TypeDoc
This is the data that is sent from the wallet to the aepp through the Event +bus
+(layer 2)
+ +// layer 2: who is the message for
{type : "to_aepp",
// layer 3: JSON RPC
data : {jsonrpc : "2.0",
method : "connection.announcePresence",
// layer 4: AWCP-specific semantics
params : {id : "{aee9e933-52b6-410a-8c3f-99c6be596b4e}",
name : "Superhero",
networkId : "ae_mainnet",
origin : "moz-extension://ee425d81-d5b2-44b6-9406-4da31b019e7c",
type : "extension"}}}
+
+Generated using TypeDoc
Actual waellet-to-aepp "address.subscribe" event data sent over the message bus
+(layer 2)
+ +This is the case where the wallet only has one keypair:
+{
"type": "to_aepp",
"data": {
"jsonrpc": "2.0",
"id": "ske-address-1",
"method": "address.subscribe",
"result": {
"subscription": [
"connected"
],
"address": {
"current": {
"ak_BMtPGuqDhWLnMVL4t6VFfS32y2hd8TSYwiYa2Z3VdmGzgNtJP": {}
},
"connected": {}
}
}
}
}
+
+
+Case of many keypairs, the current one will be in current.
{
"type": "to_aepp",
"data": {
"jsonrpc": "2.0",
"id": "ske-address-1",
"method": "address.subscribe",
"result": {
"subscription": [
"connected"
],
"address": {
"current": {
"ak_2RT9RPbcX8RtjBpMWqsKtVRVKASAbj8V4c3f7cCdJfuVdihhyL": {}
},
"connected": {
"ak_sMM2sUiyeBeMiRAj8viHVCVDxevmCacALhoHdrkobyhoqnR85": {},
"ak_o355SAx4n1V6xbrYv4Zaxm7GAYaZwEFXwgKBVEQTSm8MPnwjn": {},
"ak_2Up7dDMVBbPc4xAequf41zyzBqwWpUcVTYvcGF1ApAcCy7nGfA": {}
}
}
}
}
}
+
+Generated using TypeDoc
The actual waellet-to-aepp event passed when the wallet announces it exists
+(layer 2)
+ +{type: "to_aepp",
data: {jsonrpc: "2.0",
method: "connection.announcePresence",
params: {id : "{aee9e933-52b6-410a-8c3f-99c6be596b4e}",
name : "Superhero",
networkId : "ae_mainnet",
origin : "moz-extension://ee425d81-d5b2-44b6-9406-4da31b019e7c",
type : "extension"}}}
+
+Generated using TypeDoc
The actual waellet-to-aepp "connection.open" event data passed over the message bus
+(layer 2)
+ +{
"type": "to_aepp",
"data": {
"jsonrpc": "2.0",
"id": "ske-connect-1",
"method": "connection.open",
"result": {
"id": "mnhmmkepfddpifjkamaligfeemcbhdne",
"name": "Superhero",
"networkId": "ae_mainnet",
"origin": "chrome-extension://mnhmmkepfddpifjkamaligfeemcbhdne",
"type": "extension"
}
}
}
+
+Generated using TypeDoc
Event data for waellet-to-aepp "message.sign"
+(layer 2)
+ +{
"type": "to_aepp",
"data": {
"jsonrpc": "2.0",
"id": "sk-msg-sign-1",
"method": "message.sign",
"result": {
"signature": "3ec195484965a60dd4179fbb616947a85e4e9961cb468816a2a22870382954bc374f8569e4ddc729dfc1b14e09e670b7d2c70c33c592caca29ff6c212f1f8b0f"
}
}
}
+
+Generated using TypeDoc
Event data for waellet-to-aepp "transaction.sign" (do not propagate) response
+(layer 2)
+ +{
"type": "to_aepp",
"data": {
"jsonrpc": "2.0",
"id": "sk-tx-sign-1",
"method": "transaction.sign",
"result": {
"signedTransaction": "tx_+KILAfhCuEDxWnvffMvyrkFWnrImYej38rh99vM9f6pORl/yWTvU97nvUcY8/ck8lgtPA8w5odGSDb9LGY/JSZXsmsXhgKkHuFr4WAwBoQG7Nu65aM7NHt5yM5jz67sd02TQqjFNBwIN6tkQsRD5RKEBe2bmwwUHCDbk6XkgUj3D6lnLv9hsWLoHA+qLzQq4p2wKhg8m9WHIAAABh2hhaW5hbmF7X54G"
}
}
}
+
+Generated using TypeDoc
Event data for waellet-to-aepp "transaction.sign" (do propagate) response
+(layer 2)
+ +{
"type": "to_aepp",
"data": {
"jsonrpc": "2.0",
"id": "sk-tx-sign-1",
"method": "transaction.sign",
"result": {
"signedTransaction": "tx_+KILAfhCuEDxWnvffMvyrkFWnrImYej38rh99vM9f6pORl/yWTvU97nvUcY8/ck8lgtPA8w5odGSDb9LGY/JSZXsmsXhgKkHuFr4WAwBoQG7Nu65aM7NHt5yM5jz67sd02TQqjFNBwIN6tkQsRD5RKEBe2bmwwUHCDbk6XkgUj3D6lnLv9hsWLoHA+qLzQq4p2wKhg8m9WHIAAABh2hhaW5hbmF7X54G"
}
}
}
+
+Generated using TypeDoc
Parameter type of aepp-to-waellet "address.subscribe" call
+(layer 4)
+ +{
"type": "subscribe",
"value": "connected"
}
+
+Generated using TypeDoc
Parameters of aepp-to-waellet "connection.open" call
+(layer 4)
+ +{name : "sidekick examples",
version : 1}
+
+Optional networkGenerated using TypeDoc
Parameters for "message.sign"
+(layer 4)
+ +{
"onAccount": "ak_2RT9RPbcX8RtjBpMWqsKtVRVKASAbj8V4c3f7cCdJfuVdihhyL",
"message": "MESSSSSSSSSSAGGGGGGGGGGGGGGGGGGGGGGGGGGGE"
}
+
+Generated using TypeDoc
Parameters for "transaction.sign" (do not propagate)
+If returnSigned is false, then Superhero will propagate the transaction.
(layer 4)
+ +{
"tx": "tx_+FgMAaEBuzbuuWjOzR7ecjOY8+u7HdNk0KoxTQcCDerZELEQ+UShAXtm5sMFBwg25Ol5IFI9w+pZy7/YbFi6BwPqi80KuKdsCoYPJvVhyAAAAYdoYWluYW5h9uAnNQ==",
"returnSigned": true,
"networkId": "ae_uat"
}
+
+Generated using TypeDoc
Parameters for "transaction.sign" (do propagate)
+If returnSigned is false, then Superhero will propagate the transaction.
(layer 4)
+ +{
"tx": "tx_+FgMAaEBuzbuuWjOzR7ecjOY8+u7HdNk0KoxTQcCDerZELEQ+UShAXtm5sMFBwg25Ol5IFI9w+pZy7/YbFi6BwPqi80KuKdsCoYPJvVhyAAAAYdoYWluYW5h9uAnNQ==",
"returnSigned": false,
"networkId": "ae_uat"
}
+
+Generated using TypeDoc
Waellet-to-aepp parameters of "connection.announcePresence" cast
+(layer 4)
+ +{id : "{aee9e933-52b6-410a-8c3f-99c6be596b4e}",
name : "Superhero",
networkId : "ae_uat",
origin : "moz-extension://ee425d81-d5b2-44b6-9406-4da31b019e7c",
type : "extension"}
+
+Generated using TypeDoc
Result type of waellet-to-aepp "address.subscribe response
+(layer 4)
+ +This is if the user only has a single keypair
+{subscription : ["connected"],
address : {current : {"ak_2Wsa8iAmAm917evwDEZjouvPUXKx2nUv5Uz8e8oNXTDfDXnMRN": {}},
connected : {}}}
+
+
+This is if the user has many keypairs. The currently selected one is under
+current. Craig, I agree this is stupid, but that's how it works.
{
"subscription": [
"connected"
],
"address": {
"current": {
"ak_25C3xaAGQddyKAnaLLMjAhX24xMktH2NNZxY3fMaZQLMGED2Nf": {}
},
"connected": {
"ak_BMtPGuqDhWLnMVL4t6VFfS32y2hd8TSYwiYa2Z3VdmGzgNtJP": {},
"ak_25BqQuiVCasiqTkXHEffq7XCsuYEtgjNeZFeVFbuRtJkfC9NyX": {},
"ak_4p6gGoCcwQzLXd88KhdjRWYgd4MfTsaCeD8f99pzZhJ6vzYYV": {}
}
}
}
+
+Generated using TypeDoc
Result type of "connection.open" call
+Same as Params_W2A_connection_announcePresence empirically
+(layer 4)
+ +{id : "{aee9e933-52b6-410a-8c3f-99c6be596b4e}",
name : "Superhero",
networkId : "ae_uat",
origin : "moz-extension://ee425d81-d5b2-44b6-9406-4da31b019e7c",
type : "extension"}
+
+Generated using TypeDoc
Success result type for "message.sign"
+(layer 4)
+ +{
"signature": "3ec195484965a60dd4179fbb616947a85e4e9961cb468816a2a22870382954bc374f8569e4ddc729dfc1b14e09e670b7d2c70c33c592caca29ff6c212f1f8b0f"
}
+
+Generated using TypeDoc
Success result type for "transaction.sign" (do not propagate)
+(layer 4)
+ +{
* "signedTransaction": "tx_+KILAfhCuEDxWnvffMvyrkFWnrImYej38rh99vM9f6pORl/yWTvU97nvUcY8/ck8lgtPA8w5odGSDb9LGY/JSZXsmsXhgKkHuFr4WAwBoQG7Nu65aM7NHt5yM5jz67sd02TQqjFNBwIN6tkQsRD5RKEBe2bmwwUHCDbk6XkgUj3D6lnLv9hsWLoHA+qLzQq4p2wKhg8m9WHIAAABh2hhaW5hbmF7X54G"
* }
+
+Generated using TypeDoc
Success result type for "transaction.sign" (do propagate)
+(layer 4)
+ +"transactionHash": {
"blockHash": "mh_uJZ65APpLtiagJKjTNPZL1g1LJ7oqc2uG44qVqp1gVWwWUgLb",
"blockHeight": 806313,
"hash": "th_o3cudpezVywd99a7VMef9Yg7XPixTFueaCqGjdsnqLM99a78t",
"signatures": [
"sg_U36NDTFJFP4QEWCdjyhELDUDxsVGZNkq3DrcBCxby4NPUsPjQsFDG7VHN9s7TNUsEAd7qdC5aEjZKrqsKyfqA8apNrotz"
],
"tx": {
"amount": 10,
"fee": 16800000000000,
"nonce": 13,
"payload": "ba_aGFpbmFuYWbkNu8=",
"recipientId": "ak_wM8yFU8eSETXU7VSN48HMDmevGoCMiuveQZgkPuRn1nTiRqyv",
"senderId": "ak_2XhCkjzTwcq1coXSSzHJoMZkUzTwnjH88zmPGkkowUsFNTo9UE",
"type": "SpendTx",
"version": 1
},
"rawTx": "tx_+KILAfhCuEDOpyHRaYj8MnRwqOzMyRJSh4qud6jRK01wiAWfRHBDo/4e9klk7MsvM0Cr0ENaNkqKfwCDcaga/iDnogN5cukNuFr4WAwBoQHJY35GAOerO8Lmf8ZA6CN2RET0MFXaXVV4pJo3WvoY3KEBe2bmwwUHCDbk6XkgUj3D6lnLv9hsWLoHA+qLzQq4p2wKhg9HjghAAAANh2hhaW5hbmHkTCSc"
}
+
+Generated using TypeDoc
This type is used for requests from the client to the server that require a +response.
+(layer 3)
+ +// layer 3: json rpc
{jsonrpc : "2.0",
id : "ske-connect-1",
method : "connection.open",
// layer 4: AWCP-specific semantics
params : {name : "sidekick examples",
version : 1}}}
+
+Generated using TypeDoc
Shape of aepp-to-waellet "address.subscribe" RPC call
+(layer 3)
+ +{
"jsonrpc": "2.0",
"id": "ske-address-1",
"method": "address.subscribe",
"params": {
"type": "subscribe",
"value": "connected"
}
}
+
+Generated using TypeDoc
Shape of aepp-to-waellet "connection.open" RPC call
+(layer 3)
+ +// layer 3: json rpc
{jsonrpc : "2.0",
id : "ske-connect-1",
method : "connection.open",
// layer 4: AWCP-specific semantics
params : {name : "sidekick examples",
version : 1}}}
+
+Generated using TypeDoc
Request type for "message.sign"
+(layer 3)
+ +{
"jsonrpc": "2.0",
"id": "sk-msg-sign-1",
"method": "message.sign",
"params": {
"onAccount": "ak_2RT9RPbcX8RtjBpMWqsKtVRVKASAbj8V4c3f7cCdJfuVdihhyL",
"message": "MESSSSSSSSSSAGGGGGGGGGGGGGGGGGGGGGGGGGGGE"
}
}
+
+Generated using TypeDoc
Request type for "transaction.sign" (do not propagate)
+(layer 3)
+ +{
"jsonrpc": "2.0",
"id": "sk-tx-sign-1",
"method": "transaction.sign",
"params": {
"tx": "tx_+FgMAaEBuzbuuWjOzR7ecjOY8+u7HdNk0KoxTQcCDerZELEQ+UShAXtm5sMFBwg25Ol5IFI9w+pZy7/YbFi6BwPqi80KuKdsCoYPJvVhyAAAAYdoYWluYW5h9uAnNQ==",
"returnSigned": true,
"networkId": "ae_uat"
}
}
+
+Generated using TypeDoc
Request type for "transaction.sign" (do propagate)
+(layer 3)
+ +{
"jsonrpc": "2.0",
"id": "sk-tx-sign-1",
"method": "transaction.sign",
"params": {
"tx": "tx_+FgMAaEBuzbuuWjOzR7ecjOY8+u7HdNk0KoxTQcCDerZELEQ+UShAXtm5sMFBwg25Ol5IFI9w+pZy7/YbFi6BwPqi80KuKdsCoYPJvVhyAAAAYdoYWluYW5h9uAnNQ==",
"returnSigned": true,
"networkId": "ae_uat"
}
}
+
+Generated using TypeDoc
This type is used for "notifications", i.e. messages sent from the client to +the server that do not need a response. An example is the wallet announcing +it exists.
+(layer 3)
+ +//layer 3: JSON RPC
{jsonrpc : "2.0",
method : "connection.announcePresence",
// layer 4: AWCP-specific semantics
params : {id : "{aee9e933-52b6-410a-8c3f-99c6be596b4e}",
name : "Superhero",
networkId : "ae_mainnet",
origin : "moz-extension://ee425d81-d5b2-44b6-9406-4da31b019e7c",
type : "extension"}}
+
+Generated using TypeDoc
Shape of the waellet-to-aepp "connection.announcePresence" RPC cast
+(layer 3)
+ +{jsonrpc : "2.0",
method : "connection.announcePresence",
params : {id : "{aee9e933-52b6-410a-8c3f-99c6be596b4e}",
name : "Superhero",
networkId : "ae_mainnet",
origin : "moz-extension://ee425d81-d5b2-44b6-9406-4da31b019e7c",
type : "extension"}}
+
+Generated using TypeDoc
Error data inside the error field of a RpcResp_Err
(layer 3)
+ +{code : 4,
data : {},
message : "Operation rejected by user"}
+
+Optional data?: anyGenerated using TypeDoc
This is the shape of generic responses
+ +Successful response (RpcResp_ok)
+// layer 3: RPC
{jsonrpc : "2.0",
id : "ske-connect-1",
method : "connection.open",
// layer 4: AWCP-specific semantics
result : {id : "mnhmmkepfddpifjkamaligfeemcbhdne",
name : "Superhero",
networkId : "ae_mainnet",
origin : "chrome-extension://mnhmmkepfddpifjkamaligfeemcbhdne",
type : "extension"}}
+
+
+Unsuccessful response (RpcResp_error)
+// layer 3: RPC
{jsonrpc : "2.0",
id : "ske-address-1",
method : "address.subscribe",
// layer 4: AWCP semantics
error : {code : 4,
data : {},
message : "Operation rejected by user"}}
+
+Generated using TypeDoc
Most generic possible response
+ +Successful response (RpcResp_ok)
+// layer 3: RPC
{jsonrpc : "2.0",
id : "ske-connect-1",
method : "connection.open",
// layer 4: AWCP-specific semantics
result : {id : "mnhmmkepfddpifjkamaligfeemcbhdne",
name : "Superhero",
networkId : "ae_mainnet",
origin : "chrome-extension://mnhmmkepfddpifjkamaligfeemcbhdne",
type : "extension"}}
+
+
+Unsuccessful response (RpcResp_error)
+// layer 3: RPC
{jsonrpc : "2.0",
id : "ske-address-1",
method : "address.subscribe",
// layer 4: AWCP semantics
error : {code : 4,
data : {},
message : "Operation rejected by user"}}
+
+Generated using TypeDoc
Result of waellet-to-aepp "address.subscribe" response
+(layer 3)
+ +Case where the wallet only has one keypair
+{
"jsonrpc": "2.0",
"id": "ske-address-1",
"method": "address.subscribe",
"result": {
"subscription": [
"connected"
],
"address": {
"current": {
"ak_BMtPGuqDhWLnMVL4t6VFfS32y2hd8TSYwiYa2Z3VdmGzgNtJP": {}
},
"connected": {}
}
}
}
+
+
+Case of many keypairs
+{
"jsonrpc": "2.0",
"id": "ske-address-1",
"method": "address.subscribe",
"result": {
"subscription": [
"connected"
],
"address": {
"current": {
"ak_25C3xaAGQddyKAnaLLMjAhX24xMktH2NNZxY3fMaZQLMGED2Nf": {}
},
"connected": {
"ak_BMtPGuqDhWLnMVL4t6VFfS32y2hd8TSYwiYa2Z3VdmGzgNtJP": {},
"ak_25BqQuiVCasiqTkXHEffq7XCsuYEtgjNeZFeVFbuRtJkfC9NyX": {},
"ak_4p6gGoCcwQzLXd88KhdjRWYgd4MfTsaCeD8f99pzZhJ6vzYYV": {}
}
}
}
}
+
+Generated using TypeDoc
Shape of waellet-to-aepp "connection.open" RPC response
+(layer 3)
+ +{
"jsonrpc": "2.0",
"id": "ske-connect-1",
"method": "connection.open",
"result": {
"id": "mnhmmkepfddpifjkamaligfeemcbhdne",
"name": "Superhero",
"networkId": "ae_mainnet",
"origin": "chrome-extension://mnhmmkepfddpifjkamaligfeemcbhdne",
"type": "extension"
}
}
+
+Generated using TypeDoc
Response type for "message.sign"
+(layer 3)
+ +{
"jsonrpc": "2.0",
"id": "sk-msg-sign-1",
"method": "message.sign",
"result": {
"signature": "3ec195484965a60dd4179fbb616947a85e4e9961cb468816a2a22870382954bc374f8569e4ddc729dfc1b14e09e670b7d2c70c33c592caca29ff6c212f1f8b0f"
}
}
+
+Generated using TypeDoc
Response type for "transaction.sign" (do not propagate)
+(layer 3)
+ +{
"jsonrpc": "2.0",
"id": "sk-tx-sign-1",
"method": "transaction.sign",
"result": {
"signedTransaction": "tx_+KILAfhCuEDxWnvffMvyrkFWnrImYej38rh99vM9f6pORl/yWTvU97nvUcY8/ck8lgtPA8w5odGSDb9LGY/JSZXsmsXhgKkHuFr4WAwBoQG7Nu65aM7NHt5yM5jz67sd02TQqjFNBwIN6tkQsRD5RKEBe2bmwwUHCDbk6XkgUj3D6lnLv9hsWLoHA+qLzQq4p2wKhg8m9WHIAAABh2hhaW5hbmF7X54G"
}
}
+
+Generated using TypeDoc
Response type for "transaction.sign" (do propagate)
+(layer 3)
+ +{
"jsonrpc": "2.0",
"id": "sk-tx-sign-1",
"method": "transaction.sign",
"result": {
"signedTransaction": "tx_+KILAfhCuEDxWnvffMvyrkFWnrImYej38rh99vM9f6pORl/yWTvU97nvUcY8/ck8lgtPA8w5odGSDb9LGY/JSZXsmsXhgKkHuFr4WAwBoQG7Nu65aM7NHt5yM5jz67sd02TQqjFNBwIN6tkQsRD5RKEBe2bmwwUHCDbk6XkgUj3D6lnLv9hsWLoHA+qLzQq4p2wKhg8m9WHIAAABh2hhaW5hbmF7X54G"
}
}
+
+Generated using TypeDoc
This is the shape of unsuccessful responses
+ +From a page script, using sidekick, I asked for the user's address.
+Superhero popped up the little dialog thing asking if I wanted to connect,
+and I hit "deny". This is what was sent back. Code 4 corresponds to
+ERROR_CODE_RpcRejectedByUserError.
// layer 3: RPC
{jsonrpc : "2.0",
id : "ske-address-1",
method : "address.subscribe",
// layer 4: AWCP semantics
error : {code : 4,
data : {},
message : "Operation rejected by user"}}
+
+Generated using TypeDoc
This is the shape of successful responses
+ +// layer 3: RPC
{jsonrpc : "2.0",
id : "ske-connect-1",
method : "connection.open",
// layer 4: AWCP-specific semantics
result : {id : "mnhmmkepfddpifjkamaligfeemcbhdne",
name : "Superhero",
networkId : "ae_mainnet",
origin : "chrome-extension://mnhmmkepfddpifjkamaligfeemcbhdne",
type : "extension"}}
+
+Generated using TypeDoc
Const const ERROR_CODE_RpcBroadcastError = 3;
Generated using TypeDoc
Const This error occurs when the user rejects your attempt to connect. (I think)
+The error name here is ungrammatical but following the lead of the SDK.
+const ERROR_CODE_RpcConnectionDenyError = 9;
Generated using TypeDoc
Const This is the general "something went wrong, i dunno" negative error.
+const ERROR_CODE_RpcInternalError = 12;
Generated using TypeDoc
Const const ERROR_CODE_RpcInvalidTransactionError = 2;
Generated using TypeDoc
Const This is presumably the equivalent of the HTTP 404 error
+const ERROR_CODE_RpcMethodNotFoundError = -32601;
Generated using TypeDoc
Const This error occurs when you are not connected to the wallet.
+The error name here is ungrammatical but following the lead of the SDK.
+const ERROR_CODE_RpcNotAuthorizeError = 10;
Generated using TypeDoc
Const This error occurs when you are not address.subscribed to the wallet (I think?)
The error name here is ungrammatical but following the lead of the SDK.
+const ERROR_CODE_RpcPermissionDenyError = 11;
Generated using TypeDoc
Const const ERROR_CODE_RpcRejectedByUserError = 4;
Generated using TypeDoc
Const const ERROR_CODE_RpcUnsupportedProtocolError = 5;
Generated using TypeDoc
Internal Listens for connection.announcePresence messages
Generated using TypeDoc
does console.log
+Generated using TypeDoc
posts request to an HTTP server
+Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Get the user's address.
+ +// example positive return
{ok : true,
result : {subscription : ["connected"],
address : {current : {"ak_2XhCkjzTwcq1coXSSzHJoMZkUzTwnjH88zmPGkkowUsFNTo9UE": {}},
connected : {"ak_21HW2BeR8KQnzB76b9RSeNAXFf8SEvquLG3ichyLaXhdxUpXe9" : {},
"ak_Bd9rA8pDWucwfriVp6Zgb68csxanCzWDqstyoBKBbzUnNhpKQ" : {},
"ak_TuwioiZCt3Ajx9dgVS9qdnS9VW1t4GMWFML5zBPgzouZUGUDA" : {},
"ak_ywR1N7GDpj7djeEEEnHSTmYbQmxvWCvFgfsLpxdFpK1ptkZMU" : {}}}}}
// example negative return
{ok : false,
error : {code : 4,
data : {},
message : "Operation rejected by user"}}
+
+Generated using TypeDoc
Internal
+Block until lambda returns true or timeout
+timeout_ms should be divisible by 50
Generated using TypeDoc
construct a ConsoleLogger
Generated using TypeDoc
Connect to the wallet. This is a necessary step if you want address +to work. You must wait for Superhero to announce itself (see detect) before attempting to connect. This has the same return data as +detect. This does not pop up the confirmation dialog for the user. +Superhero never rejects the connection request. This call is instantaneous +in practice.
+ +// example calling code
await sk.connect('ske-connect-1', // message id, can be arbitrary string/number
{name: 'sidekick examples', // name can be any string
version: 1}, // version must be 1
// optional field networkId which is ae_uat or ae_mainnet
sk.TIMEOUT_DEF_CONNECT_MS, // timeout
"failed to connect to wallet", // timeout error message
sk.cl()); // logger
// example return data (positive case)
{ok : true,
result : {id : "{aee9e933-52b6-410a-8c3f-99c6be596b4e}",
name : "Superhero",
networkId : "ae_uat",
origin : "moz-extension://ee425d81-d5b2-44b6-9406-4da31b019e7c",
type : "extension"}}
// example return data (negative case)
{ok : false,
error : {code : 420,
message : "failed to detect wallet",
data : {}}}
+
+
+// example calling code
// from: https://github.com/aeternity/Vanillae/blob/0e030cb39554e9f09e4460d1da4e7654fe7456de/sidekick/examples/src/connection.ts#L68-L109
// document has a button with id=connect
// this is the function that is triggered when the button is clicked
// you want your user to do the detect sequence first
async function connect (logger: sk.Logger) : Promise<void> {
let h4 = document.getElementById("connected")!;
let pre = document.getElementById("connect-info")!;
h4.innerHTML = 'connecting...';
h4.style.color = 'GoldenRod';
// try to connect to the wallet
// will fail on timeout error
let maybe_wallet_info = await sk.connect(
'ske-connect-1',
{name: 'sidekick examples',
version: 1},
sk.TIMEOUT_DEF_CONNECT_MS,
"failed to connect to wallet",
logger
);
console.log(maybe_wallet_info);
// ok means wallet was connected
if (maybe_wallet_info.ok)
{
h4.innerHTML = "connected";
h4.style.color = "green";
pre.innerHTML = JSON.stringify(maybe_wallet_info.result, undefined, 4);
}
else
{
h4.innerHTML = "error";
h4.style.color = "crimson";
pre.innerHTML = JSON.stringify(maybe_wallet_info.error, undefined, 4);
}
}
let logger = sk.cl();
document.getElementById('connect')!.onclick = function() { connect(logger); };
+
+Generated using TypeDoc
This is the first step in connecting to the wallet. Before doing anything +else, you have to wait for the wallet to announce itself.
+This function waits for the wallet to announce itself
+Wait for wallet to announce itself, and then return.
+ +// example call
await sk.detect(sk.TIMEOUT_DEF_DETECT_MS, // timeout
"failed to detect wallet", // error on timeout
sk.cl()); // cl = console logger
// example return data (positive case)
{ok : true,
result : {id : "{aee9e933-52b6-410a-8c3f-99c6be596b4e}",
name : "Superhero",
networkId : "ae_uat",
origin : "moz-extension://ee425d81-d5b2-44b6-9406-4da31b019e7c",
type : "extension"}}
// example return data (negative case)
{ok : false,
error : {code : 420,
message : "failed to detect wallet",
data : {}}}
+
+
+// example calling code
// from: https://github.com/aeternity/Vanillae/blob/0e030cb39554e9f09e4460d1da4e7654fe7456de/sidekick/examples/src/connection.ts#L34-L66
// document has a button with id=detect
// this is the function that is triggered when the button is clicked
async function detect(logger: sk.Logger): Promise<void> {
let h4 = document.getElementById("detected")!;
let pre = document.getElementById("detect-info")!;
h4.innerHTML = 'detecting...';
h4.style.color = 'GoldenRod';
// try to detect the wallet
// will fail on timeout error
// console logger
let maybe_wallet_info =//: sk.Safe<awcp.EventData_W2A_connection_announcePresence, sk.TimeoutError> =
await sk.detect(sk.TIMEOUT_DEF_DETECT_MS, "failed to detect wallet", logger);
console.log(maybe_wallet_info);
// ok means wallet was detected
if (maybe_wallet_info.ok) {
h4.innerHTML = "detected";
h4.style.color = "green";
pre.innerHTML = JSON.stringify(maybe_wallet_info.result, undefined, 4);
}
else {
h4.innerHTML = "error";
h4.style.color = "crimson";
pre.innerHTML = JSON.stringify(maybe_wallet_info.error, undefined, 4);
}
}
// want to create a logger down here
let logger = sk.cl();
// detect button. The ! turns off a typescript warning, does not change the
// code behavior
document.getElementById('detect')!.onclick = function() { detect(logger); } ;
+
+Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Sign the given message, return the HASHED AND SALTED message signature +(see IMPORTANT CAVEAT section), encoded in hexadecimal
+ + +In order to exclude the possibility of someone using this functionality to +trick the user into signing a transaction, the wallet salts and hashes the +message, and then signs the salted/hashed message.
+Therefore, naively attempting to verify the signature will not work. You +must apply the same preprocessing steps as the wallet, THEN check the +signature against the salted/hashed message.
+-spec hashed_salted_msg(Message) -> HashedSaltedMessage
when Message :: binary(),
HashedSaltedMessage :: binary().
% @doc Salt the message then hash with blake2b. See:
% 1. https://github.com/aeternity/aepp-sdk-js/blob/370f1e30064ad0239ba59931908d9aba0a2e86b6/src/utils/crypto.ts#L83-L85
% 2. https://github.com/aeternity/eblake2/blob/60a079f00d72d1bfcc25de8e6996d28f912db3fd/src/eblake2.erl#L23-L25
hashed_salted_msg(Msg) ->
{ok, HSMsg} = eblake2:blake2b(32, salted_msg(Msg)),
HSMsg.
-spec salted_msg(Message) -> SaltedMessage
when Message :: binary(),
SaltedMessage :: binary().
% @doc Salt the message the way Superhero does before signing.
%
% See: https://github.com/aeternity/aepp-sdk-js/blob/370f1e30064ad0239ba59931908d9aba0a2e86b6/src/utils/crypto.ts#L171-L175
salted_msg(Msg) when is_binary(Msg) ->
P = <<"aeternity Signed Message:\n">>,
{ok, SP} = btc_varuint_encode(byte_size(P)),
{ok, SMsg} = btc_varuint_encode(byte_size(Msg)),
<<SP/binary,
P/binary,
SMsg/binary,
Msg/binary>>.
-spec btc_varuint_encode(Integer) -> Result
when Integer :: integer(),
Result :: {ok, Encoded :: binary()}
| {error, Reason :: term()}.
% @doc Bitcoin varuint encode
%
% See: https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer
btc_varuint_encode(N) when N < 0 ->
{error, {negative_N, N}};
btc_varuint_encode(N) when N < 16#FD ->
{ok, <<N>>};
btc_varuint_encode(N) when N =< 16#FFFF ->
NBytes = eu(N, 2),
{ok, <<16#FD, NBytes/binary>>};
btc_varuint_encode(N) when N =< 16#FFFF_FFFF ->
NBytes = eu(N, 4),
{ok, <<16#FE, NBytes/binary>>};
btc_varuint_encode(N) when N < (2 bsl 64) ->
NBytes = eu(N, 8),
{ok, <<16#FF, NBytes/binary>>}.
% eu = encode unsigned (little endian with a given byte width)
% means add zero bytes to the end as needed
eu(N, Size) ->
Bytes = binary:encode_unsigned(N, little),
NExtraZeros = Size - byte_size(Bytes),
ExtraZeros = << <<0>> || _ <- lists:seq(1, NExtraZeros) >>,
<<Bytes/binary, ExtraZeros/binary>>.
+
+
+This function is triggered when a "sign message" button is pressed. A text
+input with id="message-text" contains the message to be signed.
async function sign_msg (logger: sk.Logger) : Promise<void> {
let acc_pubkey : string = pv_address;
// @ts-ignore value property exists because i say so
let msg_text : string = document.getElementById('message-text').value;
let signed_msg = await sk.msg_sign('sk-msg-sign-1', acc_pubkey, msg_text, sk.TIMEOUT_DEF_MSG_SIGN_MS, 'message signing took too long', logger);
console.log('signed message:', signed_msg);
}
+
+Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Internal
+Stack overflow: https://stackoverflow.com/questions/951021/what-is-the-javascript-version-of-sleep
+No fucking idea what's going on here
+Some crazy async hack bullshit
+It works, who cares
+Generated using TypeDoc
Ask the wallet to sign the transaction but do not propagate the transaction, +instead just return the signed data
+Generated using TypeDoc
Ask the wallet to sign the transaction and propagate it into the network
+Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Click "sidekick" in the sidebar or hamburger menu
+Generated using TypeDoc
Callbacks you need to implement if you want logging
+Generated using TypeDoc
Generated using TypeDoc
Suppose you are the aepp and you want to communicate with a waellet. What
+you do is pick an EventTarget (typically window), and listen to its
+MessageEvents, via something like
window.addEventListener('message', my_listener);
+
+You then communicate with the wallet by sending messages back over the
+EventTarget. You should probably use the sidekick
+library to do
+this.
Keep in mind that these messages are not secret. Any browser extension or +foreign page script can intercept these messages. Imagine as an (imperfect) +analogy that you work in an office. Everyone's mail is dumped on the floor +in the middle of the office, and you are responsible for picking out which +letters are addressed to you. Anyone else can pick up letters addressed to +you, and read them.
+This module defines the shape of the messages that are sent. There are several +layers to the onion, each corresponding to natural branch points in the +protocol.
+ +// this is a aepp-to-wallet call which is sent to `window` by say sidekick
// layer 2 layer 3 layer 4
// EventData_A2W<RpcCall<"connection.open", Params_A2W_connection_open>>)
// layer 2: who is the message for
{type : "to_waellet",
// layer 3: json rpc
data : {jsonrpc : "2.0",
id : "ske-connect-1",
method : "connection.open",
// layer 4: AWCP-specific semantics
params : {name : "sidekick examples",
version : 1}}}
// this is the associated wallet-to-aepp response which is sent to `window`
// by Superhero
// layer 2 layer 3 layer 4
// EventData_W2A<RpcResp_ok<"connection.open", Result_W2A_connection_open>>)
// layer 2: who is the message for
{type : "to_aepp",
// layer 3: json rpc
data : {jsonrpc : "2.0",
id : "ske-connect-1",
method : "connection.open",
// layer 4: AWCP-specific semantics
result : {id : "mnhmmkepfddpifjkamaligfeemcbhdne",
name : "Superhero",
networkId : "ae_mainnet",
origin : "chrome-extension://mnhmmkepfddpifjkamaligfeemcbhdne",
type : "extension"}}}
+
+
+// this is a waellet-to-aepp cast (RPC verbiage: "notification"). It does
// not require a response.
// layer 2 layer 3 layer 4
// EventData_W2A<RpcCast<"connection.announcePresence", Params_W2A_connection_announcePresence>>)
// layer 2: who is the message for
{type : "to_aepp",
// layer 3: json rpc
data : {jsonrpc : "2.0",
method : "connection.announcePresence",
// layer 4: AWCP-specific semantics
params : {id : "{aee9e933-52b6-410a-8c3f-99c6be596b4e}",
name : "Superhero",
networkId : "ae_mainnet",
origin : "moz-extension://ee425d81-d5b2-44b6-9406-4da31b019e7c",
type : "extension"}}}
+
+The MessageEvent layer. This is what is actually sent as an event.
+This is an opaque object that is built into every runtime's standard
+library: https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent
The MessageEvent has a field called data, which corresponds to the
+next layer.
The EventData layer. This is what goes in message_event.data. The
+structure that goes in here is one of
This layer corresponds to the "am I supposed to pay attention to this +event?" branch point.
+Those data structures mentioned above have two fields.
+type is a string which is either "to_aepp" or "to_waellet"data contains the next layertype EventData_W2A
<t extends any>
= {type : "to_aepp",
data : t};
+
+type EventData_A2W
<t extends any>
= {type : "to_waellet",
data : t};
+
+We're at message_event.data.data. The idiom here is "JSON RPC", which
+is sort of a poor man's HTTP.
In general, the wallet is the server and the aepp is the client.
+If you are the aepp, usually you are handling a response to a request +you sent to the waellet. For instance, you formed a transaction and +sent it to the waellet to sign, and the waellet is sending you back +either the signed transaction or an error (e.g. user rejected the +transaction).
+The exception to this pattern is the wallet notifying you that it +exists, which is the only time the waellet sends a request (a "cast", or +a "notification") to the aepp. In no event does the aepp send a +response to the waellet.
+I am not 100% sure what RPC stands for, but it will be helpful to think +about it as "remote procedure call". More below. This layer roughly +corresponds to the "given that I am supposed to pay attention to this +event, what am I supposed to do with this information?"
+All requests have a method field (a string) and a params field (an
+object). There are two types of requests:
"casts" (the RPC standard calls these "notifications"). These do not +need a response. This is only used for the waellet announcing it +exists.
+"calls". These have an id field, and get a response. These are
+used when the aepp is requesting the waellet to do something. The
+response will have the same id field and the same method field.
So far nothing we've talked about is specific to Aeternity, Vanillae, +JR, or sidekick. This fourth layer is the actual semantics of the +messaging protocol between the aepp and the waellet.
+By analogy, the first two layers are developing something like TCP. The +third layer is developing HTTP. And this layer is the actual routing +table of your website, which carries with it the expected semantics of +how the website is supposed to behave.
+This module DOES NOT exhaustively define all of the communication +protocol that occurs in the SDK, only the subset that I have encountered +in practice.
+The first layer is defined by the runtime, not here. So we're starting with +layer 2.
+ + +I have subtly changed the RPC protocol to
+The only difference here is that the params field of requests is
+non-optional, and must be an object (the RPC standard allows arrays).
I have adapted the verbiage here, borrowing from Erlang, to make a +distinction between
+casts (RPC calls these "notifications"): these
+id fieldcalls: these
+id fieldThe RpcCall and RpcResp data structures each have an id_n
+type parameter.
The purpose of this is to notate (and possibly enforce) at the type level
+the constraint that, given a call with say id = 7, the response must also
+have id = 7.
MessageEvents: https://developer.mozilla.org/en-US/docs/Web/API/MessageEventGenerated using TypeDoc
From there you can do one of two things
+Forming the transactions and propagating them into the network is your +problem.
+You need a Logger for most calls. Probably you want cl. You +can write your own if you want but why would you complicate your life like +that.
+Generated using TypeDoc
This is the data that is sent from the aepp to the wallet through the Event +bus
+ +// layer 2: who is the message for
{type : "to_waellet",
// layer 3: json rpc
data : {jsonrpc : "2.0",
id : "ske-connect-1",
method : "connection.open",
// layer 4: AWCP-specific semantics
params : {name : "sidekick examples",
version : 1}}}
+
+Generated using TypeDoc
Actual aepp-to-waellet "address.subscribe" event data sent over the message bus
+(layer 2)
+ +{
"type": "to_waellet",
"data": {
"jsonrpc": "2.0",
"id": "ske-address-1",
"method": "address.subscribe",
"params": {
"type": "subscribe",
"value": "connected"
}
}
}
+
+Generated using TypeDoc
The actual aepp-to-waellet "connection.open" event data passed over the message bus
+(layer 2)
+ +{
"type": "to_waellet",
"data": {
"jsonrpc": "2.0",
"id": "ske-connect-1",
"method": "connection.open",
"params": {
"name": "sidekick examples",
"version": 1
}
}
}
+
+Generated using TypeDoc
Event data for aepp-to-waellet "message.sign"
+(layer 2)
+ +{
"type": "to_waellet",
"data": {
"jsonrpc": "2.0",
"id": "sk-msg-sign-1",
"method": "message.sign",
"params": {
"onAccount": "ak_2RT9RPbcX8RtjBpMWqsKtVRVKASAbj8V4c3f7cCdJfuVdihhyL",
"message": "MESSSSSSSSSSAGGGGGGGGGGGGGGGGGGGGGGGGGGGE"
}
}
}
+
+Generated using TypeDoc
Event data for aepp-to-waellet "transaction.sign" (do not propagate) message
+(layer 2)
+ +{
"type": "to_waellet",
"data": {
"jsonrpc": "2.0",
"id": "sk-tx-sign-1",
"method": "transaction.sign",
"params": {
"tx": "tx_+FgMAaEBuzbuuWjOzR7ecjOY8+u7HdNk0KoxTQcCDerZELEQ+UShAXtm5sMFBwg25Ol5IFI9w+pZy7/YbFi6BwPqi80KuKdsCoYPJvVhyAAAAYdoYWluYW5h9uAnNQ==",
"returnSigned": true,
"networkId": "ae_uat"
}
}
}
+
+Generated using TypeDoc
Event data for aepp-to-waellet "transaction.sign" (do propagate) message
+(layer 2)
+ +{
"type": "to_waellet",
"data": {
"jsonrpc": "2.0",
"id": "sk-tx-sign-1",
"method": "transaction.sign",
"params": {
"tx": "tx_+FgMAaEBuzbuuWjOzR7ecjOY8+u7HdNk0KoxTQcCDerZELEQ+UShAXtm5sMFBwg25Ol5IFI9w+pZy7/YbFi6BwPqi80KuKdsCoYPJvVhyAAAAYdoYWluYW5h9uAnNQ==",
"returnSigned": false,
"networkId": "ae_uat"
}
}
}
+
+Generated using TypeDoc
This is the data that is sent from the wallet to the aepp through the Event +bus
+(layer 2)
+ +// layer 2: who is the message for
{type : "to_aepp",
// layer 3: JSON RPC
data : {jsonrpc : "2.0",
method : "connection.announcePresence",
// layer 4: AWCP-specific semantics
params : {id : "{aee9e933-52b6-410a-8c3f-99c6be596b4e}",
name : "Superhero",
networkId : "ae_mainnet",
origin : "moz-extension://ee425d81-d5b2-44b6-9406-4da31b019e7c",
type : "extension"}}}
+
+Generated using TypeDoc
Actual waellet-to-aepp "address.subscribe" event data sent over the message bus
+(layer 2)
+ +This is the case where the wallet only has one keypair:
+{
"type": "to_aepp",
"data": {
"jsonrpc": "2.0",
"id": "ske-address-1",
"method": "address.subscribe",
"result": {
"subscription": [
"connected"
],
"address": {
"current": {
"ak_BMtPGuqDhWLnMVL4t6VFfS32y2hd8TSYwiYa2Z3VdmGzgNtJP": {}
},
"connected": {}
}
}
}
}
+
+
+Case of many keypairs, the current one will be in current.
{
"type": "to_aepp",
"data": {
"jsonrpc": "2.0",
"id": "ske-address-1",
"method": "address.subscribe",
"result": {
"subscription": [
"connected"
],
"address": {
"current": {
"ak_2RT9RPbcX8RtjBpMWqsKtVRVKASAbj8V4c3f7cCdJfuVdihhyL": {}
},
"connected": {
"ak_sMM2sUiyeBeMiRAj8viHVCVDxevmCacALhoHdrkobyhoqnR85": {},
"ak_o355SAx4n1V6xbrYv4Zaxm7GAYaZwEFXwgKBVEQTSm8MPnwjn": {},
"ak_2Up7dDMVBbPc4xAequf41zyzBqwWpUcVTYvcGF1ApAcCy7nGfA": {}
}
}
}
}
}
+
+Generated using TypeDoc
The actual waellet-to-aepp event passed when the wallet announces it exists
+(layer 2)
+ +{type: "to_aepp",
data: {jsonrpc: "2.0",
method: "connection.announcePresence",
params: {id : "{aee9e933-52b6-410a-8c3f-99c6be596b4e}",
name : "Superhero",
networkId : "ae_mainnet",
origin : "moz-extension://ee425d81-d5b2-44b6-9406-4da31b019e7c",
type : "extension"}}}
+
+Generated using TypeDoc
The actual waellet-to-aepp "connection.open" event data passed over the message bus
+(layer 2)
+ +{
"type": "to_aepp",
"data": {
"jsonrpc": "2.0",
"id": "ske-connect-1",
"method": "connection.open",
"result": {
"id": "mnhmmkepfddpifjkamaligfeemcbhdne",
"name": "Superhero",
"networkId": "ae_mainnet",
"origin": "chrome-extension://mnhmmkepfddpifjkamaligfeemcbhdne",
"type": "extension"
}
}
}
+
+Generated using TypeDoc
Event data for waellet-to-aepp "message.sign"
+(layer 2)
+ +{
"type": "to_aepp",
"data": {
"jsonrpc": "2.0",
"id": "sk-msg-sign-1",
"method": "message.sign",
"result": {
"signature": "3ec195484965a60dd4179fbb616947a85e4e9961cb468816a2a22870382954bc374f8569e4ddc729dfc1b14e09e670b7d2c70c33c592caca29ff6c212f1f8b0f"
}
}
}
+
+Generated using TypeDoc
Event data for waellet-to-aepp "transaction.sign" (do not propagate) response
+(layer 2)
+ +{
"type": "to_aepp",
"data": {
"jsonrpc": "2.0",
"id": "sk-tx-sign-1",
"method": "transaction.sign",
"result": {
"signedTransaction": "tx_+KILAfhCuEDxWnvffMvyrkFWnrImYej38rh99vM9f6pORl/yWTvU97nvUcY8/ck8lgtPA8w5odGSDb9LGY/JSZXsmsXhgKkHuFr4WAwBoQG7Nu65aM7NHt5yM5jz67sd02TQqjFNBwIN6tkQsRD5RKEBe2bmwwUHCDbk6XkgUj3D6lnLv9hsWLoHA+qLzQq4p2wKhg8m9WHIAAABh2hhaW5hbmF7X54G"
}
}
}
+
+Generated using TypeDoc
Event data for waellet-to-aepp "transaction.sign" (do propagate) response
+(layer 2)
+ +{
"type": "to_aepp",
"data": {
"jsonrpc": "2.0",
"id": "sk-tx-sign-1",
"method": "transaction.sign",
"result": {
"signedTransaction": "tx_+KILAfhCuEDxWnvffMvyrkFWnrImYej38rh99vM9f6pORl/yWTvU97nvUcY8/ck8lgtPA8w5odGSDb9LGY/JSZXsmsXhgKkHuFr4WAwBoQG7Nu65aM7NHt5yM5jz67sd02TQqjFNBwIN6tkQsRD5RKEBe2bmwwUHCDbk6XkgUj3D6lnLv9hsWLoHA+qLzQq4p2wKhg8m9WHIAAABh2hhaW5hbmF7X54G"
}
}
}
+
+Generated using TypeDoc
Parameter type of aepp-to-waellet "address.subscribe" call
+(layer 4)
+ +{
"type": "subscribe",
"value": "connected"
}
+
+Generated using TypeDoc
Parameters of aepp-to-waellet "connection.open" call
+(layer 4)
+ +{name : "sidekick examples",
version : 1}
+
+Optional networkGenerated using TypeDoc
Parameters for "message.sign"
+(layer 4)
+ +{
"onAccount": "ak_2RT9RPbcX8RtjBpMWqsKtVRVKASAbj8V4c3f7cCdJfuVdihhyL",
"message": "MESSSSSSSSSSAGGGGGGGGGGGGGGGGGGGGGGGGGGGE"
}
+
+Generated using TypeDoc
Parameters for "transaction.sign" (do not propagate)
+If returnSigned is false, then Superhero will propagate the transaction.
(layer 4)
+ +{
"tx": "tx_+FgMAaEBuzbuuWjOzR7ecjOY8+u7HdNk0KoxTQcCDerZELEQ+UShAXtm5sMFBwg25Ol5IFI9w+pZy7/YbFi6BwPqi80KuKdsCoYPJvVhyAAAAYdoYWluYW5h9uAnNQ==",
"returnSigned": true,
"networkId": "ae_uat"
}
+
+Generated using TypeDoc
Parameters for "transaction.sign" (do propagate)
+If returnSigned is false, then Superhero will propagate the transaction.
(layer 4)
+ +{
"tx": "tx_+FgMAaEBuzbuuWjOzR7ecjOY8+u7HdNk0KoxTQcCDerZELEQ+UShAXtm5sMFBwg25Ol5IFI9w+pZy7/YbFi6BwPqi80KuKdsCoYPJvVhyAAAAYdoYWluYW5h9uAnNQ==",
"returnSigned": false,
"networkId": "ae_uat"
}
+
+Generated using TypeDoc
Waellet-to-aepp parameters of "connection.announcePresence" cast
+(layer 4)
+ +{id : "{aee9e933-52b6-410a-8c3f-99c6be596b4e}",
name : "Superhero",
networkId : "ae_uat",
origin : "moz-extension://ee425d81-d5b2-44b6-9406-4da31b019e7c",
type : "extension"}
+
+Generated using TypeDoc
Result type of waellet-to-aepp "address.subscribe response
+(layer 4)
+ +This is if the user only has a single keypair
+{subscription : ["connected"],
address : {current : {"ak_2Wsa8iAmAm917evwDEZjouvPUXKx2nUv5Uz8e8oNXTDfDXnMRN": {}},
connected : {}}}
+
+
+This is if the user has many keypairs. The currently selected one is under
+current. Craig, I agree this is stupid, but that's how it works.
{
"subscription": [
"connected"
],
"address": {
"current": {
"ak_25C3xaAGQddyKAnaLLMjAhX24xMktH2NNZxY3fMaZQLMGED2Nf": {}
},
"connected": {
"ak_BMtPGuqDhWLnMVL4t6VFfS32y2hd8TSYwiYa2Z3VdmGzgNtJP": {},
"ak_25BqQuiVCasiqTkXHEffq7XCsuYEtgjNeZFeVFbuRtJkfC9NyX": {},
"ak_4p6gGoCcwQzLXd88KhdjRWYgd4MfTsaCeD8f99pzZhJ6vzYYV": {}
}
}
}
+
+Generated using TypeDoc
Result type of "connection.open" call
+Same as Params_W2A_connection_announcePresence empirically
+(layer 4)
+ +{id : "{aee9e933-52b6-410a-8c3f-99c6be596b4e}",
name : "Superhero",
networkId : "ae_uat",
origin : "moz-extension://ee425d81-d5b2-44b6-9406-4da31b019e7c",
type : "extension"}
+
+Generated using TypeDoc
Success result type for "message.sign"
+(layer 4)
+ +{
"signature": "3ec195484965a60dd4179fbb616947a85e4e9961cb468816a2a22870382954bc374f8569e4ddc729dfc1b14e09e670b7d2c70c33c592caca29ff6c212f1f8b0f"
}
+
+Generated using TypeDoc
Success result type for "transaction.sign" (do not propagate)
+(layer 4)
+ +{
* "signedTransaction": "tx_+KILAfhCuEDxWnvffMvyrkFWnrImYej38rh99vM9f6pORl/yWTvU97nvUcY8/ck8lgtPA8w5odGSDb9LGY/JSZXsmsXhgKkHuFr4WAwBoQG7Nu65aM7NHt5yM5jz67sd02TQqjFNBwIN6tkQsRD5RKEBe2bmwwUHCDbk6XkgUj3D6lnLv9hsWLoHA+qLzQq4p2wKhg8m9WHIAAABh2hhaW5hbmF7X54G"
* }
+
+Generated using TypeDoc
Success result type for "transaction.sign" (do propagate)
+(layer 4)
+ +{
* "signedTransaction": "tx_+KILAfhCuEDxWnvffMvyrkFWnrImYej38rh99vM9f6pORl/yWTvU97nvUcY8/ck8lgtPA8w5odGSDb9LGY/JSZXsmsXhgKkHuFr4WAwBoQG7Nu65aM7NHt5yM5jz67sd02TQqjFNBwIN6tkQsRD5RKEBe2bmwwUHCDbk6XkgUj3D6lnLv9hsWLoHA+qLzQq4p2wKhg8m9WHIAAABh2hhaW5hbmF7X54G"
* }
+
+Generated using TypeDoc
This type is used for requests from the client to the server that require a +response.
+(layer 3)
+ +// layer 3: json rpc
{jsonrpc : "2.0",
id : "ske-connect-1",
method : "connection.open",
// layer 4: AWCP-specific semantics
params : {name : "sidekick examples",
version : 1}}}
+
+Generated using TypeDoc
Shape of aepp-to-waellet "address.subscribe" RPC call
+(layer 3)
+ +{
"jsonrpc": "2.0",
"id": "ske-address-1",
"method": "address.subscribe",
"params": {
"type": "subscribe",
"value": "connected"
}
}
+
+Generated using TypeDoc
Shape of aepp-to-waellet "connection.open" RPC call
+(layer 3)
+ +// layer 3: json rpc
{jsonrpc : "2.0",
id : "ske-connect-1",
method : "connection.open",
// layer 4: AWCP-specific semantics
params : {name : "sidekick examples",
version : 1}}}
+
+Generated using TypeDoc
Request type for "message.sign"
+(layer 3)
+ +{
"jsonrpc": "2.0",
"id": "sk-msg-sign-1",
"method": "message.sign",
"params": {
"onAccount": "ak_2RT9RPbcX8RtjBpMWqsKtVRVKASAbj8V4c3f7cCdJfuVdihhyL",
"message": "MESSSSSSSSSSAGGGGGGGGGGGGGGGGGGGGGGGGGGGE"
}
}
+
+Generated using TypeDoc
Request type for "transaction.sign" (do not propagate)
+(layer 3)
+ +{
"jsonrpc": "2.0",
"id": "sk-tx-sign-1",
"method": "transaction.sign",
"params": {
"tx": "tx_+FgMAaEBuzbuuWjOzR7ecjOY8+u7HdNk0KoxTQcCDerZELEQ+UShAXtm5sMFBwg25Ol5IFI9w+pZy7/YbFi6BwPqi80KuKdsCoYPJvVhyAAAAYdoYWluYW5h9uAnNQ==",
"returnSigned": true,
"networkId": "ae_uat"
}
}
+
+Generated using TypeDoc
Request type for "transaction.sign" (do propagate)
+(layer 3)
+ +{
"jsonrpc": "2.0",
"id": "sk-tx-sign-1",
"method": "transaction.sign",
"params": {
"tx": "tx_+FgMAaEBuzbuuWjOzR7ecjOY8+u7HdNk0KoxTQcCDerZELEQ+UShAXtm5sMFBwg25Ol5IFI9w+pZy7/YbFi6BwPqi80KuKdsCoYPJvVhyAAAAYdoYWluYW5h9uAnNQ==",
"returnSigned": true,
"networkId": "ae_uat"
}
}
+
+Generated using TypeDoc
This type is used for "notifications", i.e. messages sent from the client to +the server that do not need a response. An example is the wallet announcing +it exists.
+(layer 3)
+ +//layer 3: JSON RPC
{jsonrpc : "2.0",
method : "connection.announcePresence",
// layer 4: AWCP-specific semantics
params : {id : "{aee9e933-52b6-410a-8c3f-99c6be596b4e}",
name : "Superhero",
networkId : "ae_mainnet",
origin : "moz-extension://ee425d81-d5b2-44b6-9406-4da31b019e7c",
type : "extension"}}
+
+Generated using TypeDoc
Shape of the waellet-to-aepp "connection.announcePresence" RPC cast
+(layer 3)
+ +{jsonrpc : "2.0",
method : "connection.announcePresence",
params : {id : "{aee9e933-52b6-410a-8c3f-99c6be596b4e}",
name : "Superhero",
networkId : "ae_mainnet",
origin : "moz-extension://ee425d81-d5b2-44b6-9406-4da31b019e7c",
type : "extension"}}
+
+Generated using TypeDoc
Error data inside the error field of a RpcResp_Err
(layer 3)
+ +{code : 4,
data : {},
message : "Operation rejected by user"}
+
+Optional data?: anyGenerated using TypeDoc
This is the shape of generic responses
+ +Successful response (RpcResp_ok)
+// layer 3: RPC
{jsonrpc : "2.0",
id : "ske-connect-1",
method : "connection.open",
// layer 4: AWCP-specific semantics
result : {id : "mnhmmkepfddpifjkamaligfeemcbhdne",
name : "Superhero",
networkId : "ae_mainnet",
origin : "chrome-extension://mnhmmkepfddpifjkamaligfeemcbhdne",
type : "extension"}}
+
+
+Unsuccessful response (RpcResp_error)
+// layer 3: RPC
{jsonrpc : "2.0",
id : "ske-address-1",
method : "address.subscribe",
// layer 4: AWCP semantics
error : {code : 4,
data : {},
message : "Operation rejected by user"}}
+
+Generated using TypeDoc
Most generic possible response
+ +Successful response (RpcResp_ok)
+// layer 3: RPC
{jsonrpc : "2.0",
id : "ske-connect-1",
method : "connection.open",
// layer 4: AWCP-specific semantics
result : {id : "mnhmmkepfddpifjkamaligfeemcbhdne",
name : "Superhero",
networkId : "ae_mainnet",
origin : "chrome-extension://mnhmmkepfddpifjkamaligfeemcbhdne",
type : "extension"}}
+
+
+Unsuccessful response (RpcResp_error)
+// layer 3: RPC
{jsonrpc : "2.0",
id : "ske-address-1",
method : "address.subscribe",
// layer 4: AWCP semantics
error : {code : 4,
data : {},
message : "Operation rejected by user"}}
+
+Generated using TypeDoc
Result of waellet-to-aepp "address.subscribe" response
+(layer 3)
+ +Case where the wallet only has one keypair
+{
"jsonrpc": "2.0",
"id": "ske-address-1",
"method": "address.subscribe",
"result": {
"subscription": [
"connected"
],
"address": {
"current": {
"ak_BMtPGuqDhWLnMVL4t6VFfS32y2hd8TSYwiYa2Z3VdmGzgNtJP": {}
},
"connected": {}
}
}
}
+
+
+Case of many keypairs
+{
"jsonrpc": "2.0",
"id": "ske-address-1",
"method": "address.subscribe",
"result": {
"subscription": [
"connected"
],
"address": {
"current": {
"ak_25C3xaAGQddyKAnaLLMjAhX24xMktH2NNZxY3fMaZQLMGED2Nf": {}
},
"connected": {
"ak_BMtPGuqDhWLnMVL4t6VFfS32y2hd8TSYwiYa2Z3VdmGzgNtJP": {},
"ak_25BqQuiVCasiqTkXHEffq7XCsuYEtgjNeZFeVFbuRtJkfC9NyX": {},
"ak_4p6gGoCcwQzLXd88KhdjRWYgd4MfTsaCeD8f99pzZhJ6vzYYV": {}
}
}
}
}
+
+Generated using TypeDoc
Shape of waellet-to-aepp "connection.open" RPC response
+(layer 3)
+ +{
"jsonrpc": "2.0",
"id": "ske-connect-1",
"method": "connection.open",
"result": {
"id": "mnhmmkepfddpifjkamaligfeemcbhdne",
"name": "Superhero",
"networkId": "ae_mainnet",
"origin": "chrome-extension://mnhmmkepfddpifjkamaligfeemcbhdne",
"type": "extension"
}
}
+
+Generated using TypeDoc
Response type for "message.sign"
+(layer 3)
+ +{
"jsonrpc": "2.0",
"id": "sk-msg-sign-1",
"method": "message.sign",
"result": {
"signature": "3ec195484965a60dd4179fbb616947a85e4e9961cb468816a2a22870382954bc374f8569e4ddc729dfc1b14e09e670b7d2c70c33c592caca29ff6c212f1f8b0f"
}
}
+
+Generated using TypeDoc
Response type for "transaction.sign" (do not propagate)
+(layer 3)
+ +{
"jsonrpc": "2.0",
"id": "sk-tx-sign-1",
"method": "transaction.sign",
"result": {
"signedTransaction": "tx_+KILAfhCuEDxWnvffMvyrkFWnrImYej38rh99vM9f6pORl/yWTvU97nvUcY8/ck8lgtPA8w5odGSDb9LGY/JSZXsmsXhgKkHuFr4WAwBoQG7Nu65aM7NHt5yM5jz67sd02TQqjFNBwIN6tkQsRD5RKEBe2bmwwUHCDbk6XkgUj3D6lnLv9hsWLoHA+qLzQq4p2wKhg8m9WHIAAABh2hhaW5hbmF7X54G"
}
}
+
+Generated using TypeDoc
Response type for "transaction.sign" (do propagate)
+(layer 3)
+ +{
"jsonrpc": "2.0",
"id": "sk-tx-sign-1",
"method": "transaction.sign",
"result": {
"signedTransaction": "tx_+KILAfhCuEDxWnvffMvyrkFWnrImYej38rh99vM9f6pORl/yWTvU97nvUcY8/ck8lgtPA8w5odGSDb9LGY/JSZXsmsXhgKkHuFr4WAwBoQG7Nu65aM7NHt5yM5jz67sd02TQqjFNBwIN6tkQsRD5RKEBe2bmwwUHCDbk6XkgUj3D6lnLv9hsWLoHA+qLzQq4p2wKhg8m9WHIAAABh2hhaW5hbmF7X54G"
}
}
+
+Generated using TypeDoc
This is the shape of unsuccessful responses
+ +From a page script, using sidekick, I asked for the user's address.
+Superhero popped up the little dialog thing asking if I wanted to connect,
+and I hit "deny". This is what was sent back. Code 4 corresponds to
+ERROR_CODE_RpcRejectedByUserError.
// layer 3: RPC
{jsonrpc : "2.0",
id : "ske-address-1",
method : "address.subscribe",
// layer 4: AWCP semantics
error : {code : 4,
data : {},
message : "Operation rejected by user"}}
+
+Generated using TypeDoc
This is the shape of successful responses
+ +// layer 3: RPC
{jsonrpc : "2.0",
id : "ske-connect-1",
method : "connection.open",
// layer 4: AWCP-specific semantics
result : {id : "mnhmmkepfddpifjkamaligfeemcbhdne",
name : "Superhero",
networkId : "ae_mainnet",
origin : "chrome-extension://mnhmmkepfddpifjkamaligfeemcbhdne",
type : "extension"}}
+
+Generated using TypeDoc
See Safe for context
+ +{
"ok": false,
"error": {
"code": 4,
"data": {},
"message": "Operation rejected by user"
}
}
+
+Generated using TypeDoc
See Safe for context
+ +{
"ok": true,
"result": {
"type": "to_aepp",
"data": {
"jsonrpc": "2.0",
"id": "sk-msg-sign-1",
"method": "message.sign",
"result": {
"signature": "3ec195484965a60dd4179fbb616947a85e4e9961cb468816a2a22870382954bc374f8569e4ddc729dfc1b14e09e670b7d2c70c33c592caca29ff6c212f1f8b0f"
}
}
}
}
+
+Generated using TypeDoc
The idea behind this type is that some errors are known to be likely (e.g. +the user rejects a transaction request, or something times out, etc). These +errors (called "positive errors") should not generate exceptions. Exceptions +should occur when exceptional behavior occurs (e.g. hardware faults, +dividing by zero). Exceptions should not occur on events that are known to +be likely. Instead, branching is the correct idiom.
+Furthermore, there are often many possible sources of errors. What this +provides is a single "did it work or not" branch point.
+Further, in practice, all errors (either SkTimeoutError or awcp.RpcError) have a field called code which uniquely identifies the
+error, so it's easy to algorithmically respond to specific positive errors.
+For instance, if the user rejects a request in a popup, that is code: 4
+(see awcp.ERROR_CODE_RpcRejectedByUserError). If the user does not
+do anything within the timeout parameter you specify, that generates a
+SkTimeoutError which has code: 420.
There are two branches: Ok and Error
+type Ok<ok_t>
= {ok : true,
result : ok_t};
type Error<err_t>
= {ok : false,
error : err_t};
type Safe<ok_t, err_t>
= Ok<ok_t>
| Error<err_t>;
+
+
+Suppose you are trying to get the user's address. This pops up a +confirmation dialog asking the user if he wants to connect to your +application. There's a good chance the user says no. There's also a +possibility he just doesn't do anything and things just time out.
+// there is a button in the document that when pressed triggers this function
async function address(logger: sk.Logger): Promise<void>
{
let h4 = document.getElementById("addressed")!;
let pre = document.getElementById("address-info")!;
h4.innerHTML = 'addressing...';
h4.style.color = 'GoldenRod';
// try to address to the wallet
// will fail on timeout error
let maybe_wallet_info = await sk.address(
'ske-address-1',
{type: 'subscribe',
value: 'connected'},
sk.TIMEOUT_DEF_ADDRESS_MS,
"failed to address to wallet",
logger
);
console.log(maybe_wallet_info);
// ok means wallet was addressed
if (maybe_wallet_info.ok)
{
h4.innerHTML = "addressed";
h4.style.color = "green";
pre.innerHTML = JSON.stringify(maybe_wallet_info.result, undefined, 4);
// update global variable
let the_address = Object.keys(maybe_wallet_info.result.address.current)[0];
set_pv_address(the_address);
}
else
{
h4.innerHTML = "error";
h4.style.color = "crimson";
pre.innerHTML = JSON.stringify(maybe_wallet_info.error, undefined, 4);
}
}
+
+The important part is the if/else. That branch point corresponds to "did
+it work or not?" The else branch corresponds to the subset of "not" that
+you know is likely: timeouts, rejections, etc.
Generated using TypeDoc
Timeout Error
+Generated using TypeDoc
Const const ERROR_CODE_RpcBroadcastError = 3;
Generated using TypeDoc
Const This error occurs when the user rejects your attempt to connect. (I think)
+The error name here is ungrammatical but following the lead of the SDK.
+const ERROR_CODE_RpcConnectionDenyError = 9;
Generated using TypeDoc
Const This is the general "something went wrong, i dunno" negative error.
+const ERROR_CODE_RpcInternalError = 12;
Generated using TypeDoc
Const const ERROR_CODE_RpcInvalidTransactionError = 2;
Generated using TypeDoc
Const This is presumably the equivalent of the HTTP 404 error
+const ERROR_CODE_RpcMethodNotFoundError = -32601;
Generated using TypeDoc
Const This error occurs when you are not connected to the wallet.
+The error name here is ungrammatical but following the lead of the SDK.
+const ERROR_CODE_RpcNotAuthorizeError = 10;
Generated using TypeDoc
Const This error occurs when you are not address.subscribed to the wallet (I think?)
The error name here is ungrammatical but following the lead of the SDK.
+const ERROR_CODE_RpcPermissionDenyError = 11;
Generated using TypeDoc
Const const ERROR_CODE_RpcRejectedByUserError = 4;
Generated using TypeDoc
Const const ERROR_CODE_RpcUnsupportedProtocolError = 5;
Generated using TypeDoc
Const Error code for SkTimeoutErrors
Generated using TypeDoc
Const const HR = 60*MIN
Generated using TypeDoc
Const const MIN = 1000*MS
Generated using TypeDoc
Const Unit of time; const MS = 1
Generated using TypeDoc
Const const SEC = 1000*MS
Generated using TypeDoc
Const In the general case, this pops up the modal that requires the user to +manually confirm, so is set to 5 minutes. This is where you as the developer +need to exercise some discretion.
+Generated using TypeDoc
Const 1 second (instaneous in practice)
+Generated using TypeDoc
Const 7 seconds. Superhero announces itself every 3 seconds, so this is 2 +announcements + 1 second.
+Generated using TypeDoc
Const In the general case, this pops up the modal that requires the user to +manually confirm, so is set to 5 minutes. This is an instance where you as +the developer need to exercise some discretion.
+Generated using TypeDoc
Const In the general case, this pops up the modal that requires the user to +manually confirm, so is set to 5 minutes. This is an instance where you as +the developer need to exercise some discretion.
+Generated using TypeDoc
AWCP: aepp-waellet communication protocol
+ +Suppose you are the aepp and you want to communicate with a waellet. What +you do is pick an
+ +EventTarget(typicallywindow), and listen to its +MessageEvents, via something likeYou then communicate with the wallet by sending messages back over the +
+EventTarget. You should probably use the sidekick +library to do +this.Keep in mind that these messages are not secret. Any browser extension or +foreign page script can intercept these messages. Imagine as an (imperfect) +analogy that you work in an office. Everyone's mail is dumped on the floor +in the middle of the office, and you are responsible for picking out which +letters are addressed to you. Anyone else can pick up letters addressed to +you, and read them.
+This module defines the shape of the messages that are sent. There are several +layers to the onion, each corresponding to natural branch points in the +protocol.
+ +Example
+ +Example
++
+
+
+
+
+The
+MessageEventlayer. This is what is actually sent as an event. +This is an opaque object that is built into every runtime's standard +library: https://developer.mozilla.org/en-US/docs/Web/API/MessageEventThe
+MessageEventhas a field calleddata, which corresponds to the +next layer.The
+EventDatalayer. This is what goes inmessage_event.data. The +structure that goes in here is one of+- EventData_W2A: waellet-to-aepp
+- EventData_A2W: aepp-to-waellet
+
+This layer corresponds to the "am I supposed to pay attention to this +event?" branch point.
+Those data structures mentioned above have two fields.
++
+
+
+ + +typeis a string which is either"to_aepp"or"to_waellet"datacontains the next layerWe're at
+message_event.data.data. The idiom here is "JSON RPC", which +is sort of a poor man's HTTP.In general, the wallet is the server and the aepp is the client.
+If you are the aepp, usually you are handling a response to a request +you sent to the waellet. For instance, you formed a transaction and +sent it to the waellet to sign, and the waellet is sending you back +either the signed transaction or an error (e.g. user rejected the +transaction).
+The exception to this pattern is the wallet notifying you that it +exists, which is the only time the waellet sends a request (a "cast", or +a "notification") to the aepp. In no event does the aepp send a +response to the waellet.
+I am not 100% sure what RPC stands for, but it will be helpful to think +about it as "remote procedure call". More below. This layer roughly +corresponds to the "given that I am supposed to pay attention to this +event, what am I supposed to do with this information?"
+All requests have a
+methodfield (a string) and aparamsfield (an +object). There are two types of requests:+
+
+
+"casts" (the RPC standard calls these "notifications"). These do not +need a response. This is only used for the waellet announcing it +exists.
+"calls". These have an
+idfield, and get a response. These are +used when the aepp is requesting the waellet to do something. The +response will have the sameidfield and the samemethodfield.So far nothing we've talked about is specific to Aeternity, Vanillae, +JR, or sidekick. This fourth layer is the actual semantics of the +messaging protocol between the aepp and the waellet.
+By analogy, the first two layers are developing something like TCP. The +third layer is developing HTTP. And this layer is the actual routing +table of your website, which carries with it the expected semantics of +how the website is supposed to behave.
+This module DOES NOT exhaustively define all of the communication +protocol that occurs in the SDK, only the subset that I have encountered +in practice.
+The first layer is defined by the runtime, not here. So we're starting with +layer 2.
+ + +Notes on JSON RPC 2.0
+ +I have subtly changed the RPC protocol to
++- improve it in such a way that it is easier to use in code
+- more accurately represent how it is used in practice
+
+The only difference here is that the
+ + +paramsfield of requests is +non-optional, and must be an object (the RPC standard allows arrays).Requests
+ +I have adapted the verbiage here, borrowing from Erlang, to make a +distinction between
++
+
+
+casts (RPC calls these "notifications"): these
++- do NOT have an
+- AND do NOT require a response.
+
+idfieldcalls: these
++- DO have an
+- AND DO require a response.
+
+idfieldThe RpcCall and RpcResp data structures each have an
+id_n+type parameter.The purpose of this is to notate (and possibly enforce) at the type level +the constraint that, given a call with say
+ + +id = 7, the response must also +haveid = 7.Links
+ ++
+- JSON RPC 2.0: https://www.jsonrpc.org/specification
+
+MessageEvents: https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent