# Overview

## Abstract

*The **dm3** (**D**ecentralized **M**essaging for web**3** or **D**irect **M**essage **3**) protocol is an end-to-end **encrypted** peer-to-peer messaging protocol, rooted in **ENS** (Ethereum Name Service). It is **decentralized**, has no single points of failure, has a **lean architecture** with minimum resource requirements, and enables **interoperability** with other messaging solutions while preserving the **self-sovereignty** of its users. The **dm3** protocol uses **ENS** as a central registry for necessary contact information (like public keys, addresses of delivery services, ...), stored in ENS text records, in combination with a standardized API to build an open ecosystem of message delivery services allowing to send messages from ENS name to ENS name.*

## Motivation

Messaging (such as instant messages, chats, email, etc.) has become an integral part of most people's lives. Mobile devices (such as smartphones, tablets, laptops, etc.) with instant access to the Internet make it possible to be in touch with family, friends, as well as work colleagues, and customers at any time.

While email services are still largely decentralized and interoperable, the lack of appropriate spam protection methods other than blocking and censoring has resulted in only a few large providers interacting with each other, not to mention the fact that even today a large portion of email communication is mostly unencrypted.

Messaging services on the web2 (like WhatsApp, Signal, Telegram, ...) have become closed silos, making cross-service or cross-app communication almost impossible. Although they mostly offer end-to-end encryption, some services may still have backdoors via the central service providers or can stop end-to-end encryption without the user's approval.

In the past months, several different approaches and tools have been presented in web3. Methods from the web3 such as key-based identification, encryption, and the availability of blockchain-based registries are being used. Many applications are built to meet user preferences, and several protocols have been presented. Trade-offs are often necessary - such as centralized services, application-related registries, or complex protocols. Interoperability across applications, services, and protocols is still limited, if possible at all.

With **dm3**, a protocol is presented, which is characterized by a very lean base protocol (DM3MTP - the **dm3** message transfer protocol), which can serve as a bridge between different services and can enable integration and interoperability with other services and different applications. Dm3 aims to suggest a common base standard for web3 messaging, on which further protocols and applications can be built to create a silo-free, secure, self-determined, decentralized messaging ecosystem - based on web3 technology.

**This allows users not only to have full control over their data and messages but also to choose the messaging app that best suits their needs and preferences, without the compromise of being limited to a particular ecosystem.**

## Base Architecture

The **dm3** protocol is designed as a lean peer-2-peer messaging protocol with consistent end-to-end encryption and sufficient decentralization through an open delivery service architecture.

Due to its simple base architecture, **dm3** is intended as a base protocol to bring together a variety of messaging applications and protocols so that true interoperability can be realized.

Required contact information such as public encryption keys and public keys to verify signatures as well as information on used delivery services are managed as text records in ENS (Ethereum Name Service) - the **dm3 profile**. This provides a general registry that can be accessed across applications and protocols. Thus, services using this standard do not have to rely on the technology and availability of one provider, nor does it result in the emergence of various incompatible silos in web3 as in web2.

<figure><picture><source srcset="/files/wBzrQXVpZ83YwS3pikwr" media="(prefers-color-scheme: dark)"><img src="https://1600223355-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmGk8YCcEZyeSqUV7NFpK%2Fuploads%2FbcjqAjY5L98It2MpYAYW%2Farchitecture_light.png?alt=media&amp;token=041bbc50-907d-43e2-8e34-cad1062c1044" alt=""></picture><figcaption><p>dm3 architecture</p></figcaption></figure>

## Protocol Extensions

While the specification of the **Message Transport Protocol (DM3MTP)** focuses on a standardized format description for general messages and how to deliver those messages to a delivery service defined in the receiver's **dm3** profile, several optional protocol extensions are defined to cover further topics.

The **dm3** delivery service and **dm3** compatible app implementations MAY also use the following **dm3** protocol extensions:

* **Message Access Specification**: Specifies how received messages on a delivery service can be accessed.
* **Message Storage Specification**: Specifies how messages are persisted after they are delivered.
* **Billboard Message Specification**: Specifies a protocol extension for public billboard messaging.
* **Public Message Feed Specification**: Specifies how a public message feed is created and accessed.
* **Intra-Delivery Service Messaging Specification**: Specifies additional features for messaging if the sender and receiver are using the same delivery service.
* **Group Messaging Specification**: Specifies a protocol extension to enable group messaging.
* **Encryption and Signing Key Derivation Specification**: Specifies how to derive keys from the wallet key.
* **Privacy Onion Routing Specification**: Specifies a protocol extension to enable privacy-preserving onion routing.
* **Spam Protection Specification**: Specifies additional methods, based on web3 technology, that prevent spam on the receiver's side.
* **Layer-2 Registry Specification**: Specifies how to include a layer-2 or cross-chain registry into subdomains to extend the general registry
* **Top-Level Alias Specification**: Specifies how subdomains can be mapped to non-ENS-top-level domains. This is needed for instance for cross-chain interoperability.
* **Linked Profile (Limited Scope) Specification**: Specifies the handling of sub-profiles (for instance in-app-messaging solutions). Those profiles can be temporary or anonymous.
* **Tokengated Access Specification**: Specifies the handling of token-gated access rules.

*The specifications for the protocol extensions are still in draft status and will be published soon.*


# Message Transport Protocol (DM3MTP)

The **Message Transport Protocol (DM3MTP)** is the minimum basic protocol and the foundation for interoperability. For a protocol, service, or application to be dm3-interoperable, only the DM3MTP must be implemented. Further protocol extensions are additional functions that are not necessary for interoperability.

The **Message Transport Protocol** defines:

* **Registry** for communication profiles.
* The **transmission protocol,** based on a decentralized network of delivery service nodes.
* Relevant **APIs** for Delivery Services.


# Registry

A central (but decentralized) registry is needed where a **dm3** compatible app, service, or protocol can lookup **dm3 profiles** of other users, containing

* Public keys,
* Links to delivery services.

The **dm3** protocol uses **ENS (Ethereum Name Service)** as a central (but decentralized) registry. The following text records are used for this purpose:

* `network.dm3.profile`: User profile entry
* `network.dm3.deliveryService`: Delivery service profile entry

The text records MUST be a URI containing the profile JSON string defined below.

The URI can be

* A data scheme (*data:...*) or
* A URL pointing to a profile JSON object (*HTTPS:... or IPFS:...*). To validate the integrity of the resolved profile JSON string, the URL MUST be a native IPFS URL or a URL containing a `dm3Hash` parameter containing the **SHA-256** hash of the JSON.

> **Example** `network.dm3.profile` text record entries:
>
> * `data:application/json,{profile...`
> * `https://delivery.dm3.network/profile/0xbcd6de065fd7...b3cc?dm3Hash=ab84f8...b50c8`
> * `ipfs://bafybeiemxf5abjwjz3e...vfyavhwq/`

