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
48 changes: 44 additions & 4 deletions creator-keys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,37 @@ pub mod fee {
/// Basis points per 100% (10000 = 100%).
pub const BPS_MAX: u32 = 10_000;

/// Maximum protocol share when configuring fees via [`assert_valid_fee_bps`].
///
/// Caps the on-chain configured protocol take at 50% so fee settings stay within
/// expected economic bounds before they affect market logic.
pub const PROTOCOL_BPS_MAX: u32 = 5_000;

#[derive(Clone)]
#[contracttype]
pub struct FeeConfig {
pub creator_bps: u32,
pub protocol_bps: u32,
}

/// Validates creator and protocol basis points for storage and fee-setting entrypoints.
///
/// Requires `creator_bps + protocol_bps == BPS_MAX` and `protocol_bps <= PROTOCOL_BPS_MAX`.
pub fn assert_valid_fee_bps(creator_bps: u32, protocol_bps: u32) {
let Some(sum) = creator_bps.checked_add(protocol_bps) else {
panic!("creator_bps + protocol_bps overflow");
};
if sum != BPS_MAX {
panic!("creator_bps + protocol_bps must equal 10000");
}
if protocol_bps > PROTOCOL_BPS_MAX {
panic!(
"protocol_bps exceeds maximum allowed ({} bps)",
PROTOCOL_BPS_MAX
);
}
}

/// Computes the fee split for a given total amount.
///
/// Returns `(creator_amount, protocol_amount)`. Remainder from integer division
Expand All @@ -34,6 +58,7 @@ pub mod fee {
pub enum DataKey {
Creator(Address),
FeeConfig,
KeyPrice,
}

#[derive(Clone)]
Expand Down Expand Up @@ -63,9 +88,18 @@ impl CreatorKeysContract {
env.events().publish((symbol_short!("register"),), key);
}

pub fn buy_key(env: Env, creator: Address, buyer: Address) -> u32 {
pub fn buy_key(env: Env, creator: Address, buyer: Address, payment: i128) -> u32 {
buyer.require_auth();

let price: i128 = env
.storage()
.persistent()
.get(&DataKey::KeyPrice)
.unwrap_or_else(|| panic!("key price not set"));
if payment < price {
panic!("insufficient payment");
}

let key = DataKey::Creator(creator.clone());
let mut profile: CreatorProfile = env
.storage()
Expand All @@ -88,16 +122,22 @@ impl CreatorKeysContract {

pub fn set_fee_config(env: Env, admin: Address, creator_bps: u32, protocol_bps: u32) {
admin.require_auth();
if creator_bps + protocol_bps != fee::BPS_MAX {
panic!("creator_bps + protocol_bps must equal 10000");
}
fee::assert_valid_fee_bps(creator_bps, protocol_bps);
let config = fee::FeeConfig {
creator_bps,
protocol_bps,
};
env.storage().persistent().set(&DataKey::FeeConfig, &config);
}

pub fn set_key_price(env: Env, admin: Address, price: i128) {
admin.require_auth();
if price <= 0 {
panic!("key price must be positive");
}
env.storage().persistent().set(&DataKey::KeyPrice, &price);
}

pub fn get_fee_config(env: Env) -> Option<fee::FeeConfig> {
env.storage().persistent().get(&DataKey::FeeConfig)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
{
"generators": {
"address": 4,
"nonce": 0
},
"auth": [
[],
[
[
"CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4",
{
"function": {
"contract_fn": {
"contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"function_name": "set_key_price",
"args": [
{
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4"
},
{
"i128": {
"hi": 0,
"lo": 100
}
}
]
}
},
"sub_invocations": []
}
]
],
[
[
"CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M",
{
"function": {
"contract_fn": {
"contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"function_name": "register_creator",
"args": [
{
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
},
{
"string": "alice"
}
]
}
},
"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": "Creator"
},
{
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
}
]
},
"durability": "persistent"
}
},
[
{
"last_modified_ledger_seq": 0,
"data": {
"contract_data": {
"ext": "v0",
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"key": {
"vec": [
{
"symbol": "Creator"
},
{
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
}
]
},
"durability": "persistent",
"val": {
"map": [
{
"key": {
"symbol": "creator"
},
"val": {
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
}
},
{
"key": {
"symbol": "handle"
},
"val": {
"string": "alice"
}
},
{
"key": {
"symbol": "supply"
},
"val": {
"u32": 0
}
}
]
}
}
},
"ext": "v0"
},
4095
]
],
[
{
"contract_data": {
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"key": {
"vec": [
{
"symbol": "KeyPrice"
}
]
},
"durability": "persistent"
}
},
[
{
"last_modified_ledger_seq": 0,
"data": {
"contract_data": {
"ext": "v0",
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"key": {
"vec": [
{
"symbol": "KeyPrice"
}
]
},
"durability": "persistent",
"val": {
"i128": {
"hi": 0,
"lo": 100
}
}
}
},
"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_data": {
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M",
"key": {
"ledger_key_nonce": {
"nonce": 5541220902715666415
}
},
"durability": "temporary"
}
},
[
{
"last_modified_ledger_seq": 0,
"data": {
"contract_data": {
"ext": "v0",
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M",
"key": {
"ledger_key_nonce": {
"nonce": 5541220902715666415
}
},
"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