referrerpolicy=no-referrer-when-downgrade

pallet_asset_conversion/
types.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18use super::*;
19use codec::{Decode, Encode, MaxEncodedLen};
20use core::marker::PhantomData;
21use scale_info::TypeInfo;
22use sp_runtime::traits::TryConvert;
23
24/// Represents a swap path with associated asset amounts indicating how much of the asset needs to
25/// be deposited to get the following asset's amount withdrawn (this is inclusive of fees).
26///
27/// Example:
28/// Given path [(asset1, amount_in), (asset2, amount_out2), (asset3, amount_out3)], can be resolved:
29/// 1. `asset(asset1, amount_in)` take from `user` and move to the pool(asset1, asset2);
30/// 2. `asset(asset2, amount_out2)` transfer from pool(asset1, asset2) to pool(asset2, asset3);
31/// 3. `asset(asset3, amount_out3)` move from pool(asset2, asset3) to `user`.
32pub type BalancePath<T> = Vec<(<T as Config>::AssetKind, <T as Config>::Balance)>;
33
34/// Credit of [Config::Assets].
35pub type CreditOf<T> = Credit<<T as frame_system::Config>::AccountId, <T as Config>::Assets>;
36
37/// Stores the lp_token asset id a particular pool has been assigned.
38#[derive(Decode, Encode, Default, PartialEq, Eq, MaxEncodedLen, TypeInfo)]
39pub struct PoolInfo<PoolAssetId> {
40	/// Liquidity pool asset
41	pub lp_token: PoolAssetId,
42}
43
44/// Provides means to resolve the `PoolId` and `AccountId` from a pair of assets.
45///
46/// Resulting `PoolId` remains consistent whether the asset pair is presented as (asset1, asset2)
47/// or (asset2, asset1). The derived `AccountId` may serve as an address for liquidity provider
48/// tokens.
49pub trait PoolLocator<AccountId, AssetKind, PoolId> {
50	/// Retrieves the account address associated with a valid `PoolId`.
51	fn address(id: &PoolId) -> Result<AccountId, ()>;
52	/// Identifies the `PoolId` for a given pair of assets.
53	///
54	/// Returns an error if the asset pair isn't supported.
55	fn pool_id(asset1: &AssetKind, asset2: &AssetKind) -> Result<PoolId, ()>;
56	/// Retrieves the account address associated with a given asset pair.
57	///
58	/// Returns an error if the asset pair isn't supported.
59	fn pool_address(asset1: &AssetKind, asset2: &AssetKind) -> Result<AccountId, ()> {
60		if let Ok(id) = Self::pool_id(asset1, asset2) {
61			Self::address(&id)
62		} else {
63			Err(())
64		}
65	}
66}
67
68/// Pool locator that mandates the inclusion of the specified `FirstAsset` in every asset pair.
69///
70/// The `PoolId` is represented as a tuple of `AssetKind`s with `FirstAsset` always positioned as
71/// the first element.
72pub struct WithFirstAsset<FirstAsset, AccountId, AssetKind, AccountIdConverter>(
73	PhantomData<(FirstAsset, AccountId, AssetKind, AccountIdConverter)>,
74);
75impl<FirstAsset, AccountId, AssetKind, AccountIdConverter>
76	PoolLocator<AccountId, AssetKind, (AssetKind, AssetKind)>
77	for WithFirstAsset<FirstAsset, AccountId, AssetKind, AccountIdConverter>
78where
79	AssetKind: Eq + Clone + Encode,
80	AccountId: Decode,
81	FirstAsset: Get<AssetKind>,
82	AccountIdConverter: for<'a> TryConvert<&'a (AssetKind, AssetKind), AccountId>,
83{
84	fn pool_id(asset1: &AssetKind, asset2: &AssetKind) -> Result<(AssetKind, AssetKind), ()> {
85		if asset1 == asset2 {
86			return Err(());
87		}
88		let first = FirstAsset::get();
89		if first == *asset1 {
90			Ok((first, asset2.clone()))
91		} else if first == *asset2 {
92			Ok((first, asset1.clone()))
93		} else {
94			Err(())
95		}
96	}
97	fn address(id: &(AssetKind, AssetKind)) -> Result<AccountId, ()> {
98		AccountIdConverter::try_convert(id).map_err(|_| ())
99	}
100}
101
102/// Pool locator where the `PoolId` is a tuple of `AssetKind`s arranged in ascending order.
103pub struct Ascending<AccountId, AssetKind, AccountIdConverter>(
104	PhantomData<(AccountId, AssetKind, AccountIdConverter)>,
105);
106impl<AccountId, AssetKind, AccountIdConverter>
107	PoolLocator<AccountId, AssetKind, (AssetKind, AssetKind)>
108	for Ascending<AccountId, AssetKind, AccountIdConverter>
109where
110	AssetKind: Ord + Clone + Encode,
111	AccountId: Decode,
112	AccountIdConverter: for<'a> TryConvert<&'a (AssetKind, AssetKind), AccountId>,
113{
114	fn pool_id(asset1: &AssetKind, asset2: &AssetKind) -> Result<(AssetKind, AssetKind), ()> {
115		if asset1 > asset2 {
116			Ok((asset2.clone(), asset1.clone()))
117		} else if asset1 < asset2 {
118			Ok((asset1.clone(), asset2.clone()))
119		} else {
120			Err(())
121		}
122	}
123	fn address(id: &(AssetKind, AssetKind)) -> Result<AccountId, ()> {
124		AccountIdConverter::try_convert(id).map_err(|_| ())
125	}
126}
127
128/// Pool locator that chains the `First` and `Second` implementations of [`PoolLocator`].
129///
130/// If the `First` implementation fails, it falls back to the `Second`.
131pub struct Chain<First, Second>(PhantomData<(First, Second)>);
132impl<First, Second, AccountId, AssetKind> PoolLocator<AccountId, AssetKind, (AssetKind, AssetKind)>
133	for Chain<First, Second>
134where
135	First: PoolLocator<AccountId, AssetKind, (AssetKind, AssetKind)>,
136	Second: PoolLocator<AccountId, AssetKind, (AssetKind, AssetKind)>,
137{
138	fn pool_id(asset1: &AssetKind, asset2: &AssetKind) -> Result<(AssetKind, AssetKind), ()> {
139		First::pool_id(asset1, asset2).or(Second::pool_id(asset1, asset2))
140	}
141	fn address(id: &(AssetKind, AssetKind)) -> Result<AccountId, ()> {
142		First::address(id).or(Second::address(id))
143	}
144}
145
146/// `PoolId` to `AccountId` conversion.
147pub struct AccountIdConverter<Seed, PoolId>(PhantomData<(Seed, PoolId)>);
148impl<Seed, PoolId, AccountId> TryConvert<&PoolId, AccountId> for AccountIdConverter<Seed, PoolId>
149where
150	PoolId: Encode,
151	AccountId: Decode,
152	Seed: Get<PalletId>,
153{
154	fn try_convert(id: &PoolId) -> Result<AccountId, &PoolId> {
155		sp_io::hashing::blake2_256(&Encode::encode(&(Seed::get(), id))[..])
156			.using_encoded(|e| Decode::decode(&mut TrailingZeroInput::new(e)).map_err(|_| id))
157	}
158}
159
160/// `PoolId` to `AccountId` conversion without an addition arguments to the seed.
161pub struct AccountIdConverterNoSeed<PoolId>(PhantomData<PoolId>);
162impl<PoolId, AccountId> TryConvert<&PoolId, AccountId> for AccountIdConverterNoSeed<PoolId>
163where
164	PoolId: Encode,
165	AccountId: Decode,
166{
167	fn try_convert(id: &PoolId) -> Result<AccountId, &PoolId> {
168		sp_io::hashing::blake2_256(&Encode::encode(id)[..])
169			.using_encoded(|e| Decode::decode(&mut TrailingZeroInput::new(e)).map_err(|_| id))
170	}
171}