Cosmic Bull

Realm on pearl-1

upgrade_registry

gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/upgrade_registry

realmpipeline-applicationupgrade-tracking

RenderedSourceCall builderState

curated

Records successive versions of a logical component and which is current. GitHub-pipeline application #3.

Identity

Import pathgno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/upgrade_registry
Kindrealm (/r/)
Chainpearl-1
Namespaceg1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3
Realm addressg1g453tcmapqn6hj9zlydfz3mt3vxh8gq5vwv8sg derived, never confirmed against the realm

Provenance

chain-attested
Deployed at height602,876
Deploy transaction532be90ab90521b0d6d4b3f983ede9dd315c8975cf30ad5c8984837f4d57e34d look it up on the RPC
Deployerg1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3
Gas used23,191,456
Storage17,492 bytes, deposit 1749200ugnot
Files on chaingnomod.toml upgrade_registry.gno
Deployed bytesupgrade_registry.gno — 13,940 bytes
sha256ff13c79b34e90d96910a0003207d7981737d32c0557f15beb5e730b4b4c87810

Do not take the hash above on trust. $download returns the bytes pearl-1 is actually running; this command fetches them and prints their digest, which should equal the one in the table:

curl -sS 'https://pearl.testnets.gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/upgrade_registry$download&file=upgrade_registry.gno' | shasum -a 256

Expected: ff13c79b34e90d96910a0003207d7981737d32c0557f15beb5e730b4b4c87810 — 13,940 bytes. This was checked for all 21 packages while building this site's architecture record; every one matched. Use curl: pearl's edge answers Python's default user-agent with HTTP 403.

API

chain-derived 8 exported functions, 1 type.

Every function below deep-links to gnoweb's call builder, which generates a ready-to-run gnokey maketx call for it:

AcceptOwnershipDeprecateGetInfoGetMigrationChainGetOwnerContractsRegisterRenderTransferOwnership

Overview

This package carries no package doc comment on chain, so there is nothing for vm/qdoc to return and gnoweb's $help Overview is empty. Deployed bytes are immutable, so this cannot be repaired in place — see catalog/DISCOVERY_APIDOCS.md §2.4.

Imports

Constants and variables

const (
	MaxNameLen  = 64
	MaxChainLen = 50 // GetMigrationChain traversal/output bound (marked when hit)

	// Render bounds (re-audit): rendering is paginated and the per-row
	// "latest" annotation walks a bounded number of hops, so an
	// attacker-built long chain cannot blow up the realm page.
	MaxRenderEntries = 100
	RenderLatestHops = 10
)

Types

type ContractEntry

type ContractEntry struct {
	Address      address
	Owner        address // current manager (accepted)
	PendingOwner address // nominated, not yet accepted; empty if none
	Name         string
	Deprecated   bool
	Successor    address // address of the upgraded contract, empty if current
}

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.

Exported fieldTypeDoc
Addressaddress
Owneraddresscurrent manager (accepted)
PendingOwneraddressnominated, not yet accepted; empty if none
Namestring
Deprecatedbool
Successoraddressaddress of the upgraded contract, empty if current

Functions

AcceptOwnership

func AcceptOwnership(cur realm, contractAddr address) string

Crossing function. Callable from a transaction via MsgCall, and from another realm as AcceptOwnership(cross(cur), ...).

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

Deprecate

func Deprecate(cur realm, contractAddr, successorAddr address) string

Crossing function. Callable from a transaction via MsgCall, and from another realm as Deprecate(cross(cur), ...).

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.

GetInfo

func GetInfo(contractAddr address) string

GetInfo returns a one-line summary for a contract.

GetMigrationChain

func GetMigrationChain(contractAddr address) string

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).

GetOwnerContracts

func GetOwnerContracts(owner address) string

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

Register

func Register(cur realm, name string, owner address) string

Crossing function. Callable from a transaction via MsgCall, and from another realm as Register(cross(cur), ...).

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.

Render

func Render(path string) string

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

TransferOwnership

func TransferOwnership(cur realm, contractAddr, newOwner address) string

Crossing function. Callable from a transaction via MsgCall, and from another realm as TransferOwnership(cross(cur), ...).

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.


Doc text is reproduced as vm/qdoc returns it. The node markdown-escapes doc comments, so a bracket or angle bracket may carry a backslash the committed source does not have. The source itself is at source and in this repository.

Dependencies

chain-attested
Importschain/runtime/unsafe, strconv, strings
First-party dependenciesnone
Used bynone

Known limitations

curated

The manifest records no limitation for this package. That is an absence of a recorded caveat, not a proof that none exists — the deployment record below is the fuller account, and it always carries its own "what was NOT verified live" section.

Source and records

Source filepearl/r/upgrade_registry/upgrade_registry.gno at commit 6a510c665a53 in the project repository (not public — the digest command above is the check that needs no repository)
Matches the deployed bytesyes — byte-identical
Upstream repositoryhttps://github.com/SillyZir/upgrade_registry
Deployed from commit2d5a74870b08d70ff8e56e6e1efbace1803dd3bd
Recordscatalog/applications.md#upgrade_registry
pearl/DEPLOYMENT.md