Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

upgrade_registry source realm

Constants 1

const MaxNameLen, MaxChainLen, MaxRenderEntries, RenderLatestHops

 1const (
 2	MaxNameLen = 64
 3
 4	// MaxChainLen bounds two WALKS, and is NOT a bound on how long a
 5	// migration chain can become (round-4 audit: the previous comment
 6	// named only the first of the two uses, which read as though chain
 7	// length itself were capped at 50):
 8	//
 9	//   1. GetMigrationChain's traversal and output — a chain longer than
10	//      this is explicitly marked truncated rather than presented as
11	//      ending early.
12	//   2. Deprecate's cycle-verification walk, which refuses rather than
13	//      walking unbounded.
14	//
15	// Neither bounds TOTAL chain length, because Deprecate's walk runs
16	// FORWARD from the new successor and never sees the chain BEHIND the
17	// predecessor. Its cost is proportional to the chain AHEAD of the
18	// successor, which is:
19	//
20	//   - zero hops when the successor is terminal — the ordinary
21	//     tail-append. The walk breaks immediately, so tail-appending grows
22	//     a chain without limit. The realm's own
23	//     TestMigrationChain_MarksTruncation builds MaxChainLen+5 links this
24	//     way and is expected to succeed.
25	//   - O(chain ahead) when the successor is ITSELF already deprecated — a
26	//     head-append. Deprecate does NOT reject an already-deprecated
27	//     successor (it validates only existence and ownership), so this is
28	//     a permitted call, and past MaxChainLen hops it refuses. See
29	//     TestDeprecate_BoundedWalkRefusal.
30	//
31	// This is why GetLatest documents an UNBOUNDED cost (see its COST
32	// WARNING) — that warning is accurate, not conservative.
33	//
34	// Extending a chain requires owning both ends of THE ONE NEW LINK at
35	// call time (see Deprecate, which checks exactly that and never
36	// re-verifies earlier links). That is a per-call consent check, not an
37	// invariant of the finished chain: an owner who transfers away only the
38	// TAIL entry hands the recipient the ability to extend it, and so to
39	// move GetLatest for every entry behind it, without that recipient ever
40	// having owned the root. Acquiring the tail still takes the two-step
41	// nominate/accept handoff from its owner, so no chain can be lengthened
42	// without some consenting owner along it.
43	MaxChainLen = 50
44
45	// Render bounds (re-audit): rendering is paginated and the per-row
46	// "latest" annotation walks a bounded number of hops, so an
47	// attacker-built long chain cannot blow up the realm page.
48	MaxRenderEntries = 100
49	RenderLatestHops = 10
50)
source

Functions 8

func AcceptOwnership

crossing Action
1func AcceptOwnership(cur realm, contractAddr address) string
source

AcceptOwnership completes a nominated ownership: only the pending owner can accept, and only acceptance moves the entry (and the ownerContracts index) to them.

func Deprecate

crossing Action
1func Deprecate(cur realm, contractAddr, successorAddr address) string
source

Deprecate marks a contract as deprecated and points to its successor. Only the entry's owner can deprecate. The successor must itself be a REGISTERED entry — registration is self-proving, so a successor can never be a dangling pointer or an address squatted by a third party — and the successor entry must be OWNED BY THE CALLER (re-audit: without consent, an attacker could chain their entry INTO a legitimate contract, forging "official predecessor" provenance). Consent is checked AT CALL TIME: transferring the successor entry away later does not unlink an existing chain — the attestation is that both ends shared an owner when the deprecation was recorded.

func GetInfo

Action
1func GetInfo(contractAddr address) string
source

GetInfo returns a one-line summary for a contract.

func GetMigrationChain

Action
1func GetMigrationChain(contractAddr address) string
source

GetMigrationChain returns the full upgrade path starting from the given address, at most MaxChainLen hops. A chain longer than the bound is explicitly marked as truncated (re-audit: silent truncation presented a mid-chain node as the endpoint).

func GetOwnerContracts

Action
1func GetOwnerContracts(owner address) string
source

GetOwnerContracts returns all contract addresses whose ACCEPTED owner is the given address (nominations don't count until accepted).

func Register

crossing Action
1func Register(cur realm, name string, owner address) string
source

Register adds the CALLING contract to the registry — the entry's address is the caller's own address, which is the proof of control. owner NOMINATES a manager (team EOA or governance realm); it holds no power until it calls AcceptOwnership (nobody can be made an owner without consent — re-audit). Pass "" to manage from the contract itself — but note (audit Y4): entries are permanent, so an entry managed by a contract that has no code path for calling this registry again is FROZEN as active forever: never deprecatable, never transferable. Realms registering from init() should nominate an EOA or governance manager instead.

func Render

1func Render(path string) string
source

Render returns a markdown overview of the most recent entries. Never panics.

The rendered page carries an explicit scope disclosure (round-4 audit). What this registry proves is narrow and easy to over-read: an entry's ADDRESS is self-registered and therefore verified, but its NAME is an arbitrary self-asserted label that is neither unique nor checked against anything. Two entries may carry the same name, and a name may impersonate a well-known project. A reader who keys on the bold name rather than the address is trusting something this realm does not attest. Stating that in the output is the only available mitigation: the entries are immutable, and name uniqueness is deliberately NOT enforced because first-come uniqueness on a permissionless immutable registry would let an attacker burn every valuable name permanently.

func TransferOwnership

crossing Action
1func TransferOwnership(cur realm, contractAddr, newOwner address) string
source

TransferOwnership NOMINATES a new owner for a registry entry; the nominee must AcceptOwnership to take control (two-step — re-audit). Passing "" clears a pending nomination.

Types 1

type ContractEntry

struct
1type ContractEntry struct {
2	Address      address
3	Owner        address // current manager (accepted)
4	PendingOwner address // nominated, not yet accepted; empty if none
5	Name         string
6	Deprecated   bool
7	Successor    address // address of the upgraded contract, empty if current
8}
source

ContractEntry represents a registered contract and its upgrade status.

An entry's Address is ALWAYS the address that called Register — a contract can only register itself. That call is the proof of control: nobody can claim an address they don't command, so a Deprecate redirect on an entry always originates from whoever genuinely controlled the contract. Entries are permanent by design: migration history is what consumers rely on, so it must not be erasable (and a delete would reopen re-registration squatting).

Ownership is two-step (re-audit 2026-09-02): Register/Transfer only NOMINATE an owner; the nominee must AcceptOwnership. Until then the entry is owned by the contract itself, so nobody's address can be attached as "owner" without their consent.

Imports 4

  • chain stdlib
  • chain/runtime/unsafe stdlib
  • strconv stdlib
  • strings stdlib

Source Files 3