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
MessageDispatchenum 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_view methods for the broader set of view functions.