Docs Técnicas
Common Pitfalls
Bad:
Effect Before Guard
Bad:
self.active = True
require(ctx.caller == self.lender, "only_lender")Good:
require(ctx.caller == self.lender, "only_lender")
self.active = TrueGuards must run before state mutation and before accounting intent is produced. The compiler does not enforce ordering today — it is the author's responsibility.
Writing to Privileged Fields Without a Guard
The compiler blocks this pattern (SEC-E001):
@tx
def transfer_ownership(new_owner: Address):
self.owner = new_owner # fatal: no require guardCorrect form:
@tx
def transfer_ownership(new_owner: Address):
require(ctx.caller == self.owner, "only_owner")
self.owner = new_ownerPrivileged field names that trigger SEC-E001: owner, admin, controller, operator, authority.
This applies to struct field assignments too. If self.config.admin is written without a guard, SEC-E001 fires.
Unguarded @tx Functions
Any @tx with no require or assert at all allows any caller to invoke it (SEC-W001 warning). This is intentional only for truly public entrypoints such as a deposit or mint that any participant may call.
Manual Loan Posting
Prefer loan helpers over manually assembling standard loan posting lines.
Inline Source Calls
ContractCall.source is rejected. Publish an artifact and instantiate the contract first.
Assuming All Specs Are Executable
The trea/ directory includes architecture. The implemented language is the source of truth for production contracts.
Assuming Runtime Success Means Commit Success
A local runtime test can pass while ledger commit rejects a posting route.
Add ledger integration tests for every accounting flow.