Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Docs for Pay by Swap #14445

Merged
merged 4 commits into from
Jun 23, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 47 additions & 18 deletions frame/asset-conversion/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,7 @@ pub mod pallet {
}

#[pallet::error]
pub enum Error<T>
{
pub enum Error<T> {
/// Provided assets are equal.
EqualAssets,
/// Pool already exists.
Expand Down Expand Up @@ -351,6 +350,8 @@ pub mod pallet {
PathError,
/// The provided path must consists of unique assets.
NonUniquePath,
/// No corresponding element in `amounts`.
AmountsError,
}

/// Pallet's callable functions.
Expand Down Expand Up @@ -695,6 +696,7 @@ pub mod pallet {
}

impl<T: Config> Pallet<T> {
/// Transfer an `amount` of `asset_id`, respecting the `keep_alive` requirements.
fn transfer(
asset_id: &T::MultiAssetId,
from: &T::AccountId,
Expand All @@ -713,8 +715,13 @@ pub mod pallet {
true => Preserve,
false => Expendable,
};
let amount = Self::asset_to_native(amount)?;
Ok(Self::native_to_asset(T::Currency::transfer(from, to, amount, preservation)?)?)
let amount = Self::convert_asset_balance_to_native_balance(amount)?;
Ok(Self::convert_native_balance_to_asset_balance(T::Currency::transfer(
from,
to,
amount,
preservation,
)?)?)
} else {
T::Assets::transfer(
T::MultiAssetIdConverter::try_convert(&asset_id)
Expand All @@ -727,18 +734,25 @@ pub mod pallet {
}
}

pub(crate) fn native_to_asset(amount: T::Balance) -> Result<T::AssetBalance, Error<T>> {
/// Convert a `Balance` type to an `AssetBalance`.
pub(crate) fn convert_native_balance_to_asset_balance(
amount: T::Balance,
) -> Result<T::AssetBalance, Error<T>> {
T::HigherPrecisionBalance::from(amount)
.try_into()
.map_err(|_| Error::<T>::Overflow)
}

pub(crate) fn asset_to_native(amount: T::AssetBalance) -> Result<T::Balance, Error<T>> {
/// Convert an `AssetBalance` type to a `Balance`.
pub(crate) fn convert_asset_balance_to_native_balance(
amount: T::AssetBalance,
) -> Result<T::Balance, Error<T>> {
T::HigherPrecisionBalance::from(amount)
.try_into()
.map_err(|_| Error::<T>::Overflow)
}

/// Swap assets along a `path`, depositing in `send_to`.
pub(crate) fn do_swap(
sender: &T::AccountId,
amounts: &Vec<T::AssetBalance>,
Expand All @@ -749,7 +763,8 @@ pub mod pallet {
if let Some([asset1, asset2]) = path.get(0..2) {
let pool_id = Self::get_pool_id(asset1.clone(), asset2.clone());
let pool_account = Self::get_pool_account(&pool_id);
let first_amount = amounts.first().expect("Always has more than one element");
// amounts should always a corresponding element to path.
let first_amount = amounts.first().ok_or(Error::<T>::AmountsError)?;

Self::transfer(asset1, sender, &pool_account, *first_amount, keep_alive)?;

Expand Down Expand Up @@ -797,14 +812,16 @@ pub mod pallet {
.expect("infinite length input; no invalid inputs for type; qed")
}

/// Get the `owner`'s balance of `asset`, which could be the chain's native asset or another
/// fungible. Returns a value in the form of an `AssetBalance`.
fn get_balance(
owner: &T::AccountId,
asset: &T::MultiAssetId,
) -> Result<T::AssetBalance, Error<T>> {
if T::MultiAssetIdConverter::is_native(asset) {
Self::native_to_asset(<<T as Config>::Currency>::reducible_balance(
owner, Expendable, Polite,
))
Self::convert_native_balance_to_asset_balance(
<<T as Config>::Currency>::reducible_balance(owner, Expendable, Polite),
)
} else {
Ok(<<T as Config>::Assets>::reducible_balance(
T::MultiAssetIdConverter::try_convert(asset)
Expand Down Expand Up @@ -845,6 +862,7 @@ pub mod pallet {
Ok((balance1, balance2))
}

/// Leading to an amount at the end of a `path`, get the required amounts in.
pub(crate) fn get_amounts_in(
amount_out: &T::AssetBalance,
path: &BoundedVec<T::MultiAssetId, T::MaxSwapPathLength>,
Expand All @@ -864,6 +882,7 @@ pub mod pallet {
Ok(amounts)
}

/// Following an amount into a `path`, get the corresponding amounts out.
pub(crate) fn get_amounts_out(
amount_in: &T::AssetBalance,
path: &BoundedVec<T::MultiAssetId, T::MaxSwapPathLength>,
Expand Down Expand Up @@ -973,10 +992,10 @@ pub mod pallet {
result.try_into().map_err(|_| Error::<T>::Overflow)
}

/// Calculates amount out
/// Calculates amount out.
///
/// Given an input amount of an asset and pair reserves, returns the maximum output amount
/// of the other asset
/// of the other asset.
pub fn get_amount_out(
amount_in: &T::AssetBalance,
reserve_in: &T::AssetBalance,
Expand Down Expand Up @@ -1008,10 +1027,10 @@ pub mod pallet {
result.try_into().map_err(|_| Error::<T>::Overflow)
}

/// Calculates amount in
/// Calculates amount in.
///
/// Given an output amount of an asset and pair reserves, returns a required input amount
/// of the other asset
/// of the other asset.
pub fn get_amount_in(
amount_out: &T::AssetBalance,
reserve_in: &T::AssetBalance,
Expand Down Expand Up @@ -1050,6 +1069,7 @@ pub mod pallet {
result.try_into().map_err(|_| Error::<T>::Overflow)
}

/// Ensure that a `value` meets the minimum balance requirements of an `asset` class.
fn validate_minimal_amount(
value: T::AssetBalance,
asset: &T::MultiAssetId,
Expand All @@ -1068,6 +1088,7 @@ pub mod pallet {
Ok(())
}

/// Ensure that a path is valid.
fn validate_swap_path(
path: &BoundedVec<T::MultiAssetId, T::MaxSwapPathLength>,
) -> Result<(), DispatchError> {
Expand Down Expand Up @@ -1107,7 +1128,11 @@ where
<T as pallet::Config>::Currency:
frame_support::traits::tokens::fungible::Inspect<<T as frame_system::Config>::AccountId>,
{
// If successful returns the amount in.
/// Take an `asset_id` and swap some amount for `amount_out` of the chain's native asset. If an
/// `amount_in_max` is specified, it will return an error if acquiring `amount_out` would be
/// too costly.
///
/// If successful returns the amount of the `asset_id` taken to provide `amount_out`.
fn swap_tokens_for_exact_native(
sender: T::AccountId,
asset_id: T::AssetId,
Expand All @@ -1126,7 +1151,7 @@ where
let path = path.try_into().unwrap();

// convert `amount_out` from native balance type, to asset balance type
let amount_out = Self::native_to_asset(amount_out)?;
let amount_out = Self::convert_native_balance_to_asset_balance(amount_out)?;

// calculate the amount we need to provide
let amounts = Self::get_amounts_in(&amount_out, &path)?;
Expand All @@ -1148,7 +1173,11 @@ where
Ok(amount_in)
}

// If successful returns the amount out.
/// Take an `asset_id` and swap `amount_in` of the chain's native asset for it. If an
/// `amount_out_min` is specified, it will return an error if it is unable to acquire the amount
/// desired.
///
/// If successful, returns the amount of `asset_id` acquired for the `amount_in`.
fn swap_exact_native_for_tokens(
sender: T::AccountId,
asset_id: T::AssetId,
Expand All @@ -1167,7 +1196,7 @@ where
let path = path.try_into().expect("MaxSwapPathLength must be greater than 1");

// convert `amount_in` from native balance type, to asset balance type
let amount_in = Self::native_to_asset(amount_in)?;
let amount_in = Self::convert_native_balance_to_asset_balance(amount_in)?;

// calculate the amount we should receive
let amounts = Self::get_amounts_out(&amount_in, &path)?;
Expand Down
14 changes: 10 additions & 4 deletions frame/support/src/traits/tokens/fungibles/regular.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,10 +584,13 @@ pub trait Balanced<AccountId>: Inspect<AccountId> + Unbalanced<AccountId> {
fn done_withdraw(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {}
}

/// Trait for providing methods to swap the native token to an asset and back.
/// Trait for providing methods to swap between the chain's native token and other asset classes.
pub trait SwapNative<Origin, AccountId, Balance, AssetBalance, AssetId> {
/// Swaps the provided amount of the `asset_id` into exact amount of native.
/// If successful, returns the amount of `asset_id` consumed to provide `amount_out`.
/// Take an `asset_id` and swap some amount for `amount_out` of the chain's native asset. If an
/// `amount_in_max` is specified, it will return an error if acquiring `amount_out` would be
/// too costly.
///
/// If successful returns the amount of the `asset_id` taken to provide `amount_out`.
fn swap_tokens_for_exact_native(
sender: AccountId,
asset_id: AssetId,
Expand All @@ -597,7 +600,10 @@ pub trait SwapNative<Origin, AccountId, Balance, AssetBalance, AssetId> {
keep_alive: bool,
) -> Result<AssetBalance, DispatchError>;

/// Swaps the provided exact amount of the native currency into the amount of `asset_id`.
/// Take an `asset_id` and swap `amount_in` of the chain's native asset for it. If an
/// `amount_out_min` is specified, it will return an error if it is unable to acquire the amount
/// desired.
///
/// If successful, returns the amount of `asset_id` acquired for the `amount_in`.
fn swap_exact_native_for_tokens(
sender: AccountId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2021"
license = "Apache-2.0"
homepage = "https://substrate.io"
repository = "https://github.com/paritytech/substrate/"
description = "Pallet to manage transaction payments in assets by utilising the assets conversion pallet"
description = "Pallet to manage transaction payments in assets by converting them to native assets."
readme = "README.md"

[package.metadata.docs.rs]
Expand Down
35 changes: 20 additions & 15 deletions frame/transaction-payment/asset-conversion-tx-payment/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,26 @@
//! chain's native asset.
//!
//! ## Overview

//!
//! This pallet provides a `SignedExtension` with an optional `AssetId` that specifies the asset
//! to be used for payment (defaulting to the native token on `None`). It expects an
//! [`OnChargeAssetTransaction`] implementation analogous to [`pallet-transaction-payment`]. The
//! included [`AssetConversionAdapter`] (implementing [`OnChargeAssetTransaction`]) determines the
//! fee amount by converting the fee calculated by [`pallet-transaction-payment`] in the native
//! asset into the amount required of the specified asset.
//!
//! ## Integration

//! This pallet wraps FRAME's Transaction Payment pallet and functions as a replacement. This means
//! you should include both pallets in your `construct_runtime` macro, but only include this
//! pallet's [`SignedExtension`] ([`ChargeAssetTxPayment`]).
//! ## Pallet API
//!
//! This pallet does not have any dispatchable calls or storage. It wraps FRAME's Transaction
//! Payment pallet and functions as a replacement. This means you should include both pallets in
//! your `construct_runtime` macro, but only include this pallet's [`SignedExtension`]
//! ([`ChargeAssetTxPayment`]).
//!
//! ## Terminology
//!
//! - Native Asset or Native Currency: The asset that a chain considers native, as in its default
//! for transaction fee payment, deposits, inflation, etc.
//! - Other assets: Other assets that may exist on chain, for example under the Assets pallet.

#![cfg_attr(not(feature = "std"), no_std)]

Expand Down Expand Up @@ -67,28 +74,26 @@ pub use payment::*;
/// Type aliases used for interaction with `OnChargeTransaction`.
pub(crate) type OnChargeTransactionOf<T> =
<T as pallet_transaction_payment::Config>::OnChargeTransaction;
/// Balance type alias.
/// Balance type alias for balances of the chain's native asset.
pub(crate) type BalanceOf<T> = <OnChargeTransactionOf<T> as OnChargeTransaction<T>>::Balance;
/// Liquidity info type alias.
pub(crate) type LiquidityInfoOf<T> =
<OnChargeTransactionOf<T> as OnChargeTransaction<T>>::LiquidityInfo;

/// Type alias used for interaction with fungibles (assets).
/// Balance type alias.
/// Balance type alias for balances of assets that implement the `fungibles` trait.
pub(crate) type AssetBalanceOf<T> =
<<T as Config>::Fungibles as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
/// Asset id type alias.
/// Type alias for Asset IDs.
pub(crate) type AssetIdOf<T> =
<<T as Config>::Fungibles as Inspect<<T as frame_system::Config>::AccountId>>::AssetId;

/// Type aliases used for interaction with `OnChargeAssetTransaction`.
/// Balance type alias.
/// Type alias for the interaction of balances with `OnChargeAssetTransaction`.
pub(crate) type ChargeAssetBalanceOf<T> =
<<T as Config>::OnChargeAssetTransaction as OnChargeAssetTransaction<T>>::Balance;
/// Asset id type alias.
/// Type alias for Asset IDs in their interaction with `OnChargeAssetTransaction`.
pub(crate) type ChargeAssetIdOf<T> =
<<T as Config>::OnChargeAssetTransaction as OnChargeAssetTransaction<T>>::AssetId;
/// Liquidity info type alias.
/// Liquidity info type alias for interaction with `OnChargeAssetTransaction`.
pub(crate) type ChargeAssetLiquidityOf<T> =
<<T as Config>::OnChargeAssetTransaction as OnChargeAssetTransaction<T>>::LiquidityInfo;

Expand Down Expand Up @@ -130,7 +135,7 @@ pub mod pallet {
/// has been paid by `who` in an asset `asset_id`.
AssetTxFeePaid {
who: T::AccountId,
actual_fee: BalanceOf<T>,
actual_fee: AssetBalanceOf<T>,
tip: BalanceOf<T>,
asset_id: ChargeAssetIdOf<T>,
},
Expand Down