@@ -29,15 +29,20 @@ declare_id!("metaRK9dUBnrAdZN6uUDKvxBVKW5pyCbPVmLtUZwtBp");
2929pub const SLOTS_PER_10_SECS : u64 = 25 ;
3030pub const THREE_DAYS_IN_SLOTS : u64 = 3 * 24 * 60 * 6 * SLOTS_PER_10_SECS ;
3131
32- // by default, the pass price needs to be 5% higher than the fail price
33- pub const DEFAULT_PASS_THRESHOLD_BPS : u16 = 500 ;
32+ pub const TEN_DAYS_IN_SECONDS : i64 = 10 * 24 * 60 * 60 ;
33+
34+ // by default, the pass price needs to be 3% higher than the fail price
35+ pub const DEFAULT_PASS_THRESHOLD_BPS : u16 = 300 ;
3436
3537// start at 10 SOL ($600 at current prices), decay by ~5 SOL per day
3638pub const DEFAULT_BASE_BURN_LAMPORTS : u64 = 10 * solana_program:: native_token:: LAMPORTS_PER_SOL ;
3739pub const DEFAULT_BURN_DECAY_PER_SLOT_LAMPORTS : u64 = 23_150 ;
3840
3941pub const MAX_BPS : u16 = 10_000 ;
4042
43+ // TWAP can only move by $5 per slot
44+ pub const DEFAULT_MAX_OBSERVATION_CHANGE_PER_UPDATE_LOTS : u64 = 5_000 ;
45+
4146#[ account]
4247pub struct DAO {
4348 // treasury needed even though DAO is PDA for this reason: https://solana.stackexchange.com/questions/7667/a-peculiar-problem-with-cpis
@@ -59,6 +64,7 @@ pub struct DAO {
5964 pub slots_per_proposal : u64 ,
6065 pub market_taker_fee : i64 ,
6166 pub twap_expected_value : u64 ,
67+ pub max_observation_change_per_update_lots : u64 ,
6268}
6369
6470#[ derive( Clone , Copy , AnchorSerialize , AnchorDeserialize , PartialEq , Eq ) ]
@@ -115,7 +121,9 @@ pub mod autocrat_v0 {
115121 dao. burn_decay_per_slot_lamports = DEFAULT_BURN_DECAY_PER_SLOT_LAMPORTS ;
116122 dao. slots_per_proposal = THREE_DAYS_IN_SLOTS ;
117123 dao. market_taker_fee = 0 ;
118- dao. twap_expected_value = 10_000 ; // 1 USDC per META
124+ // 100_000 price lots * quote lot size of 100 = 10_000_000 or $10 per quote lot size of meta, which is 0.1 meta
125+ dao. twap_expected_value = 100_000 ; // $100 USDC per 1 META
126+ dao. max_observation_change_per_update_lots = DEFAULT_MAX_OBSERVATION_CHANGE_PER_UPDATE_LOTS ;
119127
120128 let ( treasury_pubkey, treasury_bump) =
121129 Pubkey :: find_program_address ( & [ dao. key ( ) . as_ref ( ) ] , ctx. program_id ) ;
@@ -145,10 +153,13 @@ pub mod autocrat_v0 {
145153 AutocratError :: InvalidMarket
146154 ) ;
147155
148- // this should also be checked by `openbook_twap`, but why not take the
149- // precaution?
156+ let current_time = Clock :: get ( ) . unwrap ( ) . unix_timestamp as i64 ;
157+
158+ // The market expires a minimum of 7 days after the end of a 3 day proposal.
159+ // Make sure to do final TWAP crank after the proposal period has ended
160+ // and before the market expires, or else! Allows for rent retrieval from openbook
150161 require ! (
151- openbook_pass_market. time_expiry == 0 ,
162+ openbook_pass_market. time_expiry > current_time + TEN_DAYS_IN_SECONDS ,
152163 AutocratError :: InvalidMarket
153164 ) ;
154165 require ! (
@@ -164,7 +175,7 @@ pub mod autocrat_v0 {
164175 AutocratError :: InvalidMarket
165176 ) ;
166177 require ! (
167- openbook_pass_market. base_lot_size == 1_000_000_000 , // minimum tradeable = 1 META
178+ openbook_pass_market. base_lot_size == 100_000_000 , // minimum tradeable = 0. 1 META
168179 AutocratError :: InvalidMarket
169180 ) ;
170181 require ! (
@@ -187,7 +198,7 @@ pub mod autocrat_v0 {
187198 AutocratError :: InvalidMarket
188199 ) ;
189200 require ! (
190- openbook_fail_market. time_expiry == 0 ,
201+ openbook_fail_market. time_expiry > current_time + TEN_DAYS_IN_SECONDS ,
191202 AutocratError :: InvalidMarket
192203 ) ;
193204 require ! (
@@ -203,11 +214,11 @@ pub mod autocrat_v0 {
203214 AutocratError :: InvalidMarket
204215 ) ;
205216 require ! (
206- openbook_fail_market. base_lot_size == 1_000_000_000 ,
217+ openbook_fail_market. base_lot_size == 100_000_000 , // minimum tradeable = 0.1 META
207218 AutocratError :: InvalidMarket
208219 ) ;
209220 require ! (
210- openbook_pass_market . quote_lot_size == 100 ,
221+ openbook_fail_market . quote_lot_size == 100 ,
211222 AutocratError :: InvalidMarket
212223 ) ;
213224 require ! (
@@ -227,6 +238,20 @@ pub mod autocrat_v0 {
227238 openbook_twap_fail_market. twap_oracle. initial_slot + 50 >= clock. slot,
228239 AutocratError :: TWAPMarketTooOld
229240 ) ;
241+ require_eq ! (
242+ openbook_twap_pass_market
243+ . twap_oracle
244+ . max_observation_change_per_update_lots,
245+ dao. max_observation_change_per_update_lots,
246+ AutocratError :: TWAPOracleWrongChangeLots
247+ ) ;
248+ require_eq ! (
249+ openbook_twap_fail_market
250+ . twap_oracle
251+ . max_observation_change_per_update_lots,
252+ dao. max_observation_change_per_update_lots,
253+ AutocratError :: TWAPOracleWrongChangeLots
254+ ) ;
230255 require ! (
231256 openbook_twap_pass_market. twap_oracle. expected_value == dao. twap_expected_value,
232257 AutocratError :: TWAPMarketInvalidExpectedValue
@@ -390,10 +415,7 @@ pub mod autocrat_v0 {
390415 Ok ( ( ) )
391416 }
392417
393- pub fn update_dao (
394- ctx : Context < UpdateDao > ,
395- dao_params : UpdateDaoParams ,
396- ) -> Result < ( ) > {
418+ pub fn update_dao ( ctx : Context < UpdateDao > , dao_params : UpdateDaoParams ) -> Result < ( ) > {
397419 let dao = & mut ctx. accounts . dao ;
398420
399421 if let Some ( pass_threshold_bps) = dao_params. pass_threshold_bps {
@@ -420,6 +442,12 @@ pub mod autocrat_v0 {
420442 dao. twap_expected_value = twap_expected_value;
421443 }
422444
445+ if let Some ( max_observation_change_per_update_lots) =
446+ dao_params. max_observation_change_per_update_lots
447+ {
448+ dao. max_observation_change_per_update_lots = max_observation_change_per_update_lots;
449+ }
450+
423451 Ok ( ( ) )
424452 }
425453}
@@ -514,6 +542,7 @@ pub struct UpdateDaoParams {
514542 pub slots_per_proposal : Option < u64 > ,
515543 pub market_taker_fee : Option < i64 > ,
516544 pub twap_expected_value : Option < u64 > ,
545+ pub max_observation_change_per_update_lots : Option < u64 > ,
517546}
518547
519548#[ derive( Accounts ) ]
@@ -556,6 +585,8 @@ pub enum AutocratError {
556585 InvalidMarket ,
557586 #[ msg( "`TWAPMarket` must have an `initial_slot` within 50 slots of the proposal's `slot_enqueued`" ) ]
558587 TWAPMarketTooOld ,
588+ #[ msg( "`TWAPOracle` has an incorrect max_observation_change_per_update_lots value" ) ]
589+ TWAPOracleWrongChangeLots ,
559590 #[ msg( "`TWAPMarket` has the wrong `expected_value`" ) ]
560591 TWAPMarketInvalidExpectedValue ,
561592 #[ msg( "One of the vaults has an invalid `settlement_authority`" ) ]
0 commit comments