Module jex_include/local-awcp-0.2.2/dist/awcp

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 (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.

Example

// 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"}}}

Example

// 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"}}}
  1. 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.

  2. The EventData layer. This is what goes in message_event.data. The structure that goes in here is one of

    1. EventData_W2A: waellet-to-aepp
    2. 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.

    1. type is a string which is either "to_aepp" or "to_waellet"
    2. data contains the next layer
    type EventData_W2A
    <t extends any>
    = {type : "to_aepp",
    data : t};
    type EventData_A2W
    <t extends any>
    = {type : "to_waellet",
    data : t};
  3. 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:

    1. "casts" (the RPC standard calls these "notifications"). These do not need a response. This is only used for the waellet announcing it exists.

    2. "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.

  4. 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

  1. improve it in such a way that it is easier to use in code
  2. more accurately represent how it is used in practice

The only difference here is that the params field 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

  1. casts (RPC calls these "notifications"): these

    1. do NOT have an id field
    2. AND do NOT require a response.
  2. calls: these

    1. DO have an id field
    2. AND DO require a response.

The 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.

Links

Index

Type Aliases

Variables

Generated using TypeDoc