#fee #pallet #bonding #facilitate #token #management #operations

no-std pallet-proxy-bonding

A FRAME pallet that facilitates token bonding operations with fee management capabilities

1 unstable release

new 0.9.0-beta.0 Jan 13, 2025

#166 in Magic Beans

Custom license and GPL-3.0-only

88KB
810 lines

Proxy Bonding Pallet

A FRAME pallet that facilitates token bonding operations with fee management capabilities. This pallet allows users to bond tokens from a configurable account (we call Treasury) while paying fees in various assets. This pallet is intended to be used as an alternative to a direct bonding mechanism. In this way, the user does not need to own or hold the tokens, but can still participate in various activities by paying a fee.

Overview

The Bonding Pallet provides functionality to:

  • Bond treasury tokens on behalf of users
  • Pay a bonding fee in different assets (e.g., DOT)
  • Set the bond release to either immediate refund or time-locked release

Features

Token Bonding

  • Bond tokens from a treasury account into sub-accounts
  • Support for existential deposit management
  • Hold-based bonding mechanism using runtime-defined hold reasons

Fee Management

  • Accept fees in configurable assets (e.g., DOT)
  • Calculate fees based on bond amount and current token prices
  • Support both fee refunds and fee transfers to recipients
  • Percentage-based fee calculation in USD terms

Release Mechanisms

Two types of release mechanisms are supported:

  • Immediate refund: Bonds can be immediately returned to treasury, and fees await refunding to users.
  • Time-locked release: Bonds are locked until a specific block number, and fees can be sent to the configured fee recipient.

Extrinsics

  • transfer_bonds_back_to_treasury: Transfer bonded tokens back to the treasury when release conditions are met.
  • transfer_fees_to_recipient: Transfer collected fees to the designated fee recipient.

Public Functions

  • calculate_fee: Calculate the fee amount in the specified fee asset based on the bond amount.
  • get_bonding_account: Get the sub-account used for bonding based on a u32.
  • bond_on_behalf_of: Bond tokens from the treasury into a sub-account on behalf of a user.
  • set_release_type: Set the release type for a given derivation path and hold reason.
  • refund_fee: Refund the fee to the specified account (only if the release is set to Refunded).

Example Configuration (Similar on how it's configured on the Polimec Runtime)

parameter_types! {
	// Fee is defined as 1.5% of the USD Amount. Since fee is applied to the PLMC amount, and that is always 5 times
	// less than the usd_amount (multiplier of 5), we multiply the 1.5 by 5 to get 7.5%
	pub FeePercentage: Perbill = Perbill::from_rational(75u32, 1000u32);
	pub FeeRecipient: AccountId =  AccountId::from(hex_literal::hex!("3ea952b5fa77f4c67698e79fe2d023a764a41aae409a83991b7a7bdd9b74ab56"));
	pub RootId: PalletId = PalletId(*b"treasury");
}

impl pallet_proxy_bonding::Config for Runtime {
	type BondingToken = Balances; // The Balances pallet is used for the bonding token
	type BondingTokenDecimals = ConstU8<10>; // The PLMC token has 10 decimals
	type BondingTokenId = ConstU32<X>; // TODO: Replace with a proper number and explanation.
	type FeePercentage = FeePercentage; // The fee kept by the treasury
	type FeeRecipient = FeeRecipient; // THe account that receives the fee
	type FeeToken = ForeignAssets; // The Asset pallet is used for the fee token
	type Id = PalletId; // The ID type used for the ... account
	type PriceProvider = OraclePriceProvider<AssetId, Price, Oracle>; // The Oracle pallet is used for the price provider
	type RootId = TreasuryId; // The treasury account ID
	type Treasury = TreasuryAccount; // The treasury account
	type UsdDecimals = ConstU8<X>; // TODO: Replace with a proper number and explanation.
	type RuntimeEvent = RuntimeEvent;
	type RuntimeHoldReason = RuntimeHoldReason;
}

Example integration

The Proxy Bonding Pallet work seamlessly with the Funding Pallet to handle OTM (One-Token-Model) participation modes in project funding. Here's how the integration works:

Funding Pallet Flow

  1. When a user contributes to a project using OTM mode:
  • The Funding Pallet calls bond_on_behalf_of with:
  • Project ID as the derivation path
  • User's account
  • PLMC bond amount
  • Funding asset ID
  • Participation hold reason
  1. During project settlement phase:
  • For successful projects:
  • An OTM release type is set with a time-lock based on the multiplier
  • Bonds remain locked until the vesting duration completes
  • For failed projects:
  • Release type is set to Refunded
  • Allows immediate return of bonds to treasury
  • Enables fee refunds to participants

Key Integration

// In Funding Pallet
pub fn bond_plmc_with_mode(
	who: &T::AccountId,
	project_id: ProjectId,
	amount: Balance,
	mode: ParticipationMode,
	asset: AcceptedFundingAsset,
) -> DispatchResult {
	match mode {
		ParticipationMode::OTM => pallet_proxy_bonding::Pallet::<T>::bond_on_behalf_of(
			project_id,
			who.clone(),
			amount,
			asset.id(),
			HoldReason::Participation.into(),
		),
		ParticipationMode::Classic(_) => // ... other handling
	}
}

Settlement Process

The settlement process determines the release conditions for bonded tokens:

  • Success: Tokens remain locked with a time-based release schedule
  • Failure: Tokens are marked for immediate return to treasury with fee refunds

License

License: GPL-3.0

Dependencies

~22–37MB
~604K SLoC