Docs Técnicas
On-Chain Module Registry
Base modules (stdlib and custom) live on-chain as regular contract artifacts. A child contract resolves its impl dependencies against the registry at ContractCall time.
Base modules (stdlib and custom) live on-chain as regular contract artifacts. A child contract resolves its impl dependencies against the registry at ContractCall time.
Overview
PublishContractArtifact(BasicToken source) → artifact_id_A
PublishContractArtifact(Ownable source) → artifact_id_B
PublishContractArtifact(child source) → artifact_id_C (stores source only)
InstantiateContract(artifact_id_C) → contract_id
ContractCall(contract_id, "initialize", …) # `initialize` is decorated with @construct
└─ ledger re-parses child source
└─ resolves BasicToken → artifact_id_A → source
└─ resolves Ownable → artifact_id_B → source
└─ flattens + executesThe child artifact stores its raw source. Flattening happens on every call, not at publish time. Constructor calls follow the same resolution path as ordinary calls; the runtime enforces one-shot @construct execution after the module is flattened.
Publishing A Module
Publish a base module exactly like any other contract. No special flag is needed — any published artifact can be used as a base module:
{
"type": "PublishContractArtifact",
"name": "std.token.BasicToken",
"source": "contract BasicToken:\n storage:\n total: u128 = 0\n ..."
}The name field becomes the canonical registry key. Use the full dotted path (std.token.BasicToken, com.i<institution-uuid-simple>.CreditModule) to avoid collisions.
Naming Convention
| Namespace | Purpose | |-----------|---------| | std.token.* | Stdlib token modules | | std.access.* | Stdlib access control modules | | com.i<institution-uuid-simple>.* | Institution-specific modules | | user.<publisher-address>.* | User-published modules |
The stdlib modules (std.token.BasicToken, std.access.Ownable, std.token.Pausable, std.access.Roles) are bootstrapped by the platform at genesis and are always available.
How The Ledger Resolves Dependencies
At publish time, the ledger resolves every imported canonical name to an immutable artifact and records the artifact ID and code hash in the child artifact. At ContractCall time, the ledger loads those pinned artifacts and rejects any missing or hash-mismatched dependency.
Updating A Base Module
The original publisher may update a non-stdlib canonical name to a new immutable artifact. Existing child artifacts remain pinned to the version they resolved at publish time; newly published children resolve the updated alias. Reserved std.* names are canonical and cannot be remapped.
Institution namespaces use com.i<institution-uuid-simple>.* and may only be registered by the public key recorded for that institution.
Custom Modules
Institutions can publish their own reusable modules:
# com.i123e4567e89b12d3a456426614174000.KYCRegistry — published by that institution
contract KYCRegistry:
storage:
approved: Map[Address, bool, 8192]
@tx
def approve(account: Address):
require(ctx.caller == self.admin, "only_admin")
self.approved = map_set(self.approved, account, True)
@view
def is_approved(account: Address) -> bool:
return map_get(self.approved, account)# A child contract from Acme Bank
import com.i123e4567e89b12d3a456426614174000.KYCRegistry
contract AcmeToken impl KYCRegistry:
...Testing With The Rust API
In tests, pass a local closure as the registry instead of hitting the ledger:
use atlas_trea::{parse_contract, resolve_module_sources, compile_contract_with_modules};
use std::collections::BTreeMap;
let basic_token_src = atlas_trea::BASIC_TOKEN_SRC;
let child_src = r#"
import std.token.BasicToken
contract MyToken impl BasicToken:
...
"#;
let module = parse_contract(child_src)?;
let sources = resolve_module_sources(&module, |path| {
match path {
"std.token.BasicToken" => Some(basic_token_src.to_string()),
_ => None,
}
})?;
let refs: BTreeMap<String, &str> =
sources.iter().map(|(k, v)| (k.clone(), v.as_str())).collect();
let compiled = compile_contract_with_modules(child_src, &refs, 1)?;