This document covers the LockedAllocation struct used in register_creator, the
constraints on unlock_ledger, and what happens to bonding curve supply while keys
are locked.
pub struct LockedAllocation {
pub amount: u32,
pub unlock_ledger: u32,
pub claimed: bool,
}| Field | Type | Unit | Constraints | Description |
|---|---|---|---|---|
amount |
u32 |
keys (whole units) | > 0 |
Number of keys to lock for the creator at registration. |
unlock_ledger |
u32 |
Soroban ledger sequence number | Strictly > current ledger sequence at registration time |
The earliest ledger at which claim_locked_allocation may be called. |
claimed |
bool |
— | Read-only after storage; always false at registration |
Tracks whether the locked allocation has been claimed. Set to true by claim_locked_allocation. |
amountmust be> 0. Passing0is rejected at registration time.unlock_ledgermust be strictly greater than the ledger sequence number at the momentregister_creatoris called. Passing a value equal to or less than the current ledger returnsContractError::AllocationLocked.claimedmust befalseat registration. If alreadytruethe allocation is silently treated as already consumed.
register_creator accepts the allocation as the third parameter, wrapped in Option:
client.register_creator(
&creator,
&handle,
&Some(LockedAllocation {
amount: 100,
unlock_ledger: current_ledger + 500,
claimed: false,
}),
&None, // max_supply (optional)
);Passing &None skips locked allocation entirely.
When a LockedAllocation is included, the contract immediately adds amount to the
creator's bonding curve supply at registration time. The locked keys count as if they
were already bought, which means:
get_total_key_supply(creator)returnsamountright after registration, before any external buyer has purchased a key.get_buy_quoteandget_sell_quotecompute fees against the same fixed key price (KEY_PRICE) regardless of the locked allocation — the flat price model is supply-independent, so the locked keys do not change the price per key.- The creator's own wallet is not credited with a key balance by locking. The balance
entry is only written when
claim_locked_allocationis called after the ledger constraint is satisfied.
Implication for price: Because the current model uses a flat (constant) bonding curve, locking 100 keys does not raise or lower the unit price. If the contract is upgraded to a supply-sensitive curve in the future, a locked allocation would push the starting price up by the locked supply.
The unlock_ledger field is compared against env.ledger().sequence() at registration:
if unlock_ledger <= current_ledger_at_registration {
return Err(ContractError::AllocationLocked);
}
This means:
- Setting
unlock_ledgerto the current ledger number itself is rejected. - Callers must always pass a value at least one ledger sequence ahead of the time of
the
register_creatorcall. - There is no maximum value enforced. Very large values (e.g.,
u32::MAX) are accepted, locking the allocation indefinitely until that ledger is reached.
Once env.ledger().sequence() >= unlock_ledger, the creator may call
claim_locked_allocation(creator):
- The contract sets
claimed = truein storage so the allocation cannot be claimed a second time (ContractError::AlreadyClaimedis returned on a duplicate call). - The creator's key balance is credited with
amountkeys. - The supply in the creator profile is not changed again — it was already counted at registration.
Setup:
- Current ledger sequence:
1000 KEY_PRICE = 500- Fee config:
creator_bps = 9000,protocol_bps = 1000 - Locked allocation:
amount = 100,unlock_ledger = 1500
At registration (ledger 1000):
get_total_key_supply(creator) → 100 // locked keys counted immediately
get_key_balance(creator, creator) → 0 // creator wallet not credited yet
get_buy_quote(creator).price → 500 // flat price unchanged
Between ledger 1000 and 1499:
claim_locked_allocation(creator) → Err(ContractError::AllocationLocked)
At ledger 1500 or later:
claim_locked_allocation(creator) → Ok(())
get_key_balance(creator, creator) → 100 // creator now holds the keys
get_total_key_supply(creator) → 100 // supply unchanged (already counted)
After a buyer purchases one key (supply becomes 101):
get_buy_quote(creator).price → 500 // flat price model: supply has no effect on price