Add claim reward to vesting and mixnet contract (#1292)
* Add claim reward to vesting contract * Add compound and claim methods to nymd client * Add TrackReward message * CHANGELOG
This commit is contained in:
@@ -9,6 +9,8 @@
|
||||
- wallet: added support for multiple accounts ([#1265])
|
||||
- wallet: the wallet backend learned how to keep track of validator name, either hardcoded or by querying the status endpoint.
|
||||
- mixnet-contract: Replace all naked `-` with `saturating_sub`.
|
||||
- mixnet-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
|
||||
- vesting-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
|
||||
- validator-api: add Swagger to document the REST API ([#1249]).
|
||||
- validator-api: add `estimated_node_profit` and `estimated_operator_cost` to `reward-estimate` endpoint ([#1284])
|
||||
- all: added network compilation target to `--help` (or `--version`) commands ([#1256]).
|
||||
@@ -34,6 +36,7 @@
|
||||
[#1275]: https://github.com/nymtech/nym/pull/1275
|
||||
[#1278]: https://github.com/nymtech/nym/pull/1278
|
||||
[#1284]: https://github.com/nymtech/nym/pull/1284
|
||||
[#1292]: https://github.com/nymtech/nym/pull/1292
|
||||
|
||||
## [nym-wallet-v1.0.4](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.4) (2022-05-04)
|
||||
|
||||
|
||||
@@ -786,6 +786,89 @@ impl<C> NymdClient<C> {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn compound_operator_reward(
|
||||
&self,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NymdError>
|
||||
where
|
||||
C: SigningCosmWasmClient + Sync,
|
||||
{
|
||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||
let req = ExecuteMsg::CompoundOperatorReward {};
|
||||
self.client
|
||||
.execute(
|
||||
self.address(),
|
||||
self.mixnet_contract_address()?,
|
||||
&req,
|
||||
fee,
|
||||
"MixnetContract::CompoundOperatorReward",
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn claim_operator_reward(&self, fee: Option<Fee>) -> Result<ExecuteResult, NymdError>
|
||||
where
|
||||
C: SigningCosmWasmClient + Sync,
|
||||
{
|
||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||
let req = ExecuteMsg::ClaimOperatorReward {};
|
||||
self.client
|
||||
.execute(
|
||||
self.address(),
|
||||
self.mixnet_contract_address()?,
|
||||
&req,
|
||||
fee,
|
||||
"MixnetContract::ClaimOperatorReward",
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn compound_delegator_reward(
|
||||
&self,
|
||||
mix_identity: IdentityKey,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NymdError>
|
||||
where
|
||||
C: SigningCosmWasmClient + Sync,
|
||||
{
|
||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||
let req = ExecuteMsg::CompoundDelegatorReward { mix_identity };
|
||||
self.client
|
||||
.execute(
|
||||
self.address(),
|
||||
self.mixnet_contract_address()?,
|
||||
&req,
|
||||
fee,
|
||||
"MixnetContract::CompoundDelegatorReward",
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn claim_delegator_reward(
|
||||
&self,
|
||||
mix_identity: IdentityKey,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NymdError>
|
||||
where
|
||||
C: SigningCosmWasmClient + Sync,
|
||||
{
|
||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||
let req = ExecuteMsg::ClaimDelegatorReward { mix_identity };
|
||||
self.client
|
||||
.execute(
|
||||
self.address(),
|
||||
self.mixnet_contract_address()?,
|
||||
&req,
|
||||
fee,
|
||||
"MixnetContract::ClaimDelegatorReward",
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Announce a mixnode, paying a fee.
|
||||
pub async fn bond_mixnode(
|
||||
&self,
|
||||
|
||||
@@ -12,6 +12,28 @@ use vesting_contract_common::messages::{ExecuteMsg as VestingExecuteMsg, Vesting
|
||||
|
||||
#[async_trait]
|
||||
pub trait VestingSigningClient {
|
||||
async fn vesting_claim_operator_reward(
|
||||
&self,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NymdError>;
|
||||
|
||||
async fn vesting_claim_delegator_reward(
|
||||
&self,
|
||||
mix_identity: IdentityKey,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NymdError>;
|
||||
|
||||
async fn vesting_compound_operator_reward(
|
||||
&self,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NymdError>;
|
||||
|
||||
async fn vesting_compound_delegator_reward(
|
||||
&self,
|
||||
mix_identity: IdentityKey,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NymdError>;
|
||||
|
||||
async fn vesting_update_mixnode_config(
|
||||
&self,
|
||||
profix_margin_percent: u8,
|
||||
@@ -374,4 +396,78 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn vesting_claim_operator_reward(
|
||||
&self,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NymdError> {
|
||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||
let req = VestingExecuteMsg::ClaimOperatorReward {};
|
||||
self.client
|
||||
.execute(
|
||||
self.address(),
|
||||
self.vesting_contract_address()?,
|
||||
&req,
|
||||
fee,
|
||||
"VestingContract::ClaimOperatorReward",
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn vesting_compound_operator_reward(
|
||||
&self,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NymdError> {
|
||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||
let req = VestingExecuteMsg::CompoundOperatorReward {};
|
||||
self.client
|
||||
.execute(
|
||||
self.address(),
|
||||
self.vesting_contract_address()?,
|
||||
&req,
|
||||
fee,
|
||||
"VestingContract::CompoundOperatorReward",
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn vesting_claim_delegator_reward(
|
||||
&self,
|
||||
mix_identity: IdentityKey,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NymdError> {
|
||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||
let req = VestingExecuteMsg::ClaimDelegatorReward { mix_identity };
|
||||
self.client
|
||||
.execute(
|
||||
self.address(),
|
||||
self.vesting_contract_address()?,
|
||||
&req,
|
||||
fee,
|
||||
"VestingContract::ClaimDelegatorReward",
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn vesting_compound_delegator_reward(
|
||||
&self,
|
||||
mix_identity: IdentityKey,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NymdError> {
|
||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||
let req = VestingExecuteMsg::CompoundDelegatorReward { mix_identity };
|
||||
self.client
|
||||
.execute(
|
||||
self.address(),
|
||||
self.vesting_contract_address()?,
|
||||
&req,
|
||||
fee,
|
||||
"VestingContract::CompoundDelegatorReward",
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@ pub const CHANGE_REWARDED_SET_EVENT_TYPE: &str = "change_rewarded_set";
|
||||
pub const ADVANCE_INTERVAL_EVENT_TYPE: &str = "advance_interval";
|
||||
pub const ADVANCE_EPOCH_EVENT_TYPE: &str = "advance_epoch";
|
||||
pub const COMPOUND_DELEGATOR_REWARD_EVENT_TYPE: &str = "compound_delegator_reward";
|
||||
pub const CLAIM_DELEGATOR_REWARD_EVENT_TYPE: &str = "claim_delegator_reward";
|
||||
pub const COMPOUND_OPERATOR_REWARD_EVENT_TYPE: &str = "compound_operator_reward";
|
||||
pub const CLAIM_OPERATOR_REWARD_EVENT_TYPE: &str = "claim_operator_reward";
|
||||
pub const SNAPSHOT_MIXNODES_EVENT: &str = "snapshot_mixnodes";
|
||||
|
||||
// attributes that are used in multiple places
|
||||
@@ -151,6 +153,11 @@ pub fn new_compound_operator_reward_event(owner: &Addr, amount: Uint128) -> Even
|
||||
event.add_attribute(AMOUNT_KEY, amount.to_string())
|
||||
}
|
||||
|
||||
pub fn new_claim_operator_reward_event(owner: &Addr, amount: Uint128) -> Event {
|
||||
let event = Event::new(CLAIM_OPERATOR_REWARD_EVENT_TYPE).add_attribute(OWNER_KEY, owner);
|
||||
event.add_attribute(AMOUNT_KEY, amount.to_string())
|
||||
}
|
||||
|
||||
pub fn new_compound_delegator_reward_event(
|
||||
delegator: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
@@ -171,6 +178,26 @@ pub fn new_compound_delegator_reward_event(
|
||||
.add_attribute(DELEGATOR_KEY, delegator)
|
||||
}
|
||||
|
||||
pub fn new_claim_delegator_reward_event(
|
||||
delegator: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
amount: Uint128,
|
||||
mix_identity: IdentityKeyRef<'_>,
|
||||
) -> Event {
|
||||
let mut event =
|
||||
Event::new(CLAIM_DELEGATOR_REWARD_EVENT_TYPE).add_attribute(DELEGATOR_KEY, delegator);
|
||||
|
||||
if let Some(proxy) = proxy {
|
||||
event = event.add_attribute(PROXY_KEY, proxy)
|
||||
}
|
||||
|
||||
// coin implements Display trait and we use that implementation here
|
||||
event
|
||||
.add_attribute(AMOUNT_KEY, amount.to_string())
|
||||
.add_attribute(DELEGATION_TARGET_KEY, mix_identity)
|
||||
.add_attribute(DELEGATOR_KEY, delegator)
|
||||
}
|
||||
|
||||
pub fn new_undelegation_event(
|
||||
delegator: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
|
||||
@@ -99,6 +99,17 @@ pub enum ExecuteMsg {
|
||||
},
|
||||
// AdvanceCurrentInterval {},
|
||||
AdvanceCurrentEpoch {},
|
||||
ClaimOperatorReward {},
|
||||
ClaimOperatorRewardOnBehalf {
|
||||
owner: String,
|
||||
},
|
||||
ClaimDelegatorReward {
|
||||
mix_identity: IdentityKey,
|
||||
},
|
||||
ClaimDelegatorRewardOnBehalf {
|
||||
mix_identity: IdentityKey,
|
||||
owner: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
|
||||
@@ -20,6 +20,7 @@ pub const VESTING_UPDATE_MIXNODE_CONFIG_EVENT_TYPE: &str = "vesting_update_mixno
|
||||
pub const TRACK_MIXNODE_UNBOND_EVENT_TYPE: &str = "track_mixnode_unbond";
|
||||
pub const TRACK_GATEWAY_UNBOND_EVENT_TYPE: &str = "track_gateway_unbond";
|
||||
pub const TRACK_UNDELEGATION_EVENT_TYPE: &str = "track_undelegation";
|
||||
pub const TRACK_REWARD_EVENT_TYPE: &str = "track_reaward";
|
||||
|
||||
// attributes that are used in multiple places
|
||||
pub const OWNER_KEY: &str = "owner";
|
||||
@@ -136,3 +137,7 @@ pub fn new_track_gateway_unbond_event() -> Event {
|
||||
pub fn new_track_undelegation_event() -> Event {
|
||||
Event::new(TRACK_UNDELEGATION_EVENT_TYPE)
|
||||
}
|
||||
|
||||
pub fn new_track_reward_event() -> Event {
|
||||
Event::new(TRACK_REWARD_EVENT_TYPE)
|
||||
}
|
||||
|
||||
@@ -49,6 +49,14 @@ impl VestingSpecification {
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ExecuteMsg {
|
||||
TrackReward {
|
||||
amount: Coin,
|
||||
address: String,
|
||||
},
|
||||
ClaimOperatorReward {},
|
||||
ClaimDelegatorReward {
|
||||
mix_identity: String,
|
||||
},
|
||||
CompoundDelegatorReward {
|
||||
mix_identity: String,
|
||||
},
|
||||
|
||||
@@ -283,6 +283,32 @@ pub fn execute(
|
||||
info,
|
||||
)
|
||||
}
|
||||
ExecuteMsg::ClaimOperatorReward {} => {
|
||||
crate::rewards::transactions::try_claim_operator_reward(deps, &env, &info)
|
||||
}
|
||||
ExecuteMsg::ClaimOperatorRewardOnBehalf { owner } => {
|
||||
crate::rewards::transactions::try_claim_operator_reward_on_behalf(
|
||||
deps, &env, &info, owner,
|
||||
)
|
||||
}
|
||||
ExecuteMsg::ClaimDelegatorReward { mix_identity } => {
|
||||
crate::rewards::transactions::try_claim_delegator_reward(
|
||||
deps,
|
||||
&env,
|
||||
&info,
|
||||
&mix_identity,
|
||||
)
|
||||
}
|
||||
ExecuteMsg::ClaimDelegatorRewardOnBehalf {
|
||||
mix_identity,
|
||||
owner,
|
||||
} => crate::rewards::transactions::try_claim_delegator_reward_on_behalf(
|
||||
deps,
|
||||
&env,
|
||||
&info,
|
||||
owner,
|
||||
&mix_identity,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -153,8 +153,8 @@ pub enum ContractError {
|
||||
#[from]
|
||||
source: MixnetContractError,
|
||||
},
|
||||
#[error("No rewards to claim for mixnode {identity} for delegate {delegate}")]
|
||||
NoRewardsToClaim { identity: String, delegate: String },
|
||||
#[error("No rewards to claim for mixnode {identity} for {address}")]
|
||||
NoRewardsToClaim { identity: String, address: String },
|
||||
|
||||
#[error("Epoch not initialized yet!")]
|
||||
EpochNotInitialized,
|
||||
|
||||
@@ -15,9 +15,13 @@ use crate::mixnodes::storage::{self as mixnodes_storage, StoredMixnodeBond};
|
||||
use crate::rewards::helpers;
|
||||
use crate::support::helpers::is_authorized;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{Addr, Api, Coin, DepsMut, Env, MessageInfo, Order, Response, Storage, Uint128};
|
||||
use cosmwasm_std::{
|
||||
coins, wasm_execute, Addr, Api, BankMsg, Coin, DepsMut, Env, MessageInfo, Order, Response,
|
||||
Storage, Uint128,
|
||||
};
|
||||
use cw_storage_plus::Bound;
|
||||
use mixnet_contract_common::events::{
|
||||
new_claim_delegator_reward_event, new_claim_operator_reward_event,
|
||||
new_compound_delegator_reward_event, new_compound_operator_reward_event,
|
||||
new_mix_operator_rewarding_event, new_not_found_mix_operator_rewarding_event,
|
||||
new_too_fresh_bond_mix_operator_rewarding_event, new_zero_uptime_mix_operator_rewarding_event,
|
||||
@@ -27,6 +31,186 @@ use mixnet_contract_common::reward_params::{NodeEpochRewards, NodeRewardParams,
|
||||
use mixnet_contract_common::{Delegation, IdentityKey, RewardingStatus};
|
||||
|
||||
use mixnet_contract_common::RewardingResult;
|
||||
use vesting_contract_common::messages::ExecuteMsg as VestingContractExecuteMsg;
|
||||
use vesting_contract_common::one_ucoin;
|
||||
|
||||
// All four of the below methods need to do the following things:
|
||||
// 1. Calculate currently available rewards
|
||||
// 2. Send the rewards back to whoever claimed them
|
||||
// 3. Set the LAST_CLAIMED_HEIGHT to the current height
|
||||
pub fn try_claim_operator_reward(
|
||||
deps: DepsMut<'_>,
|
||||
env: &Env,
|
||||
info: &MessageInfo,
|
||||
) -> Result<Response, ContractError> {
|
||||
_try_claim_operator_reward(deps.storage, deps.api, env, &info.sender.to_string(), None)
|
||||
}
|
||||
|
||||
pub fn try_claim_operator_reward_on_behalf(
|
||||
deps: DepsMut<'_>,
|
||||
env: &Env,
|
||||
info: &MessageInfo,
|
||||
owner: String,
|
||||
) -> Result<Response, ContractError> {
|
||||
_try_claim_operator_reward(
|
||||
deps.storage,
|
||||
deps.api,
|
||||
env,
|
||||
&owner,
|
||||
Some(info.sender.clone()),
|
||||
)
|
||||
}
|
||||
|
||||
fn _try_claim_operator_reward(
|
||||
storage: &mut dyn Storage,
|
||||
api: &dyn Api,
|
||||
env: &Env,
|
||||
owner: &str,
|
||||
proxy: Option<Addr>,
|
||||
) -> Result<Response, ContractError> {
|
||||
let owner = api.addr_validate(owner)?;
|
||||
|
||||
let bond = match crate::mixnodes::storage::mixnodes()
|
||||
.idx
|
||||
.owner
|
||||
.item(storage, owner.clone())?
|
||||
{
|
||||
Some(record) => record.1,
|
||||
None => return Err(ContractError::NoAssociatedMixNodeBond { owner }),
|
||||
};
|
||||
|
||||
if proxy != bond.proxy {
|
||||
return Err(ContractError::ProxyMismatch {
|
||||
existing: bond
|
||||
.proxy
|
||||
.map_or_else(|| "None".to_string(), |a| a.as_str().to_string()),
|
||||
incoming: proxy.map_or_else(|| "None".to_string(), |a| a.as_str().to_string()),
|
||||
});
|
||||
}
|
||||
|
||||
let reward = calculate_operator_reward(storage, api, &owner, &bond)?;
|
||||
|
||||
OPERATOR_REWARD_CLAIMED_HEIGHT.save(
|
||||
storage,
|
||||
(owner.to_string(), bond.identity().to_string()),
|
||||
&env.block.height,
|
||||
)?;
|
||||
|
||||
if reward.is_zero() {
|
||||
return Err(ContractError::NoRewardsToClaim {
|
||||
identity: bond.identity().to_string(),
|
||||
address: owner.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
let return_tokens = BankMsg::Send {
|
||||
to_address: proxy.as_ref().unwrap_or(&owner).to_string(),
|
||||
amount: coins(reward.u128(), DENOM),
|
||||
};
|
||||
|
||||
let mut response = Response::default()
|
||||
.add_message(return_tokens)
|
||||
.add_event(new_claim_operator_reward_event(&owner, reward));
|
||||
|
||||
if let Some(proxy) = proxy {
|
||||
let msg = Some(VestingContractExecuteMsg::TrackReward {
|
||||
address: owner.to_string(),
|
||||
amount: Coin::new(reward.u128(), DENOM),
|
||||
});
|
||||
|
||||
let wasm_msg = wasm_execute(proxy, &msg, vec![one_ucoin()])?;
|
||||
response = response.add_message(wasm_msg);
|
||||
}
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
pub fn _try_claim_delegator_reward(
|
||||
storage: &mut dyn Storage,
|
||||
api: &dyn Api,
|
||||
env: &Env,
|
||||
owner: &str,
|
||||
mix_identity: &str,
|
||||
proxy: Option<Addr>,
|
||||
) -> Result<Response, ContractError> {
|
||||
let owner = api.addr_validate(owner)?;
|
||||
|
||||
let key = mixnet_contract_common::delegation::generate_storage_key(&owner, proxy.as_ref());
|
||||
let reward = calculate_delegator_reward(storage, api, key.clone(), mix_identity)?;
|
||||
|
||||
DELEGATOR_REWARD_CLAIMED_HEIGHT.save(
|
||||
storage,
|
||||
(key, mix_identity.to_string()),
|
||||
&env.block.height,
|
||||
)?;
|
||||
|
||||
if reward.is_zero() {
|
||||
return Err(ContractError::NoRewardsToClaim {
|
||||
identity: mix_identity.to_string(),
|
||||
address: owner.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
let return_tokens = BankMsg::Send {
|
||||
to_address: proxy.as_ref().unwrap_or(&owner).to_string(),
|
||||
amount: coins(reward.u128(), DENOM),
|
||||
};
|
||||
|
||||
let mut response =
|
||||
Response::default()
|
||||
.add_message(return_tokens)
|
||||
.add_event(new_claim_delegator_reward_event(
|
||||
&owner,
|
||||
&proxy,
|
||||
reward,
|
||||
mix_identity,
|
||||
));
|
||||
|
||||
if let Some(proxy) = proxy {
|
||||
let msg = Some(VestingContractExecuteMsg::TrackReward {
|
||||
address: owner.to_string(),
|
||||
amount: Coin::new(reward.u128(), DENOM),
|
||||
});
|
||||
|
||||
let wasm_msg = wasm_execute(proxy, &msg, vec![one_ucoin()])?;
|
||||
response = response.add_message(wasm_msg);
|
||||
}
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
pub fn try_claim_delegator_reward_on_behalf(
|
||||
deps: DepsMut<'_>,
|
||||
env: &Env,
|
||||
info: &MessageInfo,
|
||||
owner: String,
|
||||
mix_identity: &str,
|
||||
) -> Result<Response, ContractError> {
|
||||
_try_claim_delegator_reward(
|
||||
deps.storage,
|
||||
deps.api,
|
||||
env,
|
||||
&owner,
|
||||
mix_identity,
|
||||
Some(info.sender.clone()),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn try_claim_delegator_reward(
|
||||
deps: DepsMut<'_>,
|
||||
env: &Env,
|
||||
info: &MessageInfo,
|
||||
mix_identity: &str,
|
||||
) -> Result<Response, ContractError> {
|
||||
_try_claim_delegator_reward(
|
||||
deps.storage,
|
||||
deps.api,
|
||||
env,
|
||||
&info.sender.to_string(),
|
||||
mix_identity,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn try_compound_operator_reward_on_behalf(
|
||||
deps: DepsMut,
|
||||
|
||||
@@ -13,7 +13,8 @@ use mixnet_contract_common::{Gateway, IdentityKey, MixNode};
|
||||
use vesting_contract_common::events::{
|
||||
new_ownership_transfer_event, new_periodic_vesting_account_event,
|
||||
new_staking_address_update_event, new_track_gateway_unbond_event,
|
||||
new_track_mixnode_unbond_event, new_track_undelegation_event, new_vested_coins_withdraw_event,
|
||||
new_track_mixnode_unbond_event, new_track_reward_event, new_track_undelegation_event,
|
||||
new_vested_coins_withdraw_event,
|
||||
};
|
||||
use vesting_contract_common::messages::{
|
||||
ExecuteMsg, InitMsg, MigrateMsg, QueryMsg, VestingSpecification,
|
||||
@@ -46,6 +47,13 @@ pub fn execute(
|
||||
msg: ExecuteMsg,
|
||||
) -> Result<Response, ContractError> {
|
||||
match msg {
|
||||
ExecuteMsg::TrackReward { amount, address } => {
|
||||
try_track_reward(deps, info, amount, &address)
|
||||
}
|
||||
ExecuteMsg::ClaimOperatorReward {} => try_claim_operator_reward(deps, info),
|
||||
ExecuteMsg::ClaimDelegatorReward { mix_identity } => {
|
||||
try_claim_delegator_reward(deps, info, mix_identity)
|
||||
}
|
||||
ExecuteMsg::CompoundDelegatorReward { mix_identity } => {
|
||||
try_compound_delegator_reward(mix_identity, info, deps)
|
||||
}
|
||||
@@ -278,6 +286,20 @@ pub fn try_track_unbond_mixnode(
|
||||
Ok(Response::new().add_event(new_track_mixnode_unbond_event()))
|
||||
}
|
||||
|
||||
fn try_track_reward(
|
||||
deps: DepsMut<'_>,
|
||||
info: MessageInfo,
|
||||
amount: Coin,
|
||||
address: &str,
|
||||
) -> Result<Response, ContractError> {
|
||||
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)?;
|
||||
account.track_reward(amount, deps.storage)?;
|
||||
Ok(Response::new().add_event(new_track_reward_event()))
|
||||
}
|
||||
|
||||
fn try_track_undelegation(
|
||||
address: &str,
|
||||
mix_identity: IdentityKey,
|
||||
@@ -314,6 +336,23 @@ fn try_compound_delegator_reward(
|
||||
account.try_compound_delegator_reward(mix_identity, deps.storage)
|
||||
}
|
||||
|
||||
fn try_claim_operator_reward(
|
||||
deps: DepsMut<'_>,
|
||||
info: MessageInfo,
|
||||
) -> Result<Response, ContractError> {
|
||||
let account = account_from_address(info.sender.as_str(), deps.storage, deps.api)?;
|
||||
account.try_claim_operator_reward(deps.storage)
|
||||
}
|
||||
|
||||
fn try_claim_delegator_reward(
|
||||
deps: DepsMut<'_>,
|
||||
info: MessageInfo,
|
||||
mix_identity: String,
|
||||
) -> Result<Response, ContractError> {
|
||||
let account = account_from_address(info.sender.as_str(), deps.storage, deps.api)?;
|
||||
account.try_claim_delegator_reward(mix_identity, deps.storage)
|
||||
}
|
||||
|
||||
fn try_undelegate_from_mixnode(
|
||||
mix_identity: IdentityKey,
|
||||
info: MessageInfo,
|
||||
|
||||
@@ -8,6 +8,8 @@ pub trait MixnodeBondingAccount {
|
||||
storage: &dyn Storage,
|
||||
) -> Result<Response, ContractError>;
|
||||
|
||||
fn try_claim_operator_reward(&self, storage: &dyn Storage) -> Result<Response, ContractError>;
|
||||
|
||||
fn try_bond_mixnode(
|
||||
&self,
|
||||
mix_node: MixNode,
|
||||
|
||||
@@ -3,6 +3,12 @@ use cosmwasm_std::{Coin, Env, Response, Storage, Uint128};
|
||||
use mixnet_contract_common::IdentityKey;
|
||||
|
||||
pub trait DelegatingAccount {
|
||||
fn try_claim_delegator_reward(
|
||||
&self,
|
||||
mix_identity: IdentityKey,
|
||||
storage: &dyn Storage,
|
||||
) -> Result<Response, ContractError>;
|
||||
|
||||
fn try_compound_delegator_reward(
|
||||
&self,
|
||||
mix_identity: IdentityKey,
|
||||
|
||||
@@ -73,4 +73,5 @@ pub trait VestingAccount {
|
||||
to_address: Option<Addr>,
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<(), ContractError>;
|
||||
fn track_reward(&self, amount: Coin, storage: &mut dyn Storage) -> Result<(), ContractError>;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,25 @@ use vesting_contract_common::one_ucoin;
|
||||
use super::Account;
|
||||
|
||||
impl DelegatingAccount for Account {
|
||||
fn try_claim_delegator_reward(
|
||||
&self,
|
||||
mix_identity: IdentityKey,
|
||||
storage: &dyn Storage,
|
||||
) -> Result<Response, ContractError> {
|
||||
let msg = MixnetExecuteMsg::ClaimDelegatorRewardOnBehalf {
|
||||
owner: self.owner_address().to_string(),
|
||||
mix_identity,
|
||||
};
|
||||
|
||||
let compound_delegator_reward_msg = wasm_execute(
|
||||
MIXNET_CONTRACT_ADDRESS.load(storage)?,
|
||||
&msg,
|
||||
vec![one_ucoin()],
|
||||
)?;
|
||||
|
||||
Ok(Response::new().add_message(compound_delegator_reward_msg))
|
||||
}
|
||||
|
||||
fn try_compound_delegator_reward(
|
||||
&self,
|
||||
mix_identity: IdentityKey,
|
||||
|
||||
@@ -14,6 +14,20 @@ use vesting_contract_common::PledgeData;
|
||||
use super::Account;
|
||||
|
||||
impl MixnodeBondingAccount for Account {
|
||||
fn try_claim_operator_reward(&self, storage: &dyn Storage) -> Result<Response, ContractError> {
|
||||
let msg = MixnetExecuteMsg::ClaimOperatorRewardOnBehalf {
|
||||
owner: self.owner_address().into_string(),
|
||||
};
|
||||
|
||||
let compound_operator_reward_msg = wasm_execute(
|
||||
MIXNET_CONTRACT_ADDRESS.load(storage)?,
|
||||
&msg,
|
||||
vec![one_ucoin()],
|
||||
)?;
|
||||
|
||||
Ok(Response::new().add_message(compound_operator_reward_msg))
|
||||
}
|
||||
|
||||
fn try_compound_operator_reward(
|
||||
&self,
|
||||
storage: &dyn Storage,
|
||||
|
||||
@@ -8,6 +8,13 @@ use vesting_contract_common::{OriginalVestingResponse, Period};
|
||||
use super::Account;
|
||||
|
||||
impl VestingAccount for Account {
|
||||
fn track_reward(&self, amount: Coin, storage: &mut dyn Storage) -> Result<(), ContractError> {
|
||||
let current_balance = self.load_balance(storage)?;
|
||||
let new_balance = current_balance + amount.amount;
|
||||
self.save_balance(new_balance, storage)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn locked_coins(
|
||||
&self,
|
||||
block_time: Option<Timestamp>,
|
||||
|
||||
Reference in New Issue
Block a user