Skip to content

Commit

Permalink
[Assets] Call implementation for transfer_all (paritytech#4527)
Browse files Browse the repository at this point in the history
Closes paritytech#4517

Polkadot address: 12gMhxHw8QjEwLQvnqsmMVY1z5gFa54vND74aMUbhhwN6mJR

---------

Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>
  • Loading branch information
2 people authored and dharjeezy committed Aug 27, 2024
1 parent bc90515 commit 356472c
Show file tree
Hide file tree
Showing 11 changed files with 205 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -531,4 +531,14 @@ impl<T: frame_system::Config> pallet_assets::WeightInfo for WeightInfo<T> {
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(1))
}

fn transfer_all() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `3593`
// Minimum execution time: 46_573_000 picoseconds.
Weight::from_parts(47_385_000, 3593)
.saturating_add(T::DbWeight::get().reads(1_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -528,4 +528,14 @@ impl<T: frame_system::Config> pallet_assets::WeightInfo for WeightInfo<T> {
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(1))
}

fn transfer_all() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `3593`
// Minimum execution time: 46_573_000 picoseconds.
Weight::from_parts(47_385_000, 3593)
.saturating_add(T::DbWeight::get().reads(1_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -528,4 +528,14 @@ impl<T: frame_system::Config> pallet_assets::WeightInfo for WeightInfo<T> {
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(1))
}

fn transfer_all() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `3593`
// Minimum execution time: 46_573_000 picoseconds.
Weight::from_parts(47_385_000, 3593)
.saturating_add(T::DbWeight::get().reads(1_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -537,4 +537,14 @@ impl<T: frame_system::Config> pallet_assets::WeightInfo for WeightInfo<T> {
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(1))
}

fn transfer_all() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `3593`
// Minimum execution time: 46_573_000 picoseconds.
Weight::from_parts(47_385_000, 3593)
.saturating_add(T::DbWeight::get().reads(1_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -535,4 +535,14 @@ impl<T: frame_system::Config> pallet_assets::WeightInfo for WeightInfo<T> {
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(1))
}

fn transfer_all() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `3593`
// Minimum execution time: 46_573_000 picoseconds.
Weight::from_parts(47_385_000, 3593)
.saturating_add(T::DbWeight::get().reads(1_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -529,4 +529,14 @@ impl<T: frame_system::Config> pallet_assets::WeightInfo for WeightInfo<T> {
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(1))
}

fn transfer_all() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `3593`
// Minimum execution time: 46_573_000 picoseconds.
Weight::from_parts(47_385_000, 3593)
.saturating_add(T::DbWeight::get().reads(1_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
}
21 changes: 21 additions & 0 deletions prdoc/pr_4527.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json

title: Call implementation for `transfer_all`

doc:
- audience: Runtime Dev
description: |
This PR introduces the `transfer_all` call for `pallet-assets`.
The parameters are analog to the same call in `pallet-balances`.
This change is expected to be backwards-compatible.
This change requires running benchmarkings to set accurate weights for
the call.

crates:
- name: pallet-assets
bump: major
- name: asset-hub-rococo-runtime
bump: minor
- name: asset-hub-westend-runtime
bump: minor
13 changes: 12 additions & 1 deletion substrate/frame/assets/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use sp_runtime::traits::Bounded;
use crate::Pallet as Assets;

const SEED: u32 = 0;
const MIN_BALANCE: u32 = 1;

fn default_asset_id<T: Config<I>, I: 'static>() -> T::AssetIdParameter {
T::BenchmarkHelper::create_asset_id_parameter(0)
Expand All @@ -48,7 +49,7 @@ fn create_default_asset<T: Config<I>, I: 'static>(
asset_id.clone(),
caller_lookup.clone(),
is_sufficient,
1u32.into(),
MIN_BALANCE.into(),
)
.is_ok());
(asset_id, caller, caller_lookup)
Expand Down Expand Up @@ -553,5 +554,15 @@ benchmarks_instance_pallet! {
assert_last_event::<T, I>(Event::Blocked { asset_id: asset_id.into(), who: caller }.into());
}

transfer_all {
let amount = T::Balance::from(2 * MIN_BALANCE);
let (asset_id, caller, caller_lookup) = create_default_minted_asset::<T, I>(true, amount);
let target: T::AccountId = account("target", 0, SEED);
let target_lookup = T::Lookup::unlookup(target.clone());
}: _(SystemOrigin::Signed(caller.clone()), asset_id.clone(), target_lookup, false)
verify {
assert_last_event::<T, I>(Event::Transferred { asset_id: asset_id.into(), from: caller, to: target, amount }.into());
}

impl_benchmark_test_suite!(Assets, crate::mock::new_test_ext(), crate::mock::Test)
}
49 changes: 48 additions & 1 deletion substrate/frame/assets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,11 @@ use frame_support::{
pallet_prelude::DispatchResultWithPostInfo,
storage::KeyPrefixIterator,
traits::{
tokens::{fungibles, DepositConsequence, WithdrawConsequence},
tokens::{
fungibles, DepositConsequence, Fortitude,
Preservation::{Expendable, Preserve},
WithdrawConsequence,
},
BalanceStatus::Reserved,
Currency, EnsureOriginWithArg, Incrementable, ReservableCurrency, StoredMap,
},
Expand Down Expand Up @@ -1753,6 +1757,49 @@ pub mod pallet {
Self::deposit_event(Event::<T, I>::Blocked { asset_id: id, who });
Ok(())
}

/// Transfer the entire transferable balance from the caller asset account.
///
/// NOTE: This function only attempts to transfer _transferable_ balances. This means that
/// any held, frozen, or minimum balance (when `keep_alive` is `true`), will not be
/// transferred by this function. To ensure that this function results in a killed account,
/// you might need to prepare the account by removing any reference counters, storage
/// deposits, etc...
///
/// The dispatch origin of this call must be Signed.
///
/// - `id`: The identifier of the asset for the account holding a deposit.
/// - `dest`: The recipient of the transfer.
/// - `keep_alive`: A boolean to determine if the `transfer_all` operation should send all
/// of the funds the asset account has, causing the sender asset account to be killed
/// (false), or transfer everything except at least the minimum balance, which will
/// guarantee to keep the sender asset account alive (true).
#[pallet::call_index(32)]
#[pallet::weight(T::WeightInfo::refund_other())]
pub fn transfer_all(
origin: OriginFor<T>,
id: T::AssetIdParameter,
dest: AccountIdLookupOf<T>,
keep_alive: bool,
) -> DispatchResult {
let transactor = ensure_signed(origin)?;
let keep_alive = if keep_alive { Preserve } else { Expendable };
let reducible_balance = <Self as fungibles::Inspect<_>>::reducible_balance(
id.clone().into(),
&transactor,
keep_alive,
Fortitude::Polite,
);
let dest = T::Lookup::lookup(dest)?;
<Self as fungibles::Mutate<_>>::transfer(
id.into(),
&transactor,
&dest,
reducible_balance,
keep_alive,
)?;
Ok(())
}
}

/// Implements [`AccountTouch`] trait.
Expand Down
43 changes: 43 additions & 0 deletions substrate/frame/assets/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,49 @@ fn transferring_to_blocked_account_should_not_work() {
});
}

#[test]
fn transfer_all_works_1() {
new_test_ext().execute_with(|| {
// setup
assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 0, true, 100));
assert_ok!(Assets::mint(RuntimeOrigin::signed(0), 0, 1, 200));
assert_ok!(Assets::mint(RuntimeOrigin::signed(0), 0, 2, 100));
// transfer all and allow death
assert_ok!(Assets::transfer_all(Some(1).into(), 0, 2, false));
assert_eq!(Assets::balance(0, &1), 0);
assert_eq!(Assets::balance(0, &2), 300);
});
}

#[test]
fn transfer_all_works_2() {
new_test_ext().execute_with(|| {
// setup
assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 0, true, 100));
assert_ok!(Assets::mint(RuntimeOrigin::signed(0), 0, 1, 200));
assert_ok!(Assets::mint(RuntimeOrigin::signed(0), 0, 2, 100));
// transfer all and allow death
assert_ok!(Assets::transfer_all(Some(1).into(), 0, 2, true));
assert_eq!(Assets::balance(0, &1), 100);
assert_eq!(Assets::balance(0, &2), 200);
});
}

#[test]
fn transfer_all_works_3() {
new_test_ext().execute_with(|| {
// setup
assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 0, true, 100));
assert_ok!(Assets::mint(RuntimeOrigin::signed(0), 0, 1, 210));
set_frozen_balance(0, 1, 10);
assert_ok!(Assets::mint(RuntimeOrigin::signed(0), 0, 2, 100));
// transfer all and allow death w/ frozen
assert_ok!(Assets::transfer_all(Some(1).into(), 0, 2, false));
assert_eq!(Assets::balance(0, &1), 110);
assert_eq!(Assets::balance(0, &2), 200);
});
}

#[test]
fn origin_guards_should_work() {
new_test_ext().execute_with(|| {
Expand Down
21 changes: 21 additions & 0 deletions substrate/frame/assets/src/weights.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 356472c

Please sign in to comment.