rotate.gno
2.21 Kb · 57 lines
1// Package rotate is a single-use realm shipped at test-13 genesis whose
2// sole purpose is to swap the gnoland1 sole T1 (`oldT1`) for the test-13
3// sole T1 (`newT1`) after historical replay completes.
4//
5// The proposal-flow rotation pattern (manfred proposes self-withdraw →
6// new-T1 votes + executes) is unworkable at genesis-mode replay because
7// gov/dao exposes no API to discover the latest proposal ID across MsgRun
8// txs — and the post-replay proposal counter depends on how many
9// proposals manfred opened on gnoland1, which we can't determine
10// statically without re-executing the replay. This realm sidesteps the
11// problem entirely: a single genesis-mode MsgCall to Rotate does the
12// transfer through direct memberstore writes, no proposals involved.
13//
14// Phase-1 bootstrap (`transactions/base/bootstrap/govdao_prop1_test13.gno`) wires this package into
15// `dao.UpdateImpl(...AllowedDAOs)` at lock time, so memberstore.Get()
16// works from inside Rotate. Once Rotate runs it self-ejects from
17// AllowedDAOs, leaving the membership-mutation surface back at
18// `gno.land/r/gov/dao/v3/impl` alone.
19//
20// Single-use is enforced by the `runtime.ChainHeight() != 0` gate.
21// Migration txs run with BlockHeight=0 (forced by
22// `gnogenesis fork generate`'s readMigrationTxs), so during genesis
23// replay ChainHeight()==0 and Rotate proceeds; post-genesis any caller
24// gets a panic.
25package rotate
26
27import (
28 "chain/runtime"
29
30 "gno.land/r/gov/dao"
31 "gno.land/r/gov/dao/v3/memberstore"
32)
33
34const (
35 newT1 = address("g1aeddlftlfk27ret5rf750d7w5dume3kcsm8r8m")
36 oldT1 = address("g1manfred47kzduec920z88wfr64ylksmdcedlf5")
37)
38
39func Rotate(cur realm) {
40 if runtime.ChainHeight() != 0 {
41 panic("rotate is genesis-only")
42 }
43
44 ms := memberstore.Get(0, cur)
45 tier, ok := memberstore.GetTier(memberstore.T1)
46 if !ok {
47 panic("T1 tier not found")
48 }
49 if err := ms.SetMember(memberstore.T1, newT1, memberstore.NewMember(tier.InvitationPoints)); err != nil {
50 panic(err.Error())
51 }
52 ms.RemoveMember(oldT1)
53
54 // Pass nil DAO: bootstrap already installed impl.NewGovDAO() into dao.dao;
55 // rotate only narrows AllowedDAOs (removing itself) — DAO ref stays intact.
56 dao.UpdateImpl(cross(cur), dao.NewUpdateRequest(nil, []string{"gno.land/r/gov/dao/v3/impl"}))
57}