Skip to main content

Reading Alkane Metadata

Every Alkanes contract exports a __meta wasm function that returns its own ABI (method names, opcodes, parameter shapes, return types) as JSON. The Metashrew meta view function calls this export and returns the result, so you can ask any deployed alkane "what methods do you have?" without having to read source code or guess opcodes.

This is the same primitive the alkanes-cli alkanes inspect, alkanes-cli alkanes meta, and @alkanes/ts-sdk's provider.alkanes.getMeta() use under the hood.

How the __meta export works

When you build an alkane with the declare_alkane! macro, the runtime generates a __meta wasm export that walks the MessageDispatch enum attached to your contract and emits a JSON blob:

{
"contract": "DIESEL",
"methods": [
{ "name": "initialize", "opcode": 0, "params": [], "returns": "void" },
{ "name": "mint", "opcode": 77, "params": [], "returns": "void" },
{ "name": "get_name", "opcode": 99, "params": [], "returns": "String" },
{ "name": "get_symbol", "opcode": 100, "params": [], "returns": "String" },
{ "name": "get_total_supply", "opcode": 101, "params": [], "returns": "u128" }
]
}

Each method tells you:

  • name: human-readable method name from the MessageDispatch enum variant
  • opcode: the u128 value the calldata varint list must start with
  • params: input arguments (name + type) in order
  • returns: the type of the response data

This is the contract's source of truth, there's no separate registry. If a contract's deployed wasm changes its dispatch, the metadata changes with it automatically.

Calling from JSON-RPC

The Metashrew meta view function does this for you. The single argument is the wasm calldata produced by enciphering the alkane id target (no opcode, the view function knows it's calling __meta):

{
"jsonrpc": "2.0",
"method": "metashrew_view",
"params": [
"meta",
"0x2a020200",
"latest"
],
"id": 1
}

The hex argument 0x2a020200 is the protobuf-encoded MessageContextParcel with calldata = [2, 0] (target alkane 2:0, the DIESEL contract). Hand-rolling that hex is painful, both SDKs below build it for you from "block:tx" strings.

The response is the contract's ABI as a hex-encoded JSON string:

{
"jsonrpc": "2.0",
"result": "0x7b22636f6e7472616374223a2244...",
"id": 1
}

Decode the hex, you get the JSON blob above.

TypeScript / @alkanes/ts-sdk

import { AlkanesProvider } from '@alkanes/ts-sdk';

const provider = new AlkanesProvider({
jsonRpcUrl: 'https://mainnet.subfrost.io/jsonrpc',
});

// 1) High-level helper, `getMeta` does the encoding + hex-decode for you.
const meta = await provider.alkanes.getMeta('2:0');
console.log(meta);
// { contract: "DIESEL", methods: [...] }

// 2) Walk the methods to discover the opcode for a name.
const mintOpcode = meta.methods.find((m) => m.name === 'mint')?.opcode;
console.log(`mint opcode is ${mintOpcode}`); // 77

// 3) Use it in a simulate call (read-only contract evaluation).
const supplyResult = await provider.alkanes.simulate('2:0', {
alkanes: [],
transaction: [],
block: [],
height: 950000,
vout: 0,
txindex: 0,
calldata: [101], // opcode 101 = get_total_supply
pointer: 0,
refund_pointer: 0,
});
console.log('totalSupply (LE u128 hex):', supplyResult.execution.data);

For historical metadata (e.g. inspect what the contract looked like at height 940000 before an upgrade):

const oldMeta = await provider.alkanes.getMeta('2:0', '940000');

Rust

If you're building tooling outside the TS SDK, you can call the view function with alkanes-cli-common::provider::ConcreteProvider or roll your own:

use alkanes_cli_common::provider::{ConcreteProvider, Provider};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let provider = ConcreteProvider::new(
"https://mainnet.subfrost.io/jsonrpc".to_string(),
None, // bitcoin rpc not needed for view calls
)?;

// getMeta returns the raw JSON bytes from `__meta`.
let meta_bytes = provider.alkanes_meta("2:0", Some("latest")).await?;
let meta_str = String::from_utf8(meta_bytes)?;
let meta: serde_json::Value = serde_json::from_str(&meta_str)?;

println!("contract: {}", meta["contract"]);
for method in meta["methods"].as_array().unwrap() {
println!(
" opcode {:>4} {:<30} returns {}",
method["opcode"], method["name"], method["returns"]
);
}
Ok(())
}

Cargo.toml:

[dependencies]
alkanes-cli-common = { git = "https://github.com/kungfuflex/alkanes-rs", branch = "kungfuflex/v3.0.0" }
tokio = { version = "1", features = ["full"] }
anyhow = "1"
serde_json = "1"

From the bytecode directly (offline)

When you have an alkane's wasm bytes locally and don't want to round-trip through an indexer, you can call __meta against the wasm directly using alkanes-cli alkanes inspect:

alkanes-cli alkanes inspect <alkane-id> --meta

Programmatically the same primitive is available via @alkanes/ts-sdk's inspectBytecode:

const bytecode = await provider.alkanes.getBytecode('2:0');
const inspection = await provider.alkanes.inspectBytecode(bytecode, '2:0', {
meta: true,
});
console.log(inspection.metadata); // same shape as getMeta()

This is the inspection path the CLI uses, useful when you have a binary you haven't deployed yet, or want to verify that what's deployed matches what you compiled.

Why __meta over alkanes_meta

The alkanes_meta JSON-RPC convenience method returns a different, narrower shape ({name, symbol, decimals, totalSupply}) that assumes the contract follows token conventions. Many alkanes don't (AMM pools, factories, DAO modules), for those, metashrew_view "meta" is the only way to discover what they can actually do.

See also: metashrew_* Methods for the broader set of view functions.