Skip to content

Commit 356472c

Browse files
pandres95joepetrowski
authored andcommitted
[Assets] Call implementation for transfer_all (paritytech#4527)
Closes paritytech#4517 Polkadot address: 12gMhxHw8QjEwLQvnqsmMVY1z5gFa54vND74aMUbhhwN6mJR --------- Co-authored-by: joe petrowski <[email protected]>
1 parent bc90515 commit 356472c

File tree

11 files changed

+205
-2
lines changed

11 files changed

+205
-2
lines changed

cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_foreign.rs

+10
Original file line numberDiff line numberDiff line change
@@ -531,4 +531,14 @@ impl<T: frame_system::Config> pallet_assets::WeightInfo for WeightInfo<T> {
531531
.saturating_add(T::DbWeight::get().reads(2))
532532
.saturating_add(T::DbWeight::get().writes(1))
533533
}
534+
535+
fn transfer_all() -> Weight {
536+
// Proof Size summary in bytes:
537+
// Measured: `0`
538+
// Estimated: `3593`
539+
// Minimum execution time: 46_573_000 picoseconds.
540+
Weight::from_parts(47_385_000, 3593)
541+
.saturating_add(T::DbWeight::get().reads(1_u64))
542+
.saturating_add(T::DbWeight::get().writes(1_u64))
543+
}
534544
}

cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_local.rs

+10
Original file line numberDiff line numberDiff line change
@@ -528,4 +528,14 @@ impl<T: frame_system::Config> pallet_assets::WeightInfo for WeightInfo<T> {
528528
.saturating_add(T::DbWeight::get().reads(2))
529529
.saturating_add(T::DbWeight::get().writes(1))
530530
}
531+
532+
fn transfer_all() -> Weight {
533+
// Proof Size summary in bytes:
534+
// Measured: `0`
535+
// Estimated: `3593`
536+
// Minimum execution time: 46_573_000 picoseconds.
537+
Weight::from_parts(47_385_000, 3593)
538+
.saturating_add(T::DbWeight::get().reads(1_u64))
539+
.saturating_add(T::DbWeight::get().writes(1_u64))
540+
}
531541
}

cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_pool.rs

+10
Original file line numberDiff line numberDiff line change
@@ -528,4 +528,14 @@ impl<T: frame_system::Config> pallet_assets::WeightInfo for WeightInfo<T> {
528528
.saturating_add(T::DbWeight::get().reads(2))
529529
.saturating_add(T::DbWeight::get().writes(1))
530530
}
531+
532+
fn transfer_all() -> Weight {
533+
// Proof Size summary in bytes:
534+
// Measured: `0`
535+
// Estimated: `3593`
536+
// Minimum execution time: 46_573_000 picoseconds.
537+
Weight::from_parts(47_385_000, 3593)
538+
.saturating_add(T::DbWeight::get().reads(1_u64))
539+
.saturating_add(T::DbWeight::get().writes(1_u64))
540+
}
531541
}

cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_foreign.rs

+10
Original file line numberDiff line numberDiff line change
@@ -537,4 +537,14 @@ impl<T: frame_system::Config> pallet_assets::WeightInfo for WeightInfo<T> {
537537
.saturating_add(T::DbWeight::get().reads(2))
538538
.saturating_add(T::DbWeight::get().writes(1))
539539
}
540+
541+
fn transfer_all() -> Weight {
542+
// Proof Size summary in bytes:
543+
// Measured: `0`
544+
// Estimated: `3593`
545+
// Minimum execution time: 46_573_000 picoseconds.
546+
Weight::from_parts(47_385_000, 3593)
547+
.saturating_add(T::DbWeight::get().reads(1_u64))
548+
.saturating_add(T::DbWeight::get().writes(1_u64))
549+
}
540550
}

cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_local.rs

+10
Original file line numberDiff line numberDiff line change
@@ -535,4 +535,14 @@ impl<T: frame_system::Config> pallet_assets::WeightInfo for WeightInfo<T> {
535535
.saturating_add(T::DbWeight::get().reads(2))
536536
.saturating_add(T::DbWeight::get().writes(1))
537537
}
538+
539+
fn transfer_all() -> Weight {
540+
// Proof Size summary in bytes:
541+
// Measured: `0`
542+
// Estimated: `3593`
543+
// Minimum execution time: 46_573_000 picoseconds.
544+
Weight::from_parts(47_385_000, 3593)
545+
.saturating_add(T::DbWeight::get().reads(1_u64))
546+
.saturating_add(T::DbWeight::get().writes(1_u64))
547+
}
538548
}

cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_assets_pool.rs

+10
Original file line numberDiff line numberDiff line change
@@ -529,4 +529,14 @@ impl<T: frame_system::Config> pallet_assets::WeightInfo for WeightInfo<T> {
529529
.saturating_add(T::DbWeight::get().reads(2))
530530
.saturating_add(T::DbWeight::get().writes(1))
531531
}
532+
533+
fn transfer_all() -> Weight {
534+
// Proof Size summary in bytes:
535+
// Measured: `0`
536+
// Estimated: `3593`
537+
// Minimum execution time: 46_573_000 picoseconds.
538+
Weight::from_parts(47_385_000, 3593)
539+
.saturating_add(T::DbWeight::get().reads(1_u64))
540+
.saturating_add(T::DbWeight::get().writes(1_u64))
541+
}
532542
}

prdoc/pr_4527.prdoc

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
2+
# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
3+
4+
title: Call implementation for `transfer_all`
5+
6+
doc:
7+
- audience: Runtime Dev
8+
description: |
9+
This PR introduces the `transfer_all` call for `pallet-assets`.
10+
The parameters are analog to the same call in `pallet-balances`.
11+
This change is expected to be backwards-compatible.
12+
This change requires running benchmarkings to set accurate weights for
13+
the call.
14+
15+
crates:
16+
- name: pallet-assets
17+
bump: major
18+
- name: asset-hub-rococo-runtime
19+
bump: minor
20+
- name: asset-hub-westend-runtime
21+
bump: minor

substrate/frame/assets/src/benchmarking.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use sp_runtime::traits::Bounded;
3131
use crate::Pallet as Assets;
3232

3333
const SEED: u32 = 0;
34+
const MIN_BALANCE: u32 = 1;
3435

3536
fn default_asset_id<T: Config<I>, I: 'static>() -> T::AssetIdParameter {
3637
T::BenchmarkHelper::create_asset_id_parameter(0)
@@ -48,7 +49,7 @@ fn create_default_asset<T: Config<I>, I: 'static>(
4849
asset_id.clone(),
4950
caller_lookup.clone(),
5051
is_sufficient,
51-
1u32.into(),
52+
MIN_BALANCE.into(),
5253
)
5354
.is_ok());
5455
(asset_id, caller, caller_lookup)
@@ -553,5 +554,15 @@ benchmarks_instance_pallet! {
553554
assert_last_event::<T, I>(Event::Blocked { asset_id: asset_id.into(), who: caller }.into());
554555
}
555556

557+
transfer_all {
558+
let amount = T::Balance::from(2 * MIN_BALANCE);
559+
let (asset_id, caller, caller_lookup) = create_default_minted_asset::<T, I>(true, amount);
560+
let target: T::AccountId = account("target", 0, SEED);
561+
let target_lookup = T::Lookup::unlookup(target.clone());
562+
}: _(SystemOrigin::Signed(caller.clone()), asset_id.clone(), target_lookup, false)
563+
verify {
564+
assert_last_event::<T, I>(Event::Transferred { asset_id: asset_id.into(), from: caller, to: target, amount }.into());
565+
}
566+
556567
impl_benchmark_test_suite!(Assets, crate::mock::new_test_ext(), crate::mock::Test)
557568
}

substrate/frame/assets/src/lib.rs

+48-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,11 @@ use frame_support::{
183183
pallet_prelude::DispatchResultWithPostInfo,
184184
storage::KeyPrefixIterator,
185185
traits::{
186-
tokens::{fungibles, DepositConsequence, WithdrawConsequence},
186+
tokens::{
187+
fungibles, DepositConsequence, Fortitude,
188+
Preservation::{Expendable, Preserve},
189+
WithdrawConsequence,
190+
},
187191
BalanceStatus::Reserved,
188192
Currency, EnsureOriginWithArg, Incrementable, ReservableCurrency, StoredMap,
189193
},
@@ -1753,6 +1757,49 @@ pub mod pallet {
17531757
Self::deposit_event(Event::<T, I>::Blocked { asset_id: id, who });
17541758
Ok(())
17551759
}
1760+
1761+
/// Transfer the entire transferable balance from the caller asset account.
1762+
///
1763+
/// NOTE: This function only attempts to transfer _transferable_ balances. This means that
1764+
/// any held, frozen, or minimum balance (when `keep_alive` is `true`), will not be
1765+
/// transferred by this function. To ensure that this function results in a killed account,
1766+
/// you might need to prepare the account by removing any reference counters, storage
1767+
/// deposits, etc...
1768+
///
1769+
/// The dispatch origin of this call must be Signed.
1770+
///
1771+
/// - `id`: The identifier of the asset for the account holding a deposit.
1772+
/// - `dest`: The recipient of the transfer.
1773+
/// - `keep_alive`: A boolean to determine if the `transfer_all` operation should send all
1774+
/// of the funds the asset account has, causing the sender asset account to be killed
1775+
/// (false), or transfer everything except at least the minimum balance, which will
1776+
/// guarantee to keep the sender asset account alive (true).
1777+
#[pallet::call_index(32)]
1778+
#[pallet::weight(T::WeightInfo::refund_other())]
1779+
pub fn transfer_all(
1780+
origin: OriginFor<T>,
1781+
id: T::AssetIdParameter,
1782+
dest: AccountIdLookupOf<T>,
1783+
keep_alive: bool,
1784+
) -> DispatchResult {
1785+
let transactor = ensure_signed(origin)?;
1786+
let keep_alive = if keep_alive { Preserve } else { Expendable };
1787+
let reducible_balance = <Self as fungibles::Inspect<_>>::reducible_balance(
1788+
id.clone().into(),
1789+
&transactor,
1790+
keep_alive,
1791+
Fortitude::Polite,
1792+
);
1793+
let dest = T::Lookup::lookup(dest)?;
1794+
<Self as fungibles::Mutate<_>>::transfer(
1795+
id.into(),
1796+
&transactor,
1797+
&dest,
1798+
reducible_balance,
1799+
keep_alive,
1800+
)?;
1801+
Ok(())
1802+
}
17561803
}
17571804

17581805
/// Implements [`AccountTouch`] trait.

substrate/frame/assets/src/tests.rs

+43
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,49 @@ fn transferring_to_blocked_account_should_not_work() {
799799
});
800800
}
801801

802+
#[test]
803+
fn transfer_all_works_1() {
804+
new_test_ext().execute_with(|| {
805+
// setup
806+
assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 0, true, 100));
807+
assert_ok!(Assets::mint(RuntimeOrigin::signed(0), 0, 1, 200));
808+
assert_ok!(Assets::mint(RuntimeOrigin::signed(0), 0, 2, 100));
809+
// transfer all and allow death
810+
assert_ok!(Assets::transfer_all(Some(1).into(), 0, 2, false));
811+
assert_eq!(Assets::balance(0, &1), 0);
812+
assert_eq!(Assets::balance(0, &2), 300);
813+
});
814+
}
815+
816+
#[test]
817+
fn transfer_all_works_2() {
818+
new_test_ext().execute_with(|| {
819+
// setup
820+
assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 0, true, 100));
821+
assert_ok!(Assets::mint(RuntimeOrigin::signed(0), 0, 1, 200));
822+
assert_ok!(Assets::mint(RuntimeOrigin::signed(0), 0, 2, 100));
823+
// transfer all and allow death
824+
assert_ok!(Assets::transfer_all(Some(1).into(), 0, 2, true));
825+
assert_eq!(Assets::balance(0, &1), 100);
826+
assert_eq!(Assets::balance(0, &2), 200);
827+
});
828+
}
829+
830+
#[test]
831+
fn transfer_all_works_3() {
832+
new_test_ext().execute_with(|| {
833+
// setup
834+
assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 0, true, 100));
835+
assert_ok!(Assets::mint(RuntimeOrigin::signed(0), 0, 1, 210));
836+
set_frozen_balance(0, 1, 10);
837+
assert_ok!(Assets::mint(RuntimeOrigin::signed(0), 0, 2, 100));
838+
// transfer all and allow death w/ frozen
839+
assert_ok!(Assets::transfer_all(Some(1).into(), 0, 2, false));
840+
assert_eq!(Assets::balance(0, &1), 110);
841+
assert_eq!(Assets::balance(0, &2), 200);
842+
});
843+
}
844+
802845
#[test]
803846
fn origin_guards_should_work() {
804847
new_test_ext().execute_with(|| {

substrate/frame/assets/src/weights.rs

+21
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)