// Copyright 2021-2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 use crate::errors::ContractError; use crate::storage; use crate::storage::{account_from_address, BlockTimestampSecs, ACCOUNTS, DELEGATIONS, MIX_DENOM}; use crate::traits::VestingAccount; use crate::vesting::Account; use contracts_common::ContractBuildInformation; use cosmwasm_std::{Coin, Deps, Env, Order, StdResult, Timestamp, Uint128}; use cw_storage_plus::Bound; use mixnet_contract_common::MixId; use vesting_contract_common::{ AccountVestingCoins, AccountsResponse, AllDelegationsResponse, BaseVestingAccountInfo, DelegationTimesResponse, OriginalVestingResponse, Period, PledgeData, VestingCoinsResponse, VestingDelegation, }; /// Get current vesting period for a given [crate::vesting::Account]. pub fn try_get_current_vesting_period( address: &str, deps: Deps<'_>, env: Env, ) -> Result { let account = account_from_address(address, deps.storage, deps.api)?; account.get_current_vesting_period(env.block.time) } /// Loads mixnode bond from vesting contract storage. pub fn try_get_mixnode(address: &str, deps: Deps<'_>) -> Result, ContractError> { let account = account_from_address(address, deps.storage, deps.api)?; account.load_mixnode_pledge(deps.storage) } /// Loads gateway bond from vesting contract storage. pub fn try_get_gateway(address: &str, deps: Deps<'_>) -> Result, ContractError> { let account = account_from_address(address, deps.storage, deps.api)?; account.load_gateway_pledge(deps.storage) } pub fn try_get_account(address: &str, deps: Deps<'_>) -> Result { account_from_address(address, deps.storage, deps.api) } /// Gets build information of this contract. pub fn get_contract_version() -> ContractBuildInformation { // as per docs // env! macro will expand to the value of the named environment variable at // compile time, yielding an expression of type `&'static str` ContractBuildInformation { build_timestamp: env!("VERGEN_BUILD_TIMESTAMP").to_string(), build_version: env!("VERGEN_BUILD_SEMVER").to_string(), commit_sha: option_env!("VERGEN_GIT_SHA").unwrap_or("NONE").to_string(), commit_timestamp: option_env!("VERGEN_GIT_COMMIT_TIMESTAMP") .unwrap_or("NONE") .to_string(), commit_branch: option_env!("VERGEN_GIT_BRANCH") .unwrap_or("NONE") .to_string(), rustc_version: env!("VERGEN_RUSTC_SEMVER").to_string(), } } pub fn try_get_all_accounts( deps: Deps<'_>, start_after: Option, limit: Option, ) -> Result { let limit = limit.unwrap_or(150).min(250) as usize; let start = start_after .map(|raw| deps.api.addr_validate(&raw).map(Bound::exclusive)) .transpose()?; let accounts = ACCOUNTS .range(deps.storage, start, None, Order::Ascending) .take(limit) .map(|res| { res.map(|(_, account)| BaseVestingAccountInfo { account_id: account.storage_key(), owner: account.owner_address, }) }) .collect::>>()?; let start_next_after = accounts.last().map(|acc| acc.owner.clone()); Ok(AccountsResponse { accounts, start_next_after, }) } pub fn try_get_all_accounts_vesting_coins( deps: Deps<'_>, env: Env, start_after: Option, limit: Option, ) -> Result { let limit = limit.unwrap_or(150).min(250) as usize; let start = start_after .map(|raw| deps.api.addr_validate(&raw).map(Bound::exclusive)) .transpose()?; let accounts = ACCOUNTS .range(deps.storage, start, None, Order::Ascending) .take(limit) .map(|res| { res.map(|(_, account)| { account .get_vesting_coins(None, &env, deps.storage) .map(|still_vesting| AccountVestingCoins { account_id: account.storage_key(), owner: account.owner_address, still_vesting, }) }) }) .collect::, _>>>()??; let start_next_after = accounts.last().map(|acc| acc.owner.clone()); Ok(VestingCoinsResponse { accounts, start_next_after, }) } /// Gets currently locked coins, see [crate::traits::VestingAccount::locked_coins] pub fn try_get_locked_coins( vesting_account_address: &str, block_time: Option, env: Env, deps: Deps<'_>, ) -> Result { let account = account_from_address(vesting_account_address, deps.storage, deps.api)?; account.locked_coins(block_time, &env, deps.storage) } /// Returns currently locked coins, see [crate::traits::VestingAccount::spendable_coins] pub fn try_get_spendable_coins( vesting_account_address: &str, block_time: Option, env: Env, deps: Deps<'_>, ) -> Result { let account = account_from_address(vesting_account_address, deps.storage, deps.api)?; account.spendable_coins(block_time, &env, deps.storage) } /// Returns coins that have vested, see [crate::traits::VestingAccount::get_vested_coins] pub fn try_get_vested_coins( vesting_account_address: &str, block_time: Option, env: Env, deps: Deps<'_>, ) -> Result { let account = account_from_address(vesting_account_address, deps.storage, deps.api)?; account.get_vested_coins(block_time, &env, deps.storage) } /// Returns coins that are vesting, see [crate::traits::VestingAccount::get_vesting_coins] pub fn try_get_vesting_coins( vesting_account_address: &str, block_time: Option, env: Env, deps: Deps<'_>, ) -> Result { let account = account_from_address(vesting_account_address, deps.storage, deps.api)?; account.get_vesting_coins(block_time, &env, deps.storage) } /// See [crate::traits::VestingAccount::get_start_time] pub fn try_get_start_time( vesting_account_address: &str, deps: Deps<'_>, ) -> Result { let account = account_from_address(vesting_account_address, deps.storage, deps.api)?; Ok(account.get_start_time()) } /// See [crate::traits::VestingAccount::get_end_time] pub fn try_get_end_time( vesting_account_address: &str, deps: Deps<'_>, ) -> Result { let account = account_from_address(vesting_account_address, deps.storage, deps.api)?; Ok(account.get_end_time()) } /// See [crate::traits::VestingAccount::get_original_vesting] pub fn try_get_original_vesting( vesting_account_address: &str, deps: Deps<'_>, ) -> Result { let account = account_from_address(vesting_account_address, deps.storage, deps.api)?; account.get_original_vesting() } pub fn try_get_historical_vesting_staking_reward( vesting_account_address: &str, deps: Deps<'_>, ) -> Result { let account = account_from_address(vesting_account_address, deps.storage, deps.api)?; account.get_historical_vested_staking_rewards(deps.storage) } pub fn try_get_spendable_vested_coins( vesting_account_address: &str, deps: Deps<'_>, env: Env, ) -> Result { let account = account_from_address(vesting_account_address, deps.storage, deps.api)?; account.spendable_vested_coins(None, &env, deps.storage) } pub fn try_get_spendable_reward_coins( vesting_account_address: &str, deps: Deps<'_>, env: Env, ) -> Result { let account = account_from_address(vesting_account_address, deps.storage, deps.api)?; account.spendable_reward_coins(None, &env, deps.storage) } pub fn try_get_delegated_coins( vesting_account_address: &str, deps: Deps<'_>, ) -> Result { let account = account_from_address(vesting_account_address, deps.storage, deps.api)?; let denom = MIX_DENOM.load(deps.storage)?; let amount = account.total_delegations(deps.storage)?; Ok(Coin { denom, amount }) } pub fn try_get_pledged_coins( vesting_account_address: &str, deps: Deps<'_>, ) -> Result { let account = account_from_address(vesting_account_address, deps.storage, deps.api)?; let denom = MIX_DENOM.load(deps.storage)?; let amount = account.total_pledged(deps.storage)?; Ok(Coin { denom, amount }) } pub fn try_get_staked_coins( vesting_account_address: &str, deps: Deps<'_>, ) -> Result { let account = account_from_address(vesting_account_address, deps.storage, deps.api)?; let denom = MIX_DENOM.load(deps.storage)?; let amount = account.total_staked(deps.storage)?; Ok(Coin { denom, amount }) } pub fn try_get_withdrawn_coins( vesting_account_address: &str, deps: Deps<'_>, ) -> Result { let account = account_from_address(vesting_account_address, deps.storage, deps.api)?; let denom = MIX_DENOM.load(deps.storage)?; let amount = account.load_withdrawn(deps.storage)?; Ok(Coin { denom, amount }) } /// Returns timestamps at which delegations were made pub fn try_get_delegation_times( deps: Deps<'_>, vesting_account_address: &str, mix_id: MixId, ) -> Result { let owner = deps.api.addr_validate(vesting_account_address)?; let account = account_from_address(vesting_account_address, deps.storage, deps.api)?; let delegation_timestamps = storage::load_delegation_timestamps((account.storage_key(), mix_id), deps.storage)?; Ok(DelegationTimesResponse { owner, account_id: account.storage_key(), mix_id, delegation_timestamps, }) } pub fn try_get_all_delegations( deps: Deps<'_>, start_after: Option<(u32, MixId, BlockTimestampSecs)>, limit: Option, ) -> Result { let limit = limit.unwrap_or(100).min(200) as usize; let start = start_after.map(Bound::exclusive); let delegations = DELEGATIONS .range(deps.storage, start, None, Order::Ascending) .map(|kv| { kv.map( |((account_id, mix_id, block_timestamp), amount)| VestingDelegation { account_id, mix_id, block_timestamp, amount, }, ) }) .collect::>>()?; let start_next_after = if delegations.len() < limit { None } else { delegations .last() .map(|delegation| delegation.storage_key()) }; Ok(AllDelegationsResponse { delegations, start_next_after, }) } pub fn try_get_delegation( deps: Deps<'_>, vesting_account_address: &str, mix_id: MixId, block_timestamp_secs: BlockTimestampSecs, ) -> Result { let account = account_from_address(vesting_account_address, deps.storage, deps.api)?; let storage_key = (account.storage_key(), mix_id, block_timestamp_secs); let delegation_amount = DELEGATIONS.load(deps.storage, storage_key)?; Ok(VestingDelegation { account_id: account.storage_key(), mix_id, block_timestamp: block_timestamp_secs, amount: delegation_amount, }) } pub fn try_get_delegation_amount( deps: Deps<'_>, vesting_account_address: &str, mix_id: MixId, ) -> Result { let account = account_from_address(vesting_account_address, deps.storage, deps.api)?; let amount = DELEGATIONS .prefix((account.storage_key(), mix_id)) .range(deps.storage, None, None, Order::Ascending) .map(|kv_res| kv_res.map(|kv| kv.1)) .try_fold(Uint128::zero(), |acc, x_res| x_res.map(|x| x + acc))?; let denom = MIX_DENOM.load(deps.storage)?; Ok(Coin { denom, amount }) }