The profiles can only be changed by creating a new profile JSON and changing the corresponding text record via an Ethereum transaction (if published on layer-1). Storing this information on layer-2 or linked via CCIP ([Cross-Chain Interoperability Protocol](https://chain.link/cross-chain)) using subdomains, is possible, too. The specification thereof will be published in the protocol extension **Layer-2 Registry Specification**. This is currently under development and will be published soon.

Information read from ENS may be cached for performance reasons but the ENS TTL settings must be respected (to be fetched from the resolver).

## User Profile

The user profile MUST contain:

* **Public Signing Key:** Key used to verify a message signature (ECDSA). The public signing key is the public key of a secp256k1 private/public key pair. How to generate or derive this key pair depends on the implementation of the client. The **Encryption and Signing Key Derivation Specification** proposes a method to derive those keys based on a signature of the wallet keys. The key is presented as base64-encoded string of the key's bytes (see [key encoding](broken://pages/3fUlaV6Blpmld5a6G8K1)).
* **Public Encryption Key:** Public key used to create the key (together with the private key of the sender) to encrypt a message. As default, the algorithm **x25519-chacha20-poly1305** is used (see **\[NIR1]**). If needed (e.g., for compatibility reasons with an integrated protocol), a different encryption can be specified in the Profile Extension. Nevertheless, using the default encryption is highly recommended. The key is presented as base64-encoded string of the key's bytes (see [key encoding](broken://pages/3fUlaV6Blpmld5a6G8K1)).
* **Delivery Service List:** List with at least one delivery service' ENS name[^1].

```JavaScript
DEFINITION: UserProfile

{
  // Key used to encrypt messages
  publicEncryptionKey: string,
  // Key used to sign messages
  publicSigningKey: string,
  // ENS name list of the delivery services e.g., delivery.dm3.eth
  deliveryServices: string[], 
}
```

> **Example** UserProfile with fallback delivery service:
>
> ```JavaScript
> {
>    "publicEncryptionKey":"nyDsUmYV4EDNCsG+pK...D=",
>    "publicSigningKey":"MBpqhsSkxevwbYEGnXX9r...c=",
>    "deliveryService": ["example_deliveryservice.eth","example_fallback-deliveryservice.eth"]
> }
> ```

Additional to the user profile, the user profile extension can be queried from the user's delivery service (see user profile extension). As this information may change and depend as well on the delivery service, it MUST be requested directly from the delivery service the message will be sent to.

### Key encoding

Public keys published in the profiles are presented as base64-encoded strings of the key's bytes.

> **Example** Key encoding
>
> ```JavaScript
> Key = [134, 57, 101, ..., 167]
> KeyString = "jjllMO...qc="
> ```

## Delivery Service Profile

The delivery service profile MUST contain:

* **Public Signing Key:** Key used to verify a postmark signature (see **UserProfile**). The key is presented as base64-encoded string of the key's bytes (see [key encoding](broken://pages/3fUlaV6Blpmld5a6G8K1)).
* **Public Encryption Key:** Public key used to create the key (together with the private key of the sender) to encrypt a message. As default, the algorithm **x25519-chacha20-poly1305** is used. The key is presented as base64-encoded string of the key's bytes (see [key encoding](broken://pages/3fUlaV6Blpmld5a6G8K1)).
* **Delivery Service URL:** URL pointing to the delivery service instance.

As the encryption algorithm for the delivery service, the default algorithm **x25519-chacha20-poly1305** is mandatory.

```JavaScript
DEFINITION: DeliveryServiceProfile

{
  // Key used to sign postmarks
  publicSigningKey: string,
  // Key used to encrypt delivery information
  publicEncryptionKey: string,
  // URL pointing to the delivery service instance
  url: string
}
```

> **Example:** DeliveryServiceProfile
>
> ```JavaScript
> {
>    "publicEncryptionKey":"nyDsUmYV4EDNCsG+pK...D=",
>    "publicSigningKey":"MBpqhsSkxevwbYEGnXX9r...c=",
>    "url": "https://example_deliveryservice"
> }
> ```

[^1]: For information, on how to adapt **dm3** for ecosystems not based on Ethereum, see appendix [Cross Chain Applications](https://specification.dm3.network/base-protocol/message-transport-protocol-dm3mtp/mtp-appendix.md#cross-chain-applications).


# Message Transport

Sending (and receiving) a message takes place in 3 steps, although only the first two steps are part of the **dm3 Message Transfer Protocol**.

1. The sender app **prepares and sends the message to the receiver's delivery service**. If the primary delivery service (first on the list) is not available, the next one from the list is contacted (and so on).
2. The **delivery service buffers and processes the message** (checks envelope, creates postmark to protocol time of delivery, optionally sends a notification to the receiver, ...).
3. *The **message is picked up by the recipient**. As soon as the recipient reports the successful processing of the message to the delivery service, the latter deletes the buffered message. **!!!** This is not part of the "Message Transfer Protocol", as this depends on the implementation and objective of the delivery service. If the delivery service is following the **dm3 Access Specification** to serve **dm3** compatible clients, it offers a REST API to retrieve the messages, but a delivery service may also act as an interface/gateway to another protocol or application ecosystem, handling incoming messages according to its rules. **!!!***

## Workflow

### Step 1: Preparation of the Message and Envelope

**Get dm3 profile**

1. Read the `network.dm3.profile` text record of the receiver's ENS name. If the profile record is not set, the message cannot be delivered. It has to stay with the sender until the potential receiver publishes his/her profile.
2. The content is specified as URI (Uniform Resource Identifier). The following types must be supported:

   1. **DATA:** The content is delivered as JSON. The data scheme MUST be `application/json`. Optionally, the JSON content is **base64** encoded. This must be specified as scheme extension `application/json;base64`. If not base64 encoded, the content might be URL-encoded.

   > ***Example:*** `data:application/json,%7B%22profileRegistryEntry%22%3A...` `data:application/json;base64,eyJwdWJsaWNFbmNyeX...`

   2. **HTTPS:** The content is retrieved as a JSON object from a server and the `dm3Hash` URL parameter is used to check the integrity of the profile string.

   > ***Example:*** `https://exampleserver/example?dm3Hash=0x12ab4...`

   3. **IPFS:** The content is retrieved as a JSON object using IPFS network.

   > ***Example:*** `ipfs://QmU6n6n1Q...`
3. Interprete JSON object as **dm3 profile**.
4. Select the receiver's delivery service ENS name by reading the `deliveryServices` user profile entry at index `0`.
   1. Get the `network.dm3.deliveryService` text record of the delivery service's ENS name. The content is delivered as URI (data, HTTPS, or IPFS), as described above in point 2.
   2. Interprete JSON object as **dm3 delivery service profile**.
5. If the selected delivery service is unavailable, the sender MUST use the delivery service with the next higher index in the `deliveryServices` list as a fallback.

**Create a Message and Envelope**

1. Get ProfileExtension from delivery service
   * Read optional encryption parameters (like preferred encryption algorithm deviating from standard)
   * Read supported message types. Only supported messages must be sent.
2. Sign the message using the private sender signing key, using ECDSA.
3. Encrypt the message using the public encryption key of the receiver (part of the user profile). The default encryption algorithm is **x25519-chacha20-poly1305**. If a different algorithm is required (defined in the *ProfileExtension*), this should be used for encryption. If it is not supported by the sender, the default encryption is used.
4. Encrypt the delivery information using the public encryption key of the delivery service (part of the delivery service profile). The mandatory encryption algorithm is **x25519-chacha20-poly1305**.

{% @mermaid/diagram content="sequenceDiagram
participant AA as Alice' Client
participant E as Registry (ENS)
participant P as Profile Storage (e.g. IPFS)
AA->>E: get network.dm3.profile for Bob's ENS name
E-->>AA: network.dm3.profile text record
opt network.dm3.profile text record is an URL
AA->>P: query Bob's profile
P-->>AA: profileRegistryEntry
AA->>AA: check profileRegistryEntry integrity
end
AA->>AA: sign message
AA->>AA: encrypt message

```
AA->>E: get network.dm3.deliveryService of Bob's delivery service
E-->>AA: network.dm3.deliveryService text record
opt network.dm3.deliveryService text record is an URL
  AA->>P: query delivery service profile 
  P-->>AA: deliveryServiceRegistryEntry
  AA->>AA: check deliveryServiceRegistryEntry integrity
end

AA->>AA: sign envelope
AA->>AA: encrypt deliveryInformation" %}
```

**Submit Message**

1. Get ProfileExtension from delivery service
   * Read spam protection settings (see Profile Extension).
   * Check, if conditions are met. If not, the message must not be sent (as it will be discarded from the receiving delivery service anyway). The sender should be informed.
2. Submit the message to the delivery service using the URL defined in the delivery service profile.

### Step 2: Message processing at the delivery service

1. Decrypt delivery information.
2. Apply filter rules from the receiver's profile extension. Discard the message if conditions are not met.
3. Create a postmark. The postmark protocols the reception and buffering of the message.
4. Buffer message. The delivery service stores the encrypted message until the receiver picks it up. A delivery service may decide to have a maximum holding time. It must be at least 1 month. If the receiver didn't fetch the message within this time, the message may be deleted. This time can be queried from the delivery service's properties
5. Optional: send notification(s) to the receiver that a message is waiting for delivery.

{% @mermaid/diagram content=" sequenceDiagram
actor A as Alice
participant AA as Alice' Client
participant BD as Bobs's Delivery Service
participant CC as Alice' Data Storage Service
participant BB as Bob's Client\
A-->>AA: writes message
AA->>BD: dm3\_getProfileExtension
BD-->>AA: retrieve Bob's "profileExtension"
AA->>AA: prepare message
opt
AA->>AA: prepare attachments
opt
AA-->>CC: store attachment data at service or IPFS
end
end
AA->>BD: dm3\_getDeliveryServiceProperties
BD-->>AA: retrieve the delivery service' properties
AA->>AA: prepare envelope
AA->>BD: dm3\_submitMessage
BD->>BD: decrypt deliveryInformation
BD->>BD: apply filter rules
BD->>BD: add postmark
BD->>BD: buffer message
opt
BD->>BB: notification
end  " %}

## Message Data Structure

The message data structure stores all data belonging to the message that can only be read by the receiver. The entire data structure is encrypted (based on the public key of the receiver).

The message data structure contains the following information:

* **Message:** *(OPTIONAL)* This string contains the actual message. For service messages (like READ\_RECEIPT, RESEND\_REQUEST, or DELETE\_REQUEST), this field may be empty or undefined. The message MUST be **plain text** (UTF-8), optionally flavored with **Markdown** highlightings. If other encodings of the message are provided, those MUST be attached as an attachment (embedded with data scheme only), still providing the text representation in the message string. Clients able to interpret the encoded attachment may display this instead of the original message string. Others will visualize the message text as plain text or Markdown formatting.
* **Metadata:** This object contains all meta-information about the message. Some attributes are mandatory, others are optional. Also, application-specific attributes can be added. The [MessageMetadata-Structure](broken://pages/n2aUCvI39QTJLfIq6Rva) is described in detail below.
* **Attachments:** *(OPTIONAL)* Media or other files or special encodings of the message may be an attachment to a message, defined as an array of URIs (data, HTTPS, IPFS). [Attachments](broken://pages/n2aUCvI39QTJLfIq6Rva) are described in detail below.
* **Signature:** This is the signature with the sender's signature key on the SHA-256 hash of the message data structure without the signature field.

```json5
DEFINITION: Message Data Structure

{
   // message text
   // optional (not needed for messages of type READ_RECEIPT, DELETE_REQUEST, and RESEND_REQUEST)
   message?: string,
   // metadata added to the message.
   metadata: MessageMetadata,
   // message attachments e.g. images as an array of URIs
   // (optional)
   attachments?: Attachment[],
   //the signature of the sender
   // sign( sha256( safe-stable-stringify( struct_without_sig ) ) )
   signature: string
}
```

## Message Metadata Structure

The **message metadata structure** stores all meta information belonging to a message. While some attributes are mandatory, others are optional. If needed, application-specific meta information may be added, too.

The **message metadata structure** contains the following information:

* **To:** The ENS name the message is sent to.
* **From:** The ENS name of the sender
* **Timestamp:** The timestamp (unixtime in milliseconds) when the message was created.
* **Type:** Different types of messages can be sent. A **dm3** compatible messenger may not support all types in the UI but must at least handle not interpreted types meaningful (*example: the messenger doesn't support editing existing messages. It appends messages with the type **EDIT** as new messages at the bottom of the conversation*).
  * **NEW:** A new message.
  * **DELETE\_REQUEST:** *(OPTIONAL)* This is a service message. The sender wants the referenced message deleted. The value **referenceMessageHash** points to the message to be deleted. If the receiver's messenger doesn't support the deletion of messages, it may ignore the message.
  * **EDIT:** *(OPTIONAL)* An already existing (old) message was edited (new version). The value **referenceMessageHash** points to the message to be replaced with a new version. If edit is not supported by the receiver's messenger, the message must be added as new.
  * **REPLY:** *(OPTIONAL)* This message is a direct reply to an existing message. The value **referenceMessageHash** points to the referenced message. If threads/references are not supported, it must be added as a new message.
  * **REACTION:** *(OPTIONAL)* This is a short referenced message, containing an emoji as a **message**, and the value **referenceMessageHash** points to the referenced message.
  * **READ\_RECEIPT:** *(OPTIONAL)* This is a service message. The receiver sends this message back to the sender to signal that the message was received and displayed. Sending this message is optional and it may be ignored.
  * **RESEND\_REQUEST:** *(OPTIONAL)* This is a service message. The value **referenceMessageHash** points to the referenced message. If possible (=available), the referenced message should be sent again.
* **Reference Message Hash:** *(OPTIONAL)* The hash of a previous message that the new one references. Must be set for message types (REPLY, DELETE\_REQUEST, EDIT, REACTION, RESEND\_REQUEST).
* **Reply Delivery Instruction:** *(OPTIONAL)* It is needed for compatibility reasons with other protocols/apps. The stored information MUST be delivered with any reply (e.g., a conversation or topic id, ...) as meta information of the [encryption envelope](broken://pages/n2aUCvI39QTJLfIq6Rva). It is neither evaluated nor altered from **dm3**.

```json5
DEFINITION: Message Metadata Structure

{
   // receiver ens-name
   to: string,
   // sender ens-name
   from: string,
   // message creation timestamp
   timestamp: number,
   // specifies the message type
   type: "NEW" | "DELETE_REQUEST" | "EDIT" | "REPLY" | "REACTION" | "READ_RECEIPT" | "RESEND_REQUEST"
   // message hash of the reference message
   // optional (not needed for messages of type NEW)
   referenceMessageHash?: string,
   // instructions used by the receiver of the message on how to send a reply
   // optional (e.g., used for bridging messages to other protocols)
   replyDeliveryInstruction?: string,
   // any kind of additional metadata may be added. 
   // This might be information needed by protocol extensions or app-specific meta information.
   ...
}
```

## Attachments

Attachments can be any type of additional data or media files. These are organized as an array of URIs and metadata. Embedded content is encoded as data scheme, external data as URL or IPFS. A message can have no or an arbitrary number of attachments. The overall size of the message (inclusive of all embedded attachments) MUST be less than 20MB. The overall size of the message can be restricted additionally by the delivery service (see Delivery Service Properties.) If bigger media files need to be attached, the actual data need to be stored outside the message (still encrypted with the receiver's public key) and the attachment contains only the reference (URI with HTTPS or IPFS scheme). Otherwise, the attachment may be included with URI scheme data.

Different **dm3** compatible applications may handle attachments differently (visualization, embedding, or even ignoring them). Applications may optionally support other encodings than text/markdown for the message. These may be added as attachments and visualized instead of the original message text. It is the application's responsibility to do this properly.

```json5
DEFINITION: Attachment
{
    // the name of the attachment. In the case of a file, this is the file name.
    // optional (not needed if no name is avaialable)
    name?: string,
    // the data of the attachment (URI) or a reference to it 
    data: string
    // other metadata may be added if needed
}
```

***Examples:***

> ```json
> "attachments":[
>     {
>         "name":"file.html",
>         "data":"data:text/html;base64,dfEwwewGJsaWKklNyeX..."
>     },
>     ...],
> ```

> ```json
> "attachments":[
>     {
>         "name":"image.jpg",
>         "data":"data:image/jpeg;base64,dfEwwewGJsaWKklNyeX..."
>     },
>     ...],
> ```

> ```json
> "attachments":[
>     {
>         "data":"https://exampleservice/exampleresource"
>     },
>     ...],
> ```

> ```json
> "attachments":[
>     {
>         "name":"file.xyz",
>         "data:":"ipfs://AmE6mn1n64Q..."
>     }
>     ,...],
> ```

## Encryption Envelope Data Structure

The encryption envelope is the data structure that is sent to the delivery service. It contains delivery metadata and the encrypted message itself. The envelope is read and interpreted by the delivery service. However, the actual message is encrypted based on the receiver's key and signed with the sender's key so that it cannot be read or altered by the delivery service.

The encryption envelope contains the following data:

* **Message:** The encrypted message ([Message Data Structure](broken://pages/n2aUCvI39QTJLfIq6Rva)).
* **Metadata:** This object contains all meta information about the envelope. Some attributes are mandatory, others are optional. Also, application-specific attributes can be added. The [EnvelopeMetadata Structure](broken://pages/n2aUCvI39QTJLfIq6Rva) is described in detail below.
* **Postmark:** *(OPTIONAL)* A data struct with the information on the delivery status. Postmark is empty/undefined when the sender is sending the envelope to the delivery service. It is added by the delivery service and is encrypted based on the public key of the receiver.

```json5
DEFINITION: Encryption Envelope Structure

{
  // the message 
  // encrypted based on the receiver's public encryption key
  message: string,
  // meta information for the envelope
  metadata: EnvelopeMetadata,
  // contains information added by the delivery service
  // encrypted based on receiver's public encryption key
  postmark?: string,
}
```

## Envelope Metadata Structure

The **envelope metadata structure** stores all meta information belonging to an envelope. While some attributes are mandatory, others are optional. If needed, application-specific meta information may be added, too.

The **envelope metadata structure** contains the following data:

* **Version:** The protocol version of **dm3**.
* **Encryption Scheme:** The used encryption and signing algorithms. The default is **x25519-chacha20-poly1305**. If this field is not set (undefined), the default is being used.
* **Delivery Information:** A data struct with the delivery information needed by the delivery service (message metadata).

```json5
DEFINITION: Envelope Metadata Structure

{
  // dm3 protocol version (e.g., 1.0)
  version: string,
  // used encryption scheme of the message
  //optional: if not set, the default x25519-chacha20-poly1305 is taken
  encryptionScheme?: string,
  // datastruct with delivery info
  // Delivery information object, encrypted based on the delivery services' encryption key
  deliveryInformation: string,
  // any kind of additional metadata may be added. 
  // This might be information needed by protocol extensions or app-specific meta information.
  ...
  // the signature of the sender
  // sign( sha256( safe-stable-stringify( struct_without_sig ) ) )
  signature: string,
}
```

## Delivery Information

The delivery information contains all metadata needed by the delivery service to handle a message.

The data structure contains the following information:

* **To:** The ENS name the message is sent to.
* **From:** the ENS name of the sender
* **Delivery Instruction:** this is optional information. It is needed for compatibility reasons with other protocols/apps. The stored information (e.g., a conversation or topic id, ...) will be delivered with any reply from the receiver. It is neither evaluated nor altered from **dm3**.

```json5
DEFINITION: Delivery Information

{
  // receiver ens-name
  to: string,
  // sender ens-name
  from: string,
  // instructions used by the delivery service on how to deliver the message
  // optional (used for bridging messages to other protocols)
  deliveryInstruction?: string
}
```

## Postmark Data Structure

The postmark data structure contains information added by the delivery service regarding the delivery status.

It contains the following information:

* **Massage Hash:** the Hash (SHA-256) of the entire message.
* **Incoming Timestamp:** The unixtime in milliseconds when the delivery service received the message.
* **Delivery Information:** This is a copy of the delivery information provided in the envelope. As this info in the envelope is encrypted for the delivery service, it MUST be added from the delivery service to the postmark. The receiver can use this information to check if the sender of the message referenced in the [Message Metadata](broken://pages/n2aUCvI39QTJLfIq6Rva)) is the same as referenced in the envelope.
* **Signature:** the signature of the postmark from the delivery service. This is needed to validate the postmark information.

```json5
DEFINITION: Postmark

{
  // sha256( EncryptionEnvelope.message ) 
  messageHash: string,
  // timestamp of when the delivery service received the message
  incomingTimestamp: number,
  // a copy of the delivery information from the envelope the delivery service
  deliveryInformation: DeliveryInformation,
  // signature of the delivery service
  // sign( sha256( safe-stable-stringify( postmark_without_sig ) ) )
  signature: string,
}
```


# API Delivery-Service (Incoming Messages)

For more detailed information about delivery services, see the appendix. Relevant to DM3MTP (protocol) is the API to deliver messages (encrypted envelopes) only.

The delivery service is a JSON-RPC service, following the JSON-RPC 2.0 specification (see also **\[RPC1]**).

* [API Delivery-Service (Incoming Messages)](broken://pages/H0PvbBT5vgciPWCB7OXM)
  * [Submit Message](broken://pages/H0PvbBT5vgciPWCB7OXM)
    * [Methode](broken://pages/H0PvbBT5vgciPWCB7OXM)
    * [Request](broken://pages/H0PvbBT5vgciPWCB7OXM)
    * [Response](broken://pages/H0PvbBT5vgciPWCB7OXM)
      * [Error codes](broken://pages/H0PvbBT5vgciPWCB7OXM)
  * [Get Properties of the Delivery Service](broken://pages/H0PvbBT5vgciPWCB7OXM)
    * [Methode](broken://pages/H0PvbBT5vgciPWCB7OXM)
    * [Response](broken://pages/H0PvbBT5vgciPWCB7OXM)
  * [Get the User's Profile Extension](broken://pages/H0PvbBT5vgciPWCB7OXM)
    * [Methode](broken://pages/H0PvbBT5vgciPWCB7OXM)
    * [Request](broken://pages/H0PvbBT5vgciPWCB7OXM)
    * [Response](broken://pages/H0PvbBT5vgciPWCB7OXM)

To accept incoming messages, the delivery service MUST support the following JSON-RPC methods:

## Submit Message

The submit message method is called to deliver the complete message envelope containing the delivery information and the encrypted message.

### Methode

```TypeScript
// call to submit a message
dm3_submitMessage 
```

### Request

The request delivers the encrypted envelope containing the message itself and the delivery information as EncryptionEnvelope.

```TypeScript
// see description of EncryptionEnvelope data structure
EncryptionEnvelope
```

### Response

The response is as defined in the JSON-RPC specification. In case of an error, an error message is returned.

> **Example**
>
> ```TypeScript
> {
>  "jsonrpc": "2.0", 
>  "error": {
>    "code": -32600, 
>    "message": "Invalid Request"
>  }, 
>  "id": null
> }
> ```

#### Error codes

For default JSON-RPC error codes see appendix.

Additional, application specific error codes can be reported:

| Error code | Error text                     | Description                                        |
| ---------- | ------------------------------ | -------------------------------------------------- |
| -32000     | Invalid input                  | Missing or invalid parameters.                     |
| -32001     | Resource not found             | Requested resource not found.                      |
| -32002     | Resource unavailable           | Requested resource not available.                  |
| -32003     | Unauthorized                   | The caller was not authorized to call this method. |
| -32004     | Method not supported           | Method is not implemented.                         |
| -32005     | Limit exceeded                 | Request exceeds defined limit.                     |
| -32006     | JSON-RPC version not supported | Version of JSON-RPC protocol is not supported.     |

If the message is rejected from the delivery service, the following error codes will be returned:

| Error code | Error text | Description                                                            |
| ---------- | ---------- | ---------------------------------------------------------------------- |
| -32010     | Spam       | The sender's address didn't fit the required spam protection settings. |
| -32011     | Too big    | The size of the message exceeds the approved maximum size.             |

## Get Properties of the Delivery Service

A **delivery service** provides a set of properties that a sending client MUST evaluate and observe. These properties can be informative or define what the sender of a message must follow in order for the delivery service to accept the message at all.

(***compatibility information:** it replaces the formerly defined mutableProfileExtension provided in the `network.dm3.profile`*)

### Methode

```TypeScript
// call to get a list of properties. 
dm3_getDeliveryServiceProperties
```

### Response

* **Message TTL:** Defines, how long the delivery service guarantees to cache a message. After the guaranteed time, the message MAY be removed, even if it was not picked up by the receiver. The minimum MUST be 30 days. If the value is not set, or set to 0 or null, messages will be cached unlimited (default).
* **Size Limit:** Each delivery service can define a maximum size of incoming messages. As the content of the message incl. attachments is encrypted for the receiver, the delivery service can't restrict attachments or other embedded data by its content. The only way is to restrict the total size of the message. A sender MUST check this property before sending the message, otherwise, the message may be rejected.

```TypeScript
{
    // Number of days a delivery service must buffer a message
    // The message may be deleted if: incoming_timestamp_in_ms + days_to_ms(messageTTL) < now_in_ms
    messageTTL: number;
  
    // The delivery service accepts only envelopes which fulfill the following condition: sizeInBytes(envelope) <= sizeLimit
    sizeLimit: number; 
}
```

In case of an error, an error object is returned as described in [error codes](broken://pages/H0PvbBT5vgciPWCB7OXM).

## Get the User's Profile Extension

Profile extensions are mutable properties of a receiver (identified by his/her ENS Name, ...) that are not stored in the `network.dm3.profile` and can be changed without the need for a transaction. As these properties may vary between different delivery services, each delivery service to which the user is connected must provide this information.

### Methode

```TypeScript
// call to submit a message
dm3_getProfileExtension
```

### Request

The request passes the **name** of the receiver.

```TypeScript
// the name of the receiver
the_name
```

### Response

The profileExtension contains configuration information of the receiver:

* **Encryption Scheme:** *(OPTIONAL)* The default encryption scheme is **x25519-chacha20-poly1305**. If another encryption scheme needs to be used (e.g., because this is needed for an ecosystem that is integrated into **dm3**), this can be requested. The default algorithm MUST be accepted, too. Otherwise, it might be impossible for a sender to deliver a message when it doesn't support the requested algorithm. This is a list of supported schemes, sorted by importance. All listed algorithms MUST be supported by the receiver. The sender is free to choose but should use receiver's preferences if supported.
* **Supported Message Types:** The receiver MUST provide a list of all **message types** that the client he/she uses is supporting (see message data structure). The message type **NEW** MUST be supported always and is set as default in case no information is delivered. The sender MUST NOT send unsupported messages, as the receiver will not accept those messages.

Other information (like spam protection settings) can be added to this struct (defined in protocol extensions).

```JavaScript
{
  // Request of a specific encryption scheme.
  // (optional)
  encryptionScheme?: string[],
  // List of supported message types
  supportedMessageTypes: string[],
}
```

> **Example** Profile Exception:
>
> ```JavaScript
> {
>    "encryptionScheme": ["x25519-chacha20-poly1305"],
>    "supportedMesssageTypes": ["NEW","EDIT", "READ_RECEIPT","RESEND_REQUEST"],
> }
> ```

In case of an error, an error object is returned as described in [error codes](broken://pages/H0PvbBT5vgciPWCB7OXM).


# Appendix

## Delivery Service

A Delivery Service is an RPC endpoint where a client can deliver its message (see API).

The delivery service

1. checks whether the message satisfies the recipient's spam policy (see ProfileExtension)
2. decrypts the envelope, adds a postmark, and stores the message encrypted for the recipient until the recipient picks it up.
3. if supported, notifies the receiver that there is a new message.

Delivery service nodes can be operated as a service or self-sovereign by the user. The protocol explicitly allows (see user profile) a user to point to multiple delivery services so that if one is not available, another can be used. However, delivery service nodes can also act as gateways to other protocols, services, or applications.

<figure><img src="https://1600223355-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmGk8YCcEZyeSqUV7NFpK%2Fuploads%2F0yFhLZPHLIvbmUO94Gi7%2Fdecentralization.svg?alt=media&amp;token=24a6fd47-e1d6-46d0-9b12-4b8e66139f6b" alt=""><figcaption></figcaption></figure>

### Gateway to other service

If a delivery service works as a gateway to another protocol or service, it must implement the API to receive dm3 messages. However, how it then processes the messages and delivers them to the ecosystem to which it is acting as a gateway is completely up to it and depends only on the service or protocol to which it is connecting.

A gateway can also provide multiple delivery service nodes as primary and fallback services.

<figure><img src="https://1600223355-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmGk8YCcEZyeSqUV7NFpK%2Fuploads%2FWxhf6zbGlCh064bjKCcB%2Finterop_gateways.svg?alt=media&amp;token=e93d0736-67c4-4739-a17b-21d41652f20a" alt=""><figcaption></figcaption></figure>

## Cross Chain Applications

Although the dm3 protocol is fundamentally designed to use ENS as a central registry, the protocol can also be implemented on other chains. Name services similar to ENS can be used as a local registry in the ecosystem of this chain. For the entire dm3 ecosystem, this local registry can be directly integrated via CCIP (Cross Chain Interoperability Protocol) (and vice versa) so that interoperability can be established. A complementary extension will further simplify the handling of names of such local registries by automatic mapping of top-level domains (see top-level alias at protocol extensions).

## RPC Error Codes

Default error codes are specified in the [JSON-RPC specification](https://www.jsonrpc.org/specification).

| Error code | Error text       | Description                                                                                           |
| ---------- | ---------------- | ----------------------------------------------------------------------------------------------------- |
| -32600     | Invalid Request  | The JSON sent is not a valid Request object.                                                          |
| -32601     | Method not found | The method does not exist / is not available.                                                         |
| -32602     | Invalid params   | Invalid method parameter(s).                                                                          |
| -32603     | Internal error   | Internal JSON-RPC error.                                                                              |
| -32700     | Parse error      | Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text. |


# Billboard Message Protocol (DM3BMP)

The **billboard messaging** extension of **dm3** describes a communication scheme for a public messaging application, where many senders can send messages to one recipient and all messages are publicly viewable (billboard). The communication is only in one direction (from the senders to the billboard). There is no reply from the billboard to the sender.

Billboard messaging is used e.g. as a public comment service for public content or for displaying live public discussions in a streaming application, or similar.

The senders are not anonymous but identify themselves by their dm3 profile (wallet address).


# Architecture

Billboard messaging is based on the **dm3 Message Transport Protocol (DM3MTP)** with some particular extensions:

* **Billboard client:** This client is a special implementation of a **dm3** client. Using the **dm3 Message Access Protocol (DM3MAP)** messages are retrieved from one ore several delivery serivees. Received messages are stored in a merged conversation (all received messages), ordered by a time of reception.
* **Billboard service:** The billboard service provides an API to access the messages from the billboard and additional functions. Since the messages are visible to all in the form of a bulletin board (depending on the operation mode), the entire communication can be retrieved from this service. The transmission is not encrypted.
* **Billboard embedded component:** The embedded component visualizes the billboard (messages) and enables message sending. This UI components can be integrated in existing dApps with minimum effort. Also, it provides an interface for moderators to block inappropriate statements. It is flexible configurable to meet different use-cases.
* **Delivery Service API extenstion:** The delivery service attached to the billboard client uses an extension to **DM3MAP**, the **dm3** message access protocol, to fetch the messages (not devided in conversations).

## Message Flow

1. Statements are added to the conversation by any participant via direct message to the billboard. To do this, the participant sends a message directly to one of the billboard's delivery services (**dm3** standard, using **DM3MTP**).
2. The billboard client fetches incoming statements from the delivery service(s). The client stores the collected statements.
3. Viewers of the billboard conversation retrieve the billboard messages (list of statements) using the **billboard service API**. Viewers can be active (send and view statements) or passive (view only).

<figure><img src="https://1600223355-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmGk8YCcEZyeSqUV7NFpK%2Fuploads%2FRQdWNX7DUt3o6f8rEGn5%2Fbmp-architecture.svg?alt=media&amp;token=18171704-1673-4589-81a2-bb59f967d927" alt=""><figcaption></figcaption></figure>

## Components

The billboard message extension consists of the following components:

* **Delivery Service(s):** These service(s) receive the messages/statements. The delivery serivce implements the dm3 message access protocol with the billboard extension to access all messages (not separated into conversations).
* **Registry:** The **dm3** registry based on ENS.
* **Billboard Node:**
  * **Billboard Client** The dm3 client receiving and managing messages.
  * **Billboard Service** The cloud service providing access to the billboard's messages.
  * **Billboard Management Backend:** This service provides all functions needed to administrate the billboard, like configuration management, creation of billboards, management of ENS subdomains for virtual profiles (including CCIP integration into ENS Subdomain).
* **Billboard Embedded Widget** The UI component to be embedded in the app.

<figure><img src="https://1600223355-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmGk8YCcEZyeSqUV7NFpK%2Fuploads%2FdWQKDb2flY8SSewuQKRp%2Fbmp-components.svg?alt=media&amp;token=473dc129-0949-4c5f-b0a2-a3396e94cd7f" alt=""><figcaption></figcaption></figure>

## Moderation of the Conversation

For regulatory reasons and the need for the billboard operator to block inappropriate comments to ensure proper conversation, each billboard service may be defined a list of moderators/mediators who exercise the right and duty to delete inappropriate comments and, if necessary, block users who repeatedly defy the rules.

For this purpose, the billboard serivce provides appropriate functions (see API that can be called up by the mediators.

If a sender repeatedly sends messages that need to be deleted, the mediator can also ban this sender. This means that the sender is blacklisted from the delivery service, so that no more messages can be received from him. For this purpose the spam protection rules of DM3MTP are applied.


# Billboard Node

The **Billboard Node** is a collection of connected services. It is realized as a cloud service.

## Billboard Client

The **Billboard Client** is a hosted service that fetches messages directed to it as statements from the corresponding delivery service(s) using the extended **dm3 Message Access Protocol (DM3MAP)** and collects them as a list of statements. The messages are not managed as separate conversations with individual participants, but as a list of statements sorted by the time they were received.

Each billboard has it's own ENS name with **dm3** profile. This can be a subdomain where data is organized off-chain and linked using [CCIP](https://chain.link/cross-chain) (Cross Chain Interoperability Protocol) or it can be a separated ENS domain with a published **dm3** profile.

The client is designed to receive the statements only, as it does not send direct responses to the participants. It serves as database for the billboard service which provides the API to access the messages.

### Database

The database of the billboard client contains all messages received from any sender. As moderators can delete/block messages, entries in this database must be markable as deleted. This is done by storing the signature of the moderator who blocked the message. All messages without this blocking information are published.

<figure><img src="https://1600223355-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmGk8YCcEZyeSqUV7NFpK%2Fuploads%2FlT23jXBPiRbgXT0rorU4%2Fbmp-database.svg?alt=media&amp;token=22894d77-57ff-4d95-a888-98a0946ee6c0" alt=""><figcaption></figcaption></figure>

## Billboard Service

The Billboard service is the interface to the viewers. It provides the API to access the statements which the viewer uses to retrieve the communication. A Billboard Service can manage a number of intepended billboards. For example, a billboard server can host all billboards of an organization or an event.

The messages/statements can be retrieved using the REST API. The messages are delivered paged, in reverse order (from newest to oldest). Also, it is possible to use websocket connection to fetch new incoming messages.

## DM3MAP Extension

The **dm3** Message Access Protocol (DM3MAP) defines the standardized way to retrieve messages in conversations (with sender and receiver) from a delivery service. As billboard messaging is fully *dm3* compatible, the billboard client could retrieve messages packaged in conversations from the delivery service. For reasons of effectiveness, an additional API function is added for the billboard client, which provides the messages of all conversations for one receiver.

### Methode

tbd.

### Request

tbd.

### Response

tbd.

## Scaling

A billboard can use one or more delivery services. Depending on the expected number of statements to be received simultaneously, one or more fallback delivery services might be defined. If one is overloaded automatically the next will take over (already defined on protocol level for direct messaging).

The scaling of the billboard service can be sufficiently realized by common web2 load balancing techniques, so that enough bandwidth is available for all viewers. Caching of the current information is also essential on the server side.


# Billboard Service API

The Billboard Service API provides the functions needed to retrieve the billboard information (like messages, ...).

The billboard service is a JSON-RPC service, following the JSON-RPC 2.0 specification (see also \[RPC1]).

* [Billboard Service API](broken://pages/EfJwiQu1MMBOIRgCw2fh)
  * [Retrieve the Billboard Messages](broken://pages/EfJwiQu1MMBOIRgCw2fh)
    * [Methode](broken://pages/EfJwiQu1MMBOIRgCw2fh)
    * [Request](broken://pages/EfJwiQu1MMBOIRgCw2fh)
    * [Response](broken://pages/EfJwiQu1MMBOIRgCw2fh)
    * [Websocket connection](broken://pages/EfJwiQu1MMBOIRgCw2fh)
  * [Retrieve List of Billboards](broken://pages/EfJwiQu1MMBOIRgCw2fh)
    * [Methode](broken://pages/EfJwiQu1MMBOIRgCw2fh)
    * [Response](broken://pages/EfJwiQu1MMBOIRgCw2fh)
  * [Retrieve Billboard's Properties](broken://pages/EfJwiQu1MMBOIRgCw2fh)
    * [Methode](broken://pages/EfJwiQu1MMBOIRgCw2fh)
    * [Response](broken://pages/EfJwiQu1MMBOIRgCw2fh)
  * [Delete/block an (inappropriate) Message](broken://pages/EfJwiQu1MMBOIRgCw2fh)
    * [Methode](broken://pages/EfJwiQu1MMBOIRgCw2fh)
    * [Request](broken://pages/EfJwiQu1MMBOIRgCw2fh)
    * [Response](broken://pages/EfJwiQu1MMBOIRgCw2fh)
  * [Delete/block an (inappropriate) Message, SIWE](broken://pages/EfJwiQu1MMBOIRgCw2fh)
    * [Methode](broken://pages/EfJwiQu1MMBOIRgCw2fh)
    * [Request](broken://pages/EfJwiQu1MMBOIRgCw2fh)
    * [Response](broken://pages/EfJwiQu1MMBOIRgCw2fh)
  * [Suspend Sender](broken://pages/EfJwiQu1MMBOIRgCw2fh)
    * [Methode](broken://pages/EfJwiQu1MMBOIRgCw2fh)
    * [Request](broken://pages/EfJwiQu1MMBOIRgCw2fh)
    * [Response](broken://pages/EfJwiQu1MMBOIRgCw2fh)
  * [Get active viewers](broken://pages/EfJwiQu1MMBOIRgCw2fh)
    * [Methode](broken://pages/EfJwiQu1MMBOIRgCw2fh)
    * [Request](broken://pages/EfJwiQu1MMBOIRgCw2fh)
    * [Response](broken://pages/EfJwiQu1MMBOIRgCw2fh)

## Retrieve the Billboard Messages

The billboard is a list of statements (messages) from all participants which is ordered by the creation time. Since the number of entries can be very large, the return is paged and only a defined number of results are returned per retrieval.

Each entry in the list is a **dm3** MessageDataStructure where the message entry is not encrypted.

### Methode

This method is called to retrieve a block (page) of statements.

```TypeScript
// call to request a number of statements
dm3_billboard_getMessages
```

### Request

The request passes the **identifier** of the billboard and a description which messages must be returned. As messages may be paged, the information must be provided, which messages are already read. So it must be possible to fetch newest messeges first and get the older ones page by page, too.

These parameters must be provided to define which messages should be returned:

* **idBillboard** The **id** of the billboard which messages should be returned. This is the ENS name of the billboard.
* **time** This is the time of the newest requested message. If older messages are fetched, `time` is the timestamp of the last already fetched message. If `time` is empty or undefined, the most current message is addressed. If several messages have the same timestamp, all of these messages will be returned, even if the number of maximum messages per page is reached.
* **cursor** The time of the newest message of the complete block. If `cursor` is empty or undefined, no messages are already fetched and `cursor` is set to zero.

```TypeScript
// the id of the billboard
idBillboard = <ENS name of the requested billboard>
// the time of the message to be started of the current page
// maybe empty or undefined
time? = <the time>
// the time of the latest message of the (complete) block of messages 
cursor? = <time of the latest message of the block>
```

If `time` is empty or undefined, the first page (`k` entries) of the newest messages of the billboard is returned. The viewer can request other pages (backwards) until the `cursor` is reached (then all messages are fetched). For performance reasons it may be appropriate to only fetch the first page starting with the newest message and additional pages only if needed.

The fetching and paging process is visualized in the graph:&#x20;

<figure><img src="https://1600223355-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmGk8YCcEZyeSqUV7NFpK%2Fuploads%2FJnZsyfflnFVERS26BU8U%2Fbmp-fetch-messages.svg?alt=media&amp;token=88fb7b6d-df05-4505-8523-f89592459929" alt=""><figcaption></figcaption></figure>

### Response

The list of messages is returned.

```JavaScript
{
  messages: MessageDataStructure[],
}
```

> **Example** Billboard Messages:
>
> ```JavaScript
> {
>    "messages": 
>    [
>      {
>         "message":"message 1",
>         "metadata":{...},
>         ...
>      },{
>         "message":"message 2",
>         "metadata":{...},
>         ...
>      },
>    ]
> }
> ```

In case of an error, an error object is returned as described in [error codes](broken://pages/EfJwiQu1MMBOIRgCw2fh).

### Websocket connection

Optionally, a websocket connection can established to retrieve updates via the direct connection to the billboard service. The data from the past are then retrieved and supplemented page by page as needed (such as initialization, scrolling into the past,...). New messages are fetched directly using the websocket.

## Retrieve List of Billboards

One billboard service can host multiple billboards. The list can be queried.

### Methode

This method is called to retrieve the list of available billboards.

```TypeScript
// call to request the list of available billboards
dm3_billboard_list
```

### Response

The list with the ENS-names containing the dm3 profile for each billboard is return.

```JavaScript
{
  billboards: string[],
}
```

> **Example** List of Billboards:
>
> ```JavaScript
> {
>    "billboards": 
>    [
>      "billboard01.billboards.example.eth",
>      "billboard02.billboards.example.eth",
>    ],
> }
> ```

## Retrieve Billboard's Properties

Each billboard is defined by a ENS name providing a **dm3** profile (see dm3 profile). While this profile contains all information needed for sending messages to the billboard, additinal information and properties can be requested from the billboard service.

* **Name:** The name od the billboard. This name may be shown in the billboard message viewer.
* **Mediators:** Mediators have the task of moderating the chat conversation. They have the ability to delete/block inappropriate comments (these will then no longer be delivered). They can also exclude users from the discussion. Then all their comments will not be delivered and they will not be able to post new comments. Mediators are defined by their ENS name or address.
* **Minimum Waiting Time:** For each billboard, it is defined how long a participant has to wait after posting a comment before being allowed to post another comment. This ensures that the discussion is balanced and not dominated by individual participants. This is enforced by the UI only.

```JavaScript
DEFINITION: Billboard Properties

{
  name: string,
  mediators: string[],
  time: number,
}
```

### Methode

This method is called to retrieve the list of available billboards.

```TypeScript
// call to request the list of available billboards
dm3_billboard_list
```

### Response

The list with the ENS-names containing the dm3 profile for each billboard is return.

```JavaScript
{
  billboards: string[],
}
```

> **Example** List of Billboards:
>
> ```JavaScript
> {
>    "billboards": 
>    [
>      "billboard01.billboards.example.eth",
>      "billboard02.billboards.example.eth",
>    ],
> }
> ```

In case of an error, a RPC error message is returned.

## Delete/block an (inappropriate) Message

Mediators have the task and the right to block or delete inappropriate content. The Billboard service provides a function to mark a particular message as to be deleted. This can only be done by the mediators defined in the Billboard service, confirming this authorization with a signature.

Deleted messages will NOT any longer published by the billboard service but may kept in the database of the billboard client, marked as blocked/deleted.

### Methode

This method is called to delete/block a message.

```TypeScript
// call to delete a message
dm3_billboard_deleteMessage
```

### Request

The request passes the **identifier** of the billboard and the **identifier** of the message. Also, a signature of the mediator is passed to proof the autority to execute this function and to ensure traceability.

* **idBillboard** The **id** of the billboard where a messages should be deleted.
* **idMessage** The **id** of the message which should be deleted. This is the hash of the message.
* **mediator** The ENS name of the mediator who deleted the messages. This ENS name must contain a valid **dm3** profile.
* **signature** The signature of the above information, signed by the mediators signing key (defined in **dm3** profile)

```TypeScript
// the id of the billboard
idBillboard = <ens name of the billboard>
// the id of the message to be deleted
idMessage = <hash of the message>
// the ENS name of the mediator
mediator = <ens name of the mediator>
// signature:  
signature = sign(sha256(safe-stable-stringify(idBillboard+idMessage)))
```

### Response

The response is as defined in the JSON-RPC specification. In case of an error, an error message is returned.

> **Example**
>
> ```TypeScript
> {
>  "jsonrpc": "2.0", 
>  "error": {
>    "code": -32600, 
>    "message": "Invalid Request"
>  }, 
>  "id": null
> }
> ```

## Delete/block an (inappropriate) Message, SIWE

This is the same functions as above with the extension that temporary profiles can be used by providing additionally the SIWE message and signature.

To verify that the delete request is valid, the SIWE message must be checked for containing the correct

* address,
* domain.

### Methode

This method is called to delete/block a message.

```TypeScript
// call to delete a message
dm3_billboard_deleteMessage
```

### Request

The request passes the **identifier** of the billboard and the **identifier** of the message. Also, a signature of the mediator is passed to proof the autority to execute this function and to ensure traceability.

* **idBillboard** The **id** of the billboard where a messages should be deleted.
* **idMessage** The **id** of the message which should be deleted. This is the hash of the message.
* **mediator** The ENS name of the mediator who deleted the messages. This ENS name must contain a valid **dm3** profile.
* **signature** The signature of the above information, signed by the mediators signing key (defined in **dm3** profile)
* **SIWEMessage** the SIWE message containing the mediators address and the domain.
* **SIWESignature** the signature to the `SIWEMessage`

```TypeScript
// the id of the billboard
idBillboard = <ens name of the billboard>
// the id of the message to be deleted
idMessage = <hash of the message>
// the ENS name of the mediator
mediator = <ens name of the mediator>
// signature:  
signature = sign(sha256(safe-stable-stringify(idBillboard+idMessage)))
// SIWE message
SIWEMessage = <SIWE text message>
// SIWE signature
SIWESignature = <SIWE signature>
```

### Response

The response is as defined in the JSON-RPC specification. In case of an error, an error message is returned.

## Suspend Sender

Mediators have the task and the right to block or delete inappropriate content. If a sender repeatedly sends messages that need to be deleted, the mediator can also ban this sender. This means that the sender is blacklisted from the delivery service, so that no more messages can be received from him. For this purpose the spam protection rules of DM3MTP are applied.

All messages of blocked user are handled as deleted.

### Methode

This method is called to suspend a sender

```TypeScript
// call to suspend a sender
dm3_billboard_suspendSender
```

### Request

The request passes the ENS name of the to be suspended sender. Also, a signature of the mediator is passed to proof the autority to execute this function and to ensure traceability.

* **blockedSender** The address or ENS name of the sender to be suspended.
* **mediator** The ENS name of the mediator who deleted the messages.
* **signature** The signature of the above information, signed by the mediators signing key (defined in **dm3** profile)

```TypeScript
// the address or ENS name of the blocked sender
blockedSender = <ENS name of the sender>
// the ENS name of the mediator
mediator = <ens name of the mediator>
// signature:  
signature = sign(sha256(blockedSender))
```

### Response

The response is as defined in the JSON-RPC specification. In case of an error, an error message is returned.

> **Example**
>
> ```TypeScript
> {
>  "jsonrpc": "2.0", 
>  "error": {
>    "code": -32600, 
>    "message": "Invalid Request"
>  }, 
>  "id": null
> }
> ```

## Get active viewers

Active viewers are instances retrieving the billboard messages. This number is displayed in the billboard embedded widget.

### Methode

This method is called retrieve the number ob active viewers.

```TypeScript
// call to retrieve number of active viewers
dm3_billboard_countActiveViewers
```

### Request

The request passes the **identifier** of the billboard.

* **idBillboard** The **id** of the billboard.

```TypeScript
// the ENS name of the billboard
idBillboard = <ENS name of the billboard>
```

### Response

The number of active viewers is returned.

```JavaScript
{
  viewers: Number,
}
```

In case of an error, an error message is returned.


# Embedded Widget

With the **dm3 billboard embedded widget** a REACT component is available, based on DM3MTP and DM3BMP. A billboard chat function can be integrated into any web application with minimal effort. The appearance and look-and-feel of the component can be extensively customized to seamlessly integrate the component into applications.

* [UI/UX Overview](broken://pages/ZlZ31jGCfRbQT9ker7eK)
* [Parameters](broken://pages/ZlZ31jGCfRbQT9ker7eK)
* [Processes](broken://pages/ZlZ31jGCfRbQT9ker7eK)

## UI/UX Overview

The embedded widget displays the messages of the billboard and allows users to participate in the discussion with statements. Special users (authorized by the billboard service) act as mediators to delete inappropriate or inadmissible messages. Special functions are available for these users.

## Parameters

The component needs some parameters from the parent application:

* **Billboard ID:** The billboard id is the ENS name of the billboard. This name has a **dm3 profile** as text record containing all relevant information.
* **Login-Message:** This is a message provided as login information (like the *Login-With-Ethereum Message*). This message will be shared with the backend for verification purposes. This parameter may be **empty** or undefined if user is not logged in.
* **Login-Signature:** This is the signature to the above message by the user's private key. This parameter may be **empty** or undefined if user is not logged in.
* **User Address:** The address of the user's wallet. The address is needed to establish the connection to his/her ENS name (reverse record must be set!) and his/her avatar. In addition, the address is needed to eventually identify the user as a mediator.
* **Start Time:** The components can diplay the time of the message relative to the start time. This parameter is OPTIONAL. If it is not set, the ablolute time is displayed.
* **ENS Lookup:** The components supports ENS name lookup (showin the ENS name pointing to the address instead of the address). This parameter (**boolean**) defines, if this feature is enabled or not. If enabled, an additional signature is requested to proof that the user controls the key belonging to the address.

## Processes

### Viewer

All communications of a billboard chat are public. This means that anyone can view the communication history (the statements). In the view mode of the UI component, it is associated with a particular billboard and displays the messages retrieved via the Billboard Service API. Interaction with the billboard and statements is not possible in this view.

<figure><img src="https://1600223355-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmGk8YCcEZyeSqUV7NFpK%2Fuploads%2FtKfeflJFfX2om7ujxZrg%2Fui_only_viewing.svg?alt=media&amp;token=5030e91f-3d10-4339-9591-e775fb0b4186" alt=""><figcaption></figcaption></figure>

#### Parameters

Only the `billboard id` and optionally the `start time` is defined. The `Login-Message`, `Login-Signature`, and the user's `address` are not set.

### Discussion Participant

To join the conversation, the user must identify himself. This is done, for example, by "Login with Ethereum" in the parent application. The billboard widget is then passed a `Login-Message`, the `Login-Signature`, and the `User Address`. Based on a **random seed**, the **dm3** keys are derived and a virtual ENS name is created on the billboard delivery service (managed in the service and linked into the ENS via CCIP). This enables the user to send messages to the billboard service and thus participate in the discussion. IMPORTANT: the login process is done outside the component. After sucessful login, the parameters `Login-Message`, `Login-Signature`, and `User Address` are set.

If the parameter `ENS Lookup`is set `true`, the users can proof their wallet address by providing a signature.

<figure><img src="https://1600223355-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmGk8YCcEZyeSqUV7NFpK%2Fuploads%2F2S5ylfEEBxxFYI429OlW%2Fui_logged_in_not_validated.svg?alt=media&amp;token=dad0a399-115b-4b07-b8e5-42338d9d356b" alt=""><figcaption></figcaption></figure>

If the parameter `ENS Lookup` is set `false`, this option is not activated.

<figure><img src="https://1600223355-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmGk8YCcEZyeSqUV7NFpK%2Fuploads%2FJtUkbIRXHx42s2teAYZH%2Fui_logged_in_no_enslookup.svg?alt=media&amp;token=573a19d4-4696-467f-839b-a8785cccfbc0" alt=""><figcaption></figcaption></figure>

#### Parameters

All parameters are set.

#### Validation of the wallet address

The participation takes place under the identity of the Wallet address. If this option is activated and the user has an ENS name that is linked to this address, this name can be used instead of the address in the conversation (the reverse record in the ENS must be set correctly for this).

However, to establish this connection, it must be proven that the user is actually in possession and control of the keys to this address (to exclude tampering). This proof is provided by an additional signature.

**TEXT to be SIGNED:**

> dm3 billboard chat: Please sign this message to activate the linkage of your address to your ENS name in the chat (if reverse lookup is set!). Important: No transaction is sent to the blockchain. No fees have to be paid.

This process is triggered by pressing the button "Proof your wallet address". As soon as the signature and thus the proof has been provided, the corresponding ENS name is now displayed for this address in all viewers.

<figure><img src="https://1600223355-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmGk8YCcEZyeSqUV7NFpK%2Fuploads%2FqAk35LBoRcQuBSmsFQC7%2Fui_logged_in_validated.svg?alt=media&amp;token=d2523d48-df41-4c09-bda5-da7a3022eac0" alt=""><figcaption></figcaption></figure>

#### Sending Statements

Once the user has logged in (e.g. with Sign In With Ethereum), the user's login information and address are passed to the component and participation mode is enabled. Here the user can send his/her statements as messages to the billboard. This is done according to **dm3** standard by sending an envelope with an encrypted message to the billboard.

If a minimum waiting time is defined by the billboard service (see properties), the user must wait this time before he can send a message again.

<figure><img src="https://1600223355-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmGk8YCcEZyeSqUV7NFpK%2Fuploads%2FZ5qEuYhXmeEmpZghLP8Q%2Fui_logged_in_validated_waiting_after_sending.svg?alt=media&amp;token=5c679056-9b9c-42ba-9e0a-ae3cc8caff81" alt=""><figcaption></figcaption></figure>

### Moderator

Moderation of a discussion is necessary when inappropriate or improper statements are made. The list of authorized moderators (their ENS names or addresses) is provided by the Billboard Service. The billboard ui componente recognizes a moderator if he is logged in via SIWE and his address is on the moderator list.

In this case user joins the conversation as a moderator. The `Login Signature` must fit to `Login message`. The signature must be checked.

The moderator view provides the moderator with the option to delete inappropriate statements (via the delete link next to the message).

<figure><img src="https://1600223355-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmGk8YCcEZyeSqUV7NFpK%2Fuploads%2FL5juXjxJJDaFaybUlMBB%2Fui_logged_in_moderator_loggedin.svg?alt=media&amp;token=553323b0-0361-4d07-8082-f78dd1e00845" alt=""><figcaption></figcaption></figure>

If a statement is marked for deletion, the delete link is changed to a recovery link where the moderator has for 15s to cancel the deletion.

<figure><img src="https://1600223355-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmGk8YCcEZyeSqUV7NFpK%2Fuploads%2FV0HT8KgGuMPAYuePYkfR%2Fui_logged_in_moderator_deleted.svg?alt=media&amp;token=615fa659-05eb-494d-963a-64684bd0ac2d" alt=""><figcaption></figcaption></figure>

Only after this time, the API function is called to delete the message.

If a user sends multiple messages that need to be deleted by the moderators, the UI can also provide an option to permanently ban that user. This is done via the API function.


# Linked Profiles (DM3LPP)

(beta - in work)

## Overview

For certain use cases, standalone (or anonymous) profiles that can optionally be linked and synchronized with the main profile are required. For example, a dApp could provide integrated in-app messaging, a website could allow direct contact with designated persons, or a billboard chat allows anonymous users to post statements. These functions can, for instance, be realized using the embedded **dm3** components.

Eventually, it might be desirable for users to connect to a dApp without disclosing their identity to send messages anonymously. Users should also be able to write a message from the embedded messaging widget independently of their messenger app, which is then optionally synchronized with their inbox.

In addition, security considerations may require using limited-scope profiles with restricted rights derived from the user's wallet, which should be linked optionally to the user's inbox.

*The following description refers exclusively to ENS as a registry but can equally be applied to any other name service of any chain or layer 2 or even a cloud service.*


# Profile Links

## Limited Scope Profiles

In many applications, embedded messaging components are used so that users can exchange messages with each other or contact the app team or something similar.

With **dm3 embedded widgets**, such a component is available and fully integrated into the dm3 ecosystem. Communication in these applications often might be anonymous, i.e., users come to this page and want to start immediately without going through an elaborate authentication process. In addition, it should be possible to link this communication to the user's inbox (any **dm3-compatible** messenger) if necessary and also to ensure that the communication keys for encryption and signatures do not have to be shared with potentially risky dApps at any time.

**Limited Scope Profiles (LSP)** are local communication profiles that are created for a specific application and meet the above requirements. LSP provides:

* **Security:** Having different keys for different apps.
* **Interoperability:** LSP enables any embedded component to link with the user's main messenger (**dm3-compatible** messenger).
* **Self-sovereignty:** The users decide, if they want to connect these profiles to their inbox or not.

### General Profile Links

Besides LSP, any other **dm3** profiles can be linked together. This makes it possible to communicate with different identities but bring them together and manage them in one place.

## Create a Linked Profile

To create a **Linked Profile**, two approaches to create the communication keys are possible:

1. A unique message is provided and signed by the wallet's key. The keys (for encryption and signatures) are derived from this signature of the message.
2. The message and signature are provided by the embedding app (for example, if **Sign-in-with-Ethereum** (SIWE) is used). Then, the signature must not be used as a seed for deriving the keys (this information is potential public information and must not be used to derive keys). The keys are then derived from a random entropy.

A dm3 profile is created based on these keys and the wallet's address. For this purpose, the dApp that uses the messaging component SHOULD also operate one or more message relay nodes and a CCIP resolver back-end if **dm3** profiles are managed in a cloud service or Layer-2.

The profiles are given virtual ENS names, which are the wallet's addresses as a subdomain of the app's ENS name, which is used to publish this profile. This is usually provided via CCIP (Cross Chain Interoperability Protocol) so that the information is managed cost-effectively.

> **Example** of a virtual name for the dm3 profile :
>
> ```JavaScript
> 0x1234...789.addr.myapp.eth
> ```

#### Workflow to create a Linked Profile by signing a message

{% @mermaid/diagram content="sequenceDiagram

```
participant DM3 as DM3-Widget
participant W as Wallet
participant LIB as DM3-Lib-Lp
participant DS as DM3-Delivery Service
participant OR as DM3-Offchain Resolver

DM3 ->> W: signCreateProfileMessage()
LIB-->LIB:createLpWallet(createProfileSig)
LIB-->LIB:createProfile(addr,createProfileSig)
LIB-->>DS: getDeliveryServiceToken(lpWallet)
LIB-->>OR: claimAddress(lpWallet)
LIB-->>OR: claimSubdomain(lpWallet,lpName,ownerAddr,authSig)
LIB-->>DS: submitUserProfile(lpName,lpProfile)" %}
```

Workflow to create a Linked Profile embedded in another dApp

{% @mermaid/diagram content=" sequenceDiagram
participant DAPP as dApp
participant W as DM3-Widget
participant LIB as DM3-Lib-Lp
participant DS as DM3-Delivery Service
participant OR as DM3-Offchain Resolver

```
DAPP ->> W: props(authMessage,ownerAddr,authSig,appId,entropy)
W->>OR: lpExists(appID,ownerAddr)
opt lp.owner.appId.dm3.eth has not a linked profile yet
    W->>LIB: createNewLp(ownerAddr,appId,entropy)
        LIB-->LIB:createLpWallet(entropy)
        LIB-->LIB:createProfile(ownerAddr,lpWallet)
        LIB-->>OR: claimAddress(lpWallet)
        LIB-->>OR: claimSubdomain(lpWallet,lpName,ownerAddr,authSig)
        LIB-->>DS: submitUserProfile(lpName,lpProfile)
end
opt lp.owner.appId.dm3.eth has already a profile
W ->> DS: request privateKey for LpWallet(appId,ownerAddr)
LIB-->LIB:recreateProfile(ownerAddr,lpWallet)
LIB-->>DS: getDeliveryServiceToken(lpWallet)
end" %}
```

## Usage of the Linked Profiles (LP)

Once the LP is created, it can already be used like any other **dm3** profile. Users can send and receive messages.

These profiles are already connected to the wallet address, but have no connection to any existing **dm3** profile. So it is now possible to run an anonymous profile.

The effort for users to onboard is minimal so that the creation of LP can be effectively integrated into dApps. At most a signature of the wallet is needed if a custom message is used. When using SIWE or similar, the creation can be done completely in the background without any user interaction.

From the user's point of view, it may be desirable to have such a communication without a connection to his main **dm3** profile (or at least to start the communication that way). Especially when users don't know how much they can trust the application, there is a need to first disclose as little information as possible and still have a secure communication.

Possible applications for anonymous profiles:

* In-app messaging (e.g., in a game), where active users exchange information and the communication is only temporarily interesting,
* a public feedback form where users leave general info.
* Contact form to write directly to contact persons,
* support form, to ask for help inside a dApp.

For other use cases (including some of the above), it is useful or desirable that the communication is also managed in the user's main inbox and thus linked to the main profile.

### Linking to Main Profile

To pair a Linked Profile with a Main Profile, a service message is sent to the Main Profile containing the pairing request.

For this purpose new message types are introduced (see Message Metadata Structure):

* **LINK:** *(OPTIONAL)* This is a service message. The sender (LP) wants to link a local profile with this main profile. The receiving app (main profile) must allow the user to accept or reject a link request. If the app does not support this message, a user cannot connect his local profile and manage the communication in his inbox.
* **LINK\_RECOVER:** *(OPTIONAL)* This is a service message. The sender (LP) is already linked but needs to recover the keys (e.g., because he is accessing the dApp from another device). If the main profile knows the link, the necessary keys and information are returned in the LINK\_ACCEPT message.
* **LINK\_ACCEPT:** *(OPTIONAL)* This is a service message. The sender (Main Profile) signals that the link request is approved. If appropriate, the known private keys and other information is included.

For linking, additional metadata fields are defined to transfer the required information:

* `Profile Private Key` The local private key of the linked profile needs to be revealed to the **Main Profile**. It is needed by the Main Profile to recover linked profiles.
* `Wallet Private Key` *(OPTIONAL)* If the wallet is generated randomly, this key is needed to recover the linked profile. If the keys are generated from a signature, this field is not set.
* `Profile Name` The ENS name of the profile.
* `Profile Hash` The sha256 Hash of the profile content.
* `Nonce` The nonce used to derive the keys. It is needed to recover the profile.
* `ValidUntil` A timestamp (UNIX time) until the linkage is valid. After this time, the linkage must be renewed.
* `Link Message` The **Link Message** which needs to be signed by the user's wallet. Together with the signature it is needed to verify the ownership of the wallet and prevent unautorized tries to connect.
* `Wallet Signature` This signature by the wallet's key is needed to proof the ownership of the address. Signed is the **Link Message**.

#### Definition Link Message

> Link your local profile with your dm3 account: \[your\_ens\_name]
>
> (There is no paid transaction initiated. The signature is used off-chain only.)
>
> URI: \[dapp initiating the connection] Version: 1 Chain ID: 1 Nonce: \[...] Issued At: \[date\_time] Expiration Time: \[date\_time]

The definition of the Link Messages follows largely [EIP-4361](https://docs.login.xyz/general-information/siwe-overview/eip-4361).

#### Extension of Message Metadata Structure

```json
DEFINITION: Message Metadata Structure

{
   ...
   // specifies the message type
   type: ... | "LINK" | "LINK_RECOVER" | "LINK_ACCEPT"
   ...
   link: {
      // the local profile's private key
      profilePrivateKey?: string,
      // the wallet key if local wallet exists
      walletPrivateKey?: string,
      //the nonce used for the key generation
      nonce?: string,
      // the ENS name of the profile
      profileName: string,
      // the hash of the profile
      profileHash: string,
      // a timestamp util when the linkage is valid (UNIX time)
      validUntil: number,
      // the link message
      linkMessage: string
      // signature of the wallet (LP) or signature key (main profile)
      // sign( sha256(linkMessage) )
      signature: string
   }
}
```

#### Workflow: Link

To connect a **Local Profile** to another **dm3 Profile**, a service message from the type `LINK` with the filled data structure `link` in **Message Metadata** is sent to the profile to connect to. The `message` field of the **Envelope** is empty or may contain a fallback message informing that this is a service message only.

As result of the received LINK service message, the receiving messenger app initiates a user interaction to inform about the linking attempt. If the user agrees, a `LINK_ACCEPT` service message is returned, confirming the linkage, containing the ENS-name of the profile and the signature of the main profile's signature key.

{% @mermaid/diagram content="  sequenceDiagram
actor USER as User
participant WALLET as Wallet

```
box App with embedded dm3 widget 
participant LSP as Local Linked Profile App
participant DS1 as Delivery Service
end

box Main dm3 App
participant DS2 as Delivery Service (Main Profile)
participant DM3 as DM3-compatible Messenger (Main Profile)
end

USER-->>LSP: Requests Linkage to Main Profile
LSP -->> WALLET: Request Signature to Link-Message
WALLET -->> USER: Request Signature to Link-Message
USER -->> LSP: Signature (to Link-Message)
LSP->>DS2: Send Message (LINK)
note over LSP,DS2: includes: Link-Message, Signature, Private Keys, <br> Nonce, Profile Name, Profile Hash  
DS2->>DS2: Cache Message

DM3-->>DS2: Request new Messages
DS2->>+DM3: Deliver Message (LINK)
DM3-->>DM3: Check <br> if Linked profile does not exist 
DM3-->>USER: Requests Approval for Linkage
USER-->>DM3: Approves Linkage
DM3-->>DM3: Stores Linked Profile Keys and Info
DM3->>-DS1: Send Message (LINK_ACCEPT)
note over DM3,DS1: includes: Name of Linked Profile, Signature
DS1->>DS1: Cache Message

LSP-->>DS1: Request new Messages
DS1->>+LSP: Deliver Message (LINK_ACCEPT)
LSP-->>-LSP: Publishes Link Info in Profile <br> [network.dm3.link]" %}
```

```mermaid
  sequenceDiagram
    actor USER as User
    participant WALLET as Wallet

    box App with embedded dm3 widget 
    participant LSP as Local Linked Profile App
    participant DS1 as Delivery Service
    end
    
    box Main dm3 App
    participant DS2 as Delivery Service (Main Profile)
    participant DM3 as DM3-compatible Messenger (Main Profile)
    end
   
    USER-->>LSP: Requests Linkage to Main Profile
    LSP -->> WALLET: Request Signature to Link-Message
    WALLET -->> USER: Request Signature to Link-Message
    USER -->> LSP: Signature (to Link-Message)
    LSP->>DS2: Send Message (LINK)
    note over LSP,DS2: includes: Link-Message, Signature, Private Keys, <br> Nonce, Profile Name, Profile Hash  
    DS2->>DS2: Cache Message
   
    DM3-->>DS2: Request new Messages
    DS2->>+DM3: Deliver Message (LINK)
    DM3-->>DM3: Check <br> if Linked profile does not exist 
    DM3-->>USER: Requests Approval for Linkage
    USER-->>DM3: Approves Linkage
    DM3-->>DM3: Stores Linked Profile Keys and Info
    DM3->>-DS1: Send Message (LINK_ACCEPT)
    note over DM3,DS1: includes: Name of Linked Profile, Signature
    DS1->>DS1: Cache Message
   
    LSP-->>DS1: Request new Messages
    DS1->>+LSP: Deliver Message (LINK_ACCEPT)
    LSP-->>-LSP: Publishes Link Info in Profile <br> [network.dm3.link]

```

If a **Linked Profile** is sending the `LINK` message to a profile already being linked, only the validity date is updated, no user interaction is needed. The `LINK_ACCEPT` message is not returned.

## Profile Recovery

As **Linked Profiles** often are used for embedded messaging components in dApps, it is common for users to access the same dApp on different devices or in a different browser or browser context. Then it is not possible to automatically generate the same local profile's private keys. The user can easily use another anonymous profile, but this one would be independent and not linked to the initial profile. However, once users have connected the local profile to their main profile, they can use it to recover the local profile's private keys and information (nonce).

This is executed by sending a **LINK\_RECOVER** message to the Main Profile. The `link` substructure in the **Message Metadata Structure** is filled according the **LINK** message without setting the unknown private keys and nonce. But the `Link Message`, `Signature`, as well as `Profile Name` and `Profile Hash` must be sent. If the Main Profile receives such a message, which is already registered as a link, it transmits the requested information (private keys and nonce) in the response message (**LINK\_ACCEPT**).

{% @mermaid/diagram content="  sequenceDiagram
actor USER as User
participant WALLET as Wallet

```
box App with embedded dm3 widget
participant LSP as Local Linked Profile App
participant DS1 as Delivery Service
end

box Main dm3 App
participant DS2 as Delivery Service (Main Profile)
participant DM3 as DM3-compatible Messenger (Main Profile)
end

LSP -->> WALLET: Request Signature to Link-Message
WALLET -->> USER: Request Signature to Link-Message
USER -->> LSP: Signature (to Link-Message)

LSP->>DS2: Send Message (LINK_RECOVER)
note over LSP,DS2: includes: Link-Message, Signature, Profile Name, Profile Hash 
DS2->>DS2: Cache Message

DM3-->>DS2: Request new Messages
DS2->>+DM3: Deliver Message (LINK_RECOVER)
DM3-->>DM3: Check <br> if Linked Profile already exists  

DM3->>-DS1: Send Message (LINK_ACCEPT)
note over DM3,DS1: includes: Name of linked profile, Signature, Private keys, Nonce
DS1->>DS1: Cache Message

LSP-->>DS1: Request new Messages
DS1->>+LSP: Deliver Message (LINK_ACCEPT)
LSP-->>LSP: Stores Private Keys and Nonce
LSP-->>-LSP: Updates Link Info in Profile <br> [network.dm3.link]" %}
```

```mermaid
  sequenceDiagram
    actor USER as User
    participant WALLET as Wallet

    box App with embedded dm3 widget
    participant LSP as Local Linked Profile App
    participant DS1 as Delivery Service
    end
    
    box Main dm3 App
    participant DS2 as Delivery Service (Main Profile)
    participant DM3 as DM3-compatible Messenger (Main Profile)
    end
   
    LSP -->> WALLET: Request Signature to Link-Message
    WALLET -->> USER: Request Signature to Link-Message
    USER -->> LSP: Signature (to Link-Message)
    
    LSP->>DS2: Send Message (LINK_RECOVER)
    note over LSP,DS2: includes: Link-Message, Signature, Profile Name, Profile Hash 
    DS2->>DS2: Cache Message
   
    DM3-->>DS2: Request new Messages
    DS2->>+DM3: Deliver Message (LINK_RECOVER)
    DM3-->>DM3: Check <br> if Linked Profile already exists  
   
    DM3->>-DS1: Send Message (LINK_ACCEPT)
    note over DM3,DS1: includes: Name of linked profile, Signature, Private keys, Nonce
    DS1->>DS1: Cache Message
   
    LSP-->>DS1: Request new Messages
    DS1->>+LSP: Deliver Message (LINK_ACCEPT)
    LSP-->>LSP: Stores Private Keys and Nonce
    LSP-->>-LSP: Updates Link Info in Profile <br> [network.dm3.link]

```

### Link Profile


# Message Storage Protocol (DM3MSP)

The message storage protocol is an approach for the effective storage of conversations and messages. It is independent of the message transport protocol and can be used as a core protocol by applications.


# Storage

The dm3 protocol does not specify where the user has to store his messages. Depending on the use case and the requirements of the user, the messages can be stored in different places and ways. The user should always be in full control of his/her decision, where and how to manage conversation data.

The following approaches are possible, although not the only ones.

* **Local File Storage:** All conversations including attached media are stored in the local file system. All stored information is encrypted. While local storage is the most privacy preserving (conversation data is only stored an the user's device and in full control of the user), synchronization between devices is restricted or not possible.
* **Web3 Decentralized Storage:** The conversations are organized and pinned in IPFS. The information is stored fully encrypted. Multiple devices of the user can access the decentrally managed data.
* **Cloud Storage:** The conversations are stored at a cloud service of the user (like Google drive). The information is stored fully encrypted. The user decides whether and/or which cloud service provider to use. The availability of the conversation data thus depends on the availability of the cloud service provider. Synchronization between different devices is easy as long as the cloud drive is accessible.
* **dm3 Service Storage:** A special variant of cloud storage is the data service of a dm3 node (delivery service). As an optional service, this can offer the storage of encrypted conversations. To access the conversation history, the client must be connected to this delivery service. Synchronization between multiple delivery service nodes is optional.

*\[IMAGE to visualize storage]*

For performance reasons, a client can/should cache current conversations so that it does not have to fetch the data from a possibly remote storage each time it is accessed. If additional data is needed (e.g. earlier parts of the communication history), it can be retrieved sequentially.


# Data Structure

The conversation data is stored as a data tree grouped by conversations in containers. The structure can be realized as a single file (e.g., export record), as a file store with multiple files (e.g., on local file system, a cloud drive, or in a decentralized storage), or as a database (e.g., as a service).

The data is structured in such a way that fast access with low overhead to specific data is possible, but retrieval of larger data packages is also efficient enough.

## Architecture

The information containers are clustered in 3 types of data:

* **Root:** The root container contains a list of all conversation IDs. A conversation is specified as a collection of messages between 2 users. For each communication partner a conversation is stored. There is exactly one root container per user. The list of conversation IDs is encrypted (with the user's storage encryption key).
* **Conversations:** A conversation container contains a list of chunks, where the actual messages are stored. Each list entry, the chunk identifier, contains the chunk's id and the timestamp of the first message of the chunk. The list of chunks is encrypted (with the user's storage encryption key).
* **Chunks:** Each chunk container stores a list of messages. Those messages are sorted by timestamp. Each chunk can contain a different number of messages. The number is determined by the absolute size of the chunk. Chunks are encrypted (with the user's storage encryption key).

<figure><img src="https://1600223355-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmGk8YCcEZyeSqUV7NFpK%2Fuploads%2F52VqDUbYdlCH5FKgOJPD%2Fstorage.svg?alt=media&amp;token=044c40c3-6c7b-4778-ae96-5c169fb0c635" alt=""><figcaption></figcaption></figure>

### Root Container

The **key** of the `root` container is defined as SHA-256 hash of the signature of the user's ENS-name (represented by `$own_ens_name`).

```TypeScript
key = sha256( signature( $own_ens_name ))
```

This might be the file name, database identifier, or the section name of a file.

The **conversations** list is the list of ENS-names of the conversation contacts which are the IDs of the conversations. These are ENS domains or ENS subdomains with **dm3** profile (see registry).

```TypeScript
DEFINITION: Root Container

{
    conversations: string[]
}
```

This list is encrypted with the user's storage encryption key.

> **Example:** (unencrypted)
>
> ```TypeScript
> {
>    "conversations":  
>    [
>       "friend1.ens",
>       "0x123..abc.addr.dm3.eth" 
>    ]
> }
> ```

### Conversation Container

The **key** of a `conversations` container is defined as SHA-256 hash of the combination of the key of the root container `root.key` and the communication partner's ENS-name, which is listed in the `root` container's conversations list (represented by `root.conversations[$index]` at the `$index` of the list).

```TypeScript
key = sha256( root.key + root.conversations[$index] )
```

For the same conversation partner, only one conversation can exist. A conversation must have at least one chunk with one message. Empty conversations are not stored.

A reference to a chunk is described by an identifier (incrementing, starting with 0) and the timestamp (unix time in milliseconds) of the first message in that chunk.

***Note:** The timestamp can be used to find messages from a certain time period more easily without having to scan through all chunks.*

```TypeScript
DEFINITION: Chunk Identifier

{
    // the chunk identifier, starting with 0
    id:   number,
    // timestamp of the first message in a chunk
    timestamp: number
}
```

The **chunks** list is the list of chunk identifiers describing the existing chunks. As chunks and messages are sorted in time, the last chunk in the list is the newest one and used to add a new message.

```TypeScript
DEFINITION: Conversations Container

{
    chunks: ChunkIdentifier[]
}
```

This list is encrypted with the user's storage encryption key.

> **Example:** (unencrypted)
>
> ```TypeScript
> {
>    "chunks":  
>    [
>       { "id": 0, "timestamp": 16759549450000 },
>       { "id": 1, "timestamp": 16762446650000 }
>    ]
> }
> ```

### Chunk Container

The **key** of a `chunks` container is defined as SHA-256 hash of the combination of the key of the conversations container `$conversation.key` and the stringified chunk identifier, which is listed in the conversation's container's chunks list (represented by `$conversation` as the current conversations container and the chunk identifier `$conversation.chunks[$index]` at the `$index` of the list).

```TypeScript
key = sha256( $conversation.name + stringify( $conversation.chunks[$index] ))
```

The **messages** list contains the envelopes (see Encryption Envelope Structure) including the message. However, the fields encrypted during transmission are decrypted. The entire chunks container is subsequently encrypted with the storage encryption key.

```TypeScript
DEFINITION: Chunk Container

{
    messages: Envelope[]
}
```

The size of the chunks is defined by the maximum size. The maximum size is defined by the client.

**Recommendation:**

* minimum: 500kB,
* maximum: 10MB.

A chunk must contain at least one message. Empty chunks are not created.

***Note:** The envelope with the message contains encrypted content during transmission (end-to-end encryption). The decrypted information is used for storage so that the sender's public key is not required again to decrypt the data for future use.*

***Note:** The maximum size of a chunk must be bigger or equal to the maximum size of a message defined by the delivery service (see maximum message size).*

The messages list is encrypted with the user's storage encryption key.

> **Example:** (unencrypted)
>
> ```TypeScript
> {
>    "messages":  
>    [
>       { "message": {...}, "metadata": {...}, ...},
>       { "message": {...}, "metadata": {...}, ...}
>    ]
> }
> ```


# References

**\[NIR1]** Nir, Y.; Langler, A.: **ChaCha20 and Poly1305 for IETF Protocols.** Internet Research Task Force (IRTF), Request for Comments: 7539, ISSN: 20070-1721, <https://datatracker.ietf.org/doc/html/rfc7539>.

**\[RPC1]** JSON-RPC Working Group: JSON-RPC 2.0 Specification, Origin Date: 2010/03/26, updated 2013/01/04, <https://www.jsonrpc.org/specification>.


