XIP-21: On-chain transaction reference content type

Abstract

This content type provides a reference to an on-chain transaction, such as a transaction hash or ID, sent as a message, thereby providing a direct link to on-chain activities.

Motivation

The goal of the transaction reference content type is to provide transaction details in a message, facilitating the sharing of on-chain activities, such as token transfers, between users.

Specification

Content type

{
  authorityId: "xmtp.org",
  typeId: "transactionReference",
  versionMajor: 1,
  versionMinor: 0,
}

Transaction reference schema

type TransactionReference = {
  /**
   * The CAIP-2 chain ID where the transaction happened in the format `<namespace>:<reference>`
   */
  chainId?: string;
  /**
   * The transaction hash
   */
  transactionHash: string;
  /**
   * Optional metadata object
   */
  metadata?: {
    transactionType: string;
    currency: string;
    amount: number;
    decimals: number;
    fromAddress: string;
    toAddress: string;
  };
};

Rationale

The chainId provides details of the network used for the transaction in CAIP-2 format, while the transactionHash 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.

In addition, optional metadata can be added to provide more details and a richer display of the transaction.

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

You can find a reference implementation of this transaction reference content type in the xmtp-js-content-types repo under the packages/content-type-transaction-reference directory.

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.

All transactions should be confirmed on their respective blockchain.

Copyright

Copyright and related rights waived via CC0.

3 Likes

Hi,
It’s my first contribution and I have no intiention of disturbing anything :slightly_smiling_face:, but regarding the structure of the transaction reference, could we consider the Chain Agnostic initiative, aiming to standardise how we identify blockchain-related primitives?

For instance, this specification identifies the blockchain with namespace and networkId while the CAIP-2 specifies the chainId with namespace (eip155, etc.) and reference (1 for Ethereum mainnet, 137 for Polygon PoS mainnet, etc.). So, basically a reference property instead of networkId.

Obviously the reference would clash with this current specification using reference for the transaction hash.

Unfortunately, there is no CAIP specification (yet) for a transaction reference (it can be submitted to their proposal though).

We can think of something like this:

type TransactionReference = {
  /**
   * Identify the blockchain in a CAIP-compliant way
   */
  chainId: { // This structured object is what the caip js library uses
    namespace: string;
    reference: string;
  }; 
  // alternatively
  chainId: string; // The actual CAIP-2 syntax <namesapce>:<reference> (eip155:1) but needs to be parsed to be used. Note the caip js library provides utilities for that.

  /**
   * Lack of CAIP specification for the transaction hash, could be:
   */
  reference: string;
  // or
  transactionHash: string;
  // or something else such as txHash, transactionId, etc.

  // ...
};
1 Like

@aurel This is a great suggestion. I’d be open to aligning on standard naming for the chain, and then renaming the existing reference field to something like transaction_hash to avoid confusion.

1 Like

Awesome. Thanks

1 Like

How wonderful to hear from you, @aurel - thank you for the suggestion and for following up!

@nick - I will revert this XIP to Draft status so we can go ahead and update the XIP to align on standard naming per Aurel’s suggestion.

1 Like

Thank you for the update to the XIP, @nick! Moving the XIP to Review status now.

Hi there, I’m new to this space but definitely want to get involved more!
I am implementing this feature and noticed that the amount field is typed as number.
Should this instead be bigint?

Thanks!

1 Like

Welcome to the space, @sonicsmith! :wave:

Thank you for taking the time to review this XIP and for your question about the amount field. cc’ing @nick, a core dev on the project, to provide some guidance here. :smiley:

Please do keep an eye on this post as another change may be coming through next week.

If helpful, I thought I’d mention the XMTP Dev Community Call. Half the call is dedicated questions from the community and deep dives into XIPs. So if you ever have anything you’d like discuss, it would be great to see you there!

With aloha,

J-Ha

@sonicsmith Just checking back to let you know we’re going to await the return of the XIP author to make a holistic call on this. I will take the action item to loop us all back to your open question upon Ry’s return late Apr/early May. More soon - and thank you again for your partnership on this!

1 Like

Open item from @aurel about whether this sentence is still necessary.

Open item from @aurel:

Should we make the chainId required?
If not, the behaviour must be documented, for instance, if undefined it defaults to eip155:1 (Ethereum mainnet).
I’d personnally prefer it to be required so that there is (slightly) less cases to manage for builder implementing the specification and, in a chain-agnostic context, there is no preference to a give chain (the default one if undefined)