On-Chain Key-Value Metadata Storage for Compact Descriptors
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 IOnChainKV {
function getValue(string calldata key) external view returns (string memory value);
function hasKey(string calldata key) external view returns (bool exists);
function isSealed(string calldata key) external view returns (bool sealed);
function listKeys() external view returns (string[] memory keys);
function getByIndex(uint256 index) external view returns (string memory key, string memory value);
function count() external view returns (uint256 total);
function setValue(string calldata key, string calldata value) external;
function sealKey(string calldata key) external;
}
Reference Implementation
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract OnChainKV is IOnChainKV {
struct Entry {
string value;
bool sealed;
bool exists;
}
mapping(string => Entry) private _entries;
string[] private _keys;
function setValue(string calldata key, string calldata value) external override {
Entry storage entry = _entries[key];
require(!entry.sealed, "Key is sealed and cannot be updated");
if (!entry.exists) {
_keys.push(key);
entry.exists = true;
}
entry.value = value;
}
function sealKey(string calldata key) external override {
require(_entries[key].exists, "Key not found");
_entries[key].sealed = true;
}
function getValue(string calldata key) external view override returns (string memory) {
require(_entries[key].exists, "Key not found");
return _entries[key].value;
}
function hasKey(string calldata key) external view override returns (bool) {
return _entries[key].exists;
}
function isSealed(string calldata key) external view override returns (bool) {
require(_entries[key].exists, "Key not found");
return _entries[key].sealed;
}
function listKeys() external view override returns (string[] memory) {
return _keys;
}
function getByIndex(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 count() 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 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 when finalized.
RWA Ticker
The RWA Ticker should be chosen regards to the commodities that will be tokenized:
RWAZCH5
- whereRWA
is the ticker prefix,ZC
is the commodity (Corn),H
is month (March),5
is year (2025).RWASWSG5
- whereRWA
is the ticker prefix,SWS
is the commodity (Type of Sugar),G
is the month (February),5
is year (2025).
Avoid using the tickers too long and keep brief and descriptive.
Month Code Table
The following table lists each month and its corresponding month code as referenced in CIP-150:
Month | 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 (ERC-20/4626) |
tokenURI() | Per-token | Off-chain | Yes | NFT metadata (ERC-721/1155) |
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, 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 ERC-20 name/symbol functions and ERC-721 tokenURI, providing additional flexibility without breaking existing implementations.
Security Considerations
- Mutable entries must be explicitly managed and sealed once final.
- Gas efficiency must be considered for large-scale use.
- Contracts should restrict
setValue()
andsealKey()
to authorized parties. - Consider using versioned keys (e.g.
PROSPECTUS_V1
,PROSPECTUS_V2
) to retain history.
Conclusion
The On-Chain Key-Value Metadata Storage standard provides a flexible and secure approach to managing metadata in smart contracts. Its adoption can enhance transparency, auditability, and compliance in tokenized systems, particularly for real-world assets.
References
- Deployment Script: DeployOnChainKV.s.sol Solidity script for deploying the OnChainKV contract using the Foxar deployment framework. Automates and documents the deployment process.
- Test Suite: OnChainKV.t.sol Solidity test file containing unit tests for OnChainKV, verifying correct behavior for setting, sealing, and retrieving key-value pairs.
- Contract ABI: IOnChainKV.abi.json Application Binary Interface (ABI) for the IOnChainKV interface, defining contract methods and events for integration with external tools.
Copyright
Copyright and related rights waived via CC0.