Skip to content

Commit 2c710e0

Browse files
committed
PoS: allow to set a receiver target for claim reward tx
1 parent 060bf3c commit 2c710e0

File tree

8 files changed

+124
-58
lines changed

8 files changed

+124
-58
lines changed

crates/node/src/shell/finalize_block.rs

Lines changed: 59 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2444,15 +2444,18 @@ mod test_finalize_block {
24442444
.unwrap();
24452445

24462446
// Claim the rewards from the initial epoch
2447-
let reward_1 =
2448-
proof_of_stake::claim_reward_tokens::<
2449-
_,
2450-
governance::Store<_>,
2451-
token::Store<_>,
2452-
>(
2453-
&mut shell.state, None, &validator.address, current_epoch
2454-
)
2455-
.unwrap();
2447+
let reward_1 = proof_of_stake::claim_reward_tokens::<
2448+
_,
2449+
governance::Store<_>,
2450+
token::Store<_>,
2451+
>(
2452+
&mut shell.state,
2453+
None,
2454+
&validator.address,
2455+
None,
2456+
current_epoch,
2457+
)
2458+
.unwrap();
24562459
total_claimed += reward_1;
24572460
assert_eq!(reward_1, query_rewards);
24582461
assert!(is_reward_equal_enough(total_rewards, total_claimed, 1));
@@ -2481,7 +2484,11 @@ mod test_finalize_block {
24812484
governance::Store<_>,
24822485
token::Store<_>,
24832486
>(
2484-
&mut shell.state, None, &validator.address, current_epoch
2487+
&mut shell.state,
2488+
None,
2489+
&validator.address,
2490+
None,
2491+
current_epoch,
24852492
)
24862493
.unwrap();
24872494
assert_eq!(att, token::Amount::zero());
@@ -2520,7 +2527,11 @@ mod test_finalize_block {
25202527
governance::Store<_>,
25212528
token::Store<_>,
25222529
>(
2523-
&mut shell.state, None, &validator.address, current_epoch
2530+
&mut shell.state,
2531+
None,
2532+
&validator.address,
2533+
None,
2534+
current_epoch,
25242535
)
25252536
.unwrap();
25262537
total_claimed += rew;
@@ -2601,15 +2612,18 @@ mod test_finalize_block {
26012612
.unwrap();
26022613

26032614
// Claim tokens
2604-
let reward_2 =
2605-
proof_of_stake::claim_reward_tokens::<
2606-
_,
2607-
governance::Store<_>,
2608-
token::Store<_>,
2609-
>(
2610-
&mut shell.state, None, &validator.address, current_epoch
2611-
)
2612-
.unwrap();
2615+
let reward_2 = proof_of_stake::claim_reward_tokens::<
2616+
_,
2617+
governance::Store<_>,
2618+
token::Store<_>,
2619+
>(
2620+
&mut shell.state,
2621+
None,
2622+
&validator.address,
2623+
None,
2624+
current_epoch,
2625+
)
2626+
.unwrap();
26132627
total_claimed += reward_2;
26142628
assert_eq!(query_rewards, reward_2);
26152629

@@ -2730,15 +2744,18 @@ mod test_finalize_block {
27302744
}
27312745

27322746
// Claim the rewards for the validator for the first two epochs
2733-
let val_reward_1 =
2734-
proof_of_stake::claim_reward_tokens::<
2735-
_,
2736-
governance::Store<_>,
2737-
token::Store<_>,
2738-
>(
2739-
&mut shell.state, None, &validator.address, current_epoch
2740-
)
2741-
.unwrap();
2747+
let val_reward_1 = proof_of_stake::claim_reward_tokens::<
2748+
_,
2749+
governance::Store<_>,
2750+
token::Store<_>,
2751+
>(
2752+
&mut shell.state,
2753+
None,
2754+
&validator.address,
2755+
None,
2756+
current_epoch,
2757+
)
2758+
.unwrap();
27422759
total_claimed += val_reward_1;
27432760
assert!(is_reward_equal_enough(
27442761
total_rewards,
@@ -2758,15 +2775,18 @@ mod test_finalize_block {
27582775
total_rewards += inflation_3;
27592776

27602777
// Claim again for the validator
2761-
let val_reward_2 =
2762-
proof_of_stake::claim_reward_tokens::<
2763-
_,
2764-
governance::Store<_>,
2765-
token::Store<_>,
2766-
>(
2767-
&mut shell.state, None, &validator.address, current_epoch
2768-
)
2769-
.unwrap();
2778+
let val_reward_2 = proof_of_stake::claim_reward_tokens::<
2779+
_,
2780+
governance::Store<_>,
2781+
token::Store<_>,
2782+
>(
2783+
&mut shell.state,
2784+
None,
2785+
&validator.address,
2786+
None,
2787+
current_epoch,
2788+
)
2789+
.unwrap();
27702790

27712791
// Claim for the delegator
27722792
let del_reward_1 = proof_of_stake::claim_reward_tokens::<
@@ -2777,6 +2797,7 @@ mod test_finalize_block {
27772797
&mut shell.state,
27782798
Some(&delegator),
27792799
&validator.address,
2800+
None,
27802801
current_epoch,
27812802
)
27822803
.unwrap();

crates/proof_of_stake/src/lib.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2805,6 +2805,7 @@ pub fn claim_reward_tokens<S, Gov, Token>(
28052805
storage: &mut S,
28062806
source: Option<&Address>,
28072807
validator: &Address,
2808+
receiver: Option<&Address>,
28082809
current_epoch: Epoch,
28092810
) -> Result<token::Amount>
28102811
where
@@ -2814,8 +2815,14 @@ where
28142815
{
28152816
tracing::debug!("Claiming rewards in epoch {current_epoch}");
28162817

2817-
let source = source.cloned().unwrap_or_else(|| validator.clone());
2818-
tracing::debug!("Source {} --> Validator {}", source, validator);
2818+
let source = source.unwrap_or(validator).clone();
2819+
let receiver = receiver.unwrap_or(&source).clone();
2820+
tracing::debug!(
2821+
"Source {} --> Validator {}, Receiver {}",
2822+
source,
2823+
validator,
2824+
receiver
2825+
);
28192826

28202827
let mut reward_tokens = compute_current_rewards_from_bonds::<S, Gov>(
28212828
storage,
@@ -2832,17 +2839,23 @@ where
28322839
// Update the last claim epoch in storage
28332840
write_last_reward_claim_epoch(storage, &source, validator, current_epoch)?;
28342841

2835-
// Transfer the bonded tokens from PoS to the source
2842+
// Transfer the bonded tokens from PoS to the receiver
28362843
let staking_token = staking_token_address(storage);
2837-
Token::transfer(storage, &staking_token, &ADDRESS, &source, reward_tokens)?;
2844+
Token::transfer(
2845+
storage,
2846+
&staking_token,
2847+
&ADDRESS,
2848+
&receiver,
2849+
reward_tokens,
2850+
)?;
28382851
Token::emit_transfer_event(
28392852
storage,
28402853
CLAIM_REWARDS_EVENT_DESC.into(),
28412854
trans_token::EventLevel::Tx,
28422855
&staking_token,
28432856
reward_tokens,
28442857
trans_token::UserAccount::Internal(ADDRESS),
2845-
trans_token::UserAccount::Internal(source),
2858+
trans_token::UserAccount::Internal(receiver),
28462859
)?;
28472860

28482861
Ok(reward_tokens)

crates/sdk/src/queries/vp/pos.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,14 +1248,15 @@ mod test {
12481248
.expect("Test failed");
12491249
client.state.in_mem_mut().block.height = height + 1;
12501250

1251-
let claimed = namada_proof_of_stake::claim_reward_tokens::<
1252-
_,
1253-
governance::Store<_>,
1254-
namada_token::Store<_>,
1255-
>(
1256-
&mut client.state, Some(&delegator), &validator, epoch
1257-
)
1258-
.expect("Claiming rewards failed");
1251+
let claimed =
1252+
namada_proof_of_stake::claim_reward_tokens::<
1253+
_,
1254+
governance::Store<_>,
1255+
namada_token::Store<_>,
1256+
>(
1257+
&mut client.state, Some(&delegator), &validator, None, epoch
1258+
)
1259+
.expect("Claiming rewards failed");
12591260

12601261
assert_eq!(claimed, del_reward_epoch_3 + del_reward_epoch_2);
12611262

@@ -1264,7 +1265,7 @@ mod test {
12641265
_,
12651266
governance::Store<_>,
12661267
namada_token::Store<_>,
1267-
>(&mut client.state, None, &validator, epoch)
1268+
>(&mut client.state, None, &validator, None, epoch)
12681269
.expect("Claiming validator rewards failed");
12691270

12701271
assert_eq!(claimed_validator, val_reward_epoch_3 + val_reward_epoch_2);

crates/sdk/src/tx.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1757,7 +1757,7 @@ pub async fn build_claim_rewards(
17571757
None => Ok(source.clone()),
17581758
}?;
17591759

1760-
let data = pos::ClaimRewards { validator, source };
1760+
let data = pos::ClaimRewardsCompat { validator, source };
17611761

17621762
build(
17631763
context,

crates/tx/src/action.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use namada_core::storage::KeySeg;
1515
use namada_core::{address, storage};
1616

1717
pub use crate::data::pos::{
18-
Bond, ClaimRewards, Redelegation, Unbond, Withdraw,
18+
Bond, ClaimRewardsCompat as ClaimRewards, Redelegation, Unbond, Withdraw,
1919
};
2020

2121
/// Actions applied from txs.

crates/tx/src/data/pos.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,23 @@ pub struct ClaimRewards {
128128
/// Source address for claiming rewards from a bond. For self-bonds, the
129129
/// validator is also the source
130130
pub source: Option<Address>,
131+
/// Optional rewards receiver address
132+
pub receiver: Option<Address>,
133+
}
134+
135+
/// Compatibility data definition from previous version (before addition of a
136+
/// receiver field).
137+
///
138+
/// TODO: Temporarily replaces `crate::data::pos::ClaimRewards` that now
139+
/// contains an additional `receiver` field to maintain consensus compatibility.
140+
/// PoS VP reads this action and will need to be updated to use the new field.
141+
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, PartialEq)]
142+
pub struct ClaimRewardsCompat {
143+
/// Validator address
144+
pub validator: Address,
145+
/// Source address for claiming rewards from a bond. For self-bonds, the
146+
/// validator is also the source
147+
pub source: Option<Address>,
131148
}
132149

133150
/// A redelegation of bonded tokens from one validator to another.

crates/tx_prelude/src/proof_of_stake.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ impl Ctx {
203203
&mut self,
204204
source: Option<&Address>,
205205
validator: &Address,
206+
receiver: Option<&Address>,
206207
) -> Result<token::Amount> {
207208
// The tx must be authorized by the source address
208209
let verifier = source.as_ref().unwrap_or(&validator);
@@ -218,6 +219,7 @@ impl Ctx {
218219
self,
219220
source,
220221
validator,
222+
receiver,
221223
current_epoch,
222224
)
223225
}

wasm/tx_claim_rewards/src/lib.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,27 @@
11
//! A tx for a user to claim PoS inflationary rewards due to bonds used as
22
//! voting power in consensus.
33
4+
use namada_tx_prelude::transaction::pos;
45
use namada_tx_prelude::*;
56

67
#[transaction]
78
fn apply_tx(ctx: &mut Ctx, tx_data: BatchedTx) -> TxResult {
89
let data = ctx.get_tx_data(&tx_data)?;
9-
let withdraw = transaction::pos::Withdraw::try_from_slice(&data[..])
10-
.wrap_err("Failed to decode Withdraw value")?;
11-
12-
ctx.claim_reward_tokens(withdraw.source.as_ref(), &withdraw.validator)
10+
let (validator, source, receiver) = if let Ok(pos::ClaimRewards {
11+
validator,
12+
source,
13+
receiver,
14+
}) =
15+
pos::ClaimRewards::try_from_slice(&data[..])
16+
{
17+
(validator, source, receiver)
18+
} else {
19+
let pos::ClaimRewardsCompat { validator, source } =
20+
pos::ClaimRewardsCompat::try_from_slice(&data[..])
21+
.wrap_err("Failed to decode ClaimRewards value")?;
22+
(validator, source, None)
23+
};
24+
ctx.claim_reward_tokens(source.as_ref(), &validator, receiver.as_ref())
1325
.wrap_err("Failed to claim rewards")?;
1426

1527
Ok(())

0 commit comments

Comments
 (0)