Skip to content

Commit e49940f

Browse files
willemnealclaude
andcommitted
refactor(registry-tansu-manager): use soroban-sdk-tools typed storage
Replace the hand-rolled `DataKey` enum + raw `env.storage().instance()` calls with `#[contractstorage(auto_shorten = true)]` from `soroban-sdk-tools`. The macro generates static one-liner accessors (`Storage::get_tansu`, `Storage::set_executed`, `Storage::has_executed`, …) keyed by auto-shortened symbols, eliminating the `DataKey` enum and the persistent/instance bucket plumbing in `execute`. Behavior, ABI, and tests are unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 7d45513 commit e49940f

2 files changed

Lines changed: 25 additions & 25 deletions

File tree

contracts/registry-tansu-manager/src/lib.rs

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use soroban_sdk::{
44
contract, contractimpl, contracttype, vec, Address, Bytes, BytesN, Env, IntoVal, String,
55
Symbol, Val, Vec,
66
};
7+
use soroban_sdk_tools::{contractstorage, InstanceItem, PersistentMap};
78

89
#[soroban_sdk_tools::scerr]
910
pub enum Error {
@@ -97,12 +98,16 @@ pub struct Proposal {
9798
pub outcome_contracts: Option<Vec<OutcomeContract>>,
9899
}
99100

100-
#[contracttype]
101-
pub enum DataKey {
102-
Tansu,
103-
ProjectKey,
104-
Registry,
105-
Executed(u32),
101+
#[contractstorage(auto_shorten = true)]
102+
pub struct Storage {
103+
/// Tansu DAO contract this manager queries proposals from.
104+
tansu: InstanceItem<Address>,
105+
/// Tansu workspace key this manager represents.
106+
project_key: InstanceItem<Bytes>,
107+
/// Registry contract this manager forwards approved outcomes to.
108+
registry: InstanceItem<Address>,
109+
/// Proposal IDs that have already been executed (replay guard).
110+
executed: PersistentMap<u32, bool>,
106111
}
107112

108113
#[contract]
@@ -111,22 +116,21 @@ pub struct RegistryTansuManager;
111116
#[contractimpl]
112117
impl RegistryTansuManager {
113118
pub fn __constructor(env: Env, tansu: Address, project_key: Bytes, registry: Address) {
114-
let s = env.storage().instance();
115-
s.set(&DataKey::Tansu, &tansu);
116-
s.set(&DataKey::ProjectKey, &project_key);
117-
s.set(&DataKey::Registry, &registry);
119+
Storage::set_tansu(&env, &tansu);
120+
Storage::set_project_key(&env, &project_key);
121+
Storage::set_registry(&env, &registry);
118122
}
119123

120124
pub fn tansu(env: Env) -> Address {
121-
env.storage().instance().get(&DataKey::Tansu).unwrap()
125+
Storage::get_tansu(&env).unwrap()
122126
}
123127

124128
pub fn project_key(env: Env) -> Bytes {
125-
env.storage().instance().get(&DataKey::ProjectKey).unwrap()
129+
Storage::get_project_key(&env).unwrap()
126130
}
127131

128132
pub fn registry(env: Env) -> Address {
129-
env.storage().instance().get(&DataKey::Registry).unwrap()
133+
Storage::get_registry(&env).unwrap()
130134
}
131135

132136
/// Execute a passed Tansu proposal by forwarding its outcome to the registry.
@@ -138,23 +142,21 @@ impl RegistryTansuManager {
138142
/// contract is the direct caller (Soroban contract-auth chains for
139143
/// outgoing invocations; no `authorize_as_current_contract` is needed).
140144
///
141-
/// Replay-protected: a successful `execute` records `DataKey::Executed(id)`
142-
/// permanently; later calls with the same `proposal_id` return
145+
/// Replay-protected: a successful `execute` marks the proposal as
146+
/// executed; later calls with the same `proposal_id` return
143147
/// `AlreadyExecuted`.
144148
///
145149
/// Trust: we look up the proposal in Tansu using the stored `project_key`,
146150
/// so a wrong-project proposal cannot resolve. We do not re-verify
147151
/// `project_key` against any field of the returned proposal — Tansu's
148152
/// storage layout makes that lookup the only path.
149153
pub fn execute(env: Env, proposal_id: u32) -> Result<Val, Error> {
150-
let s = env.storage().persistent();
151-
if s.has(&DataKey::Executed(proposal_id)) {
154+
if Storage::has_executed(&env, &proposal_id) {
152155
return Err(Error::AlreadyExecuted);
153156
}
154-
let inst = env.storage().instance();
155-
let tansu: Address = inst.get(&DataKey::Tansu).unwrap();
156-
let project_key: Bytes = inst.get(&DataKey::ProjectKey).unwrap();
157-
let registry: Address = inst.get(&DataKey::Registry).unwrap();
157+
let tansu = Storage::get_tansu(&env).unwrap();
158+
let project_key = Storage::get_project_key(&env).unwrap();
159+
let registry = Storage::get_registry(&env).unwrap();
158160

159161
let proposal: Proposal = env.invoke_contract(
160162
&tansu,
@@ -177,7 +179,7 @@ impl RegistryTansuManager {
177179
}
178180

179181
let result: Val = env.invoke_contract(&registry, &oc.execute_fn, oc.args);
180-
s.set(&DataKey::Executed(proposal_id), &true);
182+
Storage::set_executed(&env, &proposal_id, &true);
181183
Ok(result)
182184
}
183185
}

contracts/registry-tansu-manager/src/test.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,7 @@ fn setup() -> Setup {
102102

103103
// Patch the manager's stored registry to the real RegistryStub address.
104104
env.as_contract(&manager, || {
105-
env.storage()
106-
.instance()
107-
.set(&crate::DataKey::Registry, &registry);
105+
crate::Storage::set_registry(&env, &registry);
108106
});
109107

110108
let manager_client = RegistryTansuManagerClient::new(&env, &manager);

0 commit comments

Comments
 (0)