From 0cba7492d679de4616d98efb702ab28ca81f613d Mon Sep 17 00:00:00 2001 From: brozorec <9572072+brozorec@users.noreply.github.com> Date: Wed, 22 Jan 2025 10:18:55 +0100 Subject: [PATCH] add storage bumps --- contracts/token/fungible/src/storage.rs | 45 ++- contracts/token/fungible/src/test.rs | 60 +++- .../test/approve_and_transfer_from.1.json | 8 +- .../test/bump_instance_works.1.json | 76 +++++ .../test_snapshots/test/burn_works.1.json | 6 +- .../extend_balance_ttl_thru_transfer.1.json | 265 ++++++++++++++++++ .../test_snapshots/test/initial_state.1.json | 4 +- .../test_snapshots/test/mint_works.1.json | 6 +- ...r_from_insufficient_allowance_fails.1.json | 4 +- ...transfer_insufficient_balance_fails.1.json | 6 +- .../test_snapshots/test/transfer_works.1.json | 8 +- .../test/update_burns_tokens.1.json | 6 +- .../test/update_mints_tokens.1.json | 6 +- .../update_transfers_between_accounts.1.json | 8 +- ...te_with_insufficient_balance_panics.1.json | 6 +- 15 files changed, 469 insertions(+), 45 deletions(-) create mode 100644 contracts/token/fungible/test_snapshots/test/bump_instance_works.1.json create mode 100644 contracts/token/fungible/test_snapshots/test/extend_balance_ttl_thru_transfer.1.json diff --git a/contracts/token/fungible/src/storage.rs b/contracts/token/fungible/src/storage.rs index e99521a..dd34959 100644 --- a/contracts/token/fungible/src/storage.rs +++ b/contracts/token/fungible/src/storage.rs @@ -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, @@ -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) } @@ -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 diff --git a/contracts/token/fungible/src/test.rs b/contracts/token/fungible/src/test.rs index 5f24da0..ddf8e44 100644 --- a/contracts/token/fungible/src/test.rs +++ b/contracts/token/fungible/src/test.rs @@ -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] @@ -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(); @@ -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(); diff --git a/contracts/token/fungible/test_snapshots/test/approve_and_transfer_from.1.json b/contracts/token/fungible/test_snapshots/test/approve_and_transfer_from.1.json index dd6a58a..ac4611b 100644 --- a/contracts/token/fungible/test_snapshots/test/approve_and_transfer_from.1.json +++ b/contracts/token/fungible/test_snapshots/test/approve_and_transfer_from.1.json @@ -188,7 +188,7 @@ }, "ext": "v0" }, - 4095 + 518400 ] ], [ @@ -236,7 +236,7 @@ }, "ext": "v0" }, - 4095 + 518400 ] ], [ @@ -284,7 +284,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ], [ @@ -371,7 +371,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ] ] diff --git a/contracts/token/fungible/test_snapshots/test/bump_instance_works.1.json b/contracts/token/fungible/test_snapshots/test/bump_instance_works.1.json new file mode 100644 index 0000000..f06aa4a --- /dev/null +++ b/contracts/token/fungible/test_snapshots/test/bump_instance_works.1.json @@ -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": [] +} \ No newline at end of file diff --git a/contracts/token/fungible/test_snapshots/test/burn_works.1.json b/contracts/token/fungible/test_snapshots/test/burn_works.1.json index 8dfe8ed..b14185c 100644 --- a/contracts/token/fungible/test_snapshots/test/burn_works.1.json +++ b/contracts/token/fungible/test_snapshots/test/burn_works.1.json @@ -62,7 +62,7 @@ }, "ext": "v0" }, - 4095 + 518400 ] ], [ @@ -110,7 +110,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ], [ @@ -131,7 +131,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ] ] diff --git a/contracts/token/fungible/test_snapshots/test/extend_balance_ttl_thru_transfer.1.json b/contracts/token/fungible/test_snapshots/test/extend_balance_ttl_thru_transfer.1.json new file mode 100644 index 0000000..6bc2f45 --- /dev/null +++ b/contracts/token/fungible/test_snapshots/test/extend_balance_ttl_thru_transfer.1.json @@ -0,0 +1,265 @@ +{ + "generators": { + "address": 3, + "nonce": 0 + }, + "auth": [ + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "", + "args": [] + } + }, + "sub_invocations": [] + } + ] + ] + ], + "ledger": { + "protocol_version": 22, + "sequence_number": 4095, + "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": "Balance" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "Balance" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + }, + "durability": "persistent", + "val": { + "i128": { + "hi": 0, + "lo": 50 + } + } + } + }, + "ext": "v0" + }, + 522495 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "Balance" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "Balance" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + }, + "durability": "persistent", + "val": { + "i128": { + "hi": 0, + "lo": 50 + } + } + } + }, + "ext": "v0" + }, + 8190 + ] + ], + [ + { + "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": [ + { + "key": { + "vec": [ + { + "symbol": "TotalSupply" + } + ] + }, + "val": { + "i128": { + "hi": 0, + "lo": 100 + } + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 120960 + ] + ], + [ + { + "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" + }, + 6316094 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 120960 + ] + ] + ] + }, + "events": [ + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "transfer" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ], + "data": { + "i128": { + "hi": 0, + "lo": 50 + } + } + } + } + }, + "failed_call": false + } + ] +} \ No newline at end of file diff --git a/contracts/token/fungible/test_snapshots/test/initial_state.1.json b/contracts/token/fungible/test_snapshots/test/initial_state.1.json index 5655749..ebf9274 100644 --- a/contracts/token/fungible/test_snapshots/test/initial_state.1.json +++ b/contracts/token/fungible/test_snapshots/test/initial_state.1.json @@ -46,7 +46,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ], [ @@ -67,7 +67,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ] ] diff --git a/contracts/token/fungible/test_snapshots/test/mint_works.1.json b/contracts/token/fungible/test_snapshots/test/mint_works.1.json index ecf85cf..7cea01f 100644 --- a/contracts/token/fungible/test_snapshots/test/mint_works.1.json +++ b/contracts/token/fungible/test_snapshots/test/mint_works.1.json @@ -62,7 +62,7 @@ }, "ext": "v0" }, - 4095 + 518400 ] ], [ @@ -110,7 +110,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ], [ @@ -131,7 +131,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ] ] diff --git a/contracts/token/fungible/test_snapshots/test/transfer_from_insufficient_allowance_fails.1.json b/contracts/token/fungible/test_snapshots/test/transfer_from_insufficient_allowance_fails.1.json index 4beddba..82d57b8 100644 --- a/contracts/token/fungible/test_snapshots/test/transfer_from_insufficient_allowance_fails.1.json +++ b/contracts/token/fungible/test_snapshots/test/transfer_from_insufficient_allowance_fails.1.json @@ -192,7 +192,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ], [ @@ -279,7 +279,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ] ] diff --git a/contracts/token/fungible/test_snapshots/test/transfer_insufficient_balance_fails.1.json b/contracts/token/fungible/test_snapshots/test/transfer_insufficient_balance_fails.1.json index 92f7aa3..cb2ff0e 100644 --- a/contracts/token/fungible/test_snapshots/test/transfer_insufficient_balance_fails.1.json +++ b/contracts/token/fungible/test_snapshots/test/transfer_insufficient_balance_fails.1.json @@ -61,7 +61,7 @@ }, "ext": "v0" }, - 4095 + 518400 ] ], [ @@ -93,7 +93,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ], [ @@ -147,7 +147,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ] ] diff --git a/contracts/token/fungible/test_snapshots/test/transfer_works.1.json b/contracts/token/fungible/test_snapshots/test/transfer_works.1.json index b41fd52..1e4cce6 100644 --- a/contracts/token/fungible/test_snapshots/test/transfer_works.1.json +++ b/contracts/token/fungible/test_snapshots/test/transfer_works.1.json @@ -76,7 +76,7 @@ }, "ext": "v0" }, - 4095 + 518400 ] ], [ @@ -124,7 +124,7 @@ }, "ext": "v0" }, - 4095 + 518400 ] ], [ @@ -172,7 +172,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ], [ @@ -226,7 +226,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ] ] diff --git a/contracts/token/fungible/test_snapshots/test/update_burns_tokens.1.json b/contracts/token/fungible/test_snapshots/test/update_burns_tokens.1.json index 8dfe8ed..b14185c 100644 --- a/contracts/token/fungible/test_snapshots/test/update_burns_tokens.1.json +++ b/contracts/token/fungible/test_snapshots/test/update_burns_tokens.1.json @@ -62,7 +62,7 @@ }, "ext": "v0" }, - 4095 + 518400 ] ], [ @@ -110,7 +110,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ], [ @@ -131,7 +131,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ] ] diff --git a/contracts/token/fungible/test_snapshots/test/update_mints_tokens.1.json b/contracts/token/fungible/test_snapshots/test/update_mints_tokens.1.json index ecf85cf..7cea01f 100644 --- a/contracts/token/fungible/test_snapshots/test/update_mints_tokens.1.json +++ b/contracts/token/fungible/test_snapshots/test/update_mints_tokens.1.json @@ -62,7 +62,7 @@ }, "ext": "v0" }, - 4095 + 518400 ] ], [ @@ -110,7 +110,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ], [ @@ -131,7 +131,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ] ] diff --git a/contracts/token/fungible/test_snapshots/test/update_transfers_between_accounts.1.json b/contracts/token/fungible/test_snapshots/test/update_transfers_between_accounts.1.json index 56d2e5b..9096897 100644 --- a/contracts/token/fungible/test_snapshots/test/update_transfers_between_accounts.1.json +++ b/contracts/token/fungible/test_snapshots/test/update_transfers_between_accounts.1.json @@ -62,7 +62,7 @@ }, "ext": "v0" }, - 4095 + 518400 ] ], [ @@ -110,7 +110,7 @@ }, "ext": "v0" }, - 4095 + 518400 ] ], [ @@ -158,7 +158,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ], [ @@ -179,7 +179,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ] ] diff --git a/contracts/token/fungible/test_snapshots/test/update_with_insufficient_balance_panics.1.json b/contracts/token/fungible/test_snapshots/test/update_with_insufficient_balance_panics.1.json index 3ba92a0..80dc3da 100644 --- a/contracts/token/fungible/test_snapshots/test/update_with_insufficient_balance_panics.1.json +++ b/contracts/token/fungible/test_snapshots/test/update_with_insufficient_balance_panics.1.json @@ -61,7 +61,7 @@ }, "ext": "v0" }, - 4095 + 518400 ] ], [ @@ -93,7 +93,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ], [ @@ -114,7 +114,7 @@ }, "ext": "v0" }, - 4095 + 120960 ] ] ]