//! Test-only NEP-141 token used by Duly test mode on NEAR testnet. //! Anyone can mint: it has no value and is never deployed to mainnet. use near_contract_standards::fungible_token::metadata::{ FungibleTokenMetadata, FungibleTokenMetadataProvider, FT_METADATA_SPEC, }; use near_contract_standards::fungible_token::{ FungibleToken, FungibleTokenCore, FungibleTokenResolver, Balance, }; use near_contract_standards::storage_management::{ StorageBalance, StorageBalanceBounds, StorageManagement, }; use near_sdk::json_types::U128; use near_sdk::{env, near, AccountId, BorshStorageKey, NearToken, PanicOnDefault, PromiseOrValue}; #[derive(BorshStorageKey)] #[near] enum Key { Ft, } #[near(contract_state)] #[derive(PanicOnDefault)] pub struct MockUsdc { token: FungibleToken, } #[near] impl MockUsdc { #[init] pub fn new() -> Self { Self { token: FungibleToken::new(Key::Ft) } } /// Mint test tokens. Registers the account if needed. Capped per call. pub fn mint(&mut self, account_id: AccountId, amount: U128) { assert!(amount.0 <= 1_000_000_000, "mint at most 1000 per call"); if self.token.accounts.get(&account_id).is_none() { self.token.internal_register_account(&account_id); } self.token.internal_deposit(&account_id, amount.0); } /// Register an account for free so test flows need no storage deposit. pub fn register(&mut self, account_id: AccountId) { if self.token.accounts.get(&account_id).is_none() { self.token.internal_register_account(&account_id); } } } #[near] impl FungibleTokenCore for MockUsdc { #[payable] fn ft_transfer(&mut self, receiver_id: AccountId, amount: U128, memo: Option) { self.token.ft_transfer(receiver_id, amount, memo) } #[payable] fn ft_transfer_call( &mut self, receiver_id: AccountId, amount: U128, memo: Option, msg: String, ) -> PromiseOrValue { self.token.ft_transfer_call(receiver_id, amount, memo, msg) } fn ft_total_supply(&self) -> U128 { self.token.ft_total_supply() } fn ft_balance_of(&self, account_id: AccountId) -> U128 { self.token.ft_balance_of(account_id) } } #[near] impl FungibleTokenResolver for MockUsdc { #[private] fn ft_resolve_transfer( &mut self, sender_id: AccountId, receiver_id: AccountId, amount: U128, ) -> U128 { let (used, _burned): (Balance, Balance) = self.token.internal_ft_resolve_transfer(&sender_id, receiver_id, amount); used.into() } } #[near] impl StorageManagement for MockUsdc { #[payable] fn storage_deposit( &mut self, account_id: Option, registration_only: Option, ) -> StorageBalance { self.token.storage_deposit(account_id, registration_only) } #[payable] fn storage_withdraw(&mut self, amount: Option) -> StorageBalance { self.token.storage_withdraw(amount) } #[payable] fn storage_unregister(&mut self, force: Option) -> bool { self.token.storage_unregister(force) } fn storage_balance_bounds(&self) -> StorageBalanceBounds { self.token.storage_balance_bounds() } fn storage_balance_of(&self, account_id: AccountId) -> Option { self.token.storage_balance_of(account_id) } } #[near] impl FungibleTokenMetadataProvider for MockUsdc { fn ft_metadata(&self) -> FungibleTokenMetadata { let _ = env::current_account_id(); FungibleTokenMetadata { spec: FT_METADATA_SPEC.to_string(), name: "Test USDC (no value)".to_string(), symbol: "tUSDC".to_string(), icon: None, reference: None, reference_hash: None, decimals: 6, } } }