cw-cyber-passport

Passport is a soulbound-style NFT (CW721-based) that represents a citizen's identity in Cyber. Each passport has a unique nickname, an avatar, optional proved addresses from other chains, and metadata fields.

Contract version: 1.0.0

Core Concepts

Passport — a CW721 NFT token identified by an auto-incremented portid. Each passport belongs to one address (owner) and stores:

Field Type Description
nickname String Unique name, 3-32 chars, [a-z0-9-] only
avatar String IPFS CID (particle)
addresses Vec<LabeledAddress> Up to 8 cryptographically proved external addresses
data Option<String> Arbitrary metadata, 3-256 chars
particle Option<String> Optional IPFS CID

Active Passport — each address can have multiple passports but only one is marked as active at a time.

Subgraphs — the contract writes cyberlinks to three subgraph contracts (name, avatar, proof) to make passport data discoverable through the Knowledge Graph.

Constitution — creating a passport requires signing the constitution CID (QmcHB9GKHAKCLQhmSj71qNJhENJJg8Gymd1PvvsCQBhG7M) with the sender's key, as an on-chain oath.

Name Pricing

Names shorter than 8 characters cost BOOT. Names 8+ characters are free.

Formula: price = 1_000_000 * 10^(8 - length) boot

Length Price (boot) Price (BOOT)
3 100,000,000,000 100,000
4 10,000,000,000 10,000
5 1,000,000,000 1,000
6 100,000,000 100
7 10,000,000 10
8+ 0 free

Pricing is hardcoded — changing it requires a contract migration.

The same pricing applies to both CreatePassport and UpdateName (the price is based on the new name length).

Execute Messages

CreatePassport

Creates a new passport NFT. Requires signing the constitution.

{
  "create_passport": {
    "nickname": "alice",
    "avatar": "QmYourAvatarCID",
    "signature": "<base64 ADR-36 signature of 'sender:constitution_cid'>"
  }
}
  • Nickname must be unique, 3-32 chars, [a-z0-9-]
  • Must send exact BOOT amount if name < 8 chars
  • Mints a new CW721 token with auto-incremented portid
  • Creates cyberlinks: nickname → address (name subgraph), nickname → avatar (avatar subgraph)
  • Sets as active passport if it's the first one for this address

UpdateName

Changes the nickname on an existing passport. Old name is released.

{
  "update_name": {
    "old_nickname": "alice-long-name",
    "new_nickname": "alice"
  }
}
  • Only the passport owner can call
  • New name must be unique and follow naming rules
  • Must send exact BOOT amount if new name < 8 chars
  • Creates cyberlink: new_nickname → address (name subgraph)
  • Old nickname→cyberhole link is NOT created (old links remain in the graph)

UpdateAvatar

{
  "update_avatar": {
    "nickname": "alice",
    "new_avatar": "QmNewAvatarCID"
  }
}
  • Creates cyberlink: nickname → new_avatar (avatar subgraph)

UpdateData

{
  "update_data": {
    "nickname": "alice",
    "data": "some metadata string"
  }
}
  • Data must be 3-256 chars, or null to clear

UpdateParticle

{
  "update_particle": {
    "nickname": "alice",
    "particle": "QmSomeParticleCID"
  }
}
  • Must be a valid particle (IPFS CID), or null to clear

ProofAddress

Cryptographically links an external address (Cosmos or Ethereum) to the passport.

{
  "proof_address": {
    "nickname": "alice",
    "address": "cosmos1abc...",
    "signature": "<base64 signature>"
  }
}
  • Supports Cosmos (ADR-36) and Ethereum (EIP-191) signatures
  • Message to sign: passport_owner_address:constitution_cid
  • Max 8 proved addresses per passport
  • Creates cyberlink: nickname → proved_address (proof subgraph)

RemoveAddress

{
  "remove_address": {
    "nickname": "alice",
    "address": "cosmos1abc..."
  }
}

SetActive

Sets which passport is the active one for the caller.

{
  "set_active": {
    "token_id": "42"
  }
}

SetAddressLabel

Sets an optional label (max 16 chars) on a proved address.

{
  "set_address_label": {
    "nickname": "alice",
    "address": "cosmos1abc...",
    "label": "main wallet"
  }
}

TransferNft

Transfers passport to a new owner. Clears proved addresses, data, and particle. Remaps nickname to the new owner.

{
  "transfer_nft": {
    "recipient": "bostrom1new...",
    "token_id": "42"
  }
}

Burn

Destroys the passport. Nickname is released. Creates cyberlink: nickname → cyberhole.

{
  "burn": {
    "token_id": "42"
  }
}

Admin-only

Message Description
Execute { msgs } Execute arbitrary Cyber messages (owner only)
SetOwner { owner } Transfer contract ownership
SetSubgraphs { name_subgraph, avatar_subgraph, proof_subgraph } Update subgraph contract addresses

Disabled

Message Status
Mint Disabled — passports can only be created through CreatePassport
SendNft Disabled

Query Messages

Query Returns Description
Config {} ConfigResponse Owner and subgraph addresses
LastPortid {} PortidResponse Last issued portid (total passports created)
PortidByNickname { nickname } PortidResponse Token ID for a nickname
AddressByNickname { nickname } AddressResponse Owner address for a nickname
PassportByNickname { nickname } TokenInfo<PassportMetadata> Full token info including owner
MetadataByNickname { nickname } PassportMetadata Passport metadata only
PassportSigned { nickname, address } SignatureResponse Check if address is proved for nickname
ActivePassport { address } TokenInfo<PassportMetadata> Active passport for an address

Standard CW721 queries (OwnerOf, NftInfo, AllNftInfo, Tokens, AllTokens, NumTokens, ContractInfo, Minter, Approval, Approvals, AllOperators) are also supported.

Interacting with the Contract

Contract is deployed on Bostrom mainnet. See deployments/bostrom-mainnet.toml for the address.

# Set contract address (from deployments/bostrom-mainnet.toml)
PASSPORT=bostrom1xut80d09q0tgtch8p0z4k5f88d3uvt8cvtzm5h3tu3tsy4jk9xlsfzhxel
NODE=https://rpc.bostrom.cybernode.ai:443

Query examples

# Get contract config (owner, subgraph addresses)
cyber query wasm contract-state smart $PASSPORT '{"config":{}}' --node $NODE -o json

# How many passports exist
cyber query wasm contract-state smart $PASSPORT '{"last_portid":{}}' --node $NODE -o json

# Look up a passport by nickname
cyber query wasm contract-state smart $PASSPORT \
  '{"passport_by_nickname":{"nickname":"master"}}' --node $NODE -o json

# Get only metadata (nickname, avatar, addresses)
cyber query wasm contract-state smart $PASSPORT \
  '{"metadata_by_nickname":{"nickname":"master"}}' --node $NODE -o json

# Resolve nickname → owner address
cyber query wasm contract-state smart $PASSPORT \
  '{"address_by_nickname":{"nickname":"master"}}' --node $NODE -o json

# Get active passport for an address
cyber query wasm contract-state smart $PASSPORT \
  '{"active_passport":{"address":"bostrom1qn8sr2hzmktlecusdtxj9hwj0upnm0jft9snar"}}' --node $NODE -o json

# Check if an address is proved for a nickname
cyber query wasm contract-state smart $PASSPORT \
  '{"passport_signed":{"nickname":"master","address":"cosmos1qn8sr2hzmktlecusdtxj9hwj0upnm0jfgkyqry"}}' --node $NODE -o json

# List all passports owned by an address (CW721)
cyber query wasm contract-state smart $PASSPORT \
  '{"tokens":{"owner":"bostrom1qn8sr2hzmktlecusdtxj9hwj0upnm0jft9snar"}}' --node $NODE -o json

# Total number of passport NFTs (CW721)
cyber query wasm contract-state smart $PASSPORT '{"num_tokens":{}}' --node $NODE -o json

Execute examples

Requires cyber CLI with a funded wallet.

TX_FLAGS="--from <your-key> --chain-id bostrom --node $NODE --gas-prices 0boot --gas-adjustment 2.5 --gas auto -y"

# Update avatar
cyber tx wasm execute $PASSPORT \
  '{"update_avatar":{"nickname":"your-nick","new_avatar":"QmNewAvatarCID"}}' \
  $TX_FLAGS

# Update name (free if new name >= 8 chars)
cyber tx wasm execute $PASSPORT \
  '{"update_name":{"old_nickname":"your-old-nick","new_nickname":"your-new-nick"}}' \
  $TX_FLAGS

# Update name (paid — 5-char name costs 1000 BOOT)
cyber tx wasm execute $PASSPORT \
  '{"update_name":{"old_nickname":"your-old-nick","new_nickname":"alice"}}' \
  --amount 1000000000boot $TX_FLAGS

# Set active passport
cyber tx wasm execute $PASSPORT \
  '{"set_active":{"token_id":"42"}}' \
  $TX_FLAGS

# Transfer passport to another address
cyber tx wasm execute $PASSPORT \
  '{"transfer_nft":{"recipient":"bostrom1...","token_id":"42"}}' \
  $TX_FLAGS

Storage

Key Type Description
config Item<Config> Contract config
portid Item<u64> Auto-increment counter for token IDs
nicknames Map<&str, AddressPortID> Nickname → (owner address, portid)
active Map<&Addr, String> Address → active portid
CW721 token storage TokenInfo<PassportMetadata> Standard CW721 storage with passport extension

Pages in this namespace

Local Graph