Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions prdoc/pr_7959.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
title: Update expire date on treasury payout
doc:
- audience: Runtime Dev
description: |-
Resets the `payout.expire_at` field with the `PayoutPeriod` every time that there is a valid Payout attempt.
Prior to this change, when a spend is approved, it receives an expiry date so that if it’s never claimed, it automatically expires. This makes sense under normal circumstances. However, if someone attempts to claim a valid payout and there isn’t sufficient liquidity to fulfill it, the expiry date currently remains unchanged. This effectively penalizes the claimant in the same way as if they had never requested the payout in the first place.
With this change users are not penalized for liquidity shortages and have a fair window to claim once the funds are available.
crates:
- name: pallet-treasury
bump: patch
1 change: 1 addition & 0 deletions substrate/frame/treasury/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,7 @@ pub mod pallet {
.map_err(|_| Error::<T, I>::PayoutError)?;

spend.status = PaymentState::Attempted { id };
spend.expire_at = now.saturating_add(T::PayoutPeriod::get());
Spends::<T, I>::insert(index, spend);

Self::deposit_event(Event::<T, I>::Paid { index, payment_id: id });
Expand Down
29 changes: 29 additions & 0 deletions substrate/frame/treasury/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,35 @@ fn spend_payout_works() {
});
}

#[test]
fn payout_extends_expiry() {
ExtBuilder::default().build().execute_with(|| {
assert_eq!(<Test as Config>::PayoutPeriod::get(), 5);

System::set_block_number(1);
assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None));
// Fail a payout at block 4
System::set_block_number(4);
assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 0));
assert_eq!(paid(6, 1), 2);
let payment_id = get_payment_id(0).expect("no payment attempt");
// spend payment is failed
set_status(payment_id, PaymentStatus::Failure);
unpay(6, 1, 2);

// check status to set the correct state
assert_ok!(Treasury::check_status(RuntimeOrigin::signed(1), 0));
System::assert_last_event(Event::<Test, _>::PaymentFailed { index: 0, payment_id }.into());

// Retrying at after the initial expiry date but before the new one succeeds
System::set_block_number(7);

// the payout can be retried now
assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 0));
assert_eq!(paid(6, 1), 2);
});
}

#[test]
fn payout_retry_works() {
ExtBuilder::default().build().execute_with(|| {
Expand Down
Loading