@@ -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]
910pub 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]
112117impl 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}
0 commit comments