You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Resolve the instance storage archival issue in the `multisig_governance` contract to prevent in-flight proposal data loss and guarantee finalization.
5
+
6
+
---
7
+
8
+
## 1. Storage Class Strategy
9
+
The `multisig_governance` contract stores all configuration state (admin address, target contract, version, proposal count) and in-flight proposal data (`PendingTransfer` structure under `KEY_PENDING`) in **Instance Storage**.
10
+
11
+
In Soroban, instance storage has a specific Time-To-Live (TTL) that is checked and decremented on every ledger close. If instance storage is not accessed or explicitly bumped for a duration exceeding its TTL, it gets archived by the host. Once archived, any contract execution that tries to read or write instance storage (including admin verification via `read_admin`, loading target contract, or voting/approving) will fail.
12
+
13
+
To prevent this:
14
+
- We introduce a centralized helper function `bump_instance_ttl` that calls `env.storage().instance().extend_ttl(...)` using pre-calculated safe bounds.
15
+
- This helper is integrated across all state-modifying entrypoints (write paths) and all read-only views (read paths). By executing a TTL extension on every contract invocation, we ensure that as long as there is active interest (either querying or writing), the contract state is kept alive automatically.
16
+
17
+
---
18
+
19
+
## 2. TTL Rationale & Parameters
20
+
21
+
The Soroban SDK functions require two parameters for TTL management:
22
+
1.`threshold`: The minimum number of ledgers remaining before a bump is triggered.
23
+
2.`bump_to`: The target ledger lifetime to extend to if the threshold is breached.
24
+
25
+
We define these as:
26
+
```rust
27
+
constINSTANCE_TTL_THRESHOLD:u32=17280; // ~1 day (assuming 5-second ledgers)
28
+
constINSTANCE_TTL_BUMP:u32=518400; // ~30 days (assuming 5-second ledgers)
29
+
```
30
+
31
+
### Rationale
32
+
-**Quorum / Timelock Lifetime**: A proposal must remain pending for a minimum timelock delay of 24 hours (`MIN_TIMELOCK_SECONDS = 86_400`) and expires after a maximum of 7 days (`PROPOSAL_TTL_SECONDS = 604_800`).
33
+
-**Safety Window**: To prevent a proposal from being archived while in-flight (waiting for the timelock to expire or gathering approvals), the instance storage TTL must comfortably exceed the maximum potential proposal lifetime (7 days + 1 day delay = 8 days).
34
+
-**Threshold (1 Day)**: Setting the threshold to 17,280 ledgers (~1 day) ensures that any interaction within a day of potential expiry triggers the extension.
35
+
-**Bump (30 Days)**: Setting the bump to 518,400 ledgers (~30 days) guarantees that the contract instance remains active for a full month on any interaction. This safely accommodates the 7-day proposal TTL + timelock and provides a significant safety margin.
36
+
37
+
---
38
+
39
+
## 3. Integration Points
40
+
The `bump_instance_ttl` helper is called in the following functions:
41
+
-`initialize`: Bumps TTL immediately upon contract creation.
42
+
-`version`: Bumps TTL on read.
43
+
-`upgrade`: Bumps TTL before upgrading contract code.
44
+
-`propose_admin_transfer`: Extends TTL on proposal creation.
45
+
-`approve_transfer`: Extends TTL on approval/voting.
46
+
-`finalize_admin_transfer`: Extends TTL before finalization.
47
+
-`cancel_admin_transfer`: Extends TTL on cancellation.
48
+
-`emergency_cancel_proposal`: Extends TTL on emergency actions.
49
+
-`expire_proposal`: Extends TTL when marking a proposal as expired.
50
+
- All view functions (`get_target`, `get_pending_transfer`, `get_pending`, `has_pending_transfer`, `get_approval_count`, `get_timelock_remaining`) and the private `read_admin` helper.
51
+
52
+
---
53
+
54
+
## 4. Verification Test
55
+
In `test.rs`, we added the integration test `test_proposal_ttl_extension_keeps_proposal_active_and_finalizable`.
56
+
This test simulates the full lifecycle of a multi-sig admin transfer proposal:
57
+
1. Propose transfer with a 24-hour timelock delay.
58
+
2. Approve from the first signer.
59
+
3. Advance the ledger sequence number by `100,000` blocks (~5.8 days) and timestamp by `200,000` seconds. This simulates a long period of inactivity during the voting window.
60
+
4. Approve from the second signer (this reads and modifies instance storage successfully, showing it was not archived).
61
+
5. Advance beyond the 24-hour timelock.
62
+
6. Finalize the proposal successfully.
63
+
64
+
This test demonstrates that the governance instance storage remains active, finalizeable, and resilient to ledger sequence advancement.
0 commit comments