Skip to main content

Dynamic Vault listing (database-based metadata)

Flexible approach to list your dapp on the Chromia Vault using database-stored metadata. Perfect for production dapps or when you need frequent content updates.

Prerequisites​

  • A deployed dapp on Chromia (Mainnet or Testnet)
  • Media files for your dapp (icons, screenshots, etc.)
  • Admin key pair for managing operations

Implementation​

Create a new module for Vault listing functionality. Copy this complete implementation into your dynamic_vault_listing.rell file:

Important customization

You only need to change "My dapp name" to your actual dapp's name in this code. All other parts can remain as shown.

./dynamic_vault_listing.rell
module;

struct module_args {
admin_pubkey: byte_array;
dapp_name: text;
}

function require_admin_signer() =
require(op_context.is_signer(chain_context.args.admin_pubkey), "The operation requires admin signer");

enum dapp_content_type {
landscape,
portrait,
promotional,
video,
icon
}

entity dapp {
key name;
mutable description: text = "";
mutable launch_url: text = "";
mutable genre: text = "";
}

entity dapp_media {
key dapp, name;
mutable url: text = "";
type: dapp_content_type;
}

entity blockchain {
key dapp, brid: byte_array;
index brid;
index mutable name: text;
mutable role: text;
}

operation create_or_update_dapp(description: text, launch_url: text, genre: text) {
require_admin_signer();
functions.create_or_update_dapp(chain_context.args.dapp_name, description, launch_url, genre);
}

operation create_or_update_blockchain(brid: byte_array, chain_name: text, role: text) {
require_admin_signer();
val dapp = get_dapp_by_name(chain_context.args.dapp_name);
functions.create_or_update_blockchain(dapp, brid, chain_name, role);
}

operation create_or_update_dapp_media(name, url: text, type: dapp_content_type) {
require_admin_signer();
functions.create_or_update_dapp_media(chain_context.args.dapp_name, name, url, type);
}

query find_dapp_details(dapp_rowid: rowid, requested_content_types: list<dapp_content_type>? = null){
val dapp = get_dapp_by_name(chain_context.args.dapp_name);
return map_dapp_details(dapp, requested_content_types);
}

namespace functions {
function create_or_update_blockchain(dapp, brid: byte_array, name: text, role: text) {
val blockchain = blockchain @? { brid };
if (empty(blockchain)) {
create blockchain ( dapp, brid, name, role );
} else {
update blockchain ( name, role );
}
}

function create_or_update_dapp(name, description: text, launch_url: text, genre: text) {
val dapp = dapp @? { name };
if (empty(dapp)) {
create dapp ( name, description, launch_url, genre );
} else {
update dapp ( description, launch_url, genre );
}
}

function create_or_update_dapp_media(dapp_name: text, name, url: text, type: dapp_content_type) {
val dapp = dapp @? { dapp_name == .name };
require(not empty(dapp), "dapp not found");
val media = dapp_media @? { dapp!!, name };
if (empty(media)) {
create dapp_media ( dapp, name, url, type );
} else {
update media ( url );
}
}
}

function get_dapp_by_name(name) = dapp @ { name };

function map_dapp_details(dapp, requested_content_types: list<dapp_content_type>? = null) {
val blockchains = find_and_map_dapp_blockchains(dapp);
val dapp_media = if (not empty(requested_content_types)) find_and_map_dapp_media(
dapp,
requested_content_types
) else null;

return (
rowid = dapp.rowid,
name = dapp.name,
description = dapp.description,
launch_url = dapp.launch_url,
genre = dapp.genre,
chain_list = blockchains,
content = dapp_media
).to_gtv_pretty();
}

function find_and_map_dapp_blockchains(dapp) =
blockchain @* { dapp } (
@omit @sort .rowid,
name = .name,
brid = .brid,
role = .role
);

function find_and_map_dapp_media(dapp, requested_content_types: list<dapp_content_type>) =
dapp_media @* {
dapp,
.type in requested_content_types
} (
@omit @sort .rowid,
name = .name,
url = .url,
type = .type
);

Configuration​

1. Include the module in your main Rell file​

Add the following line to your main Rell file (e.g., main.rell) to import the vault listing module:

import dynamic_vault_listing;

2. Update your chromia.yml file​

Update your chromia.yml file to include the Vault listing module with admin authentication:

./chromia.yml
blockchains:
<blockchain_name>:
module: main
moduleArgs:
dynamic_vault_listing:
admin_pubkey: x"<public_key>" # Your admin public key
dapp_name: <blockchain_name>

Deployment​

1. Update your dapp with Vault module

After adding the code, deploy your changes to either Testnet or Mainnet:

chr deployment update --network <deployment_name> --blockchain <blockchain_name>

2. Create dapp metadata

chr tx --network <deployment_name> --blockchain <blockchain_name> create_or_update_dapp "Your dapp description" "https://your-dapp-url.com" "Your genre"

Expected output:

transaction with rid A9B05BCC105E69AD627984463BF0B6A9496CF3D9AFD721683B21DC1C91382BCB was posted and confirmed

3. Create blockchain data

chr tx --network <deployment_name> --blockchain <blockchain_name> create_or_update_blockchain 'x"D2...3B2"' <blockchain_name> "Role description"

Expected output:

transaction with rid A9B05BCC105E69AD627984463BF0B6A9496CF3D9AFD721683B21DC1C91382BCB was posted and confirmed

4. Create media data (use a link to Filehub or external image service)

chr tx --network <deployment_name> --blockchain <blockchain_name> create_or_update_dapp_media "icon" "https://pbs.twimg.com/profile_images/1928427668728598528/xbFphaFl_400x400.jpg" 4

Expected output:

transaction with rid A9B05BCC105E69AD627984463BF0B6A9496CF3D9AFD721683B21DC1C91382BCB was posted and confirmed
Enum values

The media type parameter uses the enum index: landscape=0, portrait=1, promotional=2, video=3, icon=4.

Verify the data​

# Basic verification (no media content)
chr query --network <deployment_name> --blockchain <blockchain_name> --output-format json find_dapp_details dapp_rowid=0 'requested_content_types=[]'
# Get all media content
chr query --network <deployment_name> --blockchain <blockchain_name> --output-format json find_dapp_details dapp_rowid=0 'requested_content_types=["landscape", "portrait", "promotional", "video", "icon"]'

Automatic listing​

Once you implement the query and functions, your dapp will be automatically listed in the Chromia Vault based on the information it provides.

Making changes​

To update your dapp's metadata, call the appropriate operations:

  • Update description/URL/genre: Use create_or_update_dapp
  • Update blockchain info: Use create_or_update_blockchain
  • Add/update media: Use create_or_update_dapp_media

No redeployment is required - changes are immediate!

Admin key management​

Keep your admin key secure and accessible for making updates. The admin key is specified in your chromia.yml file and is required for all metadata operations.

Optional: Storing media content on chain​

If you want to store your media files on-chain for enhanced decentralization, you can use Filehub, Chromia's decentralized storage platform.

Filehub benefits

Consider using Filehub for decentralized media storage. Fixed cost of $0.10 per MB for perpetual storage with free access for everyone. Requires CHR tokens on the Economy Chain (minimum 1 CHR deposit).

Recommended image sizes:

  • Horizontal image preview - 180px x 100px (recommended x3 - 540px x 300px)
  • Vertical image preview - 180px x 240px (recommended x3 - 540px x 720px)
  • Big image - 510px x 286px (recommended x3 - 1530px x 858px)
  • Pagination image - 86px x 48px (recommended x3 - 258px x 144px)