Implement some more

This commit is contained in:
Drazen Urch
2021-11-17 09:19:27 +01:00
parent c041f51ba8
commit 5c693f0148
5 changed files with 334 additions and 115 deletions
+195 -54
View File
@@ -1,14 +1,16 @@
use crate::errors::ContractError;
use crate::messages::{ExecuteMsg, InitMsg, QueryMsg};
use crate::vesting::VestingPeriod;
use crate::storage::{get_account, set_account};
use crate::vesting::{DelegationAccount, VestingAccount, VestingPeriod};
use cosmwasm_std::{
entry_point, to_binary, Addr, Coin, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response,
entry_point, to_binary, Coin, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response,
Timestamp,
};
use mixnet_contract::IdentityKey;
pub const NUM_VESTING_PERIODS: u64 = 8;
pub const VESTING_PERIOD: u64 = 3 * 30 * 86400;
pub const ADMIN_ADDRESS: &str = "admin";
/// Instantiate the contract.
///
@@ -17,9 +19,9 @@ pub const VESTING_PERIOD: u64 = 3 * 30 * 86400;
/// `msg` is the contract initialization message, sort of like a constructor call.
#[entry_point]
pub fn instantiate(
deps: DepsMut,
env: Env,
info: MessageInfo,
_deps: DepsMut,
_env: Env,
_info: MessageInfo,
_msg: InitMsg,
) -> Result<Response, ContractError> {
Ok(Response::default())
@@ -34,44 +36,70 @@ pub fn execute(
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
match msg {
ExecuteMsg::DelegateToMixnode { mix_identity } => {
try_delegate_to_mixnode(mix_identity, env, deps)
}
ExecuteMsg::UndelegateFromMixnode { mix_identity } => {
try_undelegate_from_mixnode(mix_identity, env, deps)
}
ExecuteMsg::DelegateToMixnode {
mix_identity,
delegate_addr,
amount,
} => try_delegate_to_mixnode(mix_identity, delegate_addr, amount, info, env, deps),
ExecuteMsg::UndelegateFromMixnode {
mix_identity,
delegate_addr,
} => try_undelegate_from_mixnode(mix_identity, delegate_addr, info, deps),
ExecuteMsg::CreatePeriodicVestingAccount {
address,
coin,
start_time,
periods,
} => try_create_periodic_vesting_account(address, coin, start_time, env, deps),
} => try_create_periodic_vesting_account(address, coin, start_time, info, env, deps),
}
}
fn try_delegate_to_mixnode(
mix_identity: IdentityKey,
delegate_addr: String,
amount: Coin,
info: MessageInfo,
env: Env,
deps: DepsMut,
) -> Result<Response, ContractError> {
unimplemented!()
if info.sender != ADMIN_ADDRESS {
return Err(ContractError::NotAdmin(info.sender.as_str().to_string()));
}
let address = deps.api.addr_validate(&delegate_addr)?;
if let Some(account) = get_account(deps.storage, &address) {
account.try_delegate_to_mixnode(mix_identity, amount, env, deps)?;
}
Ok(Response::default())
}
fn try_undelegate_from_mixnode(
mix_identity: IdentityKey,
env: Env,
delegate_addr: String,
info: MessageInfo,
deps: DepsMut,
) -> Result<Response, ContractError> {
unimplemented!()
if info.sender != ADMIN_ADDRESS {
return Err(ContractError::NotAdmin(info.sender.as_str().to_string()));
}
let address = deps.api.addr_validate(&delegate_addr)?;
if let Some(account) = get_account(deps.storage, &address) {
account.try_undelegate_from_mixnode(mix_identity, deps)?;
}
Ok(Response::default())
}
fn try_create_periodic_vesting_account(
address: Addr,
address: String,
coin: Coin,
start_time: Option<u64>,
info: MessageInfo,
env: Env,
deps: DepsMut,
) -> Result<Response, ContractError> {
let mut deps = deps;
if info.sender != ADMIN_ADDRESS {
return Err(ContractError::NotAdmin(info.sender.as_str().to_string()));
}
let address = deps.api.addr_validate(&address)?;
let start_time = start_time.unwrap_or_else(|| env.block.time.seconds());
let mut periods = Vec::new();
// There are eight 3 month periods in two years
@@ -86,87 +114,200 @@ fn try_create_periodic_vesting_account(
coin,
Timestamp::from_seconds(start_time),
periods,
);
unimplemented!()
&mut deps,
)?;
set_account(deps.storage, account)?;
Ok(Response::default())
}
#[entry_point]
pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result<QueryResponse, ContractError> {
let query_res = match msg {
QueryMsg::LockedCoins { block_time } => {
to_binary(&try_get_locked_coins(block_time, env, deps)?)
}
QueryMsg::SpendableCoins { block_time } => {
to_binary(&try_get_spendable_coins(block_time, env, deps)?)
}
QueryMsg::GetVestedCoins { block_time } => {
to_binary(&try_get_vested_coins(block_time, env, deps)?)
}
QueryMsg::GetVestingCoins { block_time } => {
to_binary(&try_get_vesting_coins(block_time, env, deps)?)
}
QueryMsg::GetStartTime {} => to_binary(&try_get_start_time(env, deps)?),
QueryMsg::GetEndTime {} => to_binary(&try_get_end_time(env, deps)?),
QueryMsg::GetOriginalVesting {} => to_binary(&try_get_original_vesting(env, deps)?),
QueryMsg::GetDelegatedFree {} => to_binary(&try_get_delegated_free(env, deps)?),
QueryMsg::GetDelegatedVesting {} => to_binary(&try_get_delegated_vesting(env, deps)?),
QueryMsg::LockedCoins {
vesting_account_address,
block_time,
} => to_binary(&try_get_locked_coins(
vesting_account_address,
block_time,
env,
deps,
)?),
QueryMsg::SpendableCoins {
vesting_account_address,
block_time,
} => to_binary(&try_get_spendable_coins(
vesting_account_address,
block_time,
env,
deps,
)?),
QueryMsg::GetVestedCoins {
vesting_account_address,
block_time,
} => to_binary(&try_get_vested_coins(
vesting_account_address,
block_time,
env,
deps,
)?),
QueryMsg::GetVestingCoins {
vesting_account_address,
block_time,
} => to_binary(&try_get_vesting_coins(
vesting_account_address,
block_time,
env,
deps,
)?),
QueryMsg::GetStartTime {
vesting_account_address,
} => to_binary(&try_get_start_time(vesting_account_address, env, deps)?),
QueryMsg::GetEndTime {
vesting_account_address,
} => to_binary(&try_get_end_time(vesting_account_address, env, deps)?),
QueryMsg::GetOriginalVesting {
vesting_account_address,
} => to_binary(&try_get_original_vesting(
vesting_account_address,
env,
deps,
)?),
QueryMsg::GetDelegatedFree {
vesting_account_address,
} => to_binary(&try_get_delegated_free(vesting_account_address, env, deps)?),
QueryMsg::GetDelegatedVesting {
vesting_account_address,
} => to_binary(&try_get_delegated_vesting(
vesting_account_address,
env,
deps,
)?),
};
Ok(query_res?)
}
fn try_get_locked_coins(
vesting_account_address: String,
block_time: Option<Timestamp>,
env: Env,
deps: Deps,
) -> Result<Vec<Coin>, ContractError> {
) -> Result<Coin, ContractError> {
let block_time = block_time.unwrap_or(env.block.time);
unimplemented!()
let address = deps.api.addr_validate(&vesting_account_address)?;
if let Some(account) = get_account(deps.storage, &address) {
Ok(account.locked_coins(block_time, env, deps))
} else {
Err(ContractError::NoSuchAccount(vesting_account_address))
}
}
fn try_get_spendable_coins(
vesting_account_address: String,
block_time: Option<Timestamp>,
env: Env,
deps: Deps,
) -> Result<Vec<Coin>, ContractError> {
) -> Result<Coin, ContractError> {
let block_time = block_time.unwrap_or(env.block.time);
unimplemented!()
let address = deps.api.addr_validate(&vesting_account_address)?;
if let Some(account) = get_account(deps.storage, &address) {
Ok(account.spendable_coins(block_time, env, deps))
} else {
Err(ContractError::NoSuchAccount(vesting_account_address))
}
}
fn try_get_vested_coins(
vesting_account_address: String,
block_time: Option<Timestamp>,
env: Env,
deps: Deps,
) -> Result<Vec<Coin>, ContractError> {
) -> Result<Coin, ContractError> {
let block_time = block_time.unwrap_or(env.block.time);
unimplemented!()
let address = deps.api.addr_validate(&vesting_account_address)?;
if let Some(account) = get_account(deps.storage, &address) {
Ok(account.get_vested_coins(block_time))
} else {
Err(ContractError::NoSuchAccount(vesting_account_address))
}
}
fn try_get_vesting_coins(
vesting_account_address: String,
block_time: Option<Timestamp>,
env: Env,
deps: Deps,
) -> Result<Vec<Coin>, ContractError> {
) -> Result<Coin, ContractError> {
let block_time = block_time.unwrap_or(env.block.time);
unimplemented!()
let address = deps.api.addr_validate(&vesting_account_address)?;
if let Some(account) = get_account(deps.storage, &address) {
Ok(account.get_vesting_coins(block_time))
} else {
Err(ContractError::NoSuchAccount(vesting_account_address))
}
}
fn try_get_start_time(env: Env, deps: Deps) -> Result<Option<Timestamp>, ContractError> {
unimplemented!()
fn try_get_start_time(
vesting_account_address: String,
env: Env,
deps: Deps,
) -> Result<Timestamp, ContractError> {
let address = deps.api.addr_validate(&vesting_account_address)?;
if let Some(account) = get_account(deps.storage, &address) {
Ok(account.get_start_time())
} else {
Err(ContractError::NoSuchAccount(vesting_account_address))
}
}
fn try_get_end_time(env: Env, deps: Deps) -> Result<Option<Timestamp>, ContractError> {
unimplemented!()
fn try_get_end_time(
vesting_account_address: String,
env: Env,
deps: Deps,
) -> Result<Timestamp, ContractError> {
let address = deps.api.addr_validate(&vesting_account_address)?;
if let Some(account) = get_account(deps.storage, &address) {
Ok(account.get_end_time())
} else {
Err(ContractError::NoSuchAccount(vesting_account_address))
}
}
fn try_get_original_vesting(env: Env, deps: Deps) -> Result<Vec<Coin>, ContractError> {
unimplemented!()
fn try_get_original_vesting(
vesting_account_address: String,
env: Env,
deps: Deps,
) -> Result<Coin, ContractError> {
let address = deps.api.addr_validate(&vesting_account_address)?;
if let Some(account) = get_account(deps.storage, &address) {
Ok(account.get_original_vesting())
} else {
Err(ContractError::NoSuchAccount(vesting_account_address))
}
}
fn try_get_delegated_free(env: Env, deps: Deps) -> Result<Vec<Coin>, ContractError> {
unimplemented!()
fn try_get_delegated_free(
vesting_account_address: String,
env: Env,
deps: Deps,
) -> Result<Coin, ContractError> {
let address = deps.api.addr_validate(&vesting_account_address)?;
if let Some(account) = get_account(deps.storage, &address) {
Ok(account.get_delegated_free(env, deps))
} else {
Err(ContractError::NoSuchAccount(vesting_account_address))
}
}
fn try_get_delegated_vesting(env: Env, deps: Deps) -> Result<Vec<Coin>, ContractError> {
unimplemented!()
fn try_get_delegated_vesting(
vesting_account_address: String,
env: Env,
deps: Deps,
) -> Result<Coin, ContractError> {
let address = deps.api.addr_validate(&vesting_account_address)?;
if let Some(account) = get_account(deps.storage, &address) {
Ok(account.get_delegated_vesting(env, deps))
} else {
Err(ContractError::NoSuchAccount(vesting_account_address))
}
}
+4
View File
@@ -5,4 +5,8 @@ use thiserror::Error;
pub enum ContractError {
#[error("{0}")]
Std(#[from] StdError),
#[error("Account does not exist - {0}")]
NoSuchAccount(String),
#[error("Only admin can perform this action, {0} is not admin")]
NotAdmin(String),
}
+38 -12
View File
@@ -1,4 +1,4 @@
use crate::vesting::VestingPeriod;
use crate::vesting::{self, VestingPeriod};
use cosmwasm_std::{Addr, Coin, Timestamp};
use mixnet_contract::IdentityKey;
use schemars::JsonSchema;
@@ -8,30 +8,56 @@ use serde::{Deserialize, Serialize};
pub struct InitMsg {}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
DelegateToMixnode {
mix_identity: IdentityKey,
delegate_addr: String,
amount: Coin,
},
UndelegateFromMixnode {
mix_identity: IdentityKey,
delegate_addr: String,
},
CreatePeriodicVestingAccount {
address: Addr,
address: String,
coin: Coin,
start_time: Option<u64>,
periods: Option<Vec<VestingPeriod>>,
},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
LockedCoins { block_time: Option<Timestamp> },
SpendableCoins { block_time: Option<Timestamp> },
GetVestedCoins { block_time: Option<Timestamp> },
GetVestingCoins { block_time: Option<Timestamp> },
GetStartTime,
GetEndTime,
GetOriginalVesting,
GetDelegatedFree,
GetDelegatedVesting,
LockedCoins {
vesting_account_address: String,
block_time: Option<Timestamp>,
},
SpendableCoins {
vesting_account_address: String,
block_time: Option<Timestamp>,
},
GetVestedCoins {
vesting_account_address: String,
block_time: Option<Timestamp>,
},
GetVestingCoins {
vesting_account_address: String,
block_time: Option<Timestamp>,
},
GetStartTime {
vesting_account_address: String,
},
GetEndTime {
vesting_account_address: String,
},
GetOriginalVesting {
vesting_account_address: String,
},
GetDelegatedFree {
vesting_account_address: String,
},
GetDelegatedVesting {
vesting_account_address: String,
},
}
+42 -14
View File
@@ -1,51 +1,65 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::{Order, StdResult, Storage, Uint128};
use cosmwasm_storage::{
bucket, bucket_read, singleton, singleton_read, Bucket, ReadonlyBucket, ReadonlySingleton,
Singleton,
};
use cosmwasm_std::{Addr, StdResult, Storage, Uint128};
use cosmwasm_storage::{bucket, bucket_read, Bucket, ReadonlyBucket};
use mixnet_contract::IdentityKey;
use std::collections::HashMap;
use crate::vesting::{DelegationData, PeriodicVestingAccount};
use crate::{
errors::ContractError,
vesting::{DelegationData, PeriodicVestingAccount},
};
// storage prefixes
// all of them must be unique and presumably not be a prefix of a different one
// keeping them as short as possible is also desirable as they are part of each stored key
// it's not as important for singletons, but is a nice optimisation for buckets
// singletons
// buckets
const PREFIX_ACCOUNTS: &[u8] = b"ac";
const PREFIX_ACCOUNT_DELEGATIONS: &[u8] = b"ad";
const PREFIX_ACCOUNT_BALANCE: &[u8] = b"ab";
// Contract-level stuff
pub fn accounts_mut(storage: &mut dyn Storage) -> Bucket<PeriodicVestingAccount> {
fn accounts_mut(storage: &mut dyn Storage) -> Bucket<PeriodicVestingAccount> {
bucket(storage, PREFIX_ACCOUNTS)
}
pub fn accounts(storage: &dyn Storage) -> ReadonlyBucket<PeriodicVestingAccount> {
fn accounts(storage: &dyn Storage) -> ReadonlyBucket<PeriodicVestingAccount> {
bucket_read(storage, PREFIX_ACCOUNTS)
}
pub fn account_delegations_mut(
fn account_delegations_mut(
storage: &mut dyn Storage,
) -> Bucket<HashMap<IdentityKey, Vec<DelegationData>>> {
bucket(storage, PREFIX_ACCOUNT_DELEGATIONS)
}
pub fn account_delegations(
fn account_delegations(
storage: &dyn Storage,
) -> ReadonlyBucket<HashMap<IdentityKey, Vec<DelegationData>>> {
bucket_read(storage, PREFIX_ACCOUNT_DELEGATIONS)
}
pub fn get_account(storage: &dyn Storage, address: &str) -> Option<PeriodicVestingAccount> {
fn account_balance(storage: &dyn Storage) -> ReadonlyBucket<Uint128> {
bucket_read(storage, PREFIX_ACCOUNT_BALANCE)
}
fn account_balance_mut(storage: &mut dyn Storage) -> Bucket<Uint128> {
bucket(storage, PREFIX_ACCOUNT_BALANCE)
}
pub fn get_account(storage: &dyn Storage, address: &Addr) -> Option<PeriodicVestingAccount> {
// Due to using may_load this should be safe to unwrap
accounts(storage).may_load(address.as_bytes()).unwrap()
}
pub fn set_account(
storage: &mut dyn Storage,
account: PeriodicVestingAccount,
) -> Result<(), ContractError> {
Ok(accounts_mut(storage).save(account.address().as_bytes(), &account)?)
}
pub fn get_account_delegations(
storage: &dyn Storage,
address: &str,
@@ -58,12 +72,26 @@ pub fn get_account_delegations(
pub fn set_account_delegations(
storage: &mut dyn Storage,
address: &str,
address: &Addr,
delegations: HashMap<IdentityKey, Vec<DelegationData>>,
) -> StdResult<()> {
account_delegations_mut(storage).save(address.as_bytes(), &delegations)
}
pub fn get_account_balance(storage: &dyn Storage, address: &Addr) -> Option<Uint128> {
// Due to using may_load this should be safe to unwrap
account_balance(storage)
.may_load(address.as_bytes())
.unwrap()
}
pub fn set_account_balance(
storage: &mut dyn Storage,
address: &Addr,
balance: Uint128,
) -> StdResult<()> {
account_balance_mut(storage).save(address.as_bytes(), &balance)
}
#[cfg(test)]
mod tests {
use super::*;
+55 -35
View File
@@ -1,25 +1,27 @@
use crate::contract::{NUM_VESTING_PERIODS, VESTING_PERIOD};
use crate::errors::ContractError;
use crate::storage::{get_account_delegations, set_account_delegations};
use crate::storage::{
get_account_balance, get_account_delegations, set_account_balance, set_account_delegations,
};
use config::defaults::{DEFAULT_MIXNET_CONTRACT_ADDRESS, DENOM};
use cosmwasm_std::{Addr, Coin, DepsMut, Env, Timestamp, Uint128};
use cosmwasm_std::{Addr, Coin, Deps, DepsMut, Env, Timestamp, Uint128};
use mixnet_contract::ExecuteMsg as MixnetExecuteMsg;
use mixnet_contract::IdentityKey;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
trait VestingAccount {
pub trait VestingAccount {
// locked_coins returns the set of coins that are not spendable (i.e. locked),
// defined as the vesting coins that are not delegated.
//
// To get spendable coins of a vesting account, first the total balance must
// be retrieved and the locked tokens can be subtracted from the total balance.
// Note, the spendable balance can be negative.
fn locked_coins(&self, block_time: Timestamp, env: Env, deps: DepsMut) -> Coin;
fn locked_coins(&self, block_time: Timestamp, env: Env, deps: Deps) -> Coin;
// Calculates the total spendable balance that can be sent to other accounts.
fn spendable_coins(&self, block_time: Timestamp, env: Env, deps: DepsMut) -> Coin;
fn spendable_coins(&self, block_time: Timestamp, env: Env, deps: Deps) -> Coin;
fn get_vested_coins(&self, block_time: Timestamp) -> Coin;
fn get_vesting_coins(&self, block_time: Timestamp) -> Coin;
@@ -28,17 +30,16 @@ trait VestingAccount {
fn get_end_time(&self) -> Timestamp;
fn get_original_vesting(&self) -> Coin;
fn get_delegated_free(&self, env: Env, deps: DepsMut) -> Coin;
fn get_delegated_vesting(&self, env: Env, deps: DepsMut) -> Coin;
fn get_delegated_free(&self, env: Env, deps: Deps) -> Coin;
fn get_delegated_vesting(&self, env: Env, deps: Deps) -> Coin;
}
trait DelegationAccount {
// TODO: Add delegate on behalf messages in the mixnet contract.
// As the vesting account is delegating on behalf of the token holders/vesters
pub trait DelegationAccount {
fn try_delegate_to_mixnode(
&self,
mix_identity: IdentityKey,
amount: Coin,
env: Env,
deps: DepsMut,
) -> Result<(), ContractError>;
@@ -61,7 +62,11 @@ trait DelegationAccount {
) -> Result<(), ContractError>;
// track_undelegation performs internal vesting accounting necessary when a
// vesting account performs an undelegation.
fn track_undelegation(&self, mix_identity: IdentityKey, deps: DepsMut);
fn track_undelegation(
&self,
mix_identity: IdentityKey,
deps: DepsMut,
) -> Result<(), ContractError>;
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
@@ -95,14 +100,21 @@ impl PeriodicVestingAccount {
coin: Coin,
start_time: Timestamp,
periods: Vec<VestingPeriod>,
// TODO: Store coins into contract to keep track of current balance.
) -> Self {
PeriodicVestingAccount {
deps: &mut DepsMut,
) -> Result<Self, ContractError> {
let amount = coin.amount;
let account = PeriodicVestingAccount {
address,
start_time,
periods,
coin,
}
};
set_account_balance(deps.storage, &account.address, amount)?;
Ok(account)
}
pub fn address(&self) -> Addr {
self.address.clone()
}
pub fn tokens_per_period(&self) -> u128 {
@@ -129,12 +141,7 @@ impl PeriodicVestingAccount {
}
}
fn get_delegated_with_op(
&self,
op: &dyn Fn(u64, u64) -> bool,
env: Env,
deps: DepsMut,
) -> Coin {
fn get_delegated_with_op(&self, op: &dyn Fn(u64, u64) -> bool, env: Env, deps: Deps) -> Coin {
let period = self.get_current_vesting_period(env.block.time);
if period == 0 {
return Coin {
@@ -170,8 +177,8 @@ impl PeriodicVestingAccount {
}
}
fn get_balance(&self) -> Coin {
unimplemented!()
fn get_balance(&self, deps: Deps) -> Uint128 {
get_account_balance(deps.storage, &self.address).unwrap_or(Uint128(0))
}
}
@@ -180,15 +187,17 @@ impl DelegationAccount for PeriodicVestingAccount {
&self,
mix_identity: IdentityKey,
coin: Coin,
env: Env,
deps: DepsMut,
) -> Result<(), ContractError> {
let querier = deps.querier;
let msg = MixnetExecuteMsg::DelegateToMixnodeOnBehalf {
mix_identity,
mix_identity: mix_identity.clone(),
delegate_addr: self.address.clone(),
coin,
coin: coin.clone(),
};
querier.query_wasm_smart(DEFAULT_MIXNET_CONTRACT_ADDRESS, &msg)?;
self.track_delegation(env.block.time, mix_identity, coin, deps)?;
Ok(())
}
@@ -199,10 +208,11 @@ impl DelegationAccount for PeriodicVestingAccount {
) -> Result<(), ContractError> {
let querier = deps.querier;
let msg = MixnetExecuteMsg::UnDelegateFromMixnodeOnBehalf {
mix_identity,
mix_identity: mix_identity.clone(),
delegate_addr: self.address.clone(),
};
querier.query_wasm_smart(DEFAULT_MIXNET_CONTRACT_ADDRESS, &msg)?;
self.track_undelegation(mix_identity, deps)?;
Ok(())
}
@@ -220,25 +230,36 @@ impl DelegationAccount for PeriodicVestingAccount {
} else {
HashMap::new()
};
let delegation = delegations.entry(mix_identity).or_insert_with(Vec::new);
let delegation = delegations
.entry(mix_identity)
.or_insert_with(Vec::new);
delegation.push(DelegationData {
amount: delegation_amount.amount,
block_time,
});
set_account_delegations(deps.storage, self.address.as_str(), delegations)?;
set_account_delegations(deps.storage, &self.address, delegations)?;
Ok(())
}
fn track_undelegation(&self, mix_identity: IdentityKey, deps: DepsMut) {
fn track_undelegation(
&self,
mix_identity: IdentityKey,
deps: DepsMut,
) -> Result<(), ContractError> {
// This has to exist in storage at this point.
let mut delegations = get_account_delegations(deps.storage, self.address.as_str()).unwrap();
// Since we're always removing the entire delegation we can just drop the key
delegations.remove(&mix_identity);
Ok(set_account_delegations(
deps.storage,
&self.address,
delegations,
)?)
}
}
impl VestingAccount for PeriodicVestingAccount {
fn locked_coins(&self, block_time: Timestamp, env: Env, deps: DepsMut) -> Coin {
fn locked_coins(&self, block_time: Timestamp, env: Env, deps: Deps) -> Coin {
// Returns 0 in case of underflow.
Coin {
amount: Uint128(
@@ -251,11 +272,10 @@ impl VestingAccount for PeriodicVestingAccount {
}
}
fn spendable_coins(&self, block_time: Timestamp, env: Env, deps: DepsMut) -> Coin {
fn spendable_coins(&self, block_time: Timestamp, env: Env, deps: Deps) -> Coin {
Coin {
amount: Uint128(
self.get_balance()
.amount
self.get_balance(deps)
.u128()
.saturating_sub(self.locked_coins(block_time, env, deps).amount.u128()),
),
@@ -305,11 +325,11 @@ impl VestingAccount for PeriodicVestingAccount {
self.coin.clone()
}
fn get_delegated_free(&self, env: Env, deps: DepsMut) -> Coin {
fn get_delegated_free(&self, env: Env, deps: Deps) -> Coin {
self.get_delegated_with_op(&lt, env, deps)
}
fn get_delegated_vesting(&self, env: Env, deps: DepsMut) -> Coin {
fn get_delegated_vesting(&self, env: Env, deps: Deps) -> Coin {
self.get_delegated_with_op(&ge, env, deps)
}
}