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
54 changes: 48 additions & 6 deletions creator-keys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ pub enum DataKey {
Creator(Address),
FeeConfig,
KeyPrice,
TreasuryAddress,
}

#[derive(Clone)]
Expand All @@ -91,6 +92,19 @@ pub fn assert_positive_amount(amount: i128) {
}
}

/// Reads the key balance (supply) for a creator, returning `0` for unregistered creators.
///
/// Use this helper wherever repeated key balance read logic is needed to keep
/// missing-balance behavior consistent across the contract.
pub fn read_key_balance(env: &Env, creator: &Address) -> u32 {
let key = DataKey::Creator(creator.clone());
env.storage()
.persistent()
.get::<DataKey, CreatorProfile>(&key)
.map(|p| p.supply)
.unwrap_or(0)
}

#[contract]
pub struct CreatorKeysContract;

Expand All @@ -100,6 +114,10 @@ impl CreatorKeysContract {
creator.require_auth();

let key = DataKey::Creator(creator.clone());
if env.storage().persistent().has(&key) {
panic!("creator already registered");
}

let profile = CreatorProfile {
creator,
handle,
Expand Down Expand Up @@ -146,14 +164,18 @@ impl CreatorKeysContract {
/// Read-only view: returns the total key supply for a creator.
///
/// Returns `0` if the creator is not registered, avoiding panics for
/// invalid lookups.
/// invalid lookups. Delegates to the shared [`read_key_balance`] helper.
pub fn get_total_key_supply(env: Env, creator: Address) -> u32 {
read_key_balance(&env, &creator)
}

/// Read-only view: returns whether a creator is registered in the contract.
///
/// Returns `true` if a [`CreatorProfile`] exists for the given address,
/// `false` otherwise. Does not mutate state.
pub fn is_creator_registered(env: Env, creator: Address) -> bool {
let key = DataKey::Creator(creator);
env.storage()
.persistent()
.get::<DataKey, CreatorProfile>(&key)
.map(|p| p.supply)
.unwrap_or(0)
env.storage().persistent().has(&key)
}

pub fn set_fee_config(env: Env, admin: Address, creator_bps: u32, protocol_bps: u32) {
Expand All @@ -176,6 +198,26 @@ impl CreatorKeysContract {
env.storage().persistent().get(&DataKey::FeeConfig)
}

/// Sets the protocol treasury address.
///
/// Only callable by an authorized admin. Stores the treasury address used
/// for protocol fee routing.
pub fn set_treasury_address(env: Env, admin: Address, treasury: Address) {
admin.require_auth();
env.storage()
.persistent()
.set(&DataKey::TreasuryAddress, &treasury);
}

/// Read-only view: returns the current protocol treasury address.
///
/// Returns `None` if no treasury address has been configured.
/// Use this method for indexers and read-only callers that need the current
/// treasury routing target.
pub fn get_treasury_address(env: Env) -> Option<Address> {
env.storage().persistent().get(&DataKey::TreasuryAddress)
}

/// Read-only view: returns the current protocol fee configuration.
///
/// Returns a stable [`ProtocolFeeView`] regardless of whether a fee config has been set.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
{
"generators": {
"address": 2,
"nonce": 0
},
"auth": [
[],
[
[
"CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4",
{
"function": {
"contract_fn": {
"contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"function_name": "set_fee_config",
"args": [
{
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4"
},
{
"u32": 8000
},
{
"u32": 2000
}
]
}
},
"sub_invocations": []
}
]
],
[],
[]
],
"ledger": {
"protocol_version": 22,
"sequence_number": 0,
"timestamp": 0,
"network_id": "0000000000000000000000000000000000000000000000000000000000000000",
"base_reserve": 0,
"min_persistent_entry_ttl": 4096,
"min_temp_entry_ttl": 16,
"max_entry_ttl": 6312000,
"ledger_entries": [
[
{
"contract_data": {
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"key": {
"vec": [
{
"symbol": "FeeConfig"
}
]
},
"durability": "persistent"
}
},
[
{
"last_modified_ledger_seq": 0,
"data": {
"contract_data": {
"ext": "v0",
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"key": {
"vec": [
{
"symbol": "FeeConfig"
}
]
},
"durability": "persistent",
"val": {
"map": [
{
"key": {
"symbol": "creator_bps"
},
"val": {
"u32": 8000
}
},
{
"key": {
"symbol": "protocol_bps"
},
"val": {
"u32": 2000
}
}
]
}
}
},
"ext": "v0"
},
4095
]
],
[
{
"contract_data": {
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"key": "ledger_key_contract_instance",
"durability": "persistent"
}
},
[
{
"last_modified_ledger_seq": 0,
"data": {
"contract_data": {
"ext": "v0",
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"key": "ledger_key_contract_instance",
"durability": "persistent",
"val": {
"contract_instance": {
"executable": {
"wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"storage": null
}
}
}
},
"ext": "v0"
},
4095
]
],
[
{
"contract_data": {
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4",
"key": {
"ledger_key_nonce": {
"nonce": 801925984706572462
}
},
"durability": "temporary"
}
},
[
{
"last_modified_ledger_seq": 0,
"data": {
"contract_data": {
"ext": "v0",
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4",
"key": {
"ledger_key_nonce": {
"nonce": 801925984706572462
}
},
"durability": "temporary",
"val": "void"
}
},
"ext": "v0"
},
6311999
]
],
[
{
"contract_code": {
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
}
},
[
{
"last_modified_ledger_seq": 0,
"data": {
"contract_code": {
"ext": "v0",
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"code": ""
}
},
"ext": "v0"
},
4095
]
]
]
},
"events": []
}
Loading
Loading