Skip to content

Commit 2689733

Browse files
gui1117github-actions[bot]acatangiu
authored
pallet-assets: make touch other permissionless (#7456)
Fix #7450 Pallet assets don't have the assumption that Admin and Freezer are trusted by the chain, so I don't see any security concern from this change. The only difference I see is that people can create more account with 0 balance for a given asset, whereas in the past only privileged role could do it (privileged from the point of view of the asset, not the chain). That said maybe this is not the actual fix we want, maybe it would be better to have accounts being able to increase their `MaxConsumers` value by adding some deposit. --------- Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Adrian Catangiu <[email protected]>
1 parent 6d64746 commit 2689733

File tree

4 files changed

+48
-24
lines changed

4 files changed

+48
-24
lines changed

prdoc/pr_7456.prdoc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
title: 'pallet-assets: make touch other permissionless'
2+
doc:
3+
- audience: Runtime User
4+
description: |-
5+
In pallet assets, make `touch_other` call permissionless. Before this PR only `Admin` and `Freezer` of an asset could touch an account, now every account can.
6+
crates:
7+
- name: pallet-assets
8+
bump: minor

substrate/frame/assets/src/functions.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -338,23 +338,15 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
338338
}
339339

340340
/// Creates an account for `who` to hold asset `id` with a zero balance and takes a deposit.
341-
///
342-
/// When `check_depositor` is set to true, the depositor must be either the asset's Admin or
343-
/// Freezer, otherwise the depositor can be any account.
344341
pub(super) fn do_touch(
345342
id: T::AssetId,
346343
who: T::AccountId,
347344
depositor: T::AccountId,
348-
check_depositor: bool,
349345
) -> DispatchResult {
350346
ensure!(!Account::<T, I>::contains_key(&id, &who), Error::<T, I>::AlreadyExists);
351347
let deposit = T::AssetAccountDeposit::get();
352348
let mut details = Asset::<T, I>::get(&id).ok_or(Error::<T, I>::Unknown)?;
353349
ensure!(details.status == AssetStatus::Live, Error::<T, I>::AssetNotLive);
354-
ensure!(
355-
!check_depositor || &depositor == &details.admin || &depositor == &details.freezer,
356-
Error::<T, I>::NoPermission
357-
);
358350
let reason = Self::new_account(&who, &mut details, Some((&depositor, deposit)))?;
359351
T::Currency::reserve(&depositor, deposit)?;
360352
Asset::<T, I>::insert(&id, details);

substrate/frame/assets/src/lib.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
//! * `refund`: Return the deposit (if any) of the caller's asset account or a consumer reference
9595
//! (if any) of the caller's account.
9696
//! * `refund_other`: Return the deposit (if any) of a specified asset account.
97+
//! * `touch_other`: Create an asset account for specified account. Caller must place a deposit.
9798
//!
9899
//! ### Permissioned Functions
99100
//!
@@ -116,8 +117,6 @@
116117
//! Owner.
117118
//! * `set_metadata`: Set the metadata of an asset class; called by the asset class's Owner.
118119
//! * `clear_metadata`: Remove the metadata of an asset class; called by the asset class's Owner.
119-
//! * `touch_other`: Create an asset account for specified account. Caller must place a deposit;
120-
//! called by the asset class's Freezer or Admin.
121120
//! * `block`: Disallows further `transfer`s to and from an account; called by the asset class's
122121
//! Freezer.
123122
//!
@@ -1618,7 +1617,7 @@ pub mod pallet {
16181617
pub fn touch(origin: OriginFor<T>, id: T::AssetIdParameter) -> DispatchResult {
16191618
let who = ensure_signed(origin)?;
16201619
let id: T::AssetId = id.into();
1621-
Self::do_touch(id, who.clone(), who, false)
1620+
Self::do_touch(id, who.clone(), who)
16221621
}
16231622

16241623
/// Return the deposit (if any) of an asset account or a consumer reference (if any) of an
@@ -1695,9 +1694,10 @@ pub mod pallet {
16951694
///
16961695
/// A deposit will be taken from the signer account.
16971696
///
1698-
/// - `origin`: Must be Signed by `Freezer` or `Admin` of the asset `id`; the signer account
1699-
/// must have sufficient funds for a deposit to be taken.
1700-
/// - `id`: The identifier of the asset for the account to be created.
1697+
/// - `origin`: Must be Signed; the signer account must have sufficient funds for a deposit
1698+
/// to be taken.
1699+
/// - `id`: The identifier of the asset for the account to be created, the asset status must
1700+
/// be live.
17011701
/// - `who`: The account to be created.
17021702
///
17031703
/// Emits `Touched` event when successful.
@@ -1711,7 +1711,7 @@ pub mod pallet {
17111711
let origin = ensure_signed(origin)?;
17121712
let who = T::Lookup::lookup(who)?;
17131713
let id: T::AssetId = id.into();
1714-
Self::do_touch(id, who, origin, true)
1714+
Self::do_touch(id, who, origin)
17151715
}
17161716

17171717
/// Return the deposit (if any) of a target asset account. Useful if you are the depositor.
@@ -1823,7 +1823,6 @@ pub mod pallet {
18231823

18241824
/// Implements [`AccountTouch`] trait.
18251825
/// Note that a depositor can be any account, without any specific privilege.
1826-
/// This implementation is supposed to be used only for creation of system accounts.
18271826
impl<T: Config<I>, I: 'static> AccountTouch<T::AssetId, T::AccountId> for Pallet<T, I> {
18281827
type Balance = DepositBalanceOf<T, I>;
18291828

@@ -1846,7 +1845,7 @@ pub mod pallet {
18461845
who: &T::AccountId,
18471846
depositor: &T::AccountId,
18481847
) -> DispatchResult {
1849-
Self::do_touch(asset, who.clone(), depositor.clone(), false)
1848+
Self::do_touch(asset, who.clone(), depositor.clone())
18501849
}
18511850
}
18521851

substrate/frame/assets/src/tests.rs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,12 +1004,14 @@ fn touching_and_freezing_account_with_zero_asset_balance_should_work() {
10041004
});
10051005
}
10061006

1007+
// In the past only admin and freezer could call `touch_other`.
1008+
// Test that this behavior is still supported.
10071009
#[test]
1008-
fn touch_other_works() {
1010+
fn touch_other_works_legacy() {
10091011
new_test_ext().execute_with(|| {
10101012
// 1 will be admin
10111013
// 2 will be freezer
1012-
// 4 will be an account attempting to execute `touch_other`
1014+
// 4 will be an account successfully attempting to execute `touch_other`
10131015
Balances::make_free_balance_be(&1, 100);
10141016
Balances::make_free_balance_be(&2, 100);
10151017
Balances::make_free_balance_be(&4, 100);
@@ -1019,19 +1021,42 @@ fn touch_other_works() {
10191021
assert_eq!(Assets::balance(0, 1), 100);
10201022
// account `3` does not exist
10211023
assert!(!Account::<Test>::contains_key(0, &3));
1022-
// creation of asset account `3` by account `4` fails
1023-
assert_noop!(
1024-
Assets::touch_other(RuntimeOrigin::signed(4), 0, 3),
1025-
Error::<Test>::NoPermission
1026-
);
1024+
// creation of asset account `30` by account `4` works
1025+
assert_ok!(Assets::touch_other(RuntimeOrigin::signed(4), 0, 30));
10271026
// creation of asset account `3` by admin `1` works
10281027
assert!(!Account::<Test>::contains_key(0, &3));
10291028
assert_ok!(Assets::touch_other(RuntimeOrigin::signed(1), 0, 3));
10301029
assert!(Account::<Test>::contains_key(0, &3));
10311030
// creation of asset account `4` by freezer `2` works
10321031
assert!(!Account::<Test>::contains_key(0, &4));
10331032
assert_ok!(Assets::touch_other(RuntimeOrigin::signed(2), 0, 4));
1033+
});
1034+
}
1035+
1036+
#[test]
1037+
fn touch_other_works() {
1038+
new_test_ext().execute_with(|| {
1039+
Balances::make_free_balance_be(&3, 100);
1040+
assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1));
1041+
assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 3, 100));
1042+
assert_eq!(Assets::balance(0, 3), 100);
1043+
1044+
// account `4` does not exist
1045+
assert!(!Account::<Test>::contains_key(0, &4));
1046+
1047+
// creation of asset account `4` by funded account `3` works
1048+
assert_ok!(Assets::touch_other(RuntimeOrigin::signed(3), 0, 4));
10341049
assert!(Account::<Test>::contains_key(0, &4));
1050+
1051+
// account `6` does not exist
1052+
assert!(!Account::<Test>::contains_key(0, &6));
1053+
1054+
// creation of asset account `6` by not funded account `5` fails
1055+
assert_noop!(
1056+
Assets::touch_other(RuntimeOrigin::signed(5), 0, 6),
1057+
BalancesError::<Test>::InsufficientBalance,
1058+
);
1059+
assert!(!Account::<Test>::contains_key(0, &6));
10351060
});
10361061
}
10371062

0 commit comments

Comments
 (0)