Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Bounties #5715

Merged
116 commits merged into from
Sep 18, 2020
Merged
Changes from 2 commits
Commits
Show all changes
116 commits
Select commit Hold shift + click to select a range
1f31ad9
add some compact annotation
xlc Apr 21, 2020
f3e7230
implement bounties for treasury
xlc Apr 21, 2020
8c16d4f
fix test build
xlc Apr 22, 2020
3efc22a
remove some duplicated code
xlc Apr 22, 2020
817770d
fix build
xlc Apr 22, 2020
a1b30c1
add tests
xlc Apr 22, 2020
5fce0d8
Merge remote-tracking branch 'origin/master' into bounty
xlc Apr 22, 2020
d143080
fix build
xlc Apr 22, 2020
3f5d446
Merge remote-tracking branch 'origin/master' into bounty
xlc Apr 23, 2020
829dc20
fix tests
xlc Apr 23, 2020
b4f86f1
Merge branch 'master' into bounty
xlc May 20, 2020
45b7717
rename
xlc May 20, 2020
d079500
merge deposit byte fee
xlc May 20, 2020
ce0bc02
add comments
xlc May 20, 2020
19f3bc3
Merge branch 'master' into bounty
xlc May 28, 2020
2e9697e
refactor storage
xlc May 28, 2020
92e8050
Merge remote-tracking branch 'origin/master' into bounty
xlc Jun 6, 2020
a5c26bb
support sub bounty
xlc Jun 6, 2020
18c9bab
emit BountyBecameActive when sub bounty is created
xlc Jun 6, 2020
e7fa5e3
able to contribute bounty
xlc Jun 6, 2020
4968e3b
allow curator to cancel bounty
xlc Jun 7, 2020
ee57848
remove bounty contribution
xlc Jun 8, 2020
0fb4ff2
implement bounty expiry
xlc Jun 8, 2020
f9901a0
Able to extend bounty
xlc Jun 8, 2020
8129646
Merge remote-tracking branch 'origin/master' into bounty
xlc Jun 21, 2020
d58794c
fix build and update tests
xlc Jun 21, 2020
d432a7a
create sub bounty test
xlc Jun 21, 2020
8141f62
add more tests
xlc Jun 21, 2020
4b1ea01
Merge remote-tracking branch 'origin/master' into bounty
xlc Jun 25, 2020
a63680c
add benchmarks for bounties
xlc Jun 28, 2020
ecb3893
Merge remote-tracking branch 'origin/master' into bounty
xlc Jun 28, 2020
b1d8d2f
fix build
xlc Jun 28, 2020
749c66b
Merge branch 'master' into bounty
xlc Jun 29, 2020
b6786e8
line width
xlc Jul 1, 2020
88c2046
fix benchmarking test
xlc Jul 1, 2020
fbc12f0
Merge remote-tracking branch 'origin/master' into bounty
xlc Jul 1, 2020
e174c98
update trait
xlc Jul 1, 2020
697c1e3
fix typo
xlc Jul 5, 2020
1bd7fc0
Merge remote-tracking branch 'origin/master' into bounty
xlc Jul 5, 2020
e1e01ee
Update lib.rs
Jul 6, 2020
afe301b
Merge remote-tracking branch 'origin/master' into bounty
xlc Jul 7, 2020
24f58bf
Merge pull request #1 from rrtti/patch-1
xlc Jul 8, 2020
dd7739b
update docs
xlc Jul 8, 2020
e8ffa3b
Merge remote-tracking branch 'origin/master' into bounty
xlc Jul 9, 2020
08065ac
add MaximumSubBountyDepth
xlc Jul 9, 2020
aacd9af
put BountyValueMinimum into storage
xlc Jul 10, 2020
c1f9900
rework bount depth
xlc Jul 11, 2020
705775d
Merge remote-tracking branch 'origin/master' into bounty
xlc Jul 14, 2020
2b8ecaa
Merge remote-tracking branch 'origin/master' into bounty
xlc Jul 21, 2020
bfae64b
split on_initialize benchmarks
shawntabrizi Jul 21, 2020
d605cb0
remove components from constant functions
shawntabrizi Jul 21, 2020
e175bc0
Update weight integration into treasury
shawntabrizi Jul 21, 2020
2ff28ee
Update reject proposal read/writes
shawntabrizi Jul 21, 2020
6a0cc13
fix weight calculation
xlc Jul 21, 2020
c222128
Ignore weights with 0 factor
shawntabrizi Jul 21, 2020
a5c897e
Remove 0 multipliers
shawntabrizi Jul 21, 2020
be92d1f
Merge remote-tracking branch 'origin/master' into bounty
xlc Jul 27, 2020
4441cdc
add some docs
xlc Jul 27, 2020
5927720
allow unused for generated code
xlc Jul 27, 2020
4b6f6e7
line width
xlc Jul 27, 2020
8a73200
allow RejectOrigin to cancel a pending payout bounty
xlc Jul 29, 2020
2ecd9f3
require BountyValueMinimum > ED
xlc Jul 29, 2020
06a305e
make BountyValueMinimum configurable by chain spec
xlc Jul 29, 2020
e86b63d
Merge remote-tracking branch 'origin/master' into bounty
xlc Aug 3, 2020
72a7a4c
remove sub-bounty features
xlc Aug 4, 2020
3c1a020
update curator
xlc Aug 4, 2020
dc8b295
accept curator
xlc Aug 7, 2020
e9b34be
unassign and cancel
xlc Aug 9, 2020
14b758a
fix tests
xlc Aug 9, 2020
ef05e56
new tests
xlc Aug 10, 2020
c32c3ca
Merge remote-tracking branch 'origin/master' into bounty
xlc Aug 10, 2020
9f87045
Update lib.rs
Aug 10, 2020
901b915
fix test
xlc Aug 10, 2020
af3931a
Merge remote-tracking branch 'origin/master' into bounty
xlc Aug 10, 2020
e3798eb
Merge pull request #4 from rrtti/patch-2
xlc Aug 10, 2020
6f40541
update extend_bounty_expiry
xlc Aug 11, 2020
6a14ec0
fix benchmarking
xlc Aug 11, 2020
3012300
add new benchmarking code
xlc Aug 11, 2020
343eb1c
add docs
xlc Aug 11, 2020
f724898
fix tests
xlc Aug 11, 2020
1f0c809
Update benchmarking.rs
shawntabrizi Aug 11, 2020
664f6e8
Make BountyValueMinimum a trait config instead of stroage value
xlc Aug 11, 2020
571059a
fix runtime build
xlc Aug 11, 2020
858a838
Update weights
shawntabrizi Aug 11, 2020
be0967e
Merge branch 'bounty' of https://github.com/laminar-protocol/substrat…
shawntabrizi Aug 12, 2020
e4dd5ff
Update default_weights.rs
shawntabrizi Aug 12, 2020
c2ee191
update weights
shawntabrizi Aug 12, 2020
a2e6306
update
xlc Aug 12, 2020
c49981c
update comments
xlc Aug 16, 2020
465aaf3
unreserve curator fee
xlc Aug 16, 2020
2d2b1a4
update tests
xlc Aug 16, 2020
363bdec
update benchmarks
xlc Aug 18, 2020
7482e59
fix curator deposit handling
xlc Aug 18, 2020
ca54bfc
Merge remote-tracking branch 'origin/master' into bounty
xlc Aug 18, 2020
58ce671
trigger CI
xlc Aug 18, 2020
31491d3
fix benchmarking
xlc Aug 19, 2020
a81e017
use append instead of mutate push
xlc Aug 19, 2020
e0d0daf
additional noop tests
shawntabrizi Aug 19, 2020
1dec474
improve fee hanlding. update event docs
xlc Aug 19, 2020
27cd80c
RejectOrigin to unassign
xlc Aug 19, 2020
85baba7
update bounty cancel logic
xlc Aug 19, 2020
05478ba
use Zero::zero() over 0.into()
xlc Aug 23, 2020
8033517
Merge remote-tracking branch 'origin/master' into bounty
xlc Aug 23, 2020
c70d864
fix tests
xlc Aug 23, 2020
76657c7
Merge remote-tracking branch 'origin/master' into bounty
xlc Sep 9, 2020
0db424e
Merge branch 'master' into bounty
xlc Sep 16, 2020
54d0bbc
fix benchmarks
xlc Sep 16, 2020
3795109
proposed fixes to bounties
shawntabrizi Sep 17, 2020
e833a53
fix tests
shawntabrizi Sep 17, 2020
e6f95c6
fix benchmarks
shawntabrizi Sep 17, 2020
0982f46
update weightinfo
shawntabrizi Sep 17, 2020
784a69a
use closure
shawntabrizi Sep 17, 2020
f645aca
Merge pull request #5 from paritytech/shawntabrizi-bounty-fixes
xlc Sep 17, 2020
7372444
fix compile
shawntabrizi Sep 18, 2020
8015965
update weights
shawntabrizi Sep 18, 2020
bb2a86f
Merge branch 'master' into pr/5715
shawntabrizi Sep 18, 2020
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
243 changes: 238 additions & 5 deletions frame/treasury/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
//! countdown period, the median of all declared tips is paid to the reported beneficiary, along
//! with any finders fee, in case of a public (and bonded) original report.
//!
//! ### Bounty
//!
//! TODO
//!
//! ### Terminology
//!
//! - **Proposal:** A suggestion to allocate funds from the pot to a beneficiary.
Expand All @@ -63,6 +67,9 @@
//! - **Finders Fee:** Some proportion of the tip amount that is paid to the reporter of the tip,
//! rather than the main beneficiary.
//!
//! Bounty:
//! - TODO
//!
//! ## Interface
//!
//! ### Dispatchable Functions
Expand All @@ -81,6 +88,9 @@
//! - `tip` - Declare or redeclare an amount to tip for a particular reason.
//! - `close_tip` - Close and pay out a tip.
//!
//! Bounty protocol:
//! - TODO
//!
//! ## GenesisConfig
//!
//! The Treasury module depends on the [`GenesisConfig`](./struct.GenesisConfig.html).
Expand All @@ -92,7 +102,7 @@ use serde::{Serialize, Deserialize};
use sp_std::prelude::*;
use frame_support::{decl_module, decl_storage, decl_event, ensure, print, decl_error, Parameter};
use frame_support::traits::{
Currency, Get, Imbalance, OnUnbalanced, ExistenceRequirement::KeepAlive,
Currency, Get, Imbalance, OnUnbalanced, ExistenceRequirement::{KeepAlive, AllowDeath},
ReservableCurrency, WithdrawReason
};
use sp_runtime::{Permill, ModuleId, Percent, RuntimeDebug, traits::{
Expand All @@ -113,6 +123,9 @@ type NegativeImbalanceOf<T> = <<T as Trait>::Currency as Currency<<T as frame_sy
/// The treasury's module id, used for deriving its sovereign account ID.
const MODULE_ID: ModuleId = ModuleId(*b"py/trsry");

/// Maximum acceptable reason length.
const MAX_SENSIBLE_REASON_LENGTH: usize = 16384;

xlc marked this conversation as resolved.
Show resolved Hide resolved
pub trait Trait: frame_system::Trait {
/// The staking balance.
type Currency: Currency<Self::AccountId> + ReservableCurrency<Self::AccountId>;
Expand Down Expand Up @@ -156,6 +169,15 @@ pub trait Trait: frame_system::Trait {

/// Percentage of spare funds (if any) that are burnt per spend period.
type Burn: Get<Permill>;

/// The amount held on deposit for placing a bounty proposal.
type BountyDepositBase: Get<BalanceOf<Self>>;

/// The amount held on deposit per byte within bounty description.
type BountyDepositPerByte: Get<BalanceOf<Self>>;
xlc marked this conversation as resolved.
Show resolved Hide resolved

/// The delay period for which a bounty beneficiary need to wait before claim the payout.
type BountyDepositPayoutDelay: Get<Self::BlockNumber>;
}

/// An index of a proposal. Just a `u32`.
Expand Down Expand Up @@ -198,6 +220,32 @@ pub struct OpenTip<
tips: Vec<(AccountId, Balance)>,
}

/// An index of a bounty. Just a `u32`.
pub type BountyIndex = u32;

/// A bounty proposal.
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
pub struct Bounty<AccountId, Balance> {
/// The account proposing it.
proposer: AccountId,
/// The account manages this bounty.
curator: AccountId,
/// The (total) amount that should be paid if the bounty is rewarded.
value: Balance,
/// The amount held on deposit (reserved) for making this proposal.
bond: Balance,
/// The description of this bounty.
description: Vec<u8>,
xlc marked this conversation as resolved.
Show resolved Hide resolved
}

#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
pub enum BountyStatus {
Proposed,
xlc marked this conversation as resolved.
Show resolved Hide resolved
Approved,
Active,
PendingPayout,
}

decl_storage! {
trait Store for Module<T: Trait> as Treasury {
/// Number of proposals that have been made.
Expand All @@ -221,6 +269,25 @@ decl_storage! {
/// Simple preimage lookup from the reason's hash to the original data. Again, has an
/// insecure enumerable hash since the key is guaranteed to be the result of a secure hash.
pub Reasons get(fn reasons): map hasher(identity) T::Hash => Option<Vec<u8>>;

/// Number of bounty proposals that have been made.
pub BountyCount get(fn bounty_count): BountyIndex;

/// Bounties that have been made.
xlc marked this conversation as resolved.
Show resolved Hide resolved
pub Bounties get(fn bounties):
map hasher(twox_64_concat) BountyIndex
=> Option<Bounty<T::AccountId, BalanceOf<T>>>;

/// The status of each bounty.
pub BountyStatuses get(fn bounty_statuses):
map hasher(twox_64_concat) BountyIndex => Option<BountyStatus>;

/// The bounty beneficiary and the block the fund can be claimed
pub BountyBeneficiary get(fn bounty_beneficiary):
map hasher(twox_64_concat) BountyIndex => Option<(T::AccountId, T::BlockNumber)>;

/// Bounty indices that have been approved but not yet funded.
pub BountyApprovals get(fn bounty_approvals): Vec<BountyIndex>;
xlc marked this conversation as resolved.
Show resolved Hide resolved
}
add_extra_genesis {
build(|_config| {
Expand Down Expand Up @@ -262,6 +329,16 @@ decl_event!(
TipClosed(Hash, AccountId, Balance),
/// A tip suggestion has been retracted.
TipRetracted(Hash),
/// New bounty proposal.
BountyProposed(BountyIndex),
/// A bounty proposal was rejected; funds were slashed.
BountyRejected(BountyIndex, Balance),
/// A bounty proposal is funded and become active.
xlc marked this conversation as resolved.
Show resolved Hide resolved
BountyBecomeActive(BountyIndex),
xlc marked this conversation as resolved.
Show resolved Hide resolved
/// A bounty is awarded to a beneficiary.
BountyAwarded(BountyIndex, AccountId),
/// A bounty is claimed by beneficiary.
BountyClaimed(BountyIndex, Balance, AccountId),
}
);

Expand All @@ -284,6 +361,10 @@ decl_error! {
StillOpen,
/// The tip cannot be claimed/closed because it's still in the countdown period.
Premature,
/// The bounty status is unexpected.
UnexpectedStatus,
/// Require bounty curator.
RequireCurator,
}
}

Expand Down Expand Up @@ -314,6 +395,15 @@ decl_module! {
/// The amount held on deposit per byte within the tip report reason.
const TipReportDepositPerByte: BalanceOf<T> = T::TipReportDepositPerByte::get();

/// The amount held on deposit for placing a bounty proposal.
const BountyDepositBase: BalanceOf<T> = T::BountyDepositBase::get();

/// The amount held on deposit per byte within bounty description.
const BountyDepositPerByte: BalanceOf<T> = T::BountyDepositPerByte::get();

/// The delay period for which a bounty beneficiary need to wait before claim the payout.
const BountyDepositPayoutDelay: T::BlockNumber = T::BountyDepositPayoutDelay::get();

type Error = Error<T>;

fn deposit_event() = default;
Expand Down Expand Up @@ -409,7 +499,6 @@ decl_module! {
fn report_awesome(origin, reason: Vec<u8>, who: T::AccountId) {
let finder = ensure_signed(origin)?;

const MAX_SENSIBLE_REASON_LENGTH: usize = 16384;
ensure!(reason.len() <= MAX_SENSIBLE_REASON_LENGTH, Error::<T>::ReasonTooBig);

let reason_hash = T::Hashing::hash(&reason[..]);
Expand Down Expand Up @@ -480,7 +569,7 @@ decl_module! {
/// - One event.
/// # </weight>
#[weight = SimpleDispatchInfo::FixedNormal(150_000_000)]
fn tip_new(origin, reason: Vec<u8>, who: T::AccountId, tip_value: BalanceOf<T>) {
fn tip_new(origin, reason: Vec<u8>, who: T::AccountId, #[compact] tip_value: BalanceOf<T>) {
let tipper = ensure_signed(origin)?;
ensure!(T::Tippers::contains(&tipper), BadOrigin);
let reason_hash = T::Hashing::hash(&reason[..]);
Expand Down Expand Up @@ -514,7 +603,7 @@ decl_module! {
/// - Up to one event.
/// # </weight>
#[weight = SimpleDispatchInfo::FixedNormal(50_000_000)]
fn tip(origin, hash: T::Hash, tip_value: BalanceOf<T>) {
fn tip(origin, hash: T::Hash, #[compact] tip_value: BalanceOf<T>) {
let tipper = ensure_signed(origin)?;
ensure!(T::Tippers::contains(&tipper), BadOrigin);

Expand Down Expand Up @@ -552,6 +641,118 @@ decl_module! {
Self::payout_tip(hash, tip);
}

#[weight = SimpleDispatchInfo::FixedNormal(150_000_000)]
fn propose_bounty(
origin,
curator: <T::Lookup as StaticLookup>::Source,
#[compact] value: BalanceOf<T>,
description: Vec<u8>,
) {
let proposer = ensure_signed(origin)?;
let curator = T::Lookup::lookup(curator)?;

ensure!(description.len() <= MAX_SENSIBLE_REASON_LENGTH, Error::<T>::ReasonTooBig);

let bond = T::BountyDepositBase::get()
+ T::BountyDepositPerByte::get() * (description.len() as u32).into();
T::Currency::reserve(&proposer, bond)
.map_err(|_| Error::<T>::InsufficientProposersBalance)?;

let index = Self::bounty_count();
BountyCount::put(index + 1);

let bounty = Bounty {
proposer, curator, value, bond, description
};

Bounties::<T>::insert(index, &bounty);
BountyStatuses::insert(index, BountyStatus::Proposed);

Self::deposit_event(RawEvent::BountyProposed(index));
}

/// Reject a bounty proposal. The original deposit will be slashed.
///
/// # <weight>
/// - O(1).
/// - Limited storage reads.
/// - Two DB clear.
/// # </weight>
#[weight = SimpleDispatchInfo::FixedOperational(100_000_000)]
fn reject_bounty(origin, #[compact] bounty_id: BountyIndex) {
T::RejectOrigin::try_origin(origin)
.map(|_| ())
.or_else(ensure_root)?;

ensure!(Self::bounty_statuses(bounty_id) == Some(BountyStatus::Proposed), Error::<T>::UnexpectedStatus);
let bounty = <Bounties<T>>::take(&bounty_id).ok_or(Error::<T>::InvalidProposalIndex)?;

BountyStatuses::remove(bounty_id);

let value = bounty.bond;
let imbalance = T::Currency::slash_reserved(&bounty.proposer, value).0;
T::ProposalRejection::on_unbalanced(imbalance);

Self::deposit_event(Event::<T>::BountyRejected(bounty_id, value));
}

/// Approve a bounty proposal. At a later time, the bounty will be funded and become active
/// and the original deposit will be returned.
///
/// # <weight>
/// - O(1).
/// - Limited storage reads.
/// - One DB change.
/// # </weight>
#[weight = SimpleDispatchInfo::FixedOperational(100_000_000)]
fn approve_bounty(origin, #[compact] bounty_id: ProposalIndex) {
T::ApproveOrigin::try_origin(origin)
.map(|_| ())
.or_else(ensure_root)?;

ensure!(<Bounties<T>>::contains_key(bounty_id), Error::<T>::InvalidProposalIndex);
ensure!(Self::bounty_statuses(bounty_id) == Some(BountyStatus::Proposed), Error::<T>::UnexpectedStatus);
BountyStatuses::insert(bounty_id, BountyStatus::Approved);
}

#[weight = SimpleDispatchInfo::FixedOperational(100_000_000)]
fn award_bounty(origin, #[compact] bounty_id: ProposalIndex, beneficiary: <T::Lookup as StaticLookup>::Source) {
shawntabrizi marked this conversation as resolved.
Show resolved Hide resolved
let curator = ensure_signed(origin)?;
let beneficiary = T::Lookup::lookup(beneficiary)?;

ensure!(Self::bounty_statuses(bounty_id) == Some(BountyStatus::Active), Error::<T>::UnexpectedStatus);

let bounty = Self::bounties(bounty_id).ok_or(Error::<T>::InvalidProposalIndex)?;
ensure!(bounty.curator == curator, Error::<T>::RequireCurator);

BountyStatuses::insert(bounty_id, BountyStatus::PendingPayout);
BountyBeneficiary::<T>::insert(bounty_id, (&beneficiary, system::Module::<T>::block_number() + T::BountyDepositPayoutDelay::get()));

Bounties::<T>::remove(bounty_id); // no longer needed

Self::deposit_event(Event::<T>::BountyAwarded(bounty_id, beneficiary));
}

#[weight = SimpleDispatchInfo::FixedOperational(100_000_000)]
fn claim_bounty(origin, #[compact] bounty_id: ProposalIndex) {
let _ = ensure_signed(origin)?;

ensure!(Self::bounty_statuses(bounty_id) == Some(BountyStatus::PendingPayout), Error::<T>::UnexpectedStatus);
let (beneficiary, released) = Self::bounty_beneficiary(bounty_id)
.ok_or(Error::<T>::InvalidProposalIndex)?; // this should not fail

ensure!(system::Module::<T>::block_number() >= released, Error::<T>::Premature);

let bounty_account = Self::bounty_account_id(bounty_id);
let balance = T::Currency::free_balance(&bounty_account);
let _ = T::Currency::transfer(&bounty_account, &beneficiary, balance, AllowDeath); // should not fail

BountyStatuses::remove(bounty_id);
BountyBeneficiary::<T>::remove(bounty_id);

Self::deposit_event(Event::<T>::BountyClaimed(bounty_id, balance, beneficiary));
}

fn on_initialize(n: T::BlockNumber) -> Weight {
// Check to see if we should spend some funds!
if (n % T::SpendPeriod::get()).is_zero() {
Expand All @@ -574,6 +775,11 @@ impl<T: Trait> Module<T> {
MODULE_ID.into_account()
}

/// The account ID of a bounty account
pub fn bounty_account_id(id: BountyIndex) -> T::AccountId {
MODULE_ID.into_sub_account(("bounty", id))
}

/// The needed bond for a proposal whose spend is `value`.
fn calculate_bond(value: BalanceOf<T>) -> BalanceOf<T> {
T::ProposalBondMinimum::get().max(T::ProposalBond::get() * value)
Expand Down Expand Up @@ -654,6 +860,7 @@ impl<T: Trait> Module<T> {
fn spend_funds() {
let mut budget_remaining = Self::pot();
Self::deposit_event(RawEvent::Spending(budget_remaining));
let account_id = Self::account_id();

let mut missed_any = false;
let mut imbalance = <PositiveImbalanceOf<T>>::zero();
Expand Down Expand Up @@ -683,6 +890,32 @@ impl<T: Trait> Module<T> {
});
});

BountyApprovals::mutate(|v| {
v.retain(|&index| {
// Should always be true, but shouldn't panic if false or we're screwed.
if let Some(bounty) = Self::bounties(index) {
if bounty.value <= budget_remaining {
budget_remaining -= bounty.value;
BountyStatuses::insert(index, BountyStatus::Active);

// return their deposit.
let _ = T::Currency::unreserve(&bounty.proposer, bounty.bond);

// fund the bounty account
imbalance.subsume(T::Currency::deposit_creating(&Self::bounty_account_id(index), bounty.value));

Self::deposit_event(RawEvent::BountyBecomeActive(index));
false
} else {
missed_any = true;
true
}
} else {
false
}
});
});

if !missed_any {
// burn some proportion of the remaining budget if we run a surplus.
let burn = (T::Burn::get() * budget_remaining).min(budget_remaining);
Expand All @@ -696,7 +929,7 @@ impl<T: Trait> Module<T> {
// Thus we can't spend more than account free balance minus ED;
// Thus account is kept alive; qed;
if let Err(problem) = T::Currency::settle(
&Self::account_id(),
&account_id,
imbalance,
WithdrawReason::Transfer.into(),
KeepAlive
Expand Down