diff --git a/pop-api/integration-tests/src/lib.rs b/pop-api/integration-tests/src/lib.rs index ea5ccb05a..3ac534cc3 100644 --- a/pop-api/integration-tests/src/lib.rs +++ b/pop-api/integration-tests/src/lib.rs @@ -12,8 +12,8 @@ use scale::{Decode, Encode}; use sp_runtime::{traits::Hash, AccountId32, BuildStorage, DispatchError}; use pop_runtime_devnet::{ - config::assets::TrustBackedAssetsInstance, Assets, Contracts, Runtime, RuntimeOrigin, System, - UNIT, + config::assets::TrustBackedAssetsInstance, Assets, Balances, Contracts, Runtime, RuntimeOrigin, + System, UNIT, }; mod local_fungibles; diff --git a/pop-api/integration-tests/src/local_fungibles.rs b/pop-api/integration-tests/src/local_fungibles.rs index 15a644ad7..2bfea2079 100644 --- a/pop-api/integration-tests/src/local_fungibles.rs +++ b/pop-api/integration-tests/src/local_fungibles.rs @@ -304,6 +304,16 @@ fn total_supply_works() { }); } +#[test] +fn native_fungible_total_supply_works() { + new_test_ext().execute_with(|| { + let _ = env_logger::try_init(); + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + // Tokens in circulation. + assert_eq!(Balances::total_issuance(), total_supply(addr.clone(), 0)); + }); +} + #[test] fn balance_of_works() { new_test_ext().execute_with(|| { diff --git a/pop-api/src/v0/assets/balances.rs b/pop-api/src/v0/assets/balances.rs new file mode 100644 index 000000000..da35d783a --- /dev/null +++ b/pop-api/src/v0/assets/balances.rs @@ -0,0 +1,60 @@ +use crate::{ + constants::BALANCES, + primitives::{AccountId, Balance}, + Result, StatusCode, +}; +use constants::*; +use ink::env::chain_extension::ChainExtensionMethod; + +/// Helper method to build a dispatch call `ChainExtensionMethod` for native balances. +/// +/// Parameters: +/// - 'dispatchable': The index of the module dispatchable functions +fn build_dispatch(dispatchable: u8) -> ChainExtensionMethod<(), (), (), false> { + crate::v0::build_dispatch(BALANCES, dispatchable) +} + +/// Helper method to build a dispatch call `ChainExtensionMethod` for native balances. +/// +/// Parameters: +/// - 'state_query': The index of the runtime state query +fn build_read_state(state_query: u8) -> ChainExtensionMethod<(), (), (), false> { + crate::v0::build_read_state(BALANCES, state_query) +} + +mod constants { + /// - total_issuance + pub const TOTAL_ISSUANCE: u8 = 0; + /// - transfer_keep_alive + pub(super) const TRANSFER_KEEP_ALIVE: u8 = 3; +} + +/// Returns the total supply for a native token +/// +/// # Returns +/// The total supply of the token, or an error if the operation fails. +#[inline] +pub fn total_issuance() -> Result { + build_read_state(TOTAL_ISSUANCE) + .output::, true>() + .handle_error_code::() + .call(&()) +} + +/// Transfers `value` amount of tokens from the caller's account to account `to`, with additional +/// `data` in unspecified format. +/// +/// # Arguments +/// * `to` - The recipient account. +/// * `value` - The number of native tokens to transfer. +/// +/// # Returns +/// Returns `Ok(())` if successful, or an error if the transfer fails. +#[inline] +pub fn transfer_keep_alive(target: AccountId, amount: Balance) -> Result<()> { + build_dispatch(TRANSFER_KEEP_ALIVE) + .input::<(AccountId, Balance)>() + .output::, true>() + .handle_error_code::() + .call(&(target, amount)) +} diff --git a/pop-api/src/v0/assets/fungibles.rs b/pop-api/src/v0/assets/fungibles.rs index 0712a80b4..6280ff7f9 100644 --- a/pop-api/src/v0/assets/fungibles.rs +++ b/pop-api/src/v0/assets/fungibles.rs @@ -1,4 +1,5 @@ use crate::{ + assets::balances, constants::{ASSETS, BALANCES, FUNGIBLES}, primitives::{AccountId, AssetId, Balance}, Result, StatusCode, @@ -74,11 +75,15 @@ mod constants { /// The total supply of the token, or an error if the operation fails. #[inline] pub fn total_supply(id: AssetId) -> Result { - build_read_state(TOTAL_SUPPLY) - .input::() - .output::, true>() - .handle_error_code::() - .call(&(id)) + if id == 0 { + balances::total_issuance() + } else { + build_read_state(TOTAL_SUPPLY) + .input::() + .output::, true>() + .handle_error_code::() + .call(&(id)) + } } /// Returns the account balance for the specified `owner` for a given asset ID. Returns `0` if @@ -130,11 +135,15 @@ pub fn allowance(id: AssetId, owner: AccountId, spender: AccountId) -> Result Result<()> { - build_dispatch(TRANSFER) - .input::<(AssetId, AccountId, Balance)>() - .output::, true>() - .handle_error_code::() - .call(&(id, target, amount)) + if id == 0 { + balances::transfer_keep_alive(target, amount) + } else { + build_dispatch(TRANSFER) + .input::<(AssetId, AccountId, Balance)>() + .output::, true>() + .handle_error_code::() + .call(&(id, target, amount)) + } } /// Transfers `value` tokens on behalf of `from` to account `to` with additional `data` diff --git a/pop-api/src/v0/assets/mod.rs b/pop-api/src/v0/assets/mod.rs index 197db7107..d04ae24ed 100644 --- a/pop-api/src/v0/assets/mod.rs +++ b/pop-api/src/v0/assets/mod.rs @@ -1,2 +1,4 @@ #[cfg(feature = "fungibles")] +mod balances; +#[cfg(feature = "fungibles")] pub mod fungibles;