Vexidus Token Metadata Standard
Version 1.0
Overview
The Vexidus Token Metadata Standard defines the canonical schema for token metadata stored on-chain in RocksDB. It covers native tokens (VSC-7), bridged tokens, and the VXS native token, with clear mutability rules and a three-tier resolution system.
Three-Tier Metadata Resolution
- On-chain (RocksDB) -- source of truth, highest priority
- Off-chain URI (IPFS/Arweave) -- extended metadata via
metadata_uri - Community registry (future GitHub repo) -- fallback for bridged tokens missing icons
On-Chain Metadata Schema
Stored as JSON in RocksDB via token:<mint_hex> keys.
Immutable Fields (set at creation, never changeable)
| Field | Type | Max Length | Description |
|---|---|---|---|
name | string | 64 | Token name |
symbol | string | 10 | Token ticker |
decimals | u8 | - | Decimal precision |
total_supply | string | - | Total supply (raw units) |
initial_supply | string/u64 | - | Initial supply at creation |
creator | string | - | Creator address (0x hex) |
mint_address | string | - | Mint address (0x hex or Vx1) |
mint_address_hex | string | - | Mint address (0x hex, always present) |
created_at | u64 | - | Unix timestamp of creation |
standard | string | - | VSC-7, Native, VSC-21, VSC-55 |
features.mintable | bool | - | Whether new tokens can be minted |
features.burnable | bool | - | Whether tokens can be burned |
features.pausable | bool | - | Whether transfers can be paused |
features.freezable | bool | - | Whether accounts can be frozen |
Mutable Fields (changeable if is_mutable = true)
| Field | Type | Max Length | Description |
|---|---|---|---|
metadata_uri | string | 512 | Off-chain JSON metadata URI (IPFS/Arweave/HTTPS) |
image | string | 512 | Direct URL to token logo |
description | string | 1024 | Token description |
external_url | string | 256 | Project website |
twitter | string | 256 | Twitter/X link |
discord | string | 256 | Discord invite link |
telegram | string | 256 | Telegram link |
github | string | 256 | GitHub repo link |
System Fields (set by protocol, not user-editable)
| Field | Type | Description |
|---|---|---|
is_mutable | bool | true = metadata can be updated; false = permanently locked. Default: true for native tokens, false for bridged tokens. |
badge | string | native (VXS), bridge (bridged tokens). Set by protocol. |
origin | string | bridged for bridge-created tokens |
source_chain | string | Origin chain (bridged tokens only) |
source_contract | string | Origin contract address (bridged tokens only) |
bridge_tier | string | tier2 or tier3 (bridged tokens only) |
Mutability Lifecycle
Token Created --> is_mutable: true --> Creator updates metadata freely
|
v
vex_lockTokenMetadata (one-way)
|
v
is_mutable: false (permanent)
No further updates possible
Rules
- All new native tokens (VSC-7) start with
is_mutable: true - All bridged tokens are created with
is_mutable: false(permanently immutable) - Only the token creator can call
vex_lockTokenMetadata - Once locked (
is_mutable: false), it cannot be reversed -- ever vex_updateTokenMetadatachecksis_mutablebefore allowing changes- Missing
is_mutablefield is treated astrue(backward compatibility)
Off-Chain Metadata Schema (at metadata_uri)
Compatible with the Metaplex token metadata standard:
{
"name": "string (required)",
"description": "string (required)",
"image": "URI (required, PNG/JPG/SVG)",
"external_url": "URI (optional)",
"attributes": [
{ "trait_type": "string", "value": "string|number" }
],
"properties": {
"files": [
{ "uri": "string", "type": "MIME type" }
],
"category": "string (image|video|audio)"
}
}
Token Type Examples
Native Token (VSC-7)
{
"name": "My Token",
"symbol": "MTK",
"decimals": 9,
"total_supply": "1000000000000000000",
"initial_supply": 1000000000,
"creator": "0xabc...",
"mint_address": "0xdef...",
"created_at": 1739477600,
"standard": "VSC-7",
"is_mutable": true,
"features": {
"mintable": false,
"burnable": true,
"pausable": false,
"freezable": false
},
"image": "https://example.com/logo.png",
"description": "A community token",
"twitter": "https://x.com/mytoken"
}
Bridged Token
{
"name": "Bridged USDC (ethereum)",
"symbol": "USDC",
"decimals": 9,
"origin": "bridged",
"source_chain": "ethereum",
"source_contract": "0xa0b8...",
"bridge_tier": "tier2",
"mint_address": "Vx1abc...",
"mint_address_hex": "0xdef...",
"created_at": 1739477600,
"standard": "VSC-7",
"is_mutable": false,
"badge": "bridge"
}
VXS (Native Token)
VXS metadata is hardcoded in the RPC layer (not stored in token registry). It cannot be modified via vex_updateTokenMetadata.
RPC Methods
vex_updateTokenMetadata
Update mutable metadata fields. Creator only. Fails if is_mutable = false.
Parameters: [mint, sender, metadata_uri?, image?, description?, external_url?, twitter?, discord?, telegram?, github?]
vex_lockTokenMetadata
Permanently lock token metadata. Creator only. One-way operation.
Parameters: [mint, sender]
Response: { "status": "submitted", "mint": "0x...", "action": "lock_metadata" }
Reputation Impact
The metadata_integrity reputation factor (max 10 points) rewards tokens with complete, locked metadata:
| Condition | Points |
|---|---|
Metadata permanently locked (is_mutable: false) | 10/10 |
| Has image + description + at least one social link, but mutable | 5/10 |
| Incomplete metadata | 0/10 |
Metadata Sanitization (VSC-SAFE)
All metadata submitted on-chain is validated to prevent XSS, injection, and phishing attacks. This applies to token creation, metadata updates, NFT minting, and collection creation.
URI Field Validation
All URI fields (metadata_uri, image, base_uri, icon_uri, banner_uri, external_url) must pass:
| Rule | Details |
|---|---|
| Allowed schemes | https://, ipfs://, ar:// (Arweave) |
| Blocked schemes | data: (inline payloads), javascript:, http:// (insecure) |
| Pattern scanning | Rejects <script, onerror=, onclick=, <iframe, eval(, document.cookie, &# (HTML entities), and 17+ dangerous patterns |
| Max length | 512 characters (URIs), 256 characters (external URLs) |
Text Field Validation
All text fields (description, attribute keys/values) must pass:
| Rule | Details |
|---|---|
| Null bytes | Rejected (prevents string truncation attacks) |
| Pattern scanning | Same 17+ dangerous patterns as URI validation |
| Max length | 2,048 chars (descriptions), 64 chars (attribute keys), 256 chars (attribute values) |
| Max attributes | 50 per token |
What Gets Rejected
data:text/html,<script>alert(1)</script> -> Blocked: data: URI
https://evil.com/<script>alert(1) -> Blocked: <script pattern
https://evil.com/img.png?onerror=alert(1) -> Blocked: onerror= pattern
javascript:alert(1) -> Blocked: not https/ipfs/ar
Hello\0World -> Blocked: null bytes
What Passes
https://example.com/token-logo.png -> OK
ipfs://QmSomeHash/metadata.json -> OK
ar://abc123def456 -> OK
A beautiful NFT collection of 10,000 pieces -> OK
Sanitization runs at the state machine level, so it applies regardless of whether metadata is submitted via RPC, SDK, CLI, or any other path.
Future
- Community token registry:
mashiyu-devs/vexidus-token-listGitHub repo with JSON files per token, PR-based curation, CI validation - Origin chain metadata fetching: Automatic image/social pull from Ethereum/Solana registries at bridge time
- Governance override: Allow protocol governance (VSC-88) to force-update metadata on scam tokens