Rework vesting contract storage (#1061)
* Rework storage * Handle may_load failures * Set ADMIN on init * Use strings for storage keys * Add GetAccount * Move amount to msg * Use iterators everywhere * mock test properly * Configure mixnet contract on init * Updated Cargo.lock
This commit is contained in:
Generated
+8
-8
@@ -1002,9 +1002,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cosmwasm-crypto"
|
||||
version = "1.0.0-beta3"
|
||||
version = "1.0.0-beta4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a380b87642204557629c9b72988c47b55fbfe6d474960adba56b22331504956a"
|
||||
checksum = "f903ebbabc0d4880dbc76148efb8be8fc29fa4bf294c440c3d70da1c8bcafff7"
|
||||
dependencies = [
|
||||
"digest 0.9.0",
|
||||
"ed25519-zebra",
|
||||
@@ -1015,18 +1015,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cosmwasm-derive"
|
||||
version = "1.0.0-beta3"
|
||||
version = "1.0.0-beta4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "866713b2fe13f23038c7d8824c3059d1f28dd94685fb406d1533c4eeeefeefae"
|
||||
checksum = "832bebef577ecb394603de8e2bf0de429b74aa364e17dec18e15ce37e71b0cae"
|
||||
dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cosmwasm-std"
|
||||
version = "1.0.0-beta3"
|
||||
version = "1.0.0-beta4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8dbb9939b31441dfa9af3ec9740c8a24d585688401eff1b6b386abb7ad0d10a8"
|
||||
checksum = "6238c45840cc9de5a39f0f619e3a4f7c38c5d2c6ac9e3e4d72751ee045e6d7da"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"cosmwasm-crypto",
|
||||
@@ -5819,9 +5819,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde-json-wasm"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50eef3672ec8fa45f3457fd423ba131117786784a895548021976117c1ded449"
|
||||
checksum = "042ac496d97e5885149d34139bad1d617192770d7eb8f1866da2317ff4501853"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
@@ -83,6 +83,7 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
|
||||
let req = VestingExecuteMsg::BondGateway {
|
||||
gateway,
|
||||
owner_signature: owner_signature.to_string(),
|
||||
amount: pledge,
|
||||
};
|
||||
self.client
|
||||
.execute(
|
||||
@@ -91,7 +92,7 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
|
||||
&req,
|
||||
fee,
|
||||
"VestingContract::BondGateway",
|
||||
vec![cosmwasm_coin_to_cosmos_coin(pledge)],
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -143,6 +144,7 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
|
||||
let req = VestingExecuteMsg::BondMixnode {
|
||||
mix_node,
|
||||
owner_signature: owner_signature.to_string(),
|
||||
amount: pledge,
|
||||
};
|
||||
self.client
|
||||
.execute(
|
||||
@@ -151,7 +153,7 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
|
||||
&req,
|
||||
fee,
|
||||
"VestingContract::BondMixnode",
|
||||
vec![cosmwasm_coin_to_cosmos_coin(pledge)],
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -239,6 +241,7 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
|
||||
let fee = self.operation_fee(Operation::DelegateToMixnode);
|
||||
let req = VestingExecuteMsg::DelegateToMixnode {
|
||||
mix_identity: mix_identity.into(),
|
||||
amount: amount.clone(),
|
||||
};
|
||||
self.client
|
||||
.execute(
|
||||
@@ -247,7 +250,7 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
|
||||
&req,
|
||||
fee,
|
||||
"VestingContract::DeledateToMixnode",
|
||||
vec![cosmwasm_coin_to_cosmos_coin(amount.to_owned())],
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
Generated
+6
-6
@@ -245,9 +245,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cosmwasm-crypto"
|
||||
version = "1.0.0-beta3"
|
||||
version = "1.0.0-beta4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a380b87642204557629c9b72988c47b55fbfe6d474960adba56b22331504956a"
|
||||
checksum = "f903ebbabc0d4880dbc76148efb8be8fc29fa4bf294c440c3d70da1c8bcafff7"
|
||||
dependencies = [
|
||||
"digest 0.9.0",
|
||||
"ed25519-zebra",
|
||||
@@ -258,9 +258,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cosmwasm-derive"
|
||||
version = "1.0.0-beta3"
|
||||
version = "1.0.0-beta4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "866713b2fe13f23038c7d8824c3059d1f28dd94685fb406d1533c4eeeefeefae"
|
||||
checksum = "832bebef577ecb394603de8e2bf0de429b74aa364e17dec18e15ce37e71b0cae"
|
||||
dependencies = [
|
||||
"syn",
|
||||
]
|
||||
@@ -277,9 +277,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cosmwasm-std"
|
||||
version = "1.0.0-beta3"
|
||||
version = "1.0.0-beta4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8dbb9939b31441dfa9af3ec9740c8a24d585688401eff1b6b386abb7ad0d10a8"
|
||||
checksum = "6238c45840cc9de5a39f0f619e3a4f7c38c5d2c6ac9e3e4d72751ee045e6d7da"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"cosmwasm-crypto",
|
||||
|
||||
@@ -18,9 +18,9 @@ mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-
|
||||
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract" }
|
||||
config = { path = "../../common/config" }
|
||||
|
||||
cosmwasm-std = { version = "1.0.0-beta3"}
|
||||
cosmwasm-std = { version = "1.0.0-beta4"}
|
||||
cw-storage-plus = { version = "0.11.1", features = ["iterator"] }
|
||||
|
||||
schemars = "0.8"
|
||||
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
||||
thiserror = { version = "1.0.23" }
|
||||
serde = { version = "1.0", default-features = false, features = ["derive"] }
|
||||
thiserror = { version = "1.0" }
|
||||
@@ -1,11 +1,11 @@
|
||||
use crate::errors::ContractError;
|
||||
use crate::messages::{ExecuteMsg, InitMsg, QueryMsg};
|
||||
use crate::storage::account_from_address;
|
||||
use crate::messages::{ExecuteMsg, InitMsg, MigrateMsg, QueryMsg};
|
||||
use crate::storage::{account_from_address, ADMIN, MIXNET_CONTRACT_ADDRESS};
|
||||
use crate::traits::{
|
||||
DelegatingAccount, GatewayBondingAccount, MixnodeBondingAccount, VestingAccount,
|
||||
};
|
||||
use crate::vesting::{populate_vesting_periods, Account};
|
||||
use config::defaults::{DEFAULT_MIXNET_CONTRACT_ADDRESS, DENOM};
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{
|
||||
coin, entry_point, to_binary, BankMsg, Coin, Deps, DepsMut, Env, MessageInfo, QueryResponse,
|
||||
Response, Timestamp, Uint128,
|
||||
@@ -22,16 +22,22 @@ use vesting_contract_common::events::{
|
||||
// and duration of a single period is 30 days.
|
||||
pub const NUM_VESTING_PERIODS: usize = 8;
|
||||
pub const VESTING_PERIOD: u64 = 3 * 30 * 86400;
|
||||
// Address of the account set to be contract admin
|
||||
pub const ADMIN_ADDRESS: &str = "admin";
|
||||
|
||||
#[entry_point]
|
||||
pub fn instantiate(
|
||||
_deps: DepsMut,
|
||||
deps: DepsMut,
|
||||
_env: Env,
|
||||
_info: MessageInfo,
|
||||
_msg: InitMsg,
|
||||
info: MessageInfo,
|
||||
msg: InitMsg,
|
||||
) -> Result<Response, ContractError> {
|
||||
// ADMIN is set to the address that instantiated the contract, TODO: make this updatable
|
||||
ADMIN.save(deps.storage, &info.sender.to_string())?;
|
||||
MIXNET_CONTRACT_ADDRESS.save(deps.storage, &msg.mixnet_contract_address)?;
|
||||
Ok(Response::default())
|
||||
}
|
||||
|
||||
#[entry_point]
|
||||
pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||
Ok(Response::default())
|
||||
}
|
||||
|
||||
@@ -43,9 +49,10 @@ pub fn execute(
|
||||
msg: ExecuteMsg,
|
||||
) -> Result<Response, ContractError> {
|
||||
match msg {
|
||||
ExecuteMsg::DelegateToMixnode { mix_identity } => {
|
||||
try_delegate_to_mixnode(mix_identity, info, env, deps)
|
||||
}
|
||||
ExecuteMsg::DelegateToMixnode {
|
||||
mix_identity,
|
||||
amount,
|
||||
} => try_delegate_to_mixnode(mix_identity, amount, info, env, deps),
|
||||
ExecuteMsg::UndelegateFromMixnode { mix_identity } => {
|
||||
try_undelegate_from_mixnode(mix_identity, info, deps)
|
||||
}
|
||||
@@ -72,7 +79,8 @@ pub fn execute(
|
||||
ExecuteMsg::BondMixnode {
|
||||
mix_node,
|
||||
owner_signature,
|
||||
} => try_bond_mixnode(mix_node, owner_signature, info, env, deps),
|
||||
amount,
|
||||
} => try_bond_mixnode(mix_node, owner_signature, amount, info, env, deps),
|
||||
ExecuteMsg::UnbondMixnode {} => try_unbond_mixnode(info, deps),
|
||||
ExecuteMsg::TrackUnbondMixnode { owner, amount } => {
|
||||
try_track_unbond_mixnode(&owner, amount, info, deps)
|
||||
@@ -80,7 +88,8 @@ pub fn execute(
|
||||
ExecuteMsg::BondGateway {
|
||||
gateway,
|
||||
owner_signature,
|
||||
} => try_bond_gateway(gateway, owner_signature, info, env, deps),
|
||||
amount,
|
||||
} => try_bond_gateway(gateway, owner_signature, amount, info, env, deps),
|
||||
ExecuteMsg::UnbondGateway {} => try_unbond_gateway(info, deps),
|
||||
ExecuteMsg::TrackUnbondGateway { owner, amount } => {
|
||||
try_track_unbond_gateway(&owner, amount, info, deps)
|
||||
@@ -175,11 +184,12 @@ fn try_update_staking_address(
|
||||
pub fn try_bond_gateway(
|
||||
gateway: Gateway,
|
||||
owner_signature: String,
|
||||
amount: Coin,
|
||||
info: MessageInfo,
|
||||
env: Env,
|
||||
deps: DepsMut,
|
||||
) -> Result<Response, ContractError> {
|
||||
let pledge = validate_funds(&info.funds)?;
|
||||
let pledge = validate_funds(&[amount])?;
|
||||
let account = account_from_address(info.sender.as_str(), deps.storage, deps.api)?;
|
||||
account.try_bond_gateway(gateway, owner_signature, pledge, &env, deps.storage)
|
||||
}
|
||||
@@ -195,7 +205,7 @@ pub fn try_track_unbond_gateway(
|
||||
info: MessageInfo,
|
||||
deps: DepsMut,
|
||||
) -> Result<Response, ContractError> {
|
||||
if info.sender != DEFAULT_MIXNET_CONTRACT_ADDRESS {
|
||||
if info.sender != MIXNET_CONTRACT_ADDRESS.load(deps.storage)? {
|
||||
return Err(ContractError::NotMixnetContract(info.sender));
|
||||
}
|
||||
let account = account_from_address(owner, deps.storage, deps.api)?;
|
||||
@@ -206,11 +216,12 @@ pub fn try_track_unbond_gateway(
|
||||
pub fn try_bond_mixnode(
|
||||
mix_node: MixNode,
|
||||
owner_signature: String,
|
||||
amount: Coin,
|
||||
info: MessageInfo,
|
||||
env: Env,
|
||||
deps: DepsMut,
|
||||
) -> Result<Response, ContractError> {
|
||||
let pledge = validate_funds(&info.funds)?;
|
||||
let pledge = validate_funds(&[amount])?;
|
||||
let account = account_from_address(info.sender.as_str(), deps.storage, deps.api)?;
|
||||
account.try_bond_mixnode(mix_node, owner_signature, pledge, &env, deps.storage)
|
||||
}
|
||||
@@ -226,7 +237,7 @@ pub fn try_track_unbond_mixnode(
|
||||
info: MessageInfo,
|
||||
deps: DepsMut,
|
||||
) -> Result<Response, ContractError> {
|
||||
if info.sender != DEFAULT_MIXNET_CONTRACT_ADDRESS {
|
||||
if info.sender != MIXNET_CONTRACT_ADDRESS.load(deps.storage)? {
|
||||
return Err(ContractError::NotMixnetContract(info.sender));
|
||||
}
|
||||
let account = account_from_address(owner, deps.storage, deps.api)?;
|
||||
@@ -241,7 +252,7 @@ fn try_track_undelegation(
|
||||
info: MessageInfo,
|
||||
deps: DepsMut,
|
||||
) -> Result<Response, ContractError> {
|
||||
if info.sender != DEFAULT_MIXNET_CONTRACT_ADDRESS {
|
||||
if info.sender != MIXNET_CONTRACT_ADDRESS.load(deps.storage)? {
|
||||
return Err(ContractError::NotMixnetContract(info.sender));
|
||||
}
|
||||
let account = account_from_address(address, deps.storage, deps.api)?;
|
||||
@@ -251,11 +262,12 @@ fn try_track_undelegation(
|
||||
|
||||
fn try_delegate_to_mixnode(
|
||||
mix_identity: IdentityKey,
|
||||
amount: Coin,
|
||||
info: MessageInfo,
|
||||
env: Env,
|
||||
deps: DepsMut,
|
||||
) -> Result<Response, ContractError> {
|
||||
let amount = validate_funds(&info.funds)?;
|
||||
let amount = validate_funds(&[amount])?;
|
||||
let account = account_from_address(info.sender.as_str(), deps.storage, deps.api)?;
|
||||
account.try_delegate_to_mixnode(mix_identity, amount, &env, deps.storage)
|
||||
}
|
||||
@@ -277,9 +289,10 @@ fn try_create_periodic_vesting_account(
|
||||
env: Env,
|
||||
deps: DepsMut,
|
||||
) -> Result<Response, ContractError> {
|
||||
if info.sender != ADMIN_ADDRESS {
|
||||
if info.sender != ADMIN.load(deps.storage)? {
|
||||
return Err(ContractError::NotAdmin(info.sender.as_str().to_string()));
|
||||
}
|
||||
|
||||
let coin = validate_funds(&info.funds)?;
|
||||
let owner_address = deps.api.addr_validate(owner_address)?;
|
||||
let staking_address = if let Some(staking_address) = staking_address {
|
||||
@@ -375,11 +388,17 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result<QueryResponse, Contr
|
||||
env,
|
||||
deps,
|
||||
)?),
|
||||
QueryMsg::GetAccount { address } => to_binary(&try_get_account(&address, deps)?),
|
||||
};
|
||||
|
||||
Ok(query_res?)
|
||||
}
|
||||
|
||||
pub fn try_get_account(address: &str, deps: Deps) -> Result<Option<Account>, ContractError> {
|
||||
let account = account_from_address(address, deps.storage, deps.api)?;
|
||||
Ok(Some(account))
|
||||
}
|
||||
|
||||
pub fn try_get_locked_coins(
|
||||
vesting_account_address: &str,
|
||||
block_time: Option<Timestamp>,
|
||||
|
||||
@@ -5,13 +5,20 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct InitMsg {}
|
||||
pub struct InitMsg {
|
||||
pub(crate) mixnet_contract_address: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct MigrateMsg {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ExecuteMsg {
|
||||
DelegateToMixnode {
|
||||
mix_identity: IdentityKey,
|
||||
amount: Coin,
|
||||
},
|
||||
UndelegateFromMixnode {
|
||||
mix_identity: IdentityKey,
|
||||
@@ -32,6 +39,7 @@ pub enum ExecuteMsg {
|
||||
BondMixnode {
|
||||
mix_node: MixNode,
|
||||
owner_signature: String,
|
||||
amount: Coin,
|
||||
},
|
||||
UnbondMixnode {},
|
||||
TrackUnbondMixnode {
|
||||
@@ -41,6 +49,7 @@ pub enum ExecuteMsg {
|
||||
BondGateway {
|
||||
gateway: Gateway,
|
||||
owner_signature: String,
|
||||
amount: Coin,
|
||||
},
|
||||
UnbondGateway {},
|
||||
TrackUnbondGateway {
|
||||
@@ -91,4 +100,7 @@ pub enum QueryMsg {
|
||||
block_time: Option<Timestamp>,
|
||||
vesting_account_address: String,
|
||||
},
|
||||
GetAccount {
|
||||
address: String,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,22 +1,108 @@
|
||||
use crate::errors::ContractError;
|
||||
use crate::vesting::Account;
|
||||
use cosmwasm_std::{Addr, Api, Storage};
|
||||
use crate::vesting::PledgeData;
|
||||
use cosmwasm_std::{Addr, Api, Storage, Uint128};
|
||||
use cw_storage_plus::{Item, Map};
|
||||
use mixnet_contract_common::IdentityKey;
|
||||
|
||||
type BlockHeight = u64;
|
||||
|
||||
pub const KEY: Item<u32> = Item::new("key");
|
||||
const ACCOUNTS: Map<Addr, Account> = Map::new("acc");
|
||||
const ACCOUNTS: Map<String, Account> = Map::new("acc");
|
||||
// Holds data related to individual accounts
|
||||
const BALANCES: Map<u32, Uint128> = Map::new("blc");
|
||||
const BOND_PLEDGES: Map<u32, PledgeData> = Map::new("bnd");
|
||||
const GATEWAY_PLEDGES: Map<u32, PledgeData> = Map::new("gtw");
|
||||
pub const DELEGATIONS: Map<(u32, IdentityKey, BlockHeight), Uint128> = Map::new("dlg");
|
||||
pub const ADMIN: Item<String> = Item::new("adm");
|
||||
pub const MIXNET_CONTRACT_ADDRESS: Item<String> = Item::new("mix");
|
||||
|
||||
pub fn save_delegation(
|
||||
key: (u32, IdentityKey, BlockHeight),
|
||||
amount: Uint128,
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<(), ContractError> {
|
||||
DELEGATIONS.save(storage, key, &amount)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_delegation(
|
||||
key: (u32, IdentityKey, BlockHeight),
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<(), ContractError> {
|
||||
DELEGATIONS.remove(storage, key);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn delete_account(address: &Addr, storage: &mut dyn Storage) -> Result<(), ContractError> {
|
||||
ACCOUNTS.remove(storage, address.to_owned());
|
||||
ACCOUNTS.remove(storage, address.to_owned().to_string());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_balance(key: u32, storage: &dyn Storage) -> Result<Uint128, ContractError> {
|
||||
Ok(BALANCES
|
||||
.may_load(storage, key)
|
||||
.unwrap_or(None)
|
||||
.unwrap_or_else(Uint128::zero))
|
||||
}
|
||||
|
||||
pub fn save_balance(
|
||||
key: u32,
|
||||
value: Uint128,
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<(), ContractError> {
|
||||
BALANCES.save(storage, key, &value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_bond_pledge(
|
||||
key: u32,
|
||||
storage: &dyn Storage,
|
||||
) -> Result<Option<PledgeData>, ContractError> {
|
||||
Ok(BOND_PLEDGES.may_load(storage, key).unwrap_or(None))
|
||||
}
|
||||
|
||||
pub fn remove_bond_pledge(key: u32, storage: &mut dyn Storage) -> Result<(), ContractError> {
|
||||
BOND_PLEDGES.remove(storage, key);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn save_bond_pledge(
|
||||
key: u32,
|
||||
value: &PledgeData,
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<(), ContractError> {
|
||||
BOND_PLEDGES.save(storage, key, value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_gateway_pledge(
|
||||
key: u32,
|
||||
storage: &dyn Storage,
|
||||
) -> Result<Option<PledgeData>, ContractError> {
|
||||
Ok(GATEWAY_PLEDGES.may_load(storage, key).unwrap_or(None))
|
||||
}
|
||||
|
||||
pub fn save_gateway_pledge(
|
||||
key: u32,
|
||||
value: &PledgeData,
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<(), ContractError> {
|
||||
GATEWAY_PLEDGES.save(storage, key, value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_gateway_pledge(key: u32, storage: &mut dyn Storage) -> Result<(), ContractError> {
|
||||
GATEWAY_PLEDGES.remove(storage, key);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn save_account(account: &Account, storage: &mut dyn Storage) -> Result<(), ContractError> {
|
||||
// This is a bit dirty, but its a simple way to allow for both staking account and owner to load it from storage
|
||||
if let Some(staking_address) = account.staking_address() {
|
||||
ACCOUNTS.save(storage, staking_address.to_owned(), account)?;
|
||||
ACCOUNTS.save(storage, staking_address.to_owned().to_string(), account)?;
|
||||
}
|
||||
ACCOUNTS.save(storage, account.owner_address(), account)?;
|
||||
ACCOUNTS.save(storage, account.owner_address().to_string(), account)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -24,7 +110,9 @@ pub fn load_account(
|
||||
address: &Addr,
|
||||
storage: &dyn Storage,
|
||||
) -> Result<Option<Account>, ContractError> {
|
||||
Ok(ACCOUNTS.may_load(storage, address.to_owned())?)
|
||||
Ok(ACCOUNTS
|
||||
.may_load(storage, address.to_owned().to_string())
|
||||
.unwrap_or(None))
|
||||
}
|
||||
|
||||
fn validate_account(address: &Addr, storage: &dyn Storage) -> Result<Account, ContractError> {
|
||||
|
||||
@@ -9,9 +9,11 @@ pub mod helpers {
|
||||
|
||||
pub fn init_contract() -> OwnedDeps<MemoryStorage, MockApi, MockQuerier<Empty>> {
|
||||
let mut deps = mock_dependencies();
|
||||
let msg = InitMsg {};
|
||||
let msg = InitMsg {
|
||||
mixnet_contract_address: "test".to_string(),
|
||||
};
|
||||
let env = mock_env();
|
||||
let info = mock_info("creator", &[]);
|
||||
let info = mock_info("admin", &[]);
|
||||
instantiate(deps.as_mut(), env.clone(), info, msg).unwrap();
|
||||
return deps;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::errors::ContractError;
|
||||
use cosmwasm_std::{Coin, Env, Response, Storage, Timestamp, Uint128};
|
||||
use cosmwasm_std::{Coin, Env, Response, Storage, Uint128};
|
||||
use mixnet_contract_common::IdentityKey;
|
||||
|
||||
pub trait DelegatingAccount {
|
||||
@@ -18,12 +18,12 @@ pub trait DelegatingAccount {
|
||||
) -> Result<Response, ContractError>;
|
||||
|
||||
// track_delegation performs internal vesting accounting necessary when
|
||||
// delegating from a vesting account. It accepts the current block time, the
|
||||
// delegating from a vesting account. It accepts the current block height, the
|
||||
// delegation amount and balance of all coins whose denomination exists in
|
||||
// the account's original vesting balance.
|
||||
fn track_delegation(
|
||||
&self,
|
||||
block_time: Timestamp,
|
||||
block_height: u64,
|
||||
mix_identity: IdentityKey,
|
||||
// Save some gas by passing it in
|
||||
current_balance: Uint128,
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use crate::errors::ContractError;
|
||||
use crate::storage::save_delegation;
|
||||
use crate::storage::MIXNET_CONTRACT_ADDRESS;
|
||||
use crate::traits::DelegatingAccount;
|
||||
use config::defaults::{DEFAULT_MIXNET_CONTRACT_ADDRESS, DENOM};
|
||||
use cosmwasm_std::{wasm_execute, Coin, Env, Order, Response, Storage, Timestamp, Uint128};
|
||||
use cw_storage_plus::Map;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{wasm_execute, Coin, Env, Response, Storage, Uint128};
|
||||
use mixnet_contract_common::ExecuteMsg as MixnetExecuteMsg;
|
||||
use mixnet_contract_common::IdentityKey;
|
||||
use vesting_contract_common::events::{
|
||||
@@ -32,9 +33,18 @@ impl DelegatingAccount for Account {
|
||||
mix_identity: mix_identity.clone(),
|
||||
delegate: self.owner_address().into_string(),
|
||||
};
|
||||
let delegate_to_mixnode =
|
||||
wasm_execute(DEFAULT_MIXNET_CONTRACT_ADDRESS, &msg, vec![coin.clone()])?;
|
||||
self.track_delegation(env.block.time, mix_identity, current_balance, coin, storage)?;
|
||||
let delegate_to_mixnode = wasm_execute(
|
||||
MIXNET_CONTRACT_ADDRESS.load(storage)?,
|
||||
&msg,
|
||||
vec![coin.clone()],
|
||||
)?;
|
||||
self.track_delegation(
|
||||
env.block.height,
|
||||
mix_identity,
|
||||
current_balance,
|
||||
coin,
|
||||
storage,
|
||||
)?;
|
||||
|
||||
Ok(Response::new()
|
||||
.add_message(delegate_to_mixnode)
|
||||
@@ -58,7 +68,7 @@ impl DelegatingAccount for Account {
|
||||
delegate: self.owner_address().into_string(),
|
||||
};
|
||||
let undelegate_from_mixnode = wasm_execute(
|
||||
DEFAULT_MIXNET_CONTRACT_ADDRESS,
|
||||
MIXNET_CONTRACT_ADDRESS.load(storage)?,
|
||||
&msg,
|
||||
vec![Coin {
|
||||
amount: Uint128::new(0),
|
||||
@@ -73,29 +83,19 @@ impl DelegatingAccount for Account {
|
||||
|
||||
fn track_delegation(
|
||||
&self,
|
||||
block_time: Timestamp,
|
||||
block_height: u64,
|
||||
mix_identity: IdentityKey,
|
||||
current_balance: Uint128,
|
||||
delegation: Coin,
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<(), ContractError> {
|
||||
let delegation_key = (mix_identity.as_bytes(), block_time.seconds());
|
||||
let delegations_storage_key = self.delegations_key();
|
||||
let delegations: Map<(&[u8], u64), Uint128> = Map::new(&delegations_storage_key);
|
||||
|
||||
let new_delegation =
|
||||
if let Some(existing_delegation) = delegations.may_load(storage, delegation_key)? {
|
||||
existing_delegation + delegation.amount
|
||||
} else {
|
||||
delegation.amount
|
||||
};
|
||||
|
||||
delegations.save(storage, delegation_key, &new_delegation)?;
|
||||
|
||||
save_delegation(
|
||||
(self.storage_key(), mix_identity, block_height),
|
||||
delegation.amount,
|
||||
storage,
|
||||
)?;
|
||||
let new_balance = Uint128::new(current_balance.u128() - delegation.amount.u128());
|
||||
|
||||
self.save_balance(new_balance, storage)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -105,26 +105,9 @@ impl DelegatingAccount for Account {
|
||||
amount: Coin,
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<(), ContractError> {
|
||||
let mix_bytes = mix_identity.as_bytes();
|
||||
let delegations_key = self.delegations_key();
|
||||
let delegations: Map<(&[u8], u64), Uint128> = Map::new(&delegations_key);
|
||||
|
||||
// Iterate over keys matching the prefix and remove them from the map
|
||||
let block_times = delegations
|
||||
.prefix(mix_bytes)
|
||||
.keys(storage, None, None, Order::Ascending)
|
||||
// Scan will blow up on first error
|
||||
.scan((), |_, x| x.ok())
|
||||
.collect::<Vec<u64>>();
|
||||
|
||||
for t in block_times {
|
||||
delegations.remove(storage, (mix_bytes, t))
|
||||
}
|
||||
|
||||
self.remove_delegations_for_mix(&mix_identity, storage)?;
|
||||
let new_balance = Uint128::new(self.load_balance(storage)?.u128() + amount.amount.u128());
|
||||
|
||||
self.save_balance(new_balance, storage)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::PledgeData;
|
||||
use crate::errors::ContractError;
|
||||
use crate::storage::MIXNET_CONTRACT_ADDRESS;
|
||||
use crate::traits::GatewayBondingAccount;
|
||||
use config::defaults::DEFAULT_MIXNET_CONTRACT_ADDRESS;
|
||||
use cosmwasm_std::{wasm_execute, Coin, Env, Response, Storage, Uint128};
|
||||
use mixnet_contract_common::{ExecuteMsg as MixnetExecuteMsg, Gateway};
|
||||
use vesting_contract_common::events::{
|
||||
@@ -47,7 +47,8 @@ impl GatewayBondingAccount for Account {
|
||||
|
||||
let new_balance = Uint128::new(current_balance.u128() - pledge.amount.u128());
|
||||
|
||||
let bond_gateway_msg = wasm_execute(DEFAULT_MIXNET_CONTRACT_ADDRESS, &msg, vec![pledge])?;
|
||||
let bond_gateway_msg =
|
||||
wasm_execute(MIXNET_CONTRACT_ADDRESS.load(storage)?, &msg, vec![pledge])?;
|
||||
|
||||
self.save_balance(new_balance, storage)?;
|
||||
self.save_gateway_pledge(pledge_data, storage)?;
|
||||
@@ -63,7 +64,7 @@ impl GatewayBondingAccount for Account {
|
||||
};
|
||||
|
||||
if let Some(_bond) = self.load_gateway_pledge(storage)? {
|
||||
let unbond_msg = wasm_execute(DEFAULT_MIXNET_CONTRACT_ADDRESS, &msg, vec![])?;
|
||||
let unbond_msg = wasm_execute(MIXNET_CONTRACT_ADDRESS.load(storage)?, &msg, vec![])?;
|
||||
|
||||
Ok(Response::new()
|
||||
.add_message(unbond_msg)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::PledgeData;
|
||||
use crate::errors::ContractError;
|
||||
use crate::storage::MIXNET_CONTRACT_ADDRESS;
|
||||
use crate::traits::MixnodeBondingAccount;
|
||||
use config::defaults::DEFAULT_MIXNET_CONTRACT_ADDRESS;
|
||||
use cosmwasm_std::{wasm_execute, Coin, Env, Response, Storage, Uint128};
|
||||
use mixnet_contract_common::{ExecuteMsg as MixnetExecuteMsg, MixNode};
|
||||
use vesting_contract_common::events::{
|
||||
@@ -47,7 +47,8 @@ impl MixnodeBondingAccount for Account {
|
||||
|
||||
let new_balance = Uint128::new(current_balance.u128() - pledge.amount.u128());
|
||||
|
||||
let bond_mixnode_mag = wasm_execute(DEFAULT_MIXNET_CONTRACT_ADDRESS, &msg, vec![pledge])?;
|
||||
let bond_mixnode_mag =
|
||||
wasm_execute(MIXNET_CONTRACT_ADDRESS.load(storage)?, &msg, vec![pledge])?;
|
||||
|
||||
self.save_balance(new_balance, storage)?;
|
||||
self.save_mixnode_pledge(pledge_data, storage)?;
|
||||
@@ -63,7 +64,7 @@ impl MixnodeBondingAccount for Account {
|
||||
};
|
||||
|
||||
if self.load_mixnode_pledge(storage)?.is_some() {
|
||||
let unbond_msg = wasm_execute(DEFAULT_MIXNET_CONTRACT_ADDRESS, &msg, vec![])?;
|
||||
let unbond_msg = wasm_execute(MIXNET_CONTRACT_ADDRESS.load(storage)?, &msg, vec![])?;
|
||||
|
||||
Ok(Response::new()
|
||||
.add_message(unbond_msg)
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
use super::{PledgeData, VestingPeriod};
|
||||
use crate::contract::NUM_VESTING_PERIODS;
|
||||
use crate::errors::ContractError;
|
||||
use crate::storage::{save_account, KEY};
|
||||
use crate::storage::{
|
||||
load_balance, load_bond_pledge, load_gateway_pledge, remove_bond_pledge, remove_delegation,
|
||||
remove_gateway_pledge, save_account, save_balance, save_bond_pledge, save_gateway_pledge,
|
||||
DELEGATIONS, KEY,
|
||||
};
|
||||
use cosmwasm_std::{Addr, Coin, Order, Storage, Timestamp, Uint128};
|
||||
use cw_storage_plus::{Item, Map};
|
||||
use cw_storage_plus::Bound;
|
||||
use mixnet_contract_common::IdentityKey;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -13,11 +17,6 @@ mod gateway_bonding_account;
|
||||
mod mixnode_bonding_account;
|
||||
mod vesting_account;
|
||||
|
||||
const DELEGATIONS_SUFFIX: &str = "de";
|
||||
const BALANCE_SUFFIX: &str = "ba";
|
||||
const PLEDGE_SUFFIX: &str = "bo";
|
||||
const GATEWAY_SUFFIX: &str = "ga";
|
||||
|
||||
fn generate_storage_key(storage: &mut dyn Storage) -> Result<u32, ContractError> {
|
||||
let key = KEY.may_load(storage)?.unwrap_or(0) + 1;
|
||||
KEY.save(storage, &key)?;
|
||||
@@ -31,7 +30,7 @@ pub struct Account {
|
||||
start_time: Timestamp,
|
||||
periods: Vec<VestingPeriod>,
|
||||
coin: Coin,
|
||||
storage_key: String,
|
||||
storage_key: u32,
|
||||
}
|
||||
|
||||
impl Account {
|
||||
@@ -43,7 +42,7 @@ impl Account {
|
||||
periods: Vec<VestingPeriod>,
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<Self, ContractError> {
|
||||
let storage_key = generate_storage_key(storage)?.to_string();
|
||||
let storage_key = generate_storage_key(storage)?;
|
||||
let amount = coin.amount;
|
||||
let account = Account {
|
||||
owner_address,
|
||||
@@ -58,20 +57,8 @@ impl Account {
|
||||
Ok(account)
|
||||
}
|
||||
|
||||
pub fn delegations_key(&self) -> String {
|
||||
format!("{}{}", self.storage_key, DELEGATIONS_SUFFIX)
|
||||
}
|
||||
|
||||
pub fn balance_key(&self) -> String {
|
||||
format!("{}{}", self.storage_key, BALANCE_SUFFIX)
|
||||
}
|
||||
|
||||
pub fn mixnode_pledge_key(&self) -> String {
|
||||
format!("{}{}", self.storage_key, PLEDGE_SUFFIX)
|
||||
}
|
||||
|
||||
pub fn gateway_pledge_key(&self) -> String {
|
||||
format!("{}{}", self.storage_key, GATEWAY_SUFFIX)
|
||||
pub fn storage_key(&self) -> u32 {
|
||||
self.storage_key
|
||||
}
|
||||
|
||||
pub fn owner_address(&self) -> Addr {
|
||||
@@ -124,9 +111,7 @@ impl Account {
|
||||
}
|
||||
|
||||
pub fn load_balance(&self, storage: &dyn Storage) -> Result<Uint128, ContractError> {
|
||||
let key = self.balance_key();
|
||||
let balance = Item::new(&key);
|
||||
Ok(balance.may_load(storage)?.unwrap_or_else(Uint128::zero))
|
||||
load_balance(self.storage_key(), storage)
|
||||
}
|
||||
|
||||
pub fn save_balance(
|
||||
@@ -134,18 +119,14 @@ impl Account {
|
||||
amount: Uint128,
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<(), ContractError> {
|
||||
let key = self.balance_key();
|
||||
let balance = Item::new(&key);
|
||||
Ok(balance.save(storage, &amount)?)
|
||||
save_balance(self.storage_key(), amount, storage)
|
||||
}
|
||||
|
||||
pub fn load_mixnode_pledge(
|
||||
&self,
|
||||
storage: &dyn Storage,
|
||||
) -> Result<Option<PledgeData>, ContractError> {
|
||||
let key = self.mixnode_pledge_key();
|
||||
let mixnode_pledge = Item::new(&key);
|
||||
Ok(mixnode_pledge.may_load(storage)?)
|
||||
load_bond_pledge(self.storage_key(), storage)
|
||||
}
|
||||
|
||||
pub fn save_mixnode_pledge(
|
||||
@@ -153,25 +134,18 @@ impl Account {
|
||||
pledge: PledgeData,
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<(), ContractError> {
|
||||
let key = self.mixnode_pledge_key();
|
||||
let mixnode_pledge = Item::new(&key);
|
||||
Ok(mixnode_pledge.save(storage, &pledge)?)
|
||||
save_bond_pledge(self.storage_key(), &pledge, storage)
|
||||
}
|
||||
|
||||
pub fn remove_mixnode_pledge(&self, storage: &mut dyn Storage) -> Result<(), ContractError> {
|
||||
let key = self.mixnode_pledge_key();
|
||||
let mixnode_pledge: Item<PledgeData> = Item::new(&key);
|
||||
mixnode_pledge.remove(storage);
|
||||
Ok(())
|
||||
remove_bond_pledge(self.storage_key(), storage)
|
||||
}
|
||||
|
||||
pub fn load_gateway_pledge(
|
||||
&self,
|
||||
storage: &dyn Storage,
|
||||
) -> Result<Option<PledgeData>, ContractError> {
|
||||
let key = self.gateway_pledge_key();
|
||||
let gateway_pledge = Item::new(&key);
|
||||
Ok(gateway_pledge.may_load(storage)?)
|
||||
load_gateway_pledge(self.storage_key(), storage)
|
||||
}
|
||||
|
||||
pub fn save_gateway_pledge(
|
||||
@@ -179,70 +153,75 @@ impl Account {
|
||||
pledge: PledgeData,
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<(), ContractError> {
|
||||
let key = self.gateway_pledge_key();
|
||||
let gateway_pledge = Item::new(&key);
|
||||
Ok(gateway_pledge.save(storage, &pledge)?)
|
||||
save_gateway_pledge(self.storage_key(), &pledge, storage)
|
||||
}
|
||||
|
||||
pub fn remove_gateway_pledge(&self, storage: &mut dyn Storage) -> Result<(), ContractError> {
|
||||
let key = self.gateway_pledge_key();
|
||||
let gateway_pledge: Item<PledgeData> = Item::new(&key);
|
||||
gateway_pledge.remove(storage);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Returns block_time part of the delegation key
|
||||
pub fn delegation_keys_for_mix(&self, mix: &str, storage: &dyn Storage) -> Vec<u64> {
|
||||
let key = self.delegations_key();
|
||||
let delegations: Map<(&[u8], u64), Uint128> = Map::new(&key);
|
||||
delegations
|
||||
.prefix(mix.as_bytes())
|
||||
.keys(storage, None, None, Order::Ascending)
|
||||
// Scan will blow up on first error
|
||||
.scan((), |_, x| x.ok())
|
||||
.collect::<Vec<u64>>()
|
||||
remove_gateway_pledge(self.storage_key(), storage)
|
||||
}
|
||||
|
||||
pub fn any_delegation_for_mix(&self, mix: &str, storage: &dyn Storage) -> bool {
|
||||
!self.delegation_keys_for_mix(mix, storage).is_empty()
|
||||
DELEGATIONS
|
||||
.prefix((self.storage_key(), mix.to_string()))
|
||||
.range(storage, None, None, Order::Ascending)
|
||||
.next()
|
||||
.is_some()
|
||||
}
|
||||
|
||||
pub fn delegations_for_mix(
|
||||
pub fn remove_delegations_for_mix(
|
||||
&self,
|
||||
mix: IdentityKey,
|
||||
storage: &dyn Storage,
|
||||
) -> Result<Vec<Uint128>, ContractError> {
|
||||
let mix_bytes = mix.as_bytes();
|
||||
let keys = self.delegation_keys_for_mix(&mix, storage);
|
||||
let delegations_key = self.delegations_key();
|
||||
let delegations: Map<(&[u8], u64), Uint128> = Map::new(&delegations_key);
|
||||
mix: &str,
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<(), ContractError> {
|
||||
let limit = 50;
|
||||
let mut start_after = None;
|
||||
let mut block_heights = Vec::new();
|
||||
let mut prev_len = 0;
|
||||
// TODO: Test this
|
||||
loop {
|
||||
block_heights.extend(
|
||||
DELEGATIONS
|
||||
.prefix((self.storage_key(), mix.to_string()))
|
||||
.keys(storage, start_after, None, Order::Ascending)
|
||||
.take(limit)
|
||||
.filter_map(|key| key.ok()),
|
||||
);
|
||||
|
||||
let mut delegation_amounts = Vec::new();
|
||||
for key in keys {
|
||||
delegation_amounts.push(delegations.load(storage, (mix_bytes, key))?)
|
||||
if prev_len == block_heights.len() {
|
||||
break;
|
||||
}
|
||||
|
||||
prev_len = block_heights.len();
|
||||
|
||||
start_after = block_heights.last().map(|last| Bound::exclusive_int(*last));
|
||||
if start_after.is_none() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(delegation_amounts)
|
||||
for block_height in block_heights {
|
||||
remove_delegation((self.storage_key(), mix.to_string(), block_height), storage)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn total_delegations_for_mix(
|
||||
&self,
|
||||
mix: IdentityKey,
|
||||
storage: &dyn Storage,
|
||||
) -> Result<Uint128, ContractError> {
|
||||
Ok(self
|
||||
.delegations_for_mix(mix, storage)?
|
||||
.iter()
|
||||
.fold(Uint128::zero(), |acc, x| acc + *x))
|
||||
Ok(DELEGATIONS
|
||||
.prefix((self.storage_key(), mix))
|
||||
.range(storage, None, None, Order::Ascending)
|
||||
.filter_map(|x| x.ok())
|
||||
.fold(Uint128::zero(), |acc, (_key, val)| acc + val))
|
||||
}
|
||||
|
||||
pub fn total_delegations(&self, storage: &dyn Storage) -> Result<Uint128, ContractError> {
|
||||
let delegations_key = self.delegations_key();
|
||||
let delegations: Map<(&[u8], u64), Uint128> = Map::new(&delegations_key);
|
||||
Ok(delegations
|
||||
Ok(DELEGATIONS
|
||||
.sub_prefix(self.storage_key())
|
||||
.range(storage, None, None, Order::Ascending)
|
||||
.scan((), |_, x| x.ok())
|
||||
.fold(Uint128::zero(), |acc, (_, x)| acc + x))
|
||||
.filter_map(|x| x.ok())
|
||||
.fold(Uint128::zero(), |acc, (_key, val)| acc + val))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use crate::contract::NUM_VESTING_PERIODS;
|
||||
use crate::errors::ContractError;
|
||||
use crate::storage::{delete_account, save_account};
|
||||
use crate::storage::{delete_account, save_account, DELEGATIONS};
|
||||
use crate::traits::VestingAccount;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{Addr, Coin, Env, Order, Storage, Timestamp, Uint128};
|
||||
use cw_storage_plus::Map;
|
||||
|
||||
use super::Account;
|
||||
|
||||
@@ -115,21 +114,17 @@ impl VestingAccount for Account {
|
||||
let period = self.get_current_vesting_period(block_time);
|
||||
let max_vested = self.tokens_per_period()? * period as u128;
|
||||
let start_time = self.periods[period].start_time;
|
||||
let delegations_key = self.delegations_key();
|
||||
let delegations: Map<(&[u8], u64), Uint128> = Map::new(&delegations_key);
|
||||
|
||||
let delegations_keys = delegations
|
||||
.keys(storage, None, None, Order::Ascending)
|
||||
.scan((), |_, x| x.ok())
|
||||
.filter(|(_mix, block_time)| *block_time < start_time)
|
||||
.map(|(mix, block_time)| (mix, block_time))
|
||||
.collect::<Vec<(Vec<u8>, u64)>>();
|
||||
let coin = DELEGATIONS
|
||||
.sub_prefix(self.storage_key())
|
||||
.range(storage, None, None, Order::Ascending)
|
||||
.filter_map(|x| x.ok())
|
||||
.filter(|((_mix, block_time), _amount)| *block_time < start_time)
|
||||
.fold(Uint128::zero(), |acc, ((_mix, _block_time), amount)| {
|
||||
acc + amount
|
||||
});
|
||||
|
||||
let mut amount = Uint128::zero();
|
||||
for (mix, block_time) in delegations_keys {
|
||||
amount += delegations.load(storage, (&mix, block_time))?
|
||||
}
|
||||
amount = Uint128::new(amount.u128().min(max_vested));
|
||||
let amount = Uint128::new(coin.u128().min(max_vested));
|
||||
|
||||
Ok(Coin {
|
||||
amount,
|
||||
|
||||
@@ -36,7 +36,7 @@ pub fn populate_vesting_periods(start_time: u64, n: usize) -> Vec<VestingPeriod>
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::contract::{execute, ADMIN_ADDRESS, NUM_VESTING_PERIODS, VESTING_PERIOD};
|
||||
use crate::contract::{execute, NUM_VESTING_PERIODS, VESTING_PERIOD};
|
||||
use crate::messages::ExecuteMsg;
|
||||
use crate::storage::load_account;
|
||||
use crate::support::tests::helpers::{init_contract, vesting_account_fixture};
|
||||
@@ -61,7 +61,7 @@ mod tests {
|
||||
let response = execute(deps.as_mut(), env.clone(), info, msg.clone());
|
||||
assert!(response.is_err());
|
||||
|
||||
let info = mock_info(ADMIN_ADDRESS, &coins(1_000_000_000_000, DENOM));
|
||||
let info = mock_info("admin", &coins(1_000_000_000_000, DENOM));
|
||||
let _response = execute(deps.as_mut(), env.clone(), info, msg.clone());
|
||||
let created_account = load_account(&Addr::unchecked("owner"), &deps.storage)
|
||||
.unwrap()
|
||||
@@ -78,8 +78,8 @@ mod tests {
|
||||
// Test key collision avoidance
|
||||
|
||||
let account_again = vesting_account_fixture(&mut deps.storage, &env);
|
||||
assert_eq!(created_account.balance_key(), "1ba".to_string());
|
||||
assert_ne!(created_account.balance_key(), account_again.balance_key());
|
||||
assert_eq!(created_account.storage_key(), 1);
|
||||
assert_ne!(created_account.storage_key(), account_again.storage_key());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Generated
+6
-6
@@ -706,9 +706,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cosmwasm-crypto"
|
||||
version = "1.0.0-beta3"
|
||||
version = "1.0.0-beta4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a380b87642204557629c9b72988c47b55fbfe6d474960adba56b22331504956a"
|
||||
checksum = "f903ebbabc0d4880dbc76148efb8be8fc29fa4bf294c440c3d70da1c8bcafff7"
|
||||
dependencies = [
|
||||
"digest 0.9.0",
|
||||
"ed25519-zebra",
|
||||
@@ -719,18 +719,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cosmwasm-derive"
|
||||
version = "1.0.0-beta3"
|
||||
version = "1.0.0-beta4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "866713b2fe13f23038c7d8824c3059d1f28dd94685fb406d1533c4eeeefeefae"
|
||||
checksum = "832bebef577ecb394603de8e2bf0de429b74aa364e17dec18e15ce37e71b0cae"
|
||||
dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cosmwasm-std"
|
||||
version = "1.0.0-beta3"
|
||||
version = "1.0.0-beta4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8dbb9939b31441dfa9af3ec9740c8a24d585688401eff1b6b386abb7ad0d10a8"
|
||||
checksum = "6238c45840cc9de5a39f0f619e3a4f7c38c5d2c6ac9e3e4d72751ee045e6d7da"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"cosmwasm-crypto",
|
||||
|
||||
Reference in New Issue
Block a user