RWA Metadata Storage
On-Chain Key-Value Metadata Storage for Compact Descriptors.
Abstract
Smart contracts often rely on off-chain JSON documents (e.g. for NFTs) or fixed functions (e.g. name(), symbol()) for metadata. This standard introduces a flexible on-chain key-value structure for metadata that must be durable, auditable, and optionally updateable. Use cases include document fingerprints, compliance references, and structured legal proofs. The KV structure works in parallel with existing standards to enhance trust, transparency, and auditability in tokenized systems.
Motivation
This CIP defines a standardized smart contract interface for storing compact key-value (KV) metadata on-chain. It supports sealed (immutable) and unsealed (updatable) entries. It is particularly useful for Real World Asset (RWA) tokenization and complements existing practices like CBC-20 metadata and off-chain NFT metadata URLs.
Specification
Interface
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IOnChainMetadataKV {
function getMetadataValue(string calldata key) external view returns (string memory value);
function hasMetadataKey(string calldata key) external view returns (bool exists);
function isMetadataSealed(string calldata key) external view returns (bool sealed);
function listMetadataKeys() external view returns (string[] memory keys);
function getMetadataByIndex(uint256 index) external view returns (string memory key, string memory value);
function metadataCount() external view returns (uint256 total);
function setMetadataValue(string calldata key, string calldata value) external;
function sealMetadataKey(string calldata key) external;
}
Reference Implementation
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract OnChainMetadataKV is IOnChainMetadataKV {
struct Entry {
string value;
bool sealed;
bool exists;
}
mapping(string => Entry) private _entries;
string[] private _keys;
function setMetadataValue(string calldata key, string calldata value) external override {
Entry storage entry = _entries[key];
require(!entry.sealed, "Metadata key sealed");
if (!entry.exists) {
_keys.push(key);
entry.exists = true;
}
entry.value = value;
}
function sealMetadataKey(string calldata key) external override {
require(_entries[key].exists, "Key not found");
_entries[key].sealed = true;
}
function getMetadataValue(string calldata key) external view override returns (string memory) {
require(_entries[key].exists, "Key not found");
return _entries[key].value;
}
function hasMetadataKey(string calldata key) external view override returns (bool) {
return _entries[key].exists;
}
function isMetadataSealed(string calldata key) external view override returns (bool) {
require(_entries[key].exists, "Key not found");
return _entries[key].sealed;
}
function listMetadataKeys() external view override returns (string[] memory) {
return _keys;
}
function getMetadataByIndex(uint256 index) external view override returns (string memory, string memory) {
require(index < _keys.length, "Index out of bounds");
string memory key = _keys[index];
return (key, _entries[key].value);
}
function metadataCount() external view override returns (uint256) {
return _keys.length;
}
}
Real World Asset Use Case
RWA tokens frequently require referencing off-chain legal and regulatory artifacts, such as:
- Investment prospectuses
- Legal disclaimers
- KYC provider certifications
- Title deed hashes
- Security identifiers (ISIN, CUSIP)
By using on-chain metadata KV:
- Developers can store compact fingerprints or signed digests.
- Legal auditors can verify presence and integrity on-chain.
- Updates can be allowed when needed—but sealed once finalized.
RWA Ticker
The RWA ticker should be chosen according to the commodities being tokenized:
Examples:
RWAZCH5
Where:
RWA= Real World Asset prefixZC= Commodity (Corn)H= Month code (March)5= Year (2025)
Another example:
RWASWSG5
Where:
SWS= Sugar typeG= Month code (February)5= Year (2025)
Keep tickers short, descriptive, and standardized.
Month Code Table
| Month | Code |
|---|---|
| January | F |
| February | G |
| March | H |
| April | J |
| May | K |
| June | M |
| July | N |
| August | Q |
| September | U |
| October | V |
| November | X |
| December | Z |
Comparison Summary
| Method | Scope | Location | Mutable | Standard Use |
|---|---|---|---|---|
name() / symbol() | Global | On-chain | No | Identification (CBC-20/4626) |
tokenURI() | Per-token | Off-chain | Yes | NFT metadata (CBC-721/1155) |
| Metadata KV (this CIP) | Key-defined | On-chain | Optional | Contextual metadata, docs, hashes |
Rationale
The on-chain key-value metadata storage approach addresses the need for flexible, auditable, and optionally updateable metadata in smart contracts. This standard provides a middle ground between immutable on-chain data and mutable off-chain references.
This is particularly valuable for real-world asset tokenization, where legal and regulatory compliance requires both transparency and the ability to update information when necessary.
Backward Compatibility
This standard is designed to work alongside existing metadata approaches like:
- CBC-20
name()/symbol() - CBC-721
tokenURI()
It adds additional metadata capability without breaking existing implementations.
Security Considerations
- Mutable entries should be carefully permissioned.
- Metadata keys should be sealed once finalized.
- Consider role-based access control for
setMetadataValue. - Consider versioned metadata keys such as:
PROSPECTUS_V1
PROSPECTUS_V2
LEGAL_HASH_V1
to preserve historical references.
Conclusion
The On-Chain Metadata KV standard provides a flexible and secure approach to managing metadata in smart contracts. Its adoption improves transparency, auditability, and compliance in tokenized systems, especially for Real World Asset (RWA) ecosystems.
References
Deployment Script
DeployOnChainKV.s.sol Solidity deployment script using the Foxar framework.
Test Suite
OnChainKV.t.sol Unit tests validating metadata setting, sealing, and retrieval.
Contract ABI
IOnChainMetadataKV.abi.json Interface ABI for integration with external tooling.
Copyright
Copyright and related rights waived via CC0.