Skip to main content

Build custom content types for use with XMTP

Building a custom content type enables you to manage data in a way that is more personalized or specialized to the needs of your app.

For more common content types, you can usually find a standard or standards-track content type to serve your needs.

If your custom content type generates interest within the developer community, consider proposing it as a standard content type through the XIP process.

This tutorial covers how to build two example custom content types:

  • A basic example of a custom content type that multiplies two numbers

  • An advanced example of a custom content type that sends transaction hashes on the Polygon blockchain. This example also describes how to use the custom content type to render the transaction hash.

Basic: Multiply numbers using a custom content type

Build a custom content type to multiply numbers.

  1. Create the custom content type by creating a new file
import { ContentTypeId } from "@xmtp/xmtp-js";

// Create a unique identifier for your content type
const ContentTypeMultiplyNumbers = new ContentTypeId({
authorityId: "your.domain",
typeId: "multiply-number",
versionMajor: 1,
versionMinor: 0,
});

// Define the MultiplyCodec class
class ContentTypeMultiplyNumberCodec {
get contentType() {
return ContentTypeMultiplyNumbers;
}

// The encode method accepts an object with two numbers (a, b) and encodes it as a byte array
encode({ a, b }) {
return {
type: ContentTypeMultiplyNumbers,
parameters: {},
content: new TextEncoder().encode(JSON.stringify({ a, b })),
};
}

// The decode method decodes the byte array, parses the string into numbers (a, b), and returns their product
decode(content: { content: any }) {
const uint8Array = content.content;
const { a, b } = JSON.parse(new TextDecoder().decode(uint8Array));
return a * b;
}
}
  1. Import and register the custom content type.
import { ContentTypeMultiplyNumberCodec } from "./xmtp-content-type-multiply-number";

const xmtp = await Client.create(signer, {
env: "dev",
});
xmtp.registerCodec(new ContentTypeMultiplyNumberCodec());
  1. Send a message using the custom content type. This code sample demonstrates how to use the MultiplyCodec custom content type to perform multiplication operations.
const numbersToMultiply = { a: 3, b: 7 };

conversation.send(numbersToMultiply, {
contentType: ContentTypeMultiplyNumbers,
});
  1. To use the result of the multiplication operation, add a renderer for the custom content type.
if (message.contentType.sameAs(ContentTypeMultiplyNumber)) {
return message.content; // 21
}

Advanced: Send token transaction hashes

Build a custom content type to send transaction hashes on the Polygon blockchain.

  1. Create the custom content type by creating a new file, xmtp-content-type-transaction-hash.tsx. This file hosts the TransactionHash class for encoding and decoding the custom content type.
import { ContentTypeId } from "@xmtp/xmtp-js";

export const ContentTypeTransactionHash = new ContentTypeId({
authorityId: "your.domain",
typeId: "transaction-hash",
versionMajor: 1,
versionMinor: 0,
});

export class ContentTypeTransactionHashCodec {
get contentType() {
return ContentTypeTransactionHash;
}

encode(hash) {
return {
type: ContentTypeTransactionHash,
parameters: {},
content: new TextEncoder().encode(hash),
};
}

decode(content: { content: any }) {
const uint8Array = content.content;
const hash = new TextDecoder().decode(uint8Array);
return hash;
}
}
  1. Import and register the custom content type.
import {
ContentTypeTransactionHash,
ContentTypeTransactionHashCodec,
} from "./xmtp-content-type-transaction-hash";

const xmtp = await Client.create(signer, {
env: "dev",
});
xmtp.registerCodec(new ContentTypeTransactionHashCodec());
  1. Send a message using the custom content type. This code sample demonstrates how to use the TransactionHash content type to send a transaction.
// Create a wallet from a known private key
const wallet = new ethers.Wallet(privateKey);
console.log(`Wallet address: ${wallet.address}`);

//im using a burner wallet with MATIC from a faucet
//https://faucet.polygon.technology/

// Set up provider for Polygon Testnet (Mumbai)
const provider = new ethers.providers.JsonRpcProvider(
"https://rpc-mumbai.maticvigil.com",
);

// Connect the wallet to the provider
const signer = wallet.connect(provider);

// Define the recipient address and amount
const amount = ethers.utils.parseEther("0.01"); // Amount in ETH (0.01 in this case)

// Create a transaction
const transaction = {
to: recipientAddress,
value: amount,
};

// Sign and send the transaction
const tx = await signer.sendTransaction(transaction);
console.log(`Transaction hash: ${tx.hash}`);

const conversation = await xmtp.conversations.newConversation(WALLET_TO);
await conversation
.send(tx.hash, {
contentType: ContentTypeTransactionHash,
})
.then(() => {
console.log("Transaction data sent", tx.hash);
})
.catch((error) => {
console.log("Error sending transaction data: ", error);
});
  1. To use the result of the hash, add an async renderer for the custom content type.
if (message.contentType.sameAs(ContentTypeTransactionHash)) {
// Handle ContentTypeAttachment
return (
<TransactionMonitor key={message.id} encodedContent={message.content} />
);
}

const TransactionMonitor = ({ encodedContent }) => {
const [retryCount, setRetryCount] = useState(0);

const [transactionValue, setTransactionValue] = useState(null);

useEffect(() => {
const fetchTransactionReceipt = async () => {
console.log(encodedContent);
const provider = new ethers.providers.JsonRpcProvider(
"https://rpc-mumbai.maticvigil.com",
);
const receipt = await provider.getTransactionReceipt(encodedContent);
const tx = await provider.getTransaction(encodedContent);
if (tx && tx.value) {
setTransactionValue(ethers.utils.formatEther(tx.value));
}
};
fetchTransactionReceipt();
}, [encodedContent, retryCount]);

return transactionValue ? (
<div>Transaction value: {transactionValue} ETH</div>
) : (
<div>
Waiting for transaction to be mined...
<button onClick={() => setRetryCount(retryCount + 1)}>
Refresh Status 🔄
</button>
</div>
);
};

Was the information on this page helpful?
powered by XMTP