Skip to content

Commit

Permalink
add storage bumps
Browse files Browse the repository at this point in the history
  • Loading branch information
brozorec committed Jan 22, 2025
1 parent 2ab43d0 commit c3c10db
Show file tree
Hide file tree
Showing 15 changed files with 469 additions and 45 deletions.
45 changes: 37 additions & 8 deletions contracts/token/fungible/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,50 @@ use soroban_sdk::{contracttype, panic_with_error, Address, Env};

use crate::fungible::{emit_approve, emit_transfer, FungibleTokenError};

// Same values as in Stellar Asset Contract (SAC) implementation:
// https://github.com/stellar/rs-soroban-env/blob/main/soroban-env-host/src/builtin_contracts/stellar_asset_contract/storage_types.rs
pub(crate) const DAY_IN_LEDGERS: u32 = 17280;

pub(crate) const INSTANCE_EXTEND_AMOUNT: u32 = 7 * DAY_IN_LEDGERS;
pub(crate) const INSTANCE_TTL_THRESHOLD: u32 = INSTANCE_EXTEND_AMOUNT - DAY_IN_LEDGERS;

pub(crate) const BALANCE_EXTEND_AMOUNT: u32 = 30 * DAY_IN_LEDGERS;
pub(crate) const BALANCE_TTL_THRESHOLD: u32 = BALANCE_EXTEND_AMOUNT - DAY_IN_LEDGERS;

/// Storage key that maps to [`AllowanceData`]
#[contracttype]
struct AllowanceKey {
owner: Address,
spender: Address,
pub struct AllowanceKey {
pub owner: Address,
pub spender: Address,
}

/// Contains the amount of tokens for which an allowance is granted and the
/// ledger number at which this allowance expires.
/// Storage container for the amount of tokens for which an allowance is granted
/// and the ledger number at which this allowance expires.
#[contracttype]
pub struct AllowanceData {
pub value: i128,
pub live_until_ledger: u32,
}

/// Storage keys for the data associated with `FungibleToken`
#[contracttype]
enum StorageKey {
pub enum StorageKey {
TotalSupply,
Balance(Address),
Allowance(AllowanceKey),
}

/// Extends the Time-to-Live (TTL) value of the instance storage entry.
///
/// # Arguments
///
/// * `e` - Access to the Soroban environment.
/// * `ttl_threshold` - The TTL threshold below which the entry can be extended.
/// * `extend_amount` - The new TTL value.
pub fn bump_instance(e: &Env, ttl_threshold: u32, extend_amount: u32) {
e.storage().instance().extend_ttl(ttl_threshold, extend_amount);
}

// ################## QUERY STATE ##################

/// Returns the total amount of tokens in circulation. If no supply is recorded,
Expand All @@ -32,6 +55,7 @@ enum StorageKey {
///
/// * `e` - Access to the Soroban environment.
pub fn total_supply(e: &Env) -> i128 {
bump_instance(e, INSTANCE_TTL_THRESHOLD, INSTANCE_EXTEND_AMOUNT);
e.storage().instance().get(&StorageKey::TotalSupply).unwrap_or(0)
}

Expand All @@ -43,8 +67,13 @@ pub fn total_supply(e: &Env) -> i128 {
/// * `e` - Access to the Soroban environment.
/// * `account` - The address for which the balance is being queried.
pub fn balance(e: &Env, account: &Address) -> i128 {
// TODO: extend persistent?
e.storage().persistent().get(&StorageKey::Balance(account.clone())).unwrap_or(0)
let key = StorageKey::Balance(account.clone());
if let Some(balance) = e.storage().persistent().get::<_, i128>(&key) {
e.storage().persistent().extend_ttl(&key, BALANCE_TTL_THRESHOLD, BALANCE_EXTEND_AMOUNT);
balance
} else {
0
}
}

/// Returns the amount of tokens a `spender` is allowed to spend on behalf of an
Expand Down
60 changes: 57 additions & 3 deletions contracts/token/fungible/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ extern crate std;

use soroban_sdk::{
contract, symbol_short,
testutils::{Address as _, Events, Ledger},
testutils::{
storage::{Instance, Persistent},
Address as _, Events, Ledger,
},
vec, Address, Env, IntoVal,
};

use crate::storage::{
allowance, approve, balance, burn, mint, set_allowance, spend_allowance, total_supply,
transfer, transfer_from, update,
allowance, approve, balance, bump_instance, burn, mint, set_allowance, spend_allowance,
total_supply, transfer, transfer_from, update, StorageKey, BALANCE_EXTEND_AMOUNT,
};

#[contract]
Expand All @@ -27,6 +30,34 @@ fn initial_state() {
});
}

#[test]
fn bump_instance_works() {
let e = Env::default();

e.ledger().with_mut(|l| {
// Minimum TTL for persistent entries - new persistent (and instance)
// entries will have this TTL when created.
l.min_persistent_entry_ttl = 500;
});

let address = e.register(MockContract, ());

e.as_contract(&address, || {
let ttl = e.storage().instance().get_ttl();
// Note, that TTL doesn't include the current ledger, but when entry
// is created the current ledger is counted towards the number of
// ledgers specified by `min_persistent_entry_ttl`, thus
// the TTL is 1 ledger less than the respective setting.
assert_eq!(ttl, 499);

let current = e.ledger().sequence();
e.ledger().set_sequence_number(current + ttl);

bump_instance(&e, 400, 500);
assert_eq!(e.storage().instance().get_ttl(), 500);
});
}

#[test]
fn mint_works() {
let e = Env::default();
Expand Down Expand Up @@ -191,6 +222,29 @@ fn transfer_works() {
});
}

#[test]
fn extend_balance_ttl_thru_transfer() {
let e = Env::default();
e.mock_all_auths();
let address = e.register(MockContract, ());
let from = Address::generate(&e);
let recipient = Address::generate(&e);

e.as_contract(&address, || {
mint(&e, &from, 100);

let key = StorageKey::Balance(from.clone());

let ttl = e.storage().persistent().get_ttl(&key);
e.ledger().with_mut(|l| {
l.sequence_number += ttl;
});
transfer(&e, &from, &recipient, 50);
let ttl = e.storage().persistent().get_ttl(&key);
assert_eq!(ttl, BALANCE_EXTEND_AMOUNT);
});
}

#[test]
fn approve_and_transfer_from() {
let e = Env::default();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@
},
"ext": "v0"
},
4095
518400
]
],
[
Expand Down Expand Up @@ -236,7 +236,7 @@
},
"ext": "v0"
},
4095
518400
]
],
[
Expand Down Expand Up @@ -284,7 +284,7 @@
},
"ext": "v0"
},
4095
120960
]
],
[
Expand Down Expand Up @@ -371,7 +371,7 @@
},
"ext": "v0"
},
4095
120960
]
]
]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{
"generators": {
"address": 1,
"nonce": 0
},
"auth": [
[],
[]
],
"ledger": {
"protocol_version": 22,
"sequence_number": 499,
"timestamp": 0,
"network_id": "0000000000000000000000000000000000000000000000000000000000000000",
"base_reserve": 0,
"min_persistent_entry_ttl": 500,
"min_temp_entry_ttl": 16,
"max_entry_ttl": 6312000,
"ledger_entries": [
[
{
"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"
},
999
]
],
[
{
"contract_code": {
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
}
},
[
{
"last_modified_ledger_seq": 0,
"data": {
"contract_code": {
"ext": "v0",
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"code": ""
}
},
"ext": "v0"
},
999
]
]
]
},
"events": []
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
},
"ext": "v0"
},
4095
518400
]
],
[
Expand Down Expand Up @@ -110,7 +110,7 @@
},
"ext": "v0"
},
4095
120960
]
],
[
Expand All @@ -131,7 +131,7 @@
},
"ext": "v0"
},
4095
120960
]
]
]
Expand Down
Loading

0 comments on commit c3c10db

Please sign in to comment.