Cleanup
This commit is contained in:
@@ -10,7 +10,7 @@ use cosmwasm_std::{
|
||||
};
|
||||
use mixnet_contract::IdentityKey;
|
||||
|
||||
pub const NUM_VESTING_PERIODS: u64 = 8;
|
||||
pub const NUM_VESTING_PERIODS: usize = 8;
|
||||
pub const VESTING_PERIOD: u64 = 3 * 30 * 86400;
|
||||
pub const ADMIN_ADDRESS: &str = "admin";
|
||||
|
||||
@@ -55,7 +55,7 @@ pub fn execute(
|
||||
}
|
||||
}
|
||||
|
||||
fn try_withdraw_vested_coins(
|
||||
pub fn try_withdraw_vested_coins(
|
||||
amount: Coin,
|
||||
env: Env,
|
||||
info: MessageInfo,
|
||||
@@ -63,7 +63,7 @@ fn try_withdraw_vested_coins(
|
||||
) -> Result<Response, ContractError> {
|
||||
let address = info.sender;
|
||||
if let Some(account) = get_account(deps.storage, &address) {
|
||||
let spendable_coins = account.spendable_coins(None, &env, deps.storage);
|
||||
let spendable_coins = account.spendable_coins(None, &env, deps.storage)?;
|
||||
if amount.amount < spendable_coins.amount {
|
||||
if let Some(balance) = get_account_balance(deps.storage, &address) {
|
||||
let new_balance = balance.u128().saturating_sub(amount.amount.u128());
|
||||
@@ -194,15 +194,14 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result<QueryResponse, Contr
|
||||
)?),
|
||||
QueryMsg::GetStartTime {
|
||||
vesting_account_address,
|
||||
} => to_binary(&try_get_start_time(vesting_account_address, env, deps)?),
|
||||
} => to_binary(&try_get_start_time(vesting_account_address, deps)?),
|
||||
QueryMsg::GetEndTime {
|
||||
vesting_account_address,
|
||||
} => to_binary(&try_get_end_time(vesting_account_address, env, deps)?),
|
||||
} => to_binary(&try_get_end_time(vesting_account_address, deps)?),
|
||||
QueryMsg::GetOriginalVesting {
|
||||
vesting_account_address,
|
||||
} => to_binary(&try_get_original_vesting(
|
||||
vesting_account_address,
|
||||
env,
|
||||
deps,
|
||||
)?),
|
||||
QueryMsg::GetDelegatedFree {
|
||||
@@ -228,7 +227,7 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result<QueryResponse, Contr
|
||||
Ok(query_res?)
|
||||
}
|
||||
|
||||
fn try_get_locked_coins(
|
||||
pub fn try_get_locked_coins(
|
||||
vesting_account_address: String,
|
||||
block_time: Option<Timestamp>,
|
||||
env: Env,
|
||||
@@ -236,13 +235,13 @@ fn try_get_locked_coins(
|
||||
) -> Result<Coin, ContractError> {
|
||||
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.storage))
|
||||
Ok(account.locked_coins(block_time, &env, deps.storage)?)
|
||||
} else {
|
||||
Err(ContractError::NoAccountForAddress(vesting_account_address))
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_spendable_coins(
|
||||
pub fn try_get_spendable_coins(
|
||||
vesting_account_address: String,
|
||||
block_time: Option<Timestamp>,
|
||||
env: Env,
|
||||
@@ -250,13 +249,13 @@ fn try_get_spendable_coins(
|
||||
) -> Result<Coin, ContractError> {
|
||||
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.storage))
|
||||
Ok(account.spendable_coins(block_time, &env, deps.storage)?)
|
||||
} else {
|
||||
Err(ContractError::NoAccountForAddress(vesting_account_address))
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_vested_coins(
|
||||
pub fn try_get_vested_coins(
|
||||
vesting_account_address: String,
|
||||
block_time: Option<Timestamp>,
|
||||
env: Env,
|
||||
@@ -264,13 +263,13 @@ fn try_get_vested_coins(
|
||||
) -> Result<Coin, ContractError> {
|
||||
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, &env))
|
||||
Ok(account.get_vested_coins(block_time, &env)?)
|
||||
} else {
|
||||
Err(ContractError::NoAccountForAddress(vesting_account_address))
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_vesting_coins(
|
||||
pub fn try_get_vesting_coins(
|
||||
vesting_account_address: String,
|
||||
block_time: Option<Timestamp>,
|
||||
env: Env,
|
||||
@@ -278,15 +277,14 @@ fn try_get_vesting_coins(
|
||||
) -> Result<Coin, ContractError> {
|
||||
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, &env))
|
||||
Ok(account.get_vesting_coins(block_time, &env)?)
|
||||
} else {
|
||||
Err(ContractError::NoAccountForAddress(vesting_account_address))
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_start_time(
|
||||
pub 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)?;
|
||||
@@ -297,9 +295,8 @@ fn try_get_start_time(
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_end_time(
|
||||
pub 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)?;
|
||||
@@ -310,9 +307,8 @@ fn try_get_end_time(
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_original_vesting(
|
||||
pub 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)?;
|
||||
@@ -323,7 +319,7 @@ fn try_get_original_vesting(
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_delegated_free(
|
||||
pub fn try_get_delegated_free(
|
||||
block_time: Option<Timestamp>,
|
||||
vesting_account_address: String,
|
||||
env: Env,
|
||||
@@ -337,7 +333,7 @@ fn try_get_delegated_free(
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_delegated_vesting(
|
||||
pub fn try_get_delegated_vesting(
|
||||
block_time: Option<Timestamp>,
|
||||
vesting_account_address: String,
|
||||
env: Env,
|
||||
|
||||
@@ -11,10 +11,14 @@ pub enum ContractError {
|
||||
NotAdmin(String),
|
||||
#[error("Balance not found for existing account ({0}), this is a bug")]
|
||||
NoBalanceForAddress(String),
|
||||
#[error("Insufficient balance")]
|
||||
#[error("Insufficient balance for address {0} -> {1}")]
|
||||
InsufficientBalance(String, u128),
|
||||
#[error("Insufficient spendable balance")]
|
||||
#[error("Insufficient spendable balance for address {0} -> {1}")]
|
||||
InsufficientSpendable(String, u128),
|
||||
#[error("Only delegation owner can perform delegation actions, {0} is not the delegation owner")]
|
||||
#[error(
|
||||
"Only delegation owner can perform delegation actions, {0} is not the delegation owner"
|
||||
)]
|
||||
NotDelegate(String),
|
||||
#[error("Total vesting amount is inprobably low -> {0}, this is likely an error")]
|
||||
ImprobableVestingAmount(u128),
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
mod contract;
|
||||
pub mod contract;
|
||||
mod errors;
|
||||
mod messages;
|
||||
pub mod messages;
|
||||
mod storage;
|
||||
mod support;
|
||||
mod vesting;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use crate::vesting::{self, VestingPeriod};
|
||||
use cosmwasm_std::{Addr, Coin, Timestamp};
|
||||
use cosmwasm_std::{Coin, Timestamp};
|
||||
use mixnet_contract::IdentityKey;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
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::{
|
||||
errors::ContractError,
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::storage::{
|
||||
set_account_delegations,
|
||||
};
|
||||
use config::defaults::{DEFAULT_MIXNET_CONTRACT_ADDRESS, DENOM};
|
||||
use cosmwasm_std::{wasm_execute, Addr, Coin, Env, QuerierWrapper, Storage, Timestamp, Uint128};
|
||||
use cosmwasm_std::{wasm_execute, Addr, Coin, Env, Storage, Timestamp, Uint128};
|
||||
use mixnet_contract::ExecuteMsg as MixnetExecuteMsg;
|
||||
use mixnet_contract::IdentityKey;
|
||||
use schemars::JsonSchema;
|
||||
@@ -18,8 +18,12 @@ pub trait VestingAccount {
|
||||
// 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: Option<Timestamp>, env: &Env, storage: &dyn Storage)
|
||||
-> Coin;
|
||||
fn locked_coins(
|
||||
&self,
|
||||
block_time: Option<Timestamp>,
|
||||
env: &Env,
|
||||
storage: &dyn Storage,
|
||||
) -> Result<Coin, ContractError>;
|
||||
|
||||
// Calculates the total spendable balance that can be sent to other accounts.
|
||||
fn spendable_coins(
|
||||
@@ -27,10 +31,18 @@ pub trait VestingAccount {
|
||||
block_time: Option<Timestamp>,
|
||||
env: &Env,
|
||||
storage: &dyn Storage,
|
||||
) -> Coin;
|
||||
) -> Result<Coin, ContractError>;
|
||||
|
||||
fn get_vested_coins(&self, block_time: Option<Timestamp>, env: &Env) -> Coin;
|
||||
fn get_vesting_coins(&self, block_time: Option<Timestamp>, env: &Env) -> Coin;
|
||||
fn get_vested_coins(
|
||||
&self,
|
||||
block_time: Option<Timestamp>,
|
||||
env: &Env,
|
||||
) -> Result<Coin, ContractError>;
|
||||
fn get_vesting_coins(
|
||||
&self,
|
||||
block_time: Option<Timestamp>,
|
||||
env: &Env,
|
||||
) -> Result<Coin, ContractError>;
|
||||
|
||||
fn get_start_time(&self) -> Timestamp;
|
||||
fn get_end_time(&self) -> Timestamp;
|
||||
@@ -135,15 +147,20 @@ impl PeriodicVestingAccount {
|
||||
self.address.clone()
|
||||
}
|
||||
|
||||
pub fn tokens_per_period(&self) -> u128 {
|
||||
// Remainder tokens will be lumped into the last period.
|
||||
self.coin.amount.u128() / NUM_VESTING_PERIODS as u128
|
||||
pub fn tokens_per_period(&self) -> Result<u128, ContractError> {
|
||||
let amount = self.coin.amount.u128();
|
||||
if amount < NUM_VESTING_PERIODS as u128 {
|
||||
Err(ContractError::ImprobableVestingAmount(amount))
|
||||
} else {
|
||||
// Remainder tokens will be lumped into the last period.
|
||||
Ok(amount / NUM_VESTING_PERIODS as u128)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_next_vesting_period(&self, block_time: Timestamp) -> usize {
|
||||
fn get_current_vesting_period(&self, block_time: Timestamp) -> usize {
|
||||
// Returns the index of the next vesting period. Unless the current time is somehow in the past or vesting has not started yet.
|
||||
// In case vesting is over it will always return NUM_VESTING_PERIODS.
|
||||
match self
|
||||
let period = match self
|
||||
.periods
|
||||
.iter()
|
||||
.map(|period| period.start_time)
|
||||
@@ -152,12 +169,10 @@ impl PeriodicVestingAccount {
|
||||
{
|
||||
Ok(u) => u,
|
||||
Err(u) => u,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fn get_current_vesting_period(&self, block_time: Timestamp) -> usize {
|
||||
if self.get_next_vesting_period(block_time) > 0 {
|
||||
self.get_next_vesting_period(block_time) - 1
|
||||
if period > 0 {
|
||||
period - 1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
@@ -308,11 +323,11 @@ impl VestingAccount for PeriodicVestingAccount {
|
||||
block_time: Option<Timestamp>,
|
||||
env: &Env,
|
||||
storage: &dyn Storage,
|
||||
) -> Coin {
|
||||
) -> Result<Coin, ContractError> {
|
||||
// Returns 0 in case of underflow.
|
||||
Coin {
|
||||
Ok(Coin {
|
||||
amount: Uint128(
|
||||
self.get_vesting_coins(block_time, env)
|
||||
self.get_vesting_coins(block_time, env)?
|
||||
.amount
|
||||
.u128()
|
||||
.saturating_sub(
|
||||
@@ -322,7 +337,7 @@ impl VestingAccount for PeriodicVestingAccount {
|
||||
),
|
||||
),
|
||||
denom: DENOM.to_string(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn spendable_coins(
|
||||
@@ -330,46 +345,56 @@ impl VestingAccount for PeriodicVestingAccount {
|
||||
block_time: Option<Timestamp>,
|
||||
env: &Env,
|
||||
storage: &dyn Storage,
|
||||
) -> Coin {
|
||||
Coin {
|
||||
) -> Result<Coin, ContractError> {
|
||||
Ok(Coin {
|
||||
amount: Uint128(
|
||||
self.get_balance(storage)
|
||||
.u128()
|
||||
.saturating_sub(self.locked_coins(block_time, env, storage).amount.u128()),
|
||||
.saturating_sub(self.locked_coins(block_time, env, storage)?.amount.u128()),
|
||||
),
|
||||
denom: DENOM.to_string(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn get_vested_coins(&self, block_time: Option<Timestamp>, env: &Env) -> Coin {
|
||||
fn get_vested_coins(
|
||||
&self,
|
||||
block_time: Option<Timestamp>,
|
||||
env: &Env,
|
||||
) -> Result<Coin, ContractError> {
|
||||
let block_time = block_time.unwrap_or(env.block.time);
|
||||
let period = self.get_current_vesting_period(block_time);
|
||||
|
||||
match period {
|
||||
let amount = match period {
|
||||
// We're in the first period, or the vesting has not started yet.
|
||||
0 => Coin {
|
||||
amount: Uint128(0),
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
// We always have 8 vesting periods, so periods 1-7 are special
|
||||
1..=7 => Coin {
|
||||
amount: Uint128(self.tokens_per_period() * period as u128),
|
||||
amount: Uint128(self.tokens_per_period()? * period as u128),
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
_ => Coin {
|
||||
amount: self.coin.amount,
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
}
|
||||
};
|
||||
Ok(amount)
|
||||
}
|
||||
|
||||
fn get_vesting_coins(&self, block_time: Option<Timestamp>, env: &Env) -> Coin {
|
||||
Coin {
|
||||
fn get_vesting_coins(
|
||||
&self,
|
||||
block_time: Option<Timestamp>,
|
||||
env: &Env,
|
||||
) -> Result<Coin, ContractError> {
|
||||
Ok(Coin {
|
||||
amount: Uint128(
|
||||
self.get_original_vesting().amount.u128()
|
||||
- self.get_vested_coins(block_time, env).amount.u128(),
|
||||
- self.get_vested_coins(block_time, env)?.amount.u128(),
|
||||
),
|
||||
denom: DENOM.to_string(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn get_start_time(&self) -> Timestamp {
|
||||
@@ -411,16 +436,14 @@ fn ge(x: u64, y: u64) -> bool {
|
||||
x >= y
|
||||
}
|
||||
|
||||
pub fn populate_vesting_periods(start_time: u64, n: u64) -> Vec<VestingPeriod> {
|
||||
let mut periods = Vec::new();
|
||||
// There are eight 3 month periods in two years
|
||||
pub fn populate_vesting_periods(start_time: u64, n: usize) -> Vec<VestingPeriod> {
|
||||
let mut periods = Vec::with_capacity(n as usize);
|
||||
for i in 0..n {
|
||||
let period = VestingPeriod {
|
||||
start_time: start_time + i * VESTING_PERIOD,
|
||||
start_time: start_time + i as u64 * VESTING_PERIOD,
|
||||
};
|
||||
periods.push(period);
|
||||
}
|
||||
periods.shrink_to_fit();
|
||||
periods
|
||||
}
|
||||
|
||||
@@ -466,17 +489,13 @@ mod tests {
|
||||
assert_eq!(account.periods.len(), 8);
|
||||
|
||||
let current_period = account.get_current_vesting_period(Timestamp::from_seconds(0));
|
||||
let next_period = account.get_next_vesting_period(Timestamp::from_seconds(0));
|
||||
assert_eq!(0, current_period);
|
||||
assert_eq!(0, next_period);
|
||||
|
||||
let block_time = Timestamp::from_seconds(account.start_time.seconds() + VESTING_PERIOD + 1);
|
||||
let current_period = account.get_current_vesting_period(block_time);
|
||||
let next_period = account.get_next_vesting_period(block_time);
|
||||
assert_eq!(current_period, 1);
|
||||
assert_eq!(next_period, 2);
|
||||
let vested_coins = account.get_vested_coins(Some(block_time), &env);
|
||||
let vesting_coins = account.get_vesting_coins(Some(block_time), &env);
|
||||
let vested_coins = account.get_vested_coins(Some(block_time), &env).unwrap();
|
||||
let vesting_coins = account.get_vesting_coins(Some(block_time), &env).unwrap();
|
||||
assert_eq!(
|
||||
vested_coins.amount,
|
||||
Uint128(account.get_original_vesting().amount.u128() / NUM_VESTING_PERIODS as u128)
|
||||
@@ -492,11 +511,9 @@ mod tests {
|
||||
let block_time =
|
||||
Timestamp::from_seconds(account.start_time.seconds() + 5 * VESTING_PERIOD + 1);
|
||||
let current_period = account.get_current_vesting_period(block_time);
|
||||
let next_period = account.get_next_vesting_period(block_time);
|
||||
assert_eq!(current_period, 5);
|
||||
assert_eq!(next_period, 6);
|
||||
let vested_coins = account.get_vested_coins(Some(block_time), &env);
|
||||
let vesting_coins = account.get_vesting_coins(Some(block_time), &env);
|
||||
let vested_coins = account.get_vested_coins(Some(block_time), &env).unwrap();
|
||||
let vesting_coins = account.get_vesting_coins(Some(block_time), &env).unwrap();
|
||||
assert_eq!(
|
||||
vested_coins.amount,
|
||||
Uint128(5 * account.get_original_vesting().amount.u128() / NUM_VESTING_PERIODS as u128)
|
||||
|
||||
Reference in New Issue
Block a user