CIP20 API
CIP20 (Cardano Improvement Proposal 20) defines a standard for adding messages, comments, or memos to Cardano transactions using transaction metadata. This allows you to attach informational text, invoice numbers, or similar data to transactions on the Cardano blockchain. The library’s MessageMetadata wraps the CIP20 layout (label 674 with msg array) so you only worry about adding strings and serializing the CBOR when needed.
Key Features
- Standard Compliance: Full CIP20 specification support
- Message Metadata: Add messages/comments to transactions
- Validation: Built-in validation for message length (max 64 characters)
- Multiple Messages: Support for multiple messages in a single transaction
- Easy Integration: Simple API for adding metadata to transactions
Dependencies
- Group ID: com.bloxbean.cardano
- Artifact ID: cardano-client-cip20
- Dependencies: metadata
Usage Examples
Creating Message Metadata
Build the MessageMetadata object and serialize to CBOR when you need raw bytes.
The following example shows how to create CIP20 compliant message metadata with multiple messages.
// Create message metadata
MessageMetadata messageMetadata = MessageMetadata.create()
.add("Payment for services")
.add("Invoice #12345")
.add("Thank you for your business");
// Get metadata as CBOR bytes
byte[] cborBytes = messageMetadata.serialize();
String hexMetadata = HexUtil.encodeHexString(cborBytes);Adding Messages to Transactions
Attach the metadata directly in QuickTx so it is included in the auxiliary data of the transaction.
The following example shows how to add message metadata to a transaction using QuickTx.
// Create message metadata
MessageMetadata messageMetadata = MessageMetadata.create()
.add("Payment for NFT purchase")
.add("Transaction ID: " + System.currentTimeMillis());
// Create transaction with message metadata
Tx tx = new Tx()
.payToAddress(receiverAddress, Amount.ada(10))
.from(senderAddress)
.attachMetadata(messageMetadata);
// Build and sign transaction
Result<String> result = quickTxBuilder.compose(tx)
.feePayer(senderAddress)
.withSigner(SignerProviders.signerFrom(senderAccount))
.completeAndWait(System.out::println);Working with Message Lists
Retrieve the stored messages to display or process them after deserialization.
The following example shows how to retrieve and work with messages from metadata.
// Create message metadata
MessageMetadata messageMetadata = MessageMetadata.create()
.add("First message")
.add("Second message")
.add("Third message");
// Get all messages
List<String> messages = messageMetadata.getMessages();
// Process messages
for (String message : messages) {
System.out.println("Message: " + message);
}
// Check message count
System.out.println("Total messages: " + messages.size());Integration with Other Metadata
Merge CIP20 messages with other metadata maps if you need to send multiple labels in one transaction.
The following example shows how to combine CIP20 message metadata with other transaction metadata.
// Create CIP20 message metadata
MessageMetadata messageMetadata = MessageMetadata.create()
.add("Payment confirmation")
.add("Order #789");
// Create additional custom metadata
CBORMetadata customMetadata = new CBORMetadata()
.put(BigInteger.valueOf(100), "Custom field value")
.put(BigInteger.valueOf(101), "Another custom value");
// Combine metadata (CIP20 uses label 674)
CBORMetadata combinedMetadata = (CBORMetadata) customMetadata.merge(messageMetadata);
// Use in transaction
Tx tx = new Tx()
.payToAddress(receiverAddress, Amount.ada(5))
.from(senderAddress)
.attachMetadata(combinedMetadata);Practical Use Cases
Invoice Tracking
// Create invoice metadata
MessageMetadata invoiceMetadata = MessageMetadata.create()
.add("Invoice #INV-2024-001")
.add("Due: 2024-01-15")
.add("Amount: 100 ADA");
Tx paymentTx = new Tx()
.payToAddress(merchantAddress, Amount.ada(100))
.from(customerAddress)
.attachMetadata(invoiceMetadata);Payment Confirmations
// Create payment confirmation metadata
MessageMetadata confirmationMetadata = MessageMetadata.create()
.add("Payment confirmed")
.add("Ref: " + generatePaymentReference())
.add("Thank you!");
Tx confirmationTx = new Tx()
.payToAddress(recipientAddress, Amount.ada(50))
.from(payerAddress)
.attachMetadata(confirmationMetadata);Service Requests
// Create service request metadata
MessageMetadata serviceMetadata = MessageMetadata.create()
.add("Service: Web Development")
.add("Client: Acme Corp")
.add("Priority: High");
Tx serviceTx = new Tx()
.payToAddress(developerAddress, Amount.ada(25))
.from(clientAddress)
.attachMetadata(serviceMetadata);API Reference
MessageMetadata Class
The main class for creating and managing CIP20 message metadata.
Constructor
// Create new instance
public static MessageMetadata create()Methods
add(String message)
Adds a message to the metadata. Each message must be:
- Non-null
- Maximum 64 characters in UTF-8 encoding
public MessageMetadata add(String message)Parameters:
message- The message to add (max 64 characters)
Returns: The MessageMetadata instance for chaining
Throws: IllegalArgumentException if message is null or exceeds 64 characters
getMessages()
Retrieves all messages from the metadata.
public List<String> getMessages()Returns: List of all messages in the metadata
serialize()
Serializes the metadata to CBOR bytes.
public byte[] serialize()Returns: CBOR-encoded bytes of the metadata
CIP20 Specification Details
Metadata Label
CIP20 uses metadata label 674 for message metadata.
Message Format
Messages are stored as an array of strings under the “msg” key:
{
"674": {
"msg": [
"First message",
"Second message",
"Third message"
]
}
}Constraints
- Each message must be a maximum of 64 characters when encoded in UTF-8
- Messages cannot be null
- Multiple messages are supported in a single transaction
Best Practices
- Keep messages concise - The 64-character limit encourages brief, informative messages
- Use meaningful content - Include relevant information like invoice numbers, references, or confirmations
- Validate input - Always handle validation errors when adding messages
- Consider privacy - Remember that metadata is publicly visible on the blockchain
- Combine with other standards - CIP20 works well with CIP25 (NFT metadata) and other standards
Integration Examples
With CIP25 (NFT Metadata)
// Create CIP25 NFT metadata
NFT nftMetadata = NFT.create()
.name("My NFT")
.description("A sample NFT");
// Create CIP20 message metadata
MessageMetadata messageMetadata = MessageMetadata.create()
.add("NFT purchase")
.add("Collection: Art Gallery");
// Combine metadata
CBORMetadata combinedMetadata = (CBORMetadata) nftMetadata.merge(messageMetadata);With Custom Metadata
// Create custom metadata
CBORMetadata customMetadata = new CBORMetadata()
.put(BigInteger.valueOf(100), "Custom field");
// Create CIP20 message metadata
MessageMetadata messageMetadata = MessageMetadata.create()
.add("Transaction note");
// Combine and use in transaction
CBORMetadata finalMetadata = (CBORMetadata) customMetadata.merge(messageMetadata);For more information about CIP20, refer to the official CIP20 specification .