Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions creator-keys/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ pub const BLACKLIST_ADDED_EVENT_NAME: Symbol = symbol_short!("blk_add");
/// Event name for a wallet being removed from the admin blacklist.
pub const BLACKLIST_REMOVED_EVENT_NAME: Symbol = symbol_short!("blk_rem");

/// Event name for the protocol-wide buy deadline ledger being set or cleared.
pub const GLOBAL_DEADLINE_SET_EVENT_NAME: Symbol = symbol_short!("dl_set");

/// Event name for creator registration.
pub const REGISTER_EVENT_NAME: Symbol = symbol_short!("register");

Expand Down
66 changes: 66 additions & 0 deletions creator-keys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ pub enum ContractError {
WalletBlacklisted = 37,
SchemaVersionTooOld = 38,
SchemaVersionUnsupported = 39,
DeadlinePassed = 40,
}

pub mod fee {
Expand Down Expand Up @@ -315,6 +316,7 @@ pub mod constants {
pub const CURVE_SLOPE: DataKey = DataKey::CurveSlope;
pub const TREASURY_BALANCE: DataKey = DataKey::TreasuryBalance;
pub const RETENTION_POLICY: DataKey = DataKey::RetentionPolicy;
pub const GLOBAL_DEADLINE_LEDGER: DataKey = DataKey::GlobalDeadlineLedger;

pub fn curve_preset(creator: &Address) -> DataKey {
DataKey::CurvePreset(creator.clone())
Expand Down Expand Up @@ -674,6 +676,9 @@ pub enum DataKey {
Blacklisted(Address),
/// Archive retention policy configuration.
RetentionPolicy,
/// Protocol-wide ledger sequence at (and after) which buys are rejected.
/// Absent means no deadline is configured and buys are never time-gated.
GlobalDeadlineLedger,
}

/// Time-locked key allocation for creator self-vesting.
Expand Down Expand Up @@ -1084,6 +1089,27 @@ fn assert_not_blacklisted(env: &Env, wallet: &Address) -> Result<(), ContractErr
Ok(())
}

/// Reads the protocol-wide buy deadline ledger, if one has been configured.
fn read_global_deadline(env: &Env) -> Option<u32> {
env.storage()
.persistent()
.get::<DataKey, u32>(&constants::storage::GLOBAL_DEADLINE_LEDGER)
}

/// Rejects the call once the configured global deadline ledger has been reached.
///
/// The deadline is exclusive: the last ledger on which a buy is accepted is
/// `deadline - 1`, so a buy submitted *at* the deadline is already too late.
/// With no deadline configured the check is a no-op.
fn assert_before_global_deadline(env: &Env) -> Result<(), ContractError> {
if let Some(deadline) = read_global_deadline(env) {
if env.ledger().sequence() >= deadline {
return Err(ContractError::DeadlinePassed);
}
}
Ok(())
}

fn assert_is_admin(env: &Env, caller: &Address) -> Result<(), ContractError> {
let admin: Address = env
.storage()
Expand Down Expand Up @@ -1800,6 +1826,7 @@ impl CreatorKeysContract {
buyer.require_auth();
assert_not_paused(&env)?;
assert_not_blacklisted(&env, &buyer)?;
assert_before_global_deadline(&env)?;

if payment <= 0 {
return Err(ContractError::NotPositiveAmount);
Expand Down Expand Up @@ -2367,6 +2394,45 @@ impl CreatorKeysContract {
is_paused(&env)
}

/// Sets the protocol-wide deadline ledger after which buys are rejected.
///
/// Only the protocol admin may call this. The deadline is exclusive: buys
/// are accepted while `ledger < deadline_ledger` and rejected with
/// [`ContractError::DeadlinePassed`] from `deadline_ledger` onwards. Passing
/// `None` clears the deadline and reopens buying indefinitely.
///
/// Emits a `dl_set` event carrying the admin and the new deadline.
pub fn set_global_deadline(
env: Env,
admin: Address,
deadline_ledger: Option<u32>,
) -> Result<(), ContractError> {
admin.require_auth();
assert_is_admin(&env, &admin)?;

match deadline_ledger {
Some(deadline) => env
.storage()
.persistent()
.set(&constants::storage::GLOBAL_DEADLINE_LEDGER, &deadline),
None => env
.storage()
.persistent()
.remove(&constants::storage::GLOBAL_DEADLINE_LEDGER),
}

env.events().publish(
(events::GLOBAL_DEADLINE_SET_EVENT_NAME, admin),
deadline_ledger,
);
Ok(())
}

/// Read-only view: returns the configured global deadline ledger, if any.
pub fn get_global_deadline(env: Env) -> Option<u32> {
read_global_deadline(&env)
}

/// Blocks a wallet from buying, selling, or registering as a creator.
///
/// Only the protocol admin may call this. Emits a `blacklist` event.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"void",
"void",
"void",
"void",
"void"
]
}
Expand Down Expand Up @@ -178,7 +179,52 @@
},
"ext": "v0"
},
4095
6311520
]
],
[
{
"contract_data": {
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"key": {
"vec": [
{
"symbol": "CreatorTtlLiveUntil"
},
{
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
}
]
},
"durability": "persistent"
}
},
[
{
"last_modified_ledger_seq": 0,
"data": {
"contract_data": {
"ext": "v0",
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"key": {
"vec": [
{
"symbol": "CreatorTtlLiveUntil"
},
{
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
}
]
},
"durability": "persistent",
"val": {
"u32": 6311520
}
}
},
"ext": "v0"
},
6311520
]
],
[
Expand Down Expand Up @@ -223,7 +269,7 @@
},
"ext": "v0"
},
4095
6311520
]
],
[
Expand Down Expand Up @@ -265,7 +311,7 @@
},
"ext": "v0"
},
4095
6311520
]
],
[
Expand Down
Loading
Loading