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_* Methods for the broader set of view functions.