Generates a JSON ABI from deployed Aleo bytecode, and checks one ABI against another for compatibility. Rust bindings around Leo's ABI generation with full snarkVM validation — a program that does not validate does not get an ABI. Everything runs locally; nothing touches the network.
The distribution is aleo-contract-abi-generator; the import module is
aleo_abi.
import aleo_abi
abi_json = aleo_abi.generate_abi("simple.aleo", bytecode, "testnet", None)
violations = aleo_abi.check_compatibility(candidate_json, standard_json)pip install aleo-contract-abi-generatorMost callers want the friendlier hook in the main SDK instead —
aleo.abi.generate_abi accepts a Program object or a raw bytecode string,
infers the program name, and returns a dict:
from aleo import abi
from aleo.mainnet import Program
result = abi.generate_abi(Program.credits())
result["program"] # "credits.aleo"The hook imports this package lazily and raises ImportError with the
install command if it is absent — the main SDK does not depend on it.
generate_abi(program_name, bytecode, network, imports) returns a
pretty-printed JSON string describing the program: its structs, records,
mappings, and functions, each field carrying a structured type
({"Primitive": {"Int": "I32"}}, record ownership, visibility).
snarkVM validation is contextual: a program that declares imports is
rejected unless those imports are supplied. Pass them as
(program_id, bytecode) pairs in topological order — dependencies before
dependents:
abi_json = aleo_abi.generate_abi(
"shield_swap.aleo", amm_bytecode, "testnet",
[("shield_swap_multisig_core.aleo", multisig_bytecode),
("shield_swap_freezelist.aleo", freezelist_bytecode)],
)network is "mainnet", "testnet", or "canary" — it selects the
validation rules, not a connection.
The validation rules are those of the snarkVM release Leo pins, which can
trail the main SDK's by one release. Right now this package validates with
snarkVM 4.11.0 while aleo-sdk uses 4.12.0: a program with more than 31
mappings, which consensus V22 allows (live on testnet, mainnet from block
22,962,000), parses in the main SDK but is rejected here with "Program
exceeds the maximum number of mappings" until Leo moves to 4.12.
check_compatibility(candidate_abi_json, standard_abi_json) returns a list
of violation strings — empty means the candidate satisfies the standard.
Use it to pin a deployed contract's surface and fail your CI when the
deployment drifts, instead of your consumers:
violations = aleo_abi.check_compatibility(deployed_abi, pinned_abi)
assert not violations, "\n".join(violations)This is how shield-swap-sdk's live drift test guards its committed
bindings (codegen/regen-abi.sh regenerates the pin from the deployed
program).
The ABI JSON is the input format for the main SDK's aleo.codegen, which
emits typed dataclasses and entrypoint stubs from it:
python -m aleo.codegen --abi shield_swap.abi.json --out _generated.pycd sdk-abi && python -m pytest python/tests -v # hermetic — no networkFixtures and expected ABIs are vendored from Leo's own test suite, so the output shape is pinned to upstream.