Charms Visualization
To display Charms assets in your wallet, you’ll need to fetch data from the Charms API. This section explains how to retrieve and display Charms data.
Fetching Charms Data
To get all Charms associated with a specific UTXO, you can use charms_lib.wasm module (available as a Charms release artifact, can be built from the source at Charms GitHub).
To create JS bindings for the WASM module:
wasm-bindgen --out-dir target/wasm-bindgen-nodejs --target nodejs path/to/charms_lib.wasmExample
Bitcoin transaction (bitcoin-tx.json):
{ "bitcoin": "020000000001024c24d84d55241594f59337265d8bdae0bbfce8841b2d667d45129a75ea92aa130100000000ffffffffe1562b13c190c62084ee16cbf1feb354dd9029822bbb821010ba70a452c9bfc50000000000ffffffff02e803000000000000225120ec52e2809d78721dc1444ef22749b8e73c0c8f59cad4f70e7af4b13d305a2874580900000000000016001445d77e6d194773f086df5ee258d1803ea5d27b4901405495c9e8f8fca5f20fcf5130e944111d150986b67065a5030167d8f27c893c1304ffdfd8ffdece713882b0a01b4eb91912bd667b0a21cc86b73d11508444cdd80341d6516f4c39207cf3c14986997b57d069bf1e5e60b39ce867ac1a102cf56e71e49964b6ddb256c5070902c42e606af3a538ab156e19706990f7ca39ab27d53b7581fddd020063057370656c6c4d080282a36776657273696f6e07627478a1646f75747381a1001b00000009502f9000716170705f7075626c69635f696e70757473a18361749820183d187f18e718e418ce18a6121819184718af187318d70e1851181918be18bd188a18a518b718ed18fe187418bf18af186e1877189a1818184718bd189b982018c9187518d418e018c2189218fb189518ef18bd18a518c118331218d618ac181d188b185a18ef18f718f018f118e518571886184518a218da187018ff185ff699010418a41859184c1859181e18501884185d18701851187b188518181856189a18d80d1823184018cc182d18e118ed184918f4183f18c718e818e318e5081829184b1859188918a7181e18480e1833186518c518e006182018f318180a1872183f18da1887185e186f0e18ac1879187218740718e21826185b18f618d30a18da18df1820183f18d0186a184a183a10183e18ec18431823188518af18a91888186c184e183618ec189418bf1844183018ee181f186a18e01832188f0f187918ec181f09186318d818ae1849189f186f1318bd18a41877187318591860188b18ae182118b0189818dd18bd18f118ce18ee187b182318a6185a18d2188818aa0f18ab182d185918291218eb189c18e7182618a418e3182e1882189418891829185f18211871189418d9188a185e189118dd18861898187518cd09181d0918701856181c186a181a18a1184118791826184ca533185418a418591883182e1821183a18dc18ab18c318cc18b4181918c9040c0018e0186718581869181818a81898181b1888186318e8185f189c188a1869186818351857185018c31882184818af184618f618ac185e18a418db1898185c18c91879189e181a18d216187b185918f218db18fa1831185818e7187e186318c318ee184b182209188d1831186e1846186b184718d518f01875188718b90718f3188f18b018446820adcd6a7d4ea97319846d90c15b30609bf0174cb0c0f9c032e626009b6185cb17ac21c1adcd6a7d4ea97319846d90c15b30609bf0174cb0c0f9c032e626009b6185cb1700000000"}Simpe JavaScript test demonstrating how to use the API (extractAndVerifySpell.node.test.js):
const assert = require('assert');const path = require('path');const fs = require('fs');
function main() { const wasmModulePath = path.resolve(__dirname, 'path/to/wasm-bindgen-nodejs/charms_lib.js'); // Ensure wasm artifacts exist assert.ok(fs.existsSync(wasmModulePath), `Wasm JS glue not found at ${wasmModulePath}`);
const wasm = require(wasmModulePath); assert.ok(typeof wasm.extractAndVerifySpell === 'function', 'extractAndVerifySpell export not found');
const txJsonPath = path.resolve(__dirname, './bitcoin-tx.json'); assert.ok(fs.existsSync(txJsonPath), `Sample tx JSON not found at ${txJsonPath}`);
const tx = JSON.parse(fs.readFileSync(txJsonPath, 'utf8'));
// Invoke the wasm function extractAndVerifySpell const res = wasm.extractAndVerifySpell(tx, false); console.log('[extractAndVerifySpell.test] OK'); console.log('%o', res);}
if (require.main === module) { try { main(); } catch (err) { console.error('[extractAndVerifySpell.test] FAILED'); console.error(err); process.exit(1); }}Run the test:
node extractAndVerifySpell.node.test.jsThis will print the Charms spell data:
[extractAndVerifySpell.test] OK{ version: 7, tx: { ins: [ '13aa92ea759a12457d662d1b84e8fcbbe0da8b5d263793f5941524554dd8244c:1', [length]: 1 ], outs: [ Map(1) { 0 => 40000000000 }, [length]: 1 ] }, app_public_inputs: Map(1) { 't/3d7fe7e4cea6121947af73d70e5119bebd8aa5b7edfe74bfaf6e779a1847bd9b/c975d4e0c292fb95efbda5c13312d6ac1d8b5aeff7f0f1e5578645a2da70ff5f' => undefined }}API Response Structure
The extractAndVerifySpell(tx, mock) function returns the Charms spell object, describing all Charms in the outputs of the specified transaction. The response includes:
- Charms App Specifications, each containing:
- tag (‘n’ for NFTs, ‘t’ for fungible tokens)
- identity (a 32-byte identifier)
- verification key (a 32-byte verification key of the app’s compiled code)
- Input Specifications, each containing:
- UTXO ID of the input
- Output Specifications with Charms — mappings of App spec (referred by an index) to Charm content, which may be:
- Amounts (for fungible tokens)
- Arbitrary data (for NFTs and other types of charms)
NFTs are recommended (but not required) to adhere to CHIP-0420 for structuring their content.
Displaying Charms in Your Wallet
When implementing Charms visualization in your wallet:
- Scan UTXOs: For each UTXO in the user’s wallet, check if it contains Charms by querying the API
- Parse Responses: Process the API responses to extract Charm data
- Render UI Elements: Display Charms with appropriate visuals and information
- Handle Different Types: Implement different display logic for NFTs vs. fungible tokens
UI Considerations
- For NFTs, prominently display the image and name
- For tokens, show the quantity alongside the token name/symbol + image
- Include options for viewing detailed metadata (review Charms Token Metadata specification CHIP-0420)