Docs Técnicas
Construction And Address Safety
TREA contracts use @construct for one-shot construction. This is the constructor model: initialize required state once, then expose the normal @tx and @view entrypoints.
TREA contracts use @construct for one-shot construction. This is the constructor model: initialize required state once, then expose the normal @tx and @view entrypoints.
contract OwnedVault:
storage:
owner: Address
@construct
def initialize(owner: Address):
self.owner = owner
@tx
def withdraw(token: TokenId, amount: u128):
require(ctx.caller == self.owner, "only_owner")
ctx.transfer(token, ctx.vault(), self.owner, amount)The function name is not special. initialize is common because deployment tools already know it, but the constructor behavior comes from @construct. @init remains accepted as a compatibility alias for older sources.
Runtime Guarantees
If a contract declares @construct:
- the constructor may mutate storage and produce transaction-style effects;
- it must not return values;
- the verifier allows at most one constructor;
- the runtime rejects every non-constructor entrypoint until construction
succeeds;
- after success, the runtime rejects every later constructor call;
- invariants run after construction just as they do after
@tx.
Construction state is persisted in the runtime snapshot with an internal reserved marker. Contracts cannot declare storage named __trea_initialized.
Non-Zero Address Policy
Address represents a real account, contract, or protocol address. Runtime storage writes and accounting effects reject the empty/zero address.
Do not use zero address for:
- burns;
- missing values;
- already-initialized guards;
- vault or escrow custody.
Use explicit state for absence, such as active: bool, admin_active: bool, or a domain state enum encoded as an integer. For value destruction, use explicit protocol effects like ctx.burn or ctx.retire.
Implicit Contract Vault
Contracts that need to hold funds should use:
ctx.vault() -> AddressThe returned address is deterministic, non-zero, and tied to the current contract instance. It is the default custody endpoint for deposits, escrow balances, card spending vaults, and other contract-controlled balances.
@tx
def deposit(token: TokenId, amount: u128):
require(amount > 0, "amount_required")
ctx.transfer(token, ctx.caller, ctx.vault(), amount)This keeps burn semantics and custody semantics separate, which matters in an accounting-first chain.