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)