Intrinsics
Intrinsics are low-level operations built into the compiler. They complement Leo's high-level abstractions and are useful when those abstractions aren't expressive enough for a particular use case. They are prefixed with _ to make them visually distinct from user-defined functions.
_dynamic_call
Calls a function on a remote program determined at runtime, without requiring an interface definition. The target program, network, and function name are supplied as runtime values, and the full type signature is declared in the generic type parameters.
Only valid in transition contexts — it cannot be used inside final fn functions or final {} blocks.
Syntax
_dynamic_call::[TYPE_PARAMS](prog, net, func, ...args)
prog— the target program name, as a value of typeidentifieror afieldrepresenting an identifiernet— the network, as a value of typeidentifieror afieldrepresenting an identifier; currently only'aleo'is validfunc— the function name to call, as a value of typeidentifieror afieldrepresenting an identifier...args— the function arguments, matching the input types declared inTYPE_PARAMS
Type parameters
Type parameters follow one rule: the last entry is the return type; all preceding entries are input types with an optional visibility modifier (public or private). Omitting type parameters entirely means void return with compiler-inferred input visibility.
No type parameters — void return
_dynamic_call(prog, net, func, x);
Return type only — inputs are private by default
let result: u64 = _dynamic_call::[u64](prog, net, func, x);
Explicit input visibility
All type params before the last are input types. Each can carry a visibility modifier:
// One public input, then the return type
let result: u64 = _dynamic_call::[public u64, u64](prog, net, func, x);
Multiple inputs
let (a, b): (u32, u32) = _dynamic_call::[public u32, public u32, (u32, u32)](prog, net, func, x, y);
Void return with input annotations
Use () as the return type:
_dynamic_call::[public u64, ()](prog, net, func, x);
Final return
When the called function returns a Final, include it in a tuple:
let (val, f): (u32, Final) = _dynamic_call::[(u32, Final)](target, 'aleo', 'increment', val);
return (val, final {
f.run();
});
dyn record inputs and outputs
let result: dyn record = _dynamic_call::[dyn record, dyn record](prog, net, func, token);
Restrictions
_dynamic_call is not allowed in final fn functions or final {} blocks.
_dynamic_contains
Checks whether a key exists in a mapping belonging to another program, determined at runtime. Only valid inside final fn functions or final {} blocks.
Syntax
let exists: bool = _dynamic_contains(prog, net, mapping, key);
prog— the target program name, as a value of typeidentifieror afieldrepresenting an identifiernet— the network, as a value of typeidentifieror afieldrepresenting an identifier; currently only'aleo'is validmapping— the mapping name on the target program, as a value of typeidentifieror afieldrepresenting an identifierkey— a value whose type matches the target mapping's key type
Returns true if key is present, false otherwise.
Example
program checker.aleo {
mapping seen: address => bool;
fn check(prog: field, net: field, map: field, key: address) -> Final {
return final { finalize_check(prog, net, map, key); };
}
@noupgrade
constructor() {}
}
final fn finalize_check(prog: field, net: field, map: field, key: address) {
let exists: bool = _dynamic_contains(prog, net, map, key);
Mapping::set(seen, key, exists);
}
_dynamic_get
Reads a value from a mapping belonging to another program, determined at runtime. Only valid inside final fn functions or final {} blocks.
Fails at runtime if the key is not present — use _dynamic_get_or_use when the key may be absent.
Syntax
let val: T = _dynamic_get::[T](prog, net, mapping, key);
prog— the target program name, as a value of typeidentifieror afieldrepresenting an identifiernet— the network, as a value of typeidentifieror afieldrepresenting an identifier; currently only'aleo'is validmapping— the mapping name on the target program, as a value of typeidentifieror afieldrepresenting an identifierkey— a value whose type matches the target mapping's key typeT— must match the target mapping's value type
Example
program reader.aleo {
mapping result: address => u64;
fn read(prog: field, net: field, map: field, key: address) -> Final {
return final { finalize_read(prog, net, map, key); };
}
@noupgrade
constructor() {}
}
final fn finalize_read(prog: field, net: field, map: field, key: address) {
let val: u64 = _dynamic_get::[u64](prog, net, map, key);
Mapping::set(result, key, val);
}
For example, using identifier literals:
let val: u64 = _dynamic_get::[u64]('some_program', 'aleo', 'balances', key);
_dynamic_get_or_use
Reads a value from a mapping belonging to another program, determined at runtime, returning a default value if the key is absent. Only valid inside final fn functions or final {} blocks.
Syntax
let val: T = _dynamic_get_or_use::[T](prog, net, mapping, key, default);
prog— the target program name, as a value of typeidentifieror afieldrepresenting an identifiernet— the network, as a value of typeidentifieror afieldrepresenting an identifier; currently only'aleo'is validmapping— the mapping name on the target program, as a value of typeidentifieror afieldrepresenting an identifierkey— a value whose type matches the target mapping's key typedefault— the fallback value returned whenkeyis absent; must be the same type asTT— must match the target mapping's value type
Example
program reader.aleo {
mapping result: address => u64;
fn read(prog: field, net: field, map: field, key: address) -> Final {
return final { finalize_read(prog, net, map, key); };
}
@noupgrade
constructor() {}
}
final fn finalize_read(prog: field, net: field, map: field, key: address) {
let val: u64 = _dynamic_get_or_use::[u64](prog, net, map, key, 0u64);
Mapping::set(result, key, val);
}