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
44 changes: 44 additions & 0 deletions creator-keys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,10 @@ pub mod constants {
pub const PROTOCOL_FEE_RECIPIENT: DataKey = DataKey::ProtocolFeeRecipient;
pub const PROTOCOL_FEE_RECIPIENT_BALANCE: DataKey = DataKey::ProtocolFeeRecipientBalance;

pub fn creator_fee_balance(creator: &Address) -> DataKey {
DataKey::CreatorFeeBalance(creator.clone())
}

pub fn creator(creator: &Address) -> DataKey {
creator_key(creator)
}
Expand All @@ -236,6 +240,7 @@ pub mod constants {
pub const FEE_BPS: &str = "get_creator_fee_bps";
pub const FEE_CONFIG: &str = "get_creator_fee_config";
pub const FEE_RECIPIENT: &str = "get_creator_fee_recipient";
pub const FEE_RECIPIENT_BALANCE: &str = "get_creator_fee_balance";
pub const HOLDER_KEY_COUNT: &str = "get_holder_key_count";
pub const PROFILE: &str = "get_creator";
pub const SUPPLY: &str = "get_creator_supply";
Expand Down Expand Up @@ -339,6 +344,7 @@ pub enum DataKey {
AdminAddress,
ProtocolFeeRecipient,
ProtocolFeeRecipientBalance,
CreatorFeeBalance(Address),
}

#[derive(Clone, Debug, PartialEq)]
Expand Down Expand Up @@ -401,6 +407,28 @@ pub fn read_creator_handle(env: &Env, creator: &Address) -> String {
.unwrap_or_else(|| read_none_string(env))
}

/// Reads accrued creator fee balance for a creator, returning `0` when none is stored.
pub fn read_creator_fee_recipient_balance(env: &Env, creator: &Address) -> i128 {
let key = constants::storage::creator_fee_balance(creator);
env.storage().persistent().get(&key).unwrap_or(0)
}

/// Credits `amount` to the creator fee recipient balance for `creator`.
fn credit_creator_fee_recipient_balance(
env: &Env,
creator: &Address,
amount: i128,
) -> Result<(), ContractError> {
if amount <= 0 {
return Ok(());
}
let key = constants::storage::creator_fee_balance(creator);
let current = read_creator_fee_recipient_balance(env, creator);
let updated = current.checked_add(amount).ok_or(ContractError::Overflow)?;
env.storage().persistent().set(&key, &updated);
Ok(())
}

fn is_valid_handle_byte(byte: u8) -> bool {
byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'_'
}
Expand Down Expand Up @@ -687,6 +715,13 @@ impl CreatorKeysContract {
// Balance key is scoped by (creator, holder) so creator positions cannot collide.
env.storage().persistent().set(&balance_key, &new_balance);

if let Some(config) = read_protocol_fee_config(&env) {
let (creator_fee, _) =
fee::checked_compute_fee_split(price, config.creator_bps, config.protocol_bps)
.ok_or(ContractError::Overflow)?;
credit_creator_fee_recipient_balance(&env, &creator, creator_fee)?;
}

env.events().publish(
events::buy_event_topics(&creator, &buyer),
(profile.supply, payment),
Expand Down Expand Up @@ -870,6 +905,15 @@ impl CreatorKeysContract {
Ok(profile.fee_recipient)
}

/// Read-only view: returns accrued creator fee balance for the creator's fee recipient.
///
/// Fails with [`ContractError::NotRegistered`] if the creator is not registered.
/// Returns `0` when no buy has accrued fees yet.
pub fn get_creator_fee_balance(env: Env, creator: Address) -> Result<i128, ContractError> {
read_registered_creator_profile(&env, &creator)?;
Ok(read_creator_fee_recipient_balance(&env, &creator))
}

/// Read-only view: returns the configured creator fee rate in basis points.
///
/// The returned value is the creator-facing share stored in the current protocol
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,54 @@
4095
]
],
[
{
"contract_data": {
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"key": {
"vec": [
{
"symbol": "CreatorFeeBalance"
},
{
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
}
]
},
"durability": "persistent"
}
},
[
{
"last_modified_ledger_seq": 0,
"data": {
"contract_data": {
"ext": "v0",
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"key": {
"vec": [
{
"symbol": "CreatorFeeBalance"
},
{
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
}
]
},
"durability": "persistent",
"val": {
"i128": {
"hi": 0,
"lo": 500
}
}
}
},
"ext": "v0"
},
4095
]
],
[
{
"contract_data": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,54 @@
4095
]
],
[
{
"contract_data": {
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"key": {
"vec": [
{
"symbol": "CreatorFeeBalance"
},
{
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
}
]
},
"durability": "persistent"
}
},
[
{
"last_modified_ledger_seq": 0,
"data": {
"contract_data": {
"ext": "v0",
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"key": {
"vec": [
{
"symbol": "CreatorFeeBalance"
},
{
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
}
]
},
"durability": "persistent",
"val": {
"i128": {
"hi": 0,
"lo": 50
}
}
}
},
"ext": "v0"
},
4095
]
],
[
{
"contract_data": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,54 @@
4095
]
],
[
{
"contract_data": {
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"key": {
"vec": [
{
"symbol": "CreatorFeeBalance"
},
{
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
}
]
},
"durability": "persistent"
}
},
[
{
"last_modified_ledger_seq": 0,
"data": {
"contract_data": {
"ext": "v0",
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"key": {
"vec": [
{
"symbol": "CreatorFeeBalance"
},
{
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
}
]
},
"durability": "persistent",
"val": {
"i128": {
"hi": 0,
"lo": 900
}
}
}
},
"ext": "v0"
},
4095
]
],
[
{
"contract_data": {
Expand Down
Loading
Loading