charms-js
Version:
TypeScript SDK for decoding Bitcoin transactions containing Charms data
113 lines (112 loc) • 3.94 kB
JavaScript
;
/**
* WASM-based decoder for Charms.js
* Simplified implementation using charms-lib WASM module
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.decodeTransactionWithWasm = decodeTransactionWithWasm;
const wasm_wrapper_1 = require("./wasm-wrapper");
const formatter_1 = require("./formatter");
/**
* Decode transaction using WASM spell extraction
* @param txHex - Transaction hex string
* @returns Array of CharmInstance objects
*/
async function decodeTransactionWithWasm(txHex) {
try {
// Extract and verify spell using WASM
const spellData = await (0, wasm_wrapper_1.extractAndVerifySpell)(txHex, false);
if (!spellData) {
return [];
}
console.log('WASM extracted spell data:', JSON.stringify(spellData, null, 2));
// Convert WASM output to CharmInstance format
return convertWasmDataToCharms(spellData, txHex);
}
catch (error) {
console.error('WASM decoding failed:', error);
throw error;
}
}
/**
* Convert WASM spell data to CharmInstance array
*/
function convertWasmDataToCharms(spellData, txHex) {
const charms = [];
// Extract transaction ID from hex (first 32 bytes reversed)
const txId = extractTxIdFromHex(txHex);
// Process spell data structure
if (spellData.tx && spellData.tx.outs) {
spellData.tx.outs.forEach((output, index) => {
// Extract value from output
const value = extractValueFromOutput(output);
if (value > 0) {
// Reconstruct app ID from app_public_inputs
const appId = (0, formatter_1.reconstructAppId)(spellData, '$0000');
// Extract app data
const appData = extractAppData(spellData.app_public_inputs);
const charm = {
utxo: {
tx: txId,
index: index
},
address: '', // Will be filled by address derivation if needed
appId: appId,
app: appData,
appType: 'unknown',
value: value,
verified: true // WASM verification passed
};
charms.push(charm);
}
});
}
return charms;
}
/**
* Extract transaction ID from hex string
*/
function extractTxIdFromHex(txHex) {
// This is a simplified version - in practice, we'd need to properly parse the transaction
// For now, we'll use a placeholder that can be filled by the calling code
return 'PLACEHOLDER_TX_ID';
}
/**
* Extract value from output object
*/
function extractValueFromOutput(output) {
if (typeof output === 'object') {
// Look for numeric values in the output
for (const [key, value] of Object.entries(output)) {
if (typeof value === 'number' && value > 0) {
return value;
}
}
}
return 0;
}
/**
* Extract app data from app_public_inputs
*/
function extractAppData(appPublicInputs) {
if (!appPublicInputs) {
return null;
}
// If it's already an object with app data, return it
if (typeof appPublicInputs === 'object') {
// Filter out the app ID keys and keep only the app data
const appData = {};
for (const [key, value] of Object.entries(appPublicInputs)) {
// Skip app ID keys (they start with 't/')
if (typeof key === 'string' && !key.startsWith('t/')) {
appData[key] = value;
}
else if (typeof key === 'string' && key.startsWith('t/') && value && typeof value === 'object') {
// If the value contains app data, merge it
Object.assign(appData, value);
}
}
return Object.keys(appData).length > 0 ? appData : {};
}
return {};
}