Skip to content

Commit

Permalink
Merge branch 'master' into free-consensus-updates
Browse files Browse the repository at this point in the history
  • Loading branch information
claravanstaden authored Aug 3, 2024
2 parents 9391a36 + ce6938a commit f768444
Show file tree
Hide file tree
Showing 19 changed files with 1,009 additions and 20 deletions.
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 19 additions & 2 deletions cumulus/primitives/utility/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,10 +407,22 @@ impl<
let first_asset: Asset =
payment.fungible.pop_first().ok_or(XcmError::AssetNotFound)?.into();
let (fungibles_asset, balance) = FungiblesAssetMatcher::matches_fungibles(&first_asset)
.map_err(|_| XcmError::AssetNotFound)?;
.map_err(|error| {
log::trace!(
target: "xcm::weight",
"SwapFirstAssetTrader::buy_weight asset {:?} didn't match. Error: {:?}",
first_asset,
error,
);
XcmError::AssetNotFound
})?;

let swap_asset = fungibles_asset.clone().into();
if Target::get().eq(&swap_asset) {
log::trace!(
target: "xcm::weight",
"SwapFirstAssetTrader::buy_weight Asset was same as Target, swap not needed.",
);
// current trader is not applicable.
return Err(XcmError::FeesNotMet)
}
Expand All @@ -424,7 +436,12 @@ impl<
credit_in,
fee,
)
.map_err(|(credit_in, _)| {
.map_err(|(credit_in, error)| {
log::trace!(
target: "xcm::weight",
"SwapFirstAssetTrader::buy_weight swap couldn't be done. Error was: {:?}",
error,
);
drop(credit_in);
XcmError::FeesNotMet
})?;
Expand Down
6 changes: 0 additions & 6 deletions polkadot/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ where
use sc_consensus_babe_rpc::{Babe, BabeApiServer};
use sc_consensus_beefy_rpc::{Beefy, BeefyApiServer};
use sc_consensus_grandpa_rpc::{Grandpa, GrandpaApiServer};
use sc_rpc_spec_v2::chain_spec::{ChainSpec, ChainSpecApiServer};
use sc_sync_state_rpc::{SyncState, SyncStateApiServer};
use substrate_frame_rpc_system::{System, SystemApiServer};
use substrate_state_trie_migration_rpc::{StateMigration, StateMigrationApiServer};
Expand All @@ -139,11 +138,6 @@ where
finality_provider,
} = grandpa;

let chain_name = chain_spec.name().to_string();
let genesis_hash = client.hash(0).ok().flatten().expect("Genesis block exists; qed");
let properties = chain_spec.properties();

io.merge(ChainSpec::new(chain_name, genesis_hash, properties).into_rpc())?;
io.merge(StateMigration::new(client.clone(), backend.clone(), deny_unsafe).into_rpc())?;
io.merge(System::new(client.clone(), pool.clone(), deny_unsafe).into_rpc())?;
io.merge(TransactionPayment::new(client.clone()).into_rpc())?;
Expand Down
7 changes: 6 additions & 1 deletion polkadot/xcm/xcm-builder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ sp-weights = { workspace = true }
frame-support = { workspace = true }
frame-system = { workspace = true }
pallet-transaction-payment = { workspace = true }
pallet-asset-conversion = { workspace = true }
log = { workspace = true }

# Polkadot dependencies
polkadot-parachain-primitives = { workspace = true }

[dev-dependencies]
primitive-types = { workspace = true, default-features = true }
sp-core = { workspace = true, default-features = true }
primitive-types = { features = ["codec", "num-traits", "scale-info"], workspace = true }
pallet-balances = { workspace = true, default-features = true }
pallet-xcm = { workspace = true, default-features = true }
pallet-salary = { workspace = true, default-features = true }
Expand All @@ -43,6 +45,7 @@ default = ["std"]
runtime-benchmarks = [
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"pallet-asset-conversion/runtime-benchmarks",
"pallet-assets/runtime-benchmarks",
"pallet-balances/runtime-benchmarks",
"pallet-salary/runtime-benchmarks",
Expand All @@ -59,8 +62,10 @@ std = [
"frame-support/std",
"frame-system/std",
"log/std",
"pallet-asset-conversion/std",
"pallet-transaction-payment/std",
"polkadot-parachain-primitives/std",
"primitive-types/std",
"scale-info/std",
"sp-arithmetic/std",
"sp-io/std",
Expand Down
22 changes: 22 additions & 0 deletions polkadot/xcm/xcm-builder/src/asset_exchange/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

//! Adapters for the AssetExchanger config item.
//!
//! E.g. types that implement the [`xcm_executor::traits::AssetExchange`] trait.
mod single_asset_adapter;
pub use single_asset_adapter::SingleAssetExchangeAdapter;
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

//! Single asset exchange adapter.
extern crate alloc;
use alloc::vec;
use core::marker::PhantomData;
use frame_support::{ensure, traits::tokens::fungibles};
use pallet_asset_conversion::{QuotePrice, SwapCredit};
use xcm::prelude::*;
use xcm_executor::{
traits::{AssetExchange, MatchesFungibles},
AssetsInHolding,
};

/// An adapter from [`pallet_asset_conversion::SwapCredit`] and
/// [`pallet_asset_conversion::QuotePrice`] to [`xcm_executor::traits::AssetExchange`].
///
/// This adapter takes just one fungible asset in `give` and allows only one fungible asset in
/// `want`. If you need to handle more assets in either `give` or `want`, then you should use
/// another type that implements [`xcm_executor::traits::AssetExchange`] or build your own.
///
/// This adapter also only works for fungible assets.
///
/// `exchange_asset` and `quote_exchange_price` will both return an error if there's
/// more than one asset in `give` or `want`.
pub struct SingleAssetExchangeAdapter<AssetConversion, Fungibles, Matcher, AccountId>(
PhantomData<(AssetConversion, Fungibles, Matcher, AccountId)>,
);
impl<AssetConversion, Fungibles, Matcher, AccountId> AssetExchange
for SingleAssetExchangeAdapter<AssetConversion, Fungibles, Matcher, AccountId>
where
AssetConversion: SwapCredit<
AccountId,
Balance = u128,
AssetKind = Fungibles::AssetId,
Credit = fungibles::Credit<AccountId, Fungibles>,
> + QuotePrice<Balance = u128, AssetKind = Fungibles::AssetId>,
Fungibles: fungibles::Balanced<AccountId, Balance = u128>,
Matcher: MatchesFungibles<Fungibles::AssetId, Fungibles::Balance>,
{
fn exchange_asset(
_: Option<&Location>,
give: AssetsInHolding,
want: &Assets,
maximal: bool,
) -> Result<AssetsInHolding, AssetsInHolding> {
let mut give_iter = give.fungible_assets_iter();
let give_asset = give_iter.next().ok_or_else(|| {
log::trace!(
target: "xcm::SingleAssetExchangeAdapter::exchange_asset",
"No fungible asset was in `give`.",
);
give.clone()
})?;
ensure!(give_iter.next().is_none(), give.clone()); // We only support 1 asset in `give`.
ensure!(give.non_fungible_assets_iter().next().is_none(), give.clone()); // We don't allow non-fungible assets.
ensure!(want.len() == 1, give.clone()); // We only support 1 asset in `want`.
let want_asset = want.get(0).ok_or_else(|| give.clone())?;
let (give_asset_id, give_amount) =
Matcher::matches_fungibles(&give_asset).map_err(|error| {
log::trace!(
target: "xcm::SingleAssetExchangeAdapter::exchange_asset",
"Could not map XCM asset give {:?} to FRAME asset. Error: {:?}",
give_asset,
error,
);
give.clone()
})?;
let (want_asset_id, want_amount) =
Matcher::matches_fungibles(&want_asset).map_err(|error| {
log::trace!(
target: "xcm::SingleAssetExchangeAdapter::exchange_asset",
"Could not map XCM asset want {:?} to FRAME asset. Error: {:?}",
want_asset,
error,
);
give.clone()
})?;

// We have to do this to convert the XCM assets into credit the pool can use.
let swap_asset = give_asset_id.clone().into();
let credit_in = Fungibles::issue(give_asset_id, give_amount);

// Do the swap.
let (credit_out, maybe_credit_change) = if maximal {
// If `maximal`, then we swap exactly `credit_in` to get as much of `want_asset_id` as
// we can, with a minimum of `want_amount`.
let credit_out = <AssetConversion as SwapCredit<_>>::swap_exact_tokens_for_tokens(
vec![swap_asset, want_asset_id],
credit_in,
Some(want_amount),
)
.map_err(|(credit_in, error)| {
log::error!(
target: "xcm::SingleAssetExchangeAdapter::exchange_asset",
"Could not perform the swap, error: {:?}.",
error
);
drop(credit_in);
give.clone()
})?;

// We don't have leftover assets if exchange was maximal.
(credit_out, None)
} else {
// If `minimal`, then we swap as little of `credit_in` as we can to get exactly
// `want_amount` of `want_asset_id`.
let (credit_out, credit_change) =
<AssetConversion as SwapCredit<_>>::swap_tokens_for_exact_tokens(
vec![swap_asset, want_asset_id],
credit_in,
want_amount,
)
.map_err(|(credit_in, error)| {
log::error!(
target: "xcm::SingleAssetExchangeAdapter::exchange_asset",
"Could not perform the swap, error: {:?}.",
error
);
drop(credit_in);
give.clone()
})?;

(credit_out, Some(credit_change))
};

// We create an `AssetsInHolding` instance by putting in the resulting asset
// of the exchange.
let resulting_asset: Asset = (want_asset.id.clone(), credit_out.peek()).into();
let mut result: AssetsInHolding = resulting_asset.into();

// If we have some leftover assets from the exchange, also put them in the result.
if let Some(credit_change) = maybe_credit_change {
let leftover_asset: Asset = (give_asset.id.clone(), credit_change.peek()).into();
result.subsume(leftover_asset);
}

Ok(result.into())
}

fn quote_exchange_price(give: &Assets, want: &Assets, maximal: bool) -> Option<Assets> {
if give.len() != 1 || want.len() != 1 {
return None;
} // We only support 1 asset in `give` or `want`.
let give_asset = give.get(0)?;
let want_asset = want.get(0)?;
// We first match both XCM assets to the asset ID types `AssetConversion` can handle.
let (give_asset_id, give_amount) = Matcher::matches_fungibles(give_asset)
.map_err(|error| {
log::trace!(
target: "xcm::SingleAssetExchangeAdapter::quote_exchange_price",
"Could not map XCM asset {:?} to FRAME asset. Error: {:?}.",
give_asset,
error,
);
()
})
.ok()?;
let (want_asset_id, want_amount) = Matcher::matches_fungibles(want_asset)
.map_err(|error| {
log::trace!(
target: "xcm::SingleAssetExchangeAdapter::quote_exchange_price",
"Could not map XCM asset {:?} to FRAME asset. Error: {:?}.",
want_asset,
error,
);
()
})
.ok()?;
// We quote the price.
if maximal {
// The amount of `want` resulting from swapping `give`.
let resulting_want =
<AssetConversion as QuotePrice>::quote_price_exact_tokens_for_tokens(
give_asset_id,
want_asset_id,
give_amount,
true, // Include fee.
)?;

Some((want_asset.id.clone(), resulting_want).into())
} else {
// The `give` amount required to obtain `want`.
let necessary_give =
<AssetConversion as QuotePrice>::quote_price_tokens_for_exact_tokens(
give_asset_id,
want_asset_id,
want_amount,
true, // Include fee.
)?;

Some((give_asset.id.clone(), necessary_give).into())
}
}
}
Loading

0 comments on commit f768444

Please sign in to comment.