Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pallet assets-vesting #7404

Open
wants to merge 29 commits into
base: master
Choose a base branch
from

Conversation

pandres95
Copy link
Contributor

Fixes #4090.

Description

The pallet-assets-vesting is a pallet that supports handling vesting of an instances of pallet-assets through freezing fungibles.

The behaviour is analog to what already exists with pallet-vesting, with small differences (like adding an asset parameter where the AssetId goes on every call). Also, WithdrawalReasons are no longer used, since they're related to Currency.

Integration

This pallet can be integrated into any runtime that already has an instance of pallet-assets and pallet-assets-freezer.

The instance must be the same as the one that pallets mentioned above use.

type AssetsInstance = pallet_assets::Instance1;

#[derive_impl(pallet_assets::config_preludes::ParachainDefaultConfig)]
impl pallet_assets::Config<AssetsInstance> for Test {
	type Currency = Balances;
	type ForceOrigin = EnsureRoot<AccountId>;
	type CreateOrigin = EnsureSigned<AccountId>;
	type Freezer = AssetsFreezer;
}

impl pallet_assets_freezer::Config<AssetsInstance> for Runtime {
	type RuntimeFreezeReason = RuntimeFreezeReason;
	type RuntimeEvent = RuntimeEvent;
}

impl pallet_assets_vesting::Config<AssetsInstance> for Test {
	type RuntimeEvent = RuntimeEvent;
	type ForceOrigin = EnsureRoot<AccountId>;
	type Assets = Assets;
	type Freezer = AssetsFreezer;
	type BlockNumberToBalance = Identity;
	type RuntimeFreezeReason = RuntimeFreezeReason;
	type WeightInfo = ();
	type MinVestedTransfer = MinVestedTransfer;
	type BlockNumberProvider = System;
	const MAX_VESTING_SCHEDULES: u32 = 3;
}

Checklist

  • My PR includes a detailed description as outlined in the "Description" and its two subsections above.
  • My PR follows the labeling requirements of this project (at minimum one label for T required)
    • External contributors: ask maintainers to put the right label on your PR.
  • I have made corresponding changes to the documentation (if applicable)
  • I have added tests that prove my fix is effective or that my feature works (if applicable)

@pandres95 pandres95 requested a review from a team as a code owner January 31, 2025 07:01
@pandres95 pandres95 marked this pull request as draft January 31, 2025 07:01
@pandres95 pandres95 marked this pull request as ready for review February 12, 2025 02:11
@pandres95 pandres95 force-pushed the pallet-assets-vesting branch from 45f5e13 to e04b76c Compare February 12, 2025 06:22
@pandres95 pandres95 force-pushed the pallet-assets-vesting branch 3 times, most recently from 4dee538 to 178e20f Compare February 12, 2025 16:54
@pandres95 pandres95 force-pushed the pallet-assets-vesting branch from 178e20f to 66e3103 Compare February 12, 2025 16:55
@@ -0,0 +1,16 @@
title: Bridges small nits/improvements
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
title: Bridges small nits/improvements
title: "Introduce `pallet-assets-vesting`"


/// A vesting schedule over a fungible asset class. This allows a particular currency to have
/// vesting limits applied to it.
pub trait VestingSchedule<AccountId> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see anything wrong in the trait itself, but it is very different from how other fungibles features are implemented.

fungibles is defined with Inspect and Mutate, then fungibles freeze and holds have their own Inspect and Mutate.

Here we have VestingSchedule and VestingTransfer.

I think we can merge both schedule and transfer, and then split it again but into Inspect and Mutate.

Inspect trait will bound fungibles::Inspect so that AssetId, Balance are defined their and not duplicated
Mutate will bound Inspect probably fungibles::Mutate.

Then the trait can have many method already implemented similarly to other traits like in hold. But I don't mind also no default implementation.

WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, it'd be something like fungible/fungibles::vesting::Inspect and fungible/fungibles::vesting::Mutate? Then, include the methods from VestingSchedule and VestingTransfer inside.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I think so

#[derive(DefaultNoBound)]
pub struct GenesisConfig<T: Config<I>, I: 'static = ()> {
pub vesting:
Vec<(Vec<u8>, T::AccountId, BlockNumberFor<T>, BlockNumberFor<T>, BalanceOf<T, I>)>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can have a more precise type rather than a tuple?

// Total genesis `balance` minus `liquid` equals assets frozen for vesting
let frozen = balance.saturating_sub(liquid);
let length_as_balance = T::BlockNumberToBalance::convert(length);
let per_block = frozen / length_as_balance.max(One::one());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If per_block is zero here it will trigger vesting info invalid. Maybe

Suggested change
let per_block = frozen / length_as_balance.max(One::one());
let per_block = (frozen / length_as_balance.max(One::one())).max(One::one());

Comment on lines +165 to +174
let vesting_info = VestingInfo::new(frozen, per_block, begin);
if !vesting_info.is_valid() {
panic!("Invalid VestingInfo params at genesis")
};

Vesting::<T, I>::try_append(asset.clone(), who, vesting_info)
.expect("Too many vesting schedules at genesis.");

T::Freezer::set_freeze(asset, &FreezeReason::<I>::Vesting.into(), who, frozen)
.expect("Too many freezes at genesis");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of curiosity, would add_versing_schedule work? it would be simpler than manually adding the schedule.

/// - `starting_block`: `MAX(schedule1.starting_block, scheduled2.starting_block,
/// current_block)`.
/// - `ending_block`: `MAX(schedule1.ending_block, schedule2.ending_block)`.
/// - `locked`: `schedule1.locked_at(current_block) + schedule2.locked_at(current_block)`.
Copy link
Contributor

@gui1117 gui1117 Mar 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't it disadvantageous to merge if 1 or 2 schedule are future?
all the unlock from the earlier to the later is postponed to after later?

Hmm something seems wrong, if I have 2 identical vesting schedule, and I merge them I get a new vesting schedule that double the frozen amount.

AFAICT it is never advantageous to merge schedules, in any circumstances no? Do I miss something, why do have this feature to merge schedules?

EDIT: maybe we don't need this merge, we can just have vesting without merging vesting schedules.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm… good question! It was already in the Currency version (pallet-vesting), so I just moved it here to keep compatibility. Maybe we don't really need it, but there might be use cases that already take advantage from it. Not sure whether those assumptions would hold.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, let's keep it as it is, but let's add in the doc of the call that the resulting vesting is always disadvantageous to the caller, and the only advantage is to reduce the number of vesting schedule in storage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add vestedTransfer for Assets on Asset Hub
2 participants