Docs Técnicas
Static Composition
TREA contracts can inherit storage and behaviour from reusable base modules. Composition is resolved entirely at compile time — there is no virtual dispatch or runtime module loading.
TREA contracts can inherit storage and behaviour from reusable base modules. Composition is resolved entirely at compile time — there is no virtual dispatch or runtime module loading.
Declaration
import std.token.BasicToken
import std.access.Ownable
import std.token.Pausable
contract PausableToken impl BasicToken, Ownable, Pausable:
storage:
balances: Map[Address, u128, 4096]The impl list names the base modules in the order they are merged. Each name must match the short name (or alias) of an import declaration.
What Gets Inherited
Storage — base storage fields are prepended to the child's storage block, in the order the bases are listed. The child's own fields come last.
# After flattening PausableToken:
# total: u128 = 0 ← from BasicToken
# owner: Address ← from Ownable
# paused: bool = False ← from Pausable
# balances: ... ← child's own fieldFunctions — all base functions are available as if they were declared in the child. The child can call them, override them, or leave them as-is.
Helpers — helper functions defined in bases are also inherited.
Overriding a Base Function
@tx
override def mint(amount: u128):
require(self.paused == False, "contract_paused")
require(ctx.caller == self.owner, "only_owner")
require(amount > 0, "amount_must_be_positive")
self.balances[ctx.caller] = self.balances[ctx.caller] + amount
self.total = self.total + amountRules:
- The
overridekeyword is mandatory. - The
@tx,@view, or@constructdecorator must precedeoverride. - The function name must exist in at least one base. The verifier errors if no
base defines that name.
- A child function that shadows a base function without
overrideis a
compile error.
Delegating to the Base — `super.method()`
@tx
override def pause():
require(ctx.caller == self.owner, "only_owner")
super.pause()super.method(args) calls the base implementation from inside an override. The call is rewritten at compile time to a renamed internal function (__super__pause) and carries no runtime overhead beyond a normal function call. super is only valid inside override def.
Conflict Rules
| Situation | Result | |-----------|--------| | Two bases declare the same storage field | Compile error | | Child redeclares a field already in a base | Compile error | | Two bases declare the same function | Conflict — child must override | | Child shadows a base function without override | Compile error | | override names a function not in any base | Compile error |
Storage Namespacing
Base fields live in the same flat namespace as child fields. There is no BaseName.field accessor — self.total is always just self.total, regardless of which base introduced it.
This means the child can read and write inherited fields freely, which is intentional: a token contract that inherits total from BasicToken must be able to update it in its own mint override.
Compile-Time Resolution
The import paths are recorded in the artifact's uses_modules list. The compiler does not embed the base source inside the child artifact — it stores the child source only. At ContractCall time the ledger re-parses the child source and re-flattens it against the base modules fetched from the on-chain registry.
This means a child contract depends on the on-chain presence of its bases. If a base artifact is not published, ContractCall will fail at the resolution step.