diff --git a/XIPs/xip-21-transaction-reference-content-type.md b/XIPs/xip-21-transaction-reference-content-type.md
index 2c91aec..65fcc20 100644
--- a/XIPs/xip-21-transaction-reference-content-type.md
+++ b/XIPs/xip-21-transaction-reference-content-type.md
@@ -2,9 +2,8 @@
title: On-chain transaction reference content type
description: Provides an on-chain transaction hash or ID sent as a message.
author: @rygine (Ry Racherbaumer), @lourou (Louis Rouffineau), @nmalzieu (Noé Malzieu), @galligan (Matt Galligan), @nakajima (Pat Nakajima), @yash-luna (Yash Lunagaria)
-discussions-to: https://community.xmtp.org/t/xip-21-on-chain-transaction-reference-content-type/532
-status: Last Call
-type: Standards Track
+status: Final
+type: Standards
category: XRC
created: 2024-01-26
---
@@ -35,13 +34,13 @@ The goal of the transaction reference content type is to provide transaction det
```ts
type TransactionReference = {
/**
- * The namespace for the networkId
+ * The chain ID for the transaction as outlined in EIP-155
*/
- namespace?: string;
+ chainId: number;
/**
- * The networkId for the transaction, in decimal or hexidecimal format
+ * The networkId for the transaction
*/
- networkId: number | string;
+ networkId?: number;
/**
* The transaction hash
*/
@@ -52,7 +51,7 @@ type TransactionReference = {
metadata?: {
transactionType: string;
currency: string;
- amount: number;
+ amount: bigint;
decimals: number;
fromAddress: string;
toAddress: string;
@@ -62,23 +61,23 @@ type TransactionReference = {
## Rationale
-The `networkId` provides details of the network used for the transaction, while the `reference` field contains the hash of the transaction on the network. These two fields should be enough to display a basic reference to the transaction. An optional `namespace` field can be used for a more human-readable description of the network.
+The `chainId` provides details of the network used for the transaction as defined in [EIP-155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md), while the `reference` field contains the hash of the transaction on the network. These two fields should be enough to display a basic reference to the transaction. An optional `networkId` field can be used when it differs from the `chainId`.
In addition, optional `metadata` can be added to provide more details and a richer display of the transaction.
-## Backward Compatibility
+## Backward compatibility
To maintain backward compatibility, a content fallback is stored in the codec as text — ensuring that the intent of the transaction reference content type is conveyed even in non-supporting clients.
-## Test Cases
+## Test cases
Test cases will validate the interpretation of schema type and effective use of a content fallback. These are essential for ensuring interoperability across XMTP platforms.
-## Reference Implementation
+## Reference implementation
-You can find a reference implementation of this transaction reference content type in the [xmtp-js-content-types](https://github.com/xmtp/xmtp-js-content-types) repo under the [packages/content-type-transaction-reference](https://github.com/xmtp/xmtp-js-content-types/tree/main/packages/content-type-transaction-reference) directory.
+You can find a WIP reference implementation of this transaction reference content type in the [xmtp-js-content-types](https://github.com/xmtp/xmtp-js-content-types) repo under the [packages/content-type-transaction-reference](https://github.com/xmtp/xmtp-js-content-types/tree/main/packages/content-type-transaction-reference) directory.
-## Security Considerations
+## Security considerations
While there are no known negative security implications in the data of the on-chain transaction reference content type, clients could pass inaccurate or misleading values for these fields. In addition, clients could display inaccurate or misleading values for these fields and/or link to unrelated transactions.
diff --git a/XIPs/xip-36-frames-support.md b/XIPs/xip-36-frames-support.md
new file mode 100644
index 0000000..8270feb
--- /dev/null
+++ b/XIPs/xip-36-frames-support.md
@@ -0,0 +1,253 @@
+---
+xip: 36
+title: Frames Support
+description: Explores the new tooling required for XMTP apps to render and interact with Frames inside XMTP conversations
+author: Nicholas Molnar (@neekolas)
+discussions-to: https://community.xmtp.org/t/xip-36-supporting-frames-in-xmtp/534
+status: Review
+type: Standards
+category: Interface
+created: 2024-01-31
+---
+
+## Abstract
+
+This XIP explores the new tooling required for XMTP apps to render and interact with Frames inside XMTP conversations. The XIP also takes a deep dive into the Farcaster Frames specification and evaluates its compatibility with XMTP.
+
+## Motivation
+
+Developers building with XMTP have been asking for a way to embed generic interactive content into messages for a long time. [XMTP Content Types](../XIPs/xip-5-message-content-types.md) make sense for the head-of-the-curve use cases (such as replies, reactions, and media embeds) where requirements are well known ahead of time, but there is a very long tail of developer demands. Making app devs support hundreds of different content types to handle all those needs would never be a practical solution. We need a “one size fits all” way of enabling the long tail.
+
+We could build a competing protocol that would work for this, but I don’t see why we would create a new standard when one already exists and has traction. The question is: How could we extend Frames to work inside XMTP conversations, and what are the trade-offs?
+
+The goal here is to allow existing Frames developers to reach users in private DM channels outside of Farcaster and in public Farcaster posts, with the minimum amount of code changes for the Frames developers.
+
+## Specification
+
+Three new capabilities are required for client apps to render and interact with Frames:
+
+1. **Rendering**
+Client apps need to be able to render the "initial frame" before any interaction
+2. **Interaction**
+Client apps need to be able to interact with Frames, and the HTTP POST requests in those interactions need to include signed content that can irrefutably identify the sender as the holder of an XMTP identity
+3. **Verification**
+Frame developers need to be able to read the HTTP POST requests from #2 and verify the signatures, allowing them to provably know who clicked the button
+
+### Rendering
+
+Users already include URLs in standard XMTP `ContentTypeText` messages. Some client apps choose to render link previews for those URLs. Frames would just be an extension of that link preview functionality.
+
+To [render a Frame](https://docs.farcaster.xyz/learn/what-is-farcaster/frames), developers need to be able to render some special HTML meta tags into the UI, similar to how they already render Open Graph tags. This is a typical frame payload:
+
+```html
+
+
+
+
+
+
+
+
+```
+
+XMTP client app devs don’t need any special help from XMTP to render an existing Farcaster Frame.
+
+The problem is that some Frames will be able to support POST requests from XMTP clients, while others will only be able to receive POSTs from Farcaster clients that include a signed payload with an `fid`.
+
+This XIP proposes that Frames developers add a new meta tag to POSTs to tell clients they can receive XMTP responses.
+
+```html
+
+```
+
+For a prototype implementation of a rendering helper library, see this [frames-client](https://github.com/xmtp/xmtp-web/tree/main/packages/frames-client) in the **xmtp-web** GitHub repo.
+
+### Interaction
+
+When a user clicks a button in a Frame, the app POSTs a signed message to the Frame URL, or a different URL specified in the initial Frame using the `post_url` tag.
+
+This is an example Farcaster Frame payload:
+
+```json
+{
+ "untrustedData": {
+ "fid": 2,
+ "url": "https://fcpolls.com/polls/1",
+ "messageHash": "0xd2b1ddc6c88e865a33cb1a565e0058d757042974",
+ "timestamp": 1706243218,
+ "network": 1,
+ "buttonIndex": 2,
+ "castId": {
+ "fid": 226,
+ "hash": "0xa48dd46161d8e57725f5e26e34ec19c13ff7f3b9"
+ }
+ },
+ "trustedData": {
+ "messageBytes": "d2b1ddc6c88e865a33cb1a565e0058d757042974..."
+ }
+}
+```
+
+The `trustedData.messageBytes` is a serialized Protobuf of a signed Farcaster message, with the message payload matching this Protobuf schema:
+
+```protobuf
+message FrameActionBody {
+ bytes frame_url = 1; // The URL of the frame app
+ bytes button_index = 2; // The index of the button that was clicked
+ CastId cast_id = 3; // The cast which contained the frame URĽ
+}
+
+// MessageType and MessageData are extended to support the FrameAction
+enum MessageType {
+ .....
+ MESSAGE_TYPE_FRAME_ACTION = 13;
+}
+
+message MessageData {
+ oneof body {
+ ...
+ FrameActionBody frame_action_body = 16
+ }
+}
+```
+
+Developers are expected to call the `validateMessage` API on a hub, which would return a response that validates the signatures on the message.
+
+```json
+{
+ "valid": true,
+ "message": {
+ "data": {
+ "type": "MESSAGE_TYPE_FRAME_ACTION",
+ "fid": 21828,
+ "timestamp": 96774342,
+ "network": "FARCASTER_NETWORK_MAINNET",
+ "frameActionBody": {
+ "url": "aHR0cDovL2V4YW1wbGUuY29t",
+ "buttonIndex": 1,
+ "castId": {
+ "fid": 21828,
+ "hash": "0x1fd48ddc9d5910046acfa5e1b91d253763e320c3"
+ }
+ }
+ },
+ "hash": "0x230a1291ae8e220bf9173d9090716981402bdd3d",
+ "hashScheme": "HASH_SCHEME_BLAKE3",
+ "signature": "8IyQdIav4cMxFWW3onwfABHHS9IroWer6Lowo16AjL6uZ0rve3TTFhxhhuSOPMTYQ8XsncHc6ca3FUetzALJDA==",
+ "signer": "0x196a70ac9847d59e039d0cfcf0cde1adac12f5fb447bb53334d67ab18246306c"
+ }
+}
+```
+
+Other Farcaster APIs can then be used to link the `fid` to a blockchain account, and to retrieve other data from the user’s profile.
+
+There are clearly parts of this flow that are very Farcaster-specific. It references `fid`, `cast_id`, and `network`. I don’t think any of this is a blocker to interoperability, but it will require a little more branching code for developers to support both XMTP and Farcaster Frames.
+
+At a high level, what developers are doing with all this code is validating three things:
+
+1. The incoming POST was from a legitimate button click
+2. Which button was clicked
+3. Who clicked the button
+
+With this information, the developer then responds with HTML outlining an update to the Frame’s state using the same format as the initial render.
+
+In Jan 2024, Coinbase [released `FrameKit`](https://github.com/coinbase/onchainkit), with some high-level APIs designed to verify Frame POST payloads. Those APIs are `getFrameAccountAddress`, `getFrameMetadata`, and `getFrameValidatedMessage`. XMTP already has all the primitives needed to craft payloads that can enable these same workflows.
+
+We've developed a prototype implementation of a privacy-preserving interaction library. See the [frames-client](https://github.com/xmtp/xmtp-web/tree/main/packages/frames-client) in the **xmtp-web** GitHub repo.
+
+### Verification
+
+With the goal of making things as straightforward for existing Frames devs as possible, here is a proposed interaction payload structure for an XMTP Frame:
+
+```json
+{
+ "untrustedData": {
+ "wallet_address": "0x12345...",
+ "url": "https://fcpolls.com/polls/1",
+ "timestamp": 1706243218,
+ "buttonIndex": 2
+ },
+ "trustedData": {
+ "messageBytes": "d2b1ddc6c88e865a33cb1a565e0058d757042974..."
+ }
+}
+```
+
+The `messageBytes` would be an XMTP-specific Protobuf message that would include the payload and the signature. Something like:
+
+```protobuf
+message FrameActionBody {
+ string frame_url = 1;
+ uint32 button_index = 2;
+ uint64 timestamp = 3;
+}
+
+message FrameAction {
+ Signature signature = 1; // XMTP already has signature types that can be used here
+ SignedPublicKeyBundle signed_public_key_bundle = 2; // The SignedPublicKeyBundle of the signer, used to link the XMTP signature with a blockchain account through a chain of signatures.
+ bytes action_body = 3; // Serialized FrameActionBody message, so that the signature verification can happen on a byte-perfect representation of the message
+}
+```
+
+We could choose to add some additional metadata to this payload that would give the Frame developer more context about where the click originated. For example, `message_id` and `conversation_id` come to mind. The tradeoff here is privacy.
+
+All messages on the XMTP network are stored in topics. Topics have an opaque identifier, and only the participants in a conversation know that a given topic is "theirs." Adding the `message_id` or `conversation_id` to the payload would leak that information to the Frame developer, allowing them to track how many messages were sent in a particular conversation. This feels like an unnecessary privacy leak and should be avoided unless there is a _very_ strong need to share this information with the Frame developer.
+
+These payloads are meaningfully different from the Farcaster payloads. We can provide some helper libraries to allow a Frames developer to take the JSON payload above and get back the information required to move forward to the next Frame (`isValid`, `verifiedSenderWalletAddress`, `buttonIndex`). Because XMTP is a private network instead of a public one, the goal should be to include the minimum amount of metadata to make this work.
+
+On the sender side (the person clicking the button), XMTP SDKs already have generic interfaces for signing messages. All we need to do is define the payload format, and any app developer should be able to generate a payload matching this format and transmit it directly to the Frame URL.
+
+The `FrameAction` includes a signature of the `FrameActionBody` encoded as bytes. To verify and recover the wallet address from this payload, a developer must:
+
+1. Recover the public key from the signature
+2. Verify that the public key matches the identity key in the `SignedPublicKeyBundle`
+3. Recover the wallet address from the signature in the `SignedPublicKeyBundle`
+
+For a prototype implementation of a verification library that does this, see the [frames-validator](https://github.com/xmtp/xmtp-node-js-tools/tree/main/packages/frames-validator) in the **xmtp-node-js-tools** GitHub repo.
+
+## Backward compatibility
+
+- All Frames will be sent using ordinary XMTP text messages.
+- Client apps can choose to expand URLs found in these messages into Frames at their discretion.
+- No new Content Types are required.
+- No new SDK changes are necessary for XMTP SDKs that allow app developers to sign messages with the XMTP identity key.
+- The new helper libraries that facilitate Frame rendering, interaction, and verification are strictly opt-in.
+
+## Reference implementations
+
+We've developed reference implementations for all three components required to enable Frames on XMTP:
+
+1. [Rendering/interaction helper library](https://github.com/xmtp/xmtp-web/tree/main/packages/frames-client)
+Needs some updates to accommodate changes to the POST message schema made after development began
+
+2. [POST payload verification helper library](https://github.com/xmtp/xmtp-node-js-tools/tree/main/packages/frames-validator)
+Needs some updates to accommodate changes to the POST message schema made after development began
+
+3. [Open Graph Proxy service](https://github.com/neekolas/og-proxy)
+Still missing support for proxying requests for images. This support will be a hard requirement for launch.
+
+Here are some specifications you might also want to explore as a part of working with these reference implementations:
+
+- [Farcaster Frames specification](https://docs.farcaster.xyz/reference/frames/spec)
+The Frames spec for creating interactive and authenticated experiences on Farcaster, embeddable in any Farcaster client
+
+- [Open Frames specification](https://github.com/open-frames/standard)
+A lightweight extension to the Frames spec to help enable non-Farcaster apps and protocols to support Frames.
+
+## Security considerations
+
+In the Farcaster model of Frames, messages are signed on a server by the app and the server makes the POST request to the Frame URL. This means the Frame app developer only sees requests from the server IP and never the client.
+
+However, Farcaster clients, like Warpcast, download the Frame image directly. This [leaks the IP address of the viewer to the Frame developer](https://twitter.com/danfinlay/status/1752500815200399633?t=1psurRGh-JTii3AHjvUrMg). According to a reply on X, they are "[working on it](https://x.com/dwr/status/1752506807548072140?s=20)."
+
+In the proposed scheme above, messages would be signed and sent directly from the client. Privacy is a hard requirement for any Frames adoption on the XMTP network. Without it, I can create a maliciously crafted Frame that logs IP addresses and send a link to it to an anon account. This would allow me to learn their IP the moment they view the message. We absolutely cannot leak client IP addresses to Frame app developers in either the Rendering or Interaction phase.
+
+This can be solved by having developers route these requests through a proxy server to anonymize the sender. I’ve already started [prototyping what a simple Frame proxy](https://github.com/neekolas/og-proxy) would look like. This proxy server should be used for the initial Frame rendering, downloading of the Frame image, and interacting with POST requests. Client app developers can host their own instance of this open source proxy. I propose that XMTP Labs should run an instance as a public good. Developers can also use this proxy server to privately gather the information needed for link previews, which is a nice added bonus.
+
+At some scale, this becomes challenging. Signal Protocol previously used a proxy for link previews, but because of their massive scale they started getting blocked by popular websites like YouTube and had to [roll the feature back](https://community.signalusers.org/t/beta-feedback-for-the-upcoming-android-4-69-release/16219/4). Having many proxy services instead of a single proxy will help avoid this problem, but at some scale, we will need to reconsider the approach.
diff --git a/XIPs/xip-43-permission-pref-proofs.md b/XIPs/xip-43-permission-pref-proofs.md
index c208df5..f7eb79e 100644
--- a/XIPs/xip-43-permission-pref-proofs.md
+++ b/XIPs/xip-43-permission-pref-proofs.md
@@ -2,8 +2,7 @@
title: Consent proofs
description: Enables recipients to sign to specify inbox consent preferences
author: Ry Racherbaumer (@rygine), Nick Molnar (@neekolas), Saul Carlin (@saulmc)
-discussions-to: https://community.xmtp.org/t/xip-43-permission-preference-proofs/552
-status: Draft
+status: Review
type: Standards
category: Interface
created: 2024-02-22
@@ -21,13 +20,13 @@ To solve these issues, senders can simply ask users to produce a signature attes
## Specification
-There are 3 components to the proposed workflow:
+There are three components to the proposed workflow:
-1. Obtain a consent signature from the user
+1. Obtain a consent signature from the user
_Requires actions by the **sender** and **receiver**_
-2. Create a new conversation with the encoded payload
+2. Create a new conversation with the encoded payload
_Requires actions by the **sender**_
-3. Verify the consent payload to allow the sender
+3. Verify the consent payload to allow the sender
_Requires actions by the **client SDK**_
### Obtain a consent signature from the user
@@ -58,13 +57,13 @@ From Address:
For more info: https://xmtp.org/signatures/
```
-A lightweight JavaScript bundle will provide a function that will initiate the signing process and return an encoded payload that senders must store on their end. This function is intended to be used as a callback to a click event, such as clicking on a Subscribe button.
+A lightweight JavaScript bundle will provide a function that will initiate the signing process and return an encoded payload that senders must store on their end. This function is intended to be used as a callback to a click event, such as clicking a Subscribe button.
### Create a new conversation with the encoded payload
Once senders have the encoded payload, they can include it when starting a new conversation with a user.
-An example of what this might look like:
+Here is an example of what this might look like:
```ts
const conversation = await client.conversations.newConversation(
@@ -74,19 +73,19 @@ const conversation = await client.conversations.newConversation(
);
```
-Users who have created a consent signature may not have an identity on the XMTP network. Senders should check for an identity with `Client.canMessage` prior to starting a new conversation. If a user does not yet have an XMTP identity, the sender can routinely check for a network identity and start a conversation when it's found.
+Users who have created a consent signature might not have an identity on the XMTP network. Senders should check for an identity with `Client.canMessage` before starting a new conversation. If a user does not yet have an XMTP identity, the sender can routinely check for a network identity and start a conversation when it's found.
### Verify the consent payload
-In order to finalize the consent preference, SDKs must look for the consent payload in new conversations. Using this payload, SDKs can verify that the current user's wallet signed the consent message and validate that the addresses and timestamp match the expected values.
+To finalize the consent preference, SDKs must look for the consent payload in new conversations. Using this payload, SDKs can verify that the current user's wallet signed the consent message and validate that the addresses and timestamp match the expected values.
-Once the consent payload is verified and validated, the SDKs will then update network consent preferences automatically.
+After the consent payload is verified and validated, the SDKs will then automatically update network consent preferences.
-## Backward Compatibility
+## Backward compatibility
The encoded consent payload is an _optional_ parameter when starting a new conversation. Existing conversations will not be affected, and client apps using outdated SDKs will continue to work without updates.
-## Security Considerations
+## Security considerations
There are no known negative security implications introduced as a result of collecting a signature from a user and including it as part of a conversation. The contents of the message being signed will be shown to the user beforehand, and the resulting signature is only useful to SDKs connected to the wallet that signed the message.
diff --git a/XIPs/xip-47-group-chat-permissions.md b/XIPs/xip-47-group-chat-permissions.md
new file mode 100644
index 0000000..bbe900a
--- /dev/null
+++ b/XIPs/xip-47-group-chat-permissions.md
@@ -0,0 +1,170 @@
+---
+xip: 47
+title: Group Chat Permissions
+description: This proposal describes a simple, flexible, updatable group chat permissions system.
+author: Cameron Voell (@cameronvoell), Eleanor Hofstedt (@eleanorhofstedt)
+status: Review
+type: Standards
+category: Core
+created: 2024-05-07
+---
+
+## Abstract
+
+For many compelling group chat use cases—such as those with open invitations, semi-anonymous identities, or a large number of members—a permission system becomes critical for the chat to function effectively. This XIP aims to provide application developers with the tools to implement trustworthy permission features without excessive complexity, while still retaining flexibility.
+
+The following proposal describes how XMTP can use MLS Group Context Extensions to configure which users in a chat are allowed to perform actions like adding or removing group members, as well as who is allowed to modify those permissions over time.
+
+## Specification
+
+### Background
+
+The XMTP Group Chat implementation uses the Messaging Layer Security (MLS) protocol described in [IETF RFC 9420](https://www.rfc-editor.org/rfc/rfc9420.html). The MLS standard includes a `Group Context` object that represents the shared configuration between all group members and contains flexibility for defining custom `UnknownExtensions` that contain arbitrary byte data.
+
+By using MLS Group Context Extensions to store our “Permissions” configuration data, we can ensure that:
+
+- All group members agree on the current state of the permissions parameters of the group
+- Settings remain encrypted and unreadable to any non-members
+- No one outside the group will have the ability to affect the permissions configuration
+
+Currently, XMTP Group Chat beta provides the following **Permissions Policies**:
+
+- `add_member_policy`
+- `remove_member_policy`
+- `update_metadata_policy`
+
+Each of these policies can have one of the following **Permission Options**:
+
+- `UNSPECIFIED`
+- `ALLOW`
+- `DENY`
+- `CREATOR_ONLY`
+
+### Mutable Admin Permissions Update Specification
+
+This XIP proposes to add the following new **Permission Policies**:
+
+- `add_admin_policy`
+- `remove_admin_policy`
+- `update_permissions_policy`
+
+We also propose to add the following new **Permission Options**:
+
+- `ALLOW_IF_ADMIN_OR_SUPER_ADMIN`
+- `ALLOW_IF_SUPER_ADMIN`
+
+To enable the two new permission options, we propose adding the following to Mutable metadata Protobuf definitions:
+
+```proto
+message GroupMutableMetadataV1 {
+...
+ AccountAddresses admin_list = 2;
+ AccountAddresses super_admin_list = 3;
+}
+
+// Wrapper around a list of repeated EVM Account Addresses
+message AccountAddresses {
+ repeated string account_addresses = 1;
+}
+```
+
+These new **Permission Options** will enable use cases such as:
+
+- **Admins can update permissions**: The group starts small with open permissions and then adds restrictions over time as they pass a few dozen users so that only admins can remove users or update the group name and project URL.
+
+- **Group creator can add another admin**: The leader of an online project creates a group chat with themself as the super admin who can add and remove admins and update group information, etc. There is no fear that admins will take over the group because the group creator is still the only super admin. After some time, if the group creator wants to move on from the project, they can make someone else the super admin.
+
+- **Admins can update permissions when new functionality is available**: In the future, XMTP may add new group features, such as mute members. These permission options provide an update path so existing groups can get these new features without losing the existing group history.
+
+### Sensible Default Options
+
+This proposal aims to provide only a few default permission sets that can cover most use cases and easily pass in as parameters on group creation. This approach allows flexibility of permissions without making it too confusing for developers and users.
+
+For developers who want to fine-tune individual permission options for different group actions, we will allow those developers to construct their own initial permission set on group creation. In both cases, we will allow updates to permission sets over time, following the `update_permissions_policy`. Example default policies include:
+
+- All Members Policy:
+ - All group members can add new members
+ - Only admins can remove members, update metadata
+ - Only super admins can add/remove admins, update permissions
+- Admins Only Policy:
+ - Only admins can add/remove members, update metadata
+ - Only super admins can add/remove admins, update permissions
+
+There are a few more rules that apply to all permission policies:
+
+- The group creator always defaults as the group's only super admin
+- Admins can not remove super admins from a group
+- Only super admins can add other super admins
+- Super admins can remove other super admins from the group or remove the super admin role from an address, but there must always be at least one super admin in the group. So removing all super admin will fail. This means you can remove yourself as a super admin if at least one other super admin is in the group.
+
+## Rationale
+
+For anyone who has ever used Discord, Telegram, or tried to maintain the usefulness of a group chat with over a few dozen people, the need for admin functionality in larger-sized groups is self-evident.
+
+One implementation detail we considered is whether permissions could function on a two-tier system of members and admins or if we needed a three-tiered system of members, admins, and super admins.
+
+At this point, contributors agree the three-tier system is necessary based on the use case in which a group creator wants to delegate some responsibilities (`remove_member`, `update_metadata`) to be "admin only," and they don't want to immediately risk other admins removing them as an admin. In other words, the three-tier system allows a happy medium of delegatable admin responsibilities without risking group takeover.
+
+Another consideration was whether the extra complexity is worth making permissions updatable. The choice to allow permissions to be updated, as long as the member performing the update qualifies against the `update_permissions_policy`, seems necessary.
+
+The ability to update permissions is needed to address the use cases of initial group permission misconfiguration and the inevitable evolution of a group’s trust dynamic. For example, just because an online project group chat starts as a small group of well-intentioned contributors does not mean that the group may not evolve to have a larger variety of member trustworthiness and contributor types over time.
+
+## Backward compatibility
+
+In addition to adding the new **Permission Policies** and **Permission Options** and making **Permissions Updatable**, we will also make the permission system itself updatable in the following ways:
+
+- `libxmtp` can be updated so existing groups can add new **Permission Policies** via the proto `map update_metadata_policy`. This means that if later on we want to add a new Permission Policy to groups, such as "The Ability to Mute Group Members," we can add it without breaking any existing groups.
+
+- Deprecation and update of the Permissions or Metadata Extensions in an existing group's Group Context
+
+- Existing groups will not be able to include an entirely new Permissions or Metadata Extension until all group members update to a new version of libxmtp and perform a "leaf node update commit" that updates their "supported capabilities."
+
+ One way this could work for existing groups would be to have a generous grace period, such as a few weeks or months, after which an admin could remove any group member who has not upgraded. We could then update the group to enable new permission / metadata extensions. The hope is that we might never need to perform this type of update or that it will be rare and even less frequent as time passes. For more information, see [MLS RFC - Required Capabilities](https://www.rfc-editor.org/rfc/rfc9420.html#name-required-capabilities).
+
+## Reference implementation
+
+For an example of the updates required for protobuf objects, see this [Mutable Group Permissions PR](https://github.com/xmtp/proto/pull/175) in the XMTP **proto** GitHub repo.
+
+```solidity
+// Message for group mutable permissions
+message GroupMutablePermissionsV1 {
+ PolicySet policies = 1;
+}
+
+// The set of policies that govern the group
+message PolicySet {
+ MembershipPolicy add_member_policy = 1;
+ MembershipPolicy remove_member_policy = 2;
+ map update_metadata_policy = 3;
+ PermissionsUpdatePolicy add_admin_policy = 4;
+ PermissionsUpdatePolicy remove_admin_policy = 5;
+ PermissionsUpdatePolicy update_permissions_policy = 6;
+}
+
+// Message for group mutable metadata
+message GroupMutableMetadataV1 {
+ // Map to store various metadata attributes (Group name, etc.)
+ map attributes = 1;
+ AccountAddresses admin_list = 2;
+ // Creator starts as only super_admin
+ // Only super_admin can add/remove other super_admin
+ AccountAddresses super_admin_list = 3;
+}
+
+// Wrapper around a list of repeated EVM Account Addresses
+message AccountAddresses {
+ repeated string account_addresses = 1;
+}
+```
+
+## Security considerations
+
+The main security considerations for this update are to ensure that:
+
+- Developers and users of XMTP understand how permissions work
+
+- Permissions do not have any bugs that would allow a super admin to be kicked out of their own group or for group permissions to not behave as expected. Though it will likely always be possible for someone to lose admin control over their own group if they take action to remove themself, we will strive to provide tests, documentation, and intuitive default permission options to minimize this risk.
+
+## Copyright
+
+Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
diff --git a/XIPs/z-stagnant_xip-14-convo-context-metadata-schema.md b/XIPs/z-stagnant_xip-14-convo-context-metadata-schema.md
new file mode 100644
index 0000000..1ae2683
--- /dev/null
+++ b/XIPs/z-stagnant_xip-14-convo-context-metadata-schema.md
@@ -0,0 +1,90 @@
+---
+xip: 14
+title: Conversation context metadata schema
+description: Schema to enable standardized sharing of conversation context
+author: Yash Lunagaria (@yash-luna)
+status: Stagnant
+type: Standards Track
+category: XRC
+created: 2023-01-31
+---
+
+## Abstract
+
+This XIP proposes a schema for sharing additional context about a conversation beyond `conversationId`. It introduces associated conversation metadata alongside a `conversationId` to enable front-ends to display useful contextual information consistently and in a user-friendly manner while maintaining flexibility in UI and UX.
+
+## Motivation
+
+The SDK API currently accepts a unique `conversationId` per address pair and allows `metadata` to be set as well. Today, different apps use these parameters in different ways. Therefore an app may not know how to correctly render in its UI `conversationId` and `metadata` for conversations originating from other apps. We propose a schema to standardize the use of conversation `metadata` for the purpose of app brand expression stemming from the `conversationId`. The `metadata` field may include other non-standard (or future standard) properties.
+
+Note that the schema is only applicable when a valid`conversationId` is set. If `conversationId` is null, the SDK does not allow setting `metadata`.
+
+## Specification
+
+Proposed `displayInfo` schema in conversation `metadata`
+
+```json
+{
+ conversationId: "mydomain.xyz/abc/qrs",
+ metadata: {
+ "displayInfo.prettyName": "My company",
+ "displayInfo.profileImage": "mydomain.xyz/assets/myimage.png",
+ "displayInfo.primaryColor": "#ffffff" }
+}
+```
+
+Example `displayInfo` implementation for a chat app named Galaxy
+
+```json
+{
+ conversationId: "galaxy.chat/dm/uniqueIdentifier",
+ metadata: {
+ "displayInfo.prettyName": "Galaxy",
+ "displayInfo.profileImage": "galaxychat.xyz/brandassets/logo.png",
+ "displayInfo.primaryColor": "#6865B8" }
+}
+```
+
+The `profileImage` must meet the following criteria:
+
+- Aspect ratio: 1:1
+- Minimum resolution: 100x100
+- Maximum resolution: 800x800
+- Format: .PNG, .WEBP
+
+The `primaryColor` must be a hex color code.
+
+## Backward compatibility
+
+Existing conversations will not be affected by the adoption of the new schema. Only conversations created after the new schema is finalized will follow the updated schema.
+
+To maintain backward compatibility, clients may consider rendering popular but older schemas (such as Lens), present in conversations created before the finalization of this XRC, in a manner consistent with their updated schema that follows this XRC.
+
+Old Lens schema:
+
+```json
+{
+ conversationId: "lens.dev/dm/${memberA}-${memberB}"
+ metadata: {}
+}
+```
+
+New Lens schema
+
+```json
+{
+ conversationId: "lens.dev/dm/${memberA}-${memberB}"
+ metadata: {
+ "displayInfo.prettyName": "Lens",
+ "displayInfo.profileImage": "lens.xyz/assets/myimage.png",
+ "displayInfo.primaryColor": "#ffffff" }
+}
+```
+
+## Security considerations
+
+The `metadata` fields can be spoofed by malicious apps to display names and profile images that degrade the user experience and harm brand perception. A mechanism for apps to sign payloads such as conversation metadata and messages can enable frontends to verify the sending client's identity and prevent such spoofing. An affordance for client verifiability is under consideration.
+
+## Copyright
+
+Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
diff --git a/XIPs/z-stagnant_xip-23-reaction-content-type.md b/XIPs/z-stagnant_xip-23-reaction-content-type.md
new file mode 100644
index 0000000..6d4aabc
--- /dev/null
+++ b/XIPs/z-stagnant_xip-23-reaction-content-type.md
@@ -0,0 +1,60 @@
+---
+xip: 23
+title: Reaction Content Type
+description: Proposes a content type that lets users react to messages using emojis
+author: Kunal Mondal (@Im-Kunal-13)
+status: Stagnant
+type: Standards
+category: XRC
+created: 2023-03-24
+---
+
+**Important**: The finalized Reaction Content Type is defined by [XRC-20: Reactions content type](./xrc-20-reaction-content-type.md). For the original pull request submitted by Kunal Mondal (@Im-Kunal-13), see [https://github.com/xmtp/XIPs/pull/23](https://github.com/xmtp/XIPs/pull/23).
+
+## Abstract
+
+This XRC proposes a new content type that enriches the messaging experience and lets users express themselves using emojis. It attempts to include only the bare minimum for clients to determine how to display such messages to provide flexibility for more rich types in the future.
+
+## Motivation
+
+When it comes to having a comfortable conversation, reacting to messages with emojis is necessary as it gives users the freedom to express their messages in the form of emojis. To provide users with a real messaging platform, XMTP needs to provide this capability.
+
+## Specification
+
+Proposed content type:
+
+```js
+{
+ authorityId: "xmtp.org",
+ typeId: "reaction",
+ versionMajor: 1,
+ versionMinor: 0,
+}
+```
+
+The reaction MUST include the following parameters:
+
+```ts
+{
+ // The message ID that this reaction is being added to
+ reactingToID: string
+}
+```
+
+The content of the encoded message must be a string consisting of a single emoji character.
+
+## Backward compatibility
+
+Clients encountering messages of this type must already be able to deal with messages of an unknown content type, so whatever considerations they're making there should work here, too.
+
+## Reference implementation
+
+- [PR implementation for the JS SDK](https://github.com/xmtp/xmtp-js-content-types/blob/d859187c00d216069cffbb2f6a847cd276e5225a/reaction/src/Reaction.ts)
+
+## Security considerations
+
+Different message content structures in content types break uniformity, which might be risky, but this is also the case for other content types since there's no server-side validation of message contents other than size. The same protections we have now would be in place, while the same pitfalls would still be there.
+
+## Copyright
+
+Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
diff --git a/XIPs/z-stagnant_xip-28-universal-consent-layer.md b/XIPs/z-stagnant_xip-28-universal-consent-layer.md
new file mode 100644
index 0000000..0e6d27e
--- /dev/null
+++ b/XIPs/z-stagnant_xip-28-universal-consent-layer.md
@@ -0,0 +1,89 @@
+---
+xip: 28
+title: Universal Consent Layer for XMTP
+description: Proposes adding a universal consent layer to the XMTP protocol to prevent spam
+author: Pol Maire (pol@getconverse.app)
+status: Stagnant
+type: Standards
+category: XRC
+created: 2024-01-26
+---
+
+**Important**: This XIP inspired [XIP-42: Universal allow and block preferences](https://github.com/xmtp/XIPs/blob/main/XIPs/xip-42-universal-allow-block-preferences.md). For the original pull request that proposed this XIP-28, see [https://github.com/xmtp/XIPs/pull/28](https://github.com/xmtp/XIPs/pull/28).
+
+## Abstract
+
+This XIP proposes adding a universal consent layer to the XMTP protocol to prevent spam and allow users to maintain their communication preferences across applications.
+
+## Motivation
+
+Currently, the XMTP network allows anyone to write to anyone without the option to opt-in or opt-out of conversations with other users. Implementing a universal consent layer will provide users with more control over their communication preferences, reduce spam, and enhance privacy.
+
+## Specification
+
+### Consent layers
+
+- **Opted-in**: The user has explicitly accepted talking with the other user.
+
+- **Opted-out**: The user has explicitly blocked the other user by clicking on a button in the interface of an XMTP client. Every conversation with the opted-out user is also considered opted-out.
+
+- **Neither opted-in nor opted-out**: The user received a message from another user but did not send anything nor click on any consent button.
+
+### User interface
+
+- Clients should create a "requests" section in their user interface containing all conversations with users in the "Neither opted-in nor opted-out" category.
+
+- Clients can add an additional layer of consent, "Implicitly opted-in":
+ - This is not at the protocol level but only a UX guideline at the client level; hence will not be synced between clients.
+ - The condition for implicit opt-in of a conversation could be that:
+ - The user has sent at least one message in the conversation (the client will need to keep syncing messages in the conversation until it reaches the beginning of the conversation or the first message sent by the user).
+ - There is a good chance of a positive interaction (e.g., having an on-chain transaction with the peer or following the peer on Lens or Farcaster).
+
+### User settings
+
+- We need "protocol-level user settings" (= user preferences) to store these consent settings.
+ - It could be a specific protected topic `settings-0x.....` that clients can write to using the XMTP Key to store encrypted settings. We could either post the whole settings to the topic every time the settings change or have some way to store incremental data.
+ - This would enable sharing preferences between multiple clients and help clients provide a consistent experience rather than building their preferences outside of the XMTP protocol (where switching to another client would make the user lose their preferences).
+ - We could all agree on specific "keys" and a format to store some data, including consent data.
+- The SDKs would have a simple way to retrieve the settings (like `await client.retrieveUserSettings()`) in a JSON format.
+- We would have a specific key called `consent` in the settings, with a format that could look like:
+
+ ```json
+ {
+ "consent": {
+ "version": "1.0.0",
+ "peers": {
+ "0xa.....": "OPTED_IN",
+ "0xb.....": "OPTED_OUT"
+ }
+ }
+ }
+ ```
+
+- It means that we trust the clients to not write malicious data to those settings (i.e., automatically Opt-In to partners, etc.) But we already trust clients with our XMTP keys to not send malicious messages from our accounts, so this is probably OK.
+
+### Compliance requirement
+
+This XIP is a requirement for compliant clients. Any contact MUST be tagged with one of the three consent statuses.
+
+## Rationale
+
+Introducing a universal consent layer will provide users with more control over their communication preferences, allowing them to avoid unwanted messages and reduce the amount of spam on the XMTP network.
+
+Additionally, creating a "requests" section in the UI will help users manage their communication requests more effectively. Allowing clients to add an "Implicitly opted-in" layer at the client level will enable seamless communication with trusted users while maintaining user privacy and control.
+
+## Backward compatibility
+
+This XIP does not introduce any significant backward compatibility issues. Clients that have previously introduced the ability to "block" users locally can migrate to this protocol-level opt-out mechanism.
+
+## Implementation
+
+XMTP clients can start implementing the universal consent layer by incorporating the three consent levels into their existing application logic.
+
+Clients should update their user interfaces to include the "requests" section and the additional "Implicitly opted-in" layer at the client level, as suggested in this proposal.
+
+The list of opted-out users should be added to the user settings at the protocol level once they are implemented.
+
+## Copyright
+
+This XIP is released under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).