near_contract_standards/storage_management/mod.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
use near_sdk::{ext_contract, near, AccountId, NearToken};
#[near(serializers=[borsh, json])]
pub struct StorageBalance {
pub total: NearToken,
pub available: NearToken,
}
#[near(serializers=[borsh, json])]
pub struct StorageBalanceBounds {
pub min: NearToken,
pub max: Option<NearToken>,
}
/// Ensures that when fungible token storage grows by collections adding entries,
/// the storage is be paid by the caller. This ensures that storage cannot grow to a point
/// that the FT contract runs out of Ⓝ.
/// Takes name of the Contract struct, the inner field for the token and optional method name to
/// call when the account was closed.
///
/// # Examples
///
/// ```
/// use near_sdk::{near, PanicOnDefault, AccountId, NearToken, log};
/// use near_sdk::collections::LazyOption;
/// use near_sdk::json_types::U128;
/// use near_contract_standards::fungible_token::FungibleToken;
/// use near_contract_standards::storage_management::{
/// StorageBalance, StorageBalanceBounds, StorageManagement,
/// };
/// use near_contract_standards::fungible_token::metadata::FungibleTokenMetadata;
///
/// #[near(contract_state)]
/// #[derive(PanicOnDefault)]
/// pub struct Contract {
/// token: FungibleToken,
/// metadata: LazyOption<FungibleTokenMetadata>,
/// }
///
/// #[near]
/// impl StorageManagement for Contract {
/// #[payable]
/// fn storage_deposit(
/// &mut self,
/// account_id: Option<AccountId>,
/// registration_only: Option<bool>,
/// ) -> StorageBalance {
/// self.token.storage_deposit(account_id, registration_only)
/// }
///
/// #[payable]
/// fn storage_withdraw(&mut self, amount: Option<NearToken>) -> StorageBalance {
/// self.token.storage_withdraw(amount)
/// }
///
/// #[payable]
/// fn storage_unregister(&mut self, force: Option<bool>) -> bool {
/// #[allow(unused_variables)]
/// if let Some((account_id, balance)) = self.token.internal_storage_unregister(force) {
/// log!("Closed @{} with {}", account_id, balance);
/// true
/// } else {
/// false
/// }
/// }
///
/// fn storage_balance_bounds(&self) -> StorageBalanceBounds {
/// self.token.storage_balance_bounds()
/// }
///
/// fn storage_balance_of(&self, account_id: AccountId) -> Option<StorageBalance> {
/// self.token.storage_balance_of(account_id)
/// }
/// }
///
/// ```
///
#[ext_contract(ext_storage_management)]
pub trait StorageManagement {
// if `registration_only=true` MUST refund above the minimum balance if the account didn't exist and
// refund full deposit if the account exists.
fn storage_deposit(
&mut self,
account_id: Option<AccountId>,
registration_only: Option<bool>,
) -> StorageBalance;
/// Withdraw specified amount of available Ⓝ for predecessor account.
///
/// This method is safe to call. It MUST NOT remove data.
///
/// `amount` is sent as a string representing an unsigned 128-bit integer. If
/// omitted, contract MUST refund full `available` balance. If `amount` exceeds
/// predecessor account's available balance, contract MUST panic.
///
/// If predecessor account not registered, contract MUST panic.
///
/// MUST require exactly 1 yoctoNEAR attached balance to prevent restricted
/// function-call access-key call (UX wallet security)
///
/// Returns the StorageBalance structure showing updated balances.
fn storage_withdraw(&mut self, amount: Option<NearToken>) -> StorageBalance;
/// Unregisters the predecessor account and returns the storage NEAR deposit back.
///
/// If the predecessor account is not registered, the function MUST return `false` without panic.
///
/// If `force=true` the function SHOULD ignore account balances (burn them) and close the account.
/// Otherwise, MUST panic if caller has a positive registered balance (eg token holdings) or
/// the contract doesn't support force deregistration.
/// MUST require exactly 1 yoctoNEAR attached balance to prevent restricted function-call access-key call
/// (UX wallet security)
/// Returns `true` iff the account was unregistered.
/// Returns `false` iff account was not registered before.
fn storage_unregister(&mut self, force: Option<bool>) -> bool;
fn storage_balance_bounds(&self) -> StorageBalanceBounds;
fn storage_balance_of(&self, account_id: AccountId) -> Option<StorageBalance>;
}