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

feat: on chain swaps #5595

Merged
merged 9 commits into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from 5 commits
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
10 changes: 5 additions & 5 deletions Cargo.lock

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

56 changes: 52 additions & 4 deletions state-chain/chains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,7 @@ pub enum SwapOrigin<AccountId> {
broker_id: Option<AccountId>,
},
Internal,
OnChainAccount(AccountId),
}

impl<AccountId> SwapOrigin<AccountId> {
Expand All @@ -690,6 +691,7 @@ impl<AccountId> SwapOrigin<AccountId> {
Self::DepositChannel { ref broker_id, .. } => Some(broker_id),
Self::Vault { ref broker_id, .. } => broker_id.as_ref(),
Self::Internal => None,
Self::OnChainAccount(_) => None,
}
}
}
Expand Down Expand Up @@ -911,6 +913,55 @@ pub struct ChannelRefundParameters<A> {
pub min_price: Price,
}

#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, TypeInfo, MaxEncodedLen, PartialOrd, Ord)]
pub struct RefundParametersExtendedGeneric<Address, AccountId> {
pub retry_duration: cf_primitives::BlockNumber,
pub refund_destination: RefundDestination<Address, AccountId>,
pub min_price: Price,
}

pub type RefundParametersExtended<AccountId> =
RefundParametersExtendedGeneric<ForeignChainAddress, AccountId>;
msgmaxim marked this conversation as resolved.
Show resolved Hide resolved
pub type RefundParametersExtendedEncoded<AccountId> =
RefundParametersExtendedGeneric<EncodedAddress, AccountId>;

impl<AccountId> RefundParametersExtended<AccountId> {
pub fn to_encoded<Converter: AddressConverter>(
self,
) -> RefundParametersExtendedEncoded<AccountId> {
RefundParametersExtendedEncoded {
retry_duration: self.retry_duration,
refund_destination: match self.refund_destination {
RefundDestination::ExternalAddress(address) =>
RefundDestination::ExternalAddress(Converter::to_encoded_address(address)),
RefundDestination::OnChainAccount(account_id) =>
RefundDestination::OnChainAccount(account_id),
},
min_price: self.min_price,
}
}

pub fn min_output_amount(&self, input_amount: AssetAmount) -> AssetAmount {
use sp_runtime::traits::UniqueSaturatedInto;
cf_amm_math::output_amount_ceil(input_amount.into(), self.min_price).unique_saturated_into()
}
}

#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, TypeInfo, MaxEncodedLen, PartialOrd, Ord)]
pub enum RefundDestination<Address, AccountId> {
ExternalAddress(Address),
OnChainAccount(AccountId),
}

#[cfg(feature = "runtime-benchmarks")]
impl<Address: BenchmarkValue, AccountId: BenchmarkValue> BenchmarkValue
for RefundDestination<Address, AccountId>
{
fn benchmark_value() -> Self {
RefundDestination::ExternalAddress(BenchmarkValue::benchmark_value())
}
}

#[cfg(feature = "runtime-benchmarks")]
impl<A: BenchmarkValue> BenchmarkValue for ChannelRefundParameters<A> {
fn benchmark_value() -> Self {
Expand All @@ -921,6 +972,7 @@ impl<A: BenchmarkValue> BenchmarkValue for ChannelRefundParameters<A> {
}
}
}

#[cfg(feature = "std")]
pub type RefundParametersRpc = ChannelRefundParameters<crate::address::AddressString>;
pub type ChannelRefundParametersDecoded = ChannelRefundParameters<ForeignChainAddress>;
Expand All @@ -944,10 +996,6 @@ impl<A: Clone> ChannelRefundParameters<A> {
min_price: self.min_price,
})
}
pub fn min_output_amount(&self, input_amount: AssetAmount) -> AssetAmount {
use sp_runtime::traits::UniqueSaturatedInto;
cf_amm_math::output_amount_ceil(input_amount.into(), self.min_price).unique_saturated_into()
}
}

pub enum RequiresSignatureRefresh<C: ChainCrypto, Api: ApiCall<C>> {
Expand Down
20 changes: 14 additions & 6 deletions state-chain/pallets/cf-ingress-egress/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ use cf_chains::{
AllBatch, AllBatchError, CcmAdditionalData, CcmChannelMetadata, CcmDepositMetadata, CcmMessage,
Chain, ChainCrypto, ChannelLifecycleHooks, ChannelRefundParametersDecoded, ConsolidateCall,
DepositChannel, DepositDetailsToTransactionInId, DepositOriginType, ExecutexSwapAndCall,
FetchAssetParams, ForeignChainAddress, IntoTransactionInIdForAnyChain, RejectCall, SwapOrigin,
TransferAssetParams,
FetchAssetParams, ForeignChainAddress, IntoTransactionInIdForAnyChain,
RefundParametersExtended, RejectCall, SwapOrigin, TransferAssetParams,
};
use cf_primitives::{
AccountRole, AffiliateShortId, Affiliates, Asset, AssetAmount, BasisPoints, Beneficiaries,
Expand All @@ -46,7 +46,7 @@ use cf_traits::{
ChannelIdAllocator, DepositApi, EgressApi, EpochInfo, FeePayment,
FetchesTransfersLimitProvider, GetBlockHeight, IngressEgressFeeApi, IngressSink, IngressSource,
NetworkEnvironmentProvider, OnDeposit, PoolApi, ScheduledEgressDetails, SwapLimitsProvider,
SwapRequestHandler, SwapRequestType,
SwapOutputAction, SwapRequestHandler, SwapRequestType,
};
use frame_support::{
pallet_prelude::{OptionQuery, *},
Expand Down Expand Up @@ -1911,11 +1911,19 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
amount_after_fees.into(),
destination_asset,
SwapRequestType::Regular {
ccm_deposit_metadata: deposit_metadata,
output_address: destination_address,
output_action: SwapOutputAction::Egress {
ccm_deposit_metadata: deposit_metadata,
output_address: destination_address,
},
},
broker_fees,
refund_params,
refund_params.map(|params| RefundParametersExtended {
retry_duration: params.retry_duration,
refund_destination: cf_chains::RefundDestination::ExternalAddress(
params.refund_address,
),
min_price: params.min_price,
}),
dca_params,
origin.into(),
);
Expand Down
29 changes: 23 additions & 6 deletions state-chain/pallets/cf-ingress-egress/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ use cf_traits::{
swap_request_api::{MockSwapRequest, MockSwapRequestHandler},
},
BalanceApi, DepositApi, EgressApi, EpochInfo, FetchesTransfersLimitProvider, FundingInfo,
GetBlockHeight, SafeMode, ScheduledEgressDetails, SwapRequestType,
GetBlockHeight, SafeMode, ScheduledEgressDetails, SwapOutputAction, SwapRequestType,
};
use frame_support::{
assert_err, assert_noop, assert_ok,
Expand Down Expand Up @@ -1865,7 +1865,12 @@ fn can_request_swap_via_extrinsic() {
input_asset: INPUT_ASSET,
output_asset: OUTPUT_ASSET,
input_amount: INPUT_AMOUNT,
swap_type: SwapRequestType::Regular { output_address, ccm_deposit_metadata: None },
swap_type: SwapRequestType::Regular {
output_action: SwapOutputAction::Egress {
output_address,
ccm_deposit_metadata: None
}
},
broker_fees: bounded_vec![Beneficiary { account: BROKER, bps: 0 }],
origin: SwapOrigin::Vault {
tx_id: TransactionInIdForAnyChain::Evm(H256::default()),
Expand Down Expand Up @@ -1925,7 +1930,12 @@ fn vault_swaps_support_affiliate_fees() {
input_asset: INPUT_ASSET,
output_asset: OUTPUT_ASSET,
input_amount: INPUT_AMOUNT,
swap_type: SwapRequestType::Regular { output_address, ccm_deposit_metadata: None },
swap_type: SwapRequestType::Regular {
output_action: SwapOutputAction::Egress {
output_address,
ccm_deposit_metadata: None
}
},
broker_fees: bounded_vec![
Beneficiary { account: BROKER, bps: BROKER_FEE },
// Only one affiliate is used (short id for affiliate 2 has not been
Expand Down Expand Up @@ -1982,7 +1992,12 @@ fn charge_no_broker_fees_on_unknown_primary_broker() {
input_asset: INPUT_ASSET,
output_asset: OUTPUT_ASSET,
input_amount: INPUT_AMOUNT,
swap_type: SwapRequestType::Regular { output_address, ccm_deposit_metadata: None },
swap_type: SwapRequestType::Regular {
output_action: SwapOutputAction::Egress {
output_address,
ccm_deposit_metadata: None
}
},
broker_fees: Default::default(),
origin: SwapOrigin::Vault {
tx_id: cf_chains::TransactionInIdForAnyChain::Evm(H256::default()),
Expand Down Expand Up @@ -2040,8 +2055,10 @@ fn can_request_ccm_swap_via_extrinsic() {
output_asset: OUTPUT_ASSET,
input_amount: INPUT_AMOUNT,
swap_type: SwapRequestType::Regular {
output_address,
ccm_deposit_metadata: Some(ccm_deposit_metadata)
output_action: SwapOutputAction::Egress {
output_address,
ccm_deposit_metadata: Some(ccm_deposit_metadata)
}
},
broker_fees: bounded_vec![Beneficiary { account: BROKER, bps: 0 }],
origin: SwapOrigin::Vault {
Expand Down
8 changes: 6 additions & 2 deletions state-chain/pallets/cf-ingress-egress/src/tests/boost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,8 @@ fn taking_network_fee_from_boost_fee() {

mod vault_swaps {

use cf_traits::SwapOutputAction;

use crate::BoostedVaultTransactions;

use super::*;
Expand Down Expand Up @@ -1229,8 +1231,10 @@ mod vault_swaps {
output_asset: OUTPUT_ASSET,
input_amount: DEPOSIT_AMOUNT - BOOST_FEE - INGRESS_FEE,
swap_type: SwapRequestType::Regular {
output_address,
ccm_deposit_metadata: None
output_action: SwapOutputAction::Egress {
output_address,
ccm_deposit_metadata: None
}
},
broker_fees: bounded_vec![Beneficiary { account: BROKER, bps: 5 }],
origin: SwapOrigin::Vault {
Expand Down
11 changes: 3 additions & 8 deletions state-chain/pallets/cf-lp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,17 +424,12 @@ impl<T: Config> LpRegistration for Pallet<T> {
LiquidityRefundAddress::<T>::insert(account_id, address.chain(), address);
}

fn ensure_has_refund_address_for_pair(
fn ensure_has_refund_address_for_asset(
account_id: &Self::AccountId,
base_asset: Asset,
quote_asset: Asset,
asset: Asset,
) -> DispatchResult {
ensure!(
LiquidityRefundAddress::<T>::contains_key(account_id, ForeignChain::from(base_asset)) &&
LiquidityRefundAddress::<T>::contains_key(
account_id,
ForeignChain::from(quote_asset)
),
LiquidityRefundAddress::<T>::contains_key(account_id, ForeignChain::from(asset)),
Error::<T>::NoLiquidityRefundAddressRegistered
);
Ok(())
Expand Down
3 changes: 2 additions & 1 deletion state-chain/pallets/cf-pools/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1698,7 +1698,8 @@ impl<T: Config> Pallet<T> {
quote_asset: any::Asset,
f: F,
) -> Result<R, DispatchError> {
T::LpRegistrationApi::ensure_has_refund_address_for_pair(lp, base_asset, quote_asset)?;
T::LpRegistrationApi::ensure_has_refund_address_for_asset(lp, base_asset)?;
T::LpRegistrationApi::ensure_has_refund_address_for_asset(lp, quote_asset)?;
let asset_pair = AssetPair::try_new::<T>(base_asset, quote_asset)?;
Self::inner_sweep(lp)?;
Self::try_mutate_pool(asset_pair, f)
Expand Down
31 changes: 31 additions & 0 deletions state-chain/pallets/cf-swapping/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,5 +199,36 @@ mod benchmarks {
);
}

#[benchmark]
fn internal_swap() {
let lp_id =
T::AccountRoleRegistry::whitelisted_caller_with_role(AccountRole::LiquidityProvider)
.unwrap();

T::LpRegistrationApi::register_liquidity_refund_address(
&lp_id,
ForeignChainAddress::Eth(Default::default()),
);

let caller = OriginFor::<T>::signed(lp_id.clone());

T::BalanceApi::credit_account(&lp_id, Asset::Eth, 1000);

#[block]
{
assert_ok!(Pallet::<T>::internal_swap(
caller.clone(),
1000,
Asset::Eth,
Asset::Flip,
0,
Default::default(),
None
));
}

assert_eq!(SwapRequests::<T>::iter().count(), 1, "Swap request must have been created");
}

impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test,);
}
Loading
Loading