Skip to content

Commit

Permalink
Feat: Boost Support for Vault Swaps (#5437)
Browse files Browse the repository at this point in the history
* feat: boost support for vault swaps

* feat: make deposit_address and channel_id optional in events

* refactor: vault_deposit_witness macro and other small changes

* refactor: inline process_deposit_witnesses

* refactor: rename add_prewitnessed_deposits

* test: assembling_broker_fees

* fix: Vec -> Box (addressing bouncer decoding issue)

* feat: infallible credit_account

* fix: clippy

* feat: include origin type in InsufficientBoostLiquidity event

* chore: fix tests with a process_channel_deposit_full_witness wrapper

* chore: fix another unit test

* test: add extra test
  • Loading branch information
msgmaxim authored Dec 4, 2024
1 parent 0218198 commit 74e50be
Show file tree
Hide file tree
Showing 33 changed files with 1,449 additions and 881 deletions.
38 changes: 16 additions & 22 deletions engine/src/witness/arb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ use cf_chains::{
evm::{DepositDetails, H256},
Arbitrum, CcmDepositMetadata,
};
use cf_primitives::{
chains::assets::arb::Asset as ArbAsset, Asset, AssetAmount, Beneficiary, EpochIndex,
};
use cf_primitives::{chains::assets::arb::Asset as ArbAsset, Asset, AssetAmount, EpochIndex};
use cf_utilities::task_scope::Scope;
use futures_core::Future;
use itertools::Itertools;
use pallet_cf_ingress_egress::VaultDepositWitness;
use sp_core::H160;

use crate::{
Expand All @@ -30,7 +29,7 @@ use crate::{

use super::{
common::{chain_source::extension::ChainSourceExt, epoch_source::EpochSourceBuilder},
evm::source::EvmSource,
evm::{source::EvmSource, vault::vault_deposit_witness},
};

use anyhow::{Context, Result};
Expand Down Expand Up @@ -185,6 +184,7 @@ impl super::evm::vault::IngressCallBuilder for ArbCallBuilder {
type Chain = Arbitrum;

fn vault_swap_request(
block_height: u64,
source_asset: Asset,
deposit_amount: AssetAmount,
destination_asset: Asset,
Expand All @@ -193,26 +193,20 @@ impl super::evm::vault::IngressCallBuilder for ArbCallBuilder {
tx_id: H256,
vault_swap_parameters: VaultSwapParameters,
) -> state_chain_runtime::RuntimeCall {
let deposit = vault_deposit_witness!(
source_asset,
deposit_amount,
destination_asset,
destination_address,
deposit_metadata,
tx_id,
vault_swap_parameters
);

state_chain_runtime::RuntimeCall::ArbitrumIngressEgress(
pallet_cf_ingress_egress::Call::vault_swap_request {
input_asset: source_asset.try_into().expect("invalid asset for chain"),
output_asset: destination_asset,
deposit_amount,
destination_address,
deposit_metadata,
tx_id,
deposit_details: Box::new(DepositDetails { tx_hashes: Some(vec![tx_id]) }),
broker_fee: vault_swap_parameters.broker_fee,
affiliate_fees: vault_swap_parameters
.affiliate_fees
.into_iter()
.map(|entry| Beneficiary { account: entry.affiliate, bps: entry.fee.into() })
.collect_vec()
.try_into()
.expect("runtime supports at least as many affiliates as we allow in cf_parameters encoding"),
boost_fee: vault_swap_parameters.boost_fee.into(),
dca_params: vault_swap_parameters.dca_params,
refund_params: Box::new(vault_swap_parameters.refund_params),
block_height,
deposit: Box::new(deposit),
},
)
}
Expand Down
24 changes: 19 additions & 5 deletions engine/src/witness/btc/deposits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ use itertools::Itertools;
use pallet_cf_ingress_egress::{DepositChannelDetails, DepositWitness};
use state_chain_runtime::BitcoinInstance;

use super::super::common::chunked_chain_source::chunked_by_vault::{
builder::ChunkedByVaultBuilder, private_deposit_channels::BrokerPrivateChannels, ChunkedByVault,
use super::{
super::common::chunked_chain_source::chunked_by_vault::{
builder::ChunkedByVaultBuilder, private_deposit_channels::BrokerPrivateChannels,
ChunkedByVault,
},
vault_swaps::BtcIngressEgressCall,
};
use crate::{
btc::rpc::VerboseTransaction,
Expand Down Expand Up @@ -71,6 +75,7 @@ impl<Inner: ChunkedByVault> ChunkedByVaultBuilder<Inner> {
private_channels.clone().into_iter().map(move |(broker_id, channel_id)| {
(
broker_id,
channel_id,
DepositAddress::new(
key,
channel_id.try_into().expect("BTC channel id must fit in u32"),
Expand All @@ -80,14 +85,23 @@ impl<Inner: ChunkedByVault> ChunkedByVaultBuilder<Inner> {
})
};

for (broker_id, vault_address) in vault_addresses {
for (broker_id, channel_id, vault_address) in vault_addresses {
for tx in &txs {
if let Some(call) = super::vault_swaps::try_extract_vault_swap_call(
if let Some(deposit) = super::vault_swaps::try_extract_vault_swap_witness(
tx,
&vault_address,
channel_id,
&broker_id,
) {
process_call(call.into(), epoch.index).await;
process_call(
BtcIngressEgressCall::vault_swap_request {
block_height: header.index,
deposit: Box::new(deposit),
}
.into(),
epoch.index,
)
.await;
}
}
}
Expand Down
42 changes: 26 additions & 16 deletions engine/src/witness/btc/vault_swaps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use cf_chains::{
},
ChannelRefundParameters, ForeignChainAddress,
};
use cf_primitives::{AccountId, Beneficiary, DcaParameters};
use cf_primitives::{AccountId, Beneficiary, ChannelId, DcaParameters};
use cf_utilities::SliceToArray;
use codec::Decode;
use itertools::Itertools;
Expand Down Expand Up @@ -77,14 +77,18 @@ fn script_buf_to_script_pubkey(script: &ScriptBuf) -> Option<ScriptPubkey> {
Some(pubkey)
}

type BtcIngressEgressCall =
pub(super) type BtcIngressEgressCall =
pallet_cf_ingress_egress::Call<state_chain_runtime::Runtime, BitcoinInstance>;

pub fn try_extract_vault_swap_call(
type VaultDepositWitness =
pallet_cf_ingress_egress::VaultDepositWitness<state_chain_runtime::Runtime, BitcoinInstance>;

pub fn try_extract_vault_swap_witness(
tx: &VerboseTransaction,
vault_address: &DepositAddress,
channel_id: ChannelId,
broker_id: &AccountId,
) -> Option<BtcIngressEgressCall> {
) -> Option<VaultDepositWitness> {
// A correctly constructed transaction carrying CF swap parameters must have at least 3 outputs:
let [utxo_to_vault, nulldata_utxo, change_utxo, ..] = &tx.vout[..] else {
return None;
Expand Down Expand Up @@ -130,18 +134,18 @@ pub fn try_extract_vault_swap_call(

let tx_id: [u8; 32] = tx.txid.to_byte_array();

Some(BtcIngressEgressCall::vault_swap_request {
Some(VaultDepositWitness {
input_asset: NATIVE_ASSET,
output_asset: data.output_asset,
deposit_amount,
destination_address: data.output_address,
tx_id: H256::from(tx_id),
deposit_details: Box::new(Utxo {
deposit_details: Utxo {
// we require the deposit to be the first UTXO
id: UtxoId { tx_id: tx_id.into(), vout: 0 },
amount: deposit_amount,
deposit_address: vault_address.clone(),
}),
},
deposit_metadata: None, // No ccm for BTC (yet?)
broker_fee: Beneficiary {
account: broker_id.clone(),
Expand All @@ -155,17 +159,19 @@ pub fn try_extract_vault_swap_call(
.collect_vec()
.try_into()
.expect("runtime supports at least as many affiliates as we allow in UTXO encoding"),
refund_params: Box::new(ChannelRefundParameters {
refund_params: ChannelRefundParameters {
retry_duration: data.parameters.retry_duration.into(),
refund_address: ForeignChainAddress::Btc(refund_address),
min_price,
}),
},
dca_params: Some(DcaParameters {
number_of_chunks: data.parameters.number_of_chunks.into(),
chunk_interval: data.parameters.chunk_interval.into(),
}),
// This is only to be checked in the pre-witnessed version
boost_fee: data.parameters.boost_fee.into(),
channel_id: Some(channel_id),
deposit_address: Some(vault_address.script_pubkey()),
})
}

Expand Down Expand Up @@ -288,38 +294,42 @@ mod tests {
None,
);

const CHANNEL_ID: ChannelId = 7;

assert_eq!(
try_extract_vault_swap_call(&tx, &vault_deposit_address, &BROKER),
Some(BtcIngressEgressCall::vault_swap_request {
try_extract_vault_swap_witness(&tx, &vault_deposit_address, CHANNEL_ID, &BROKER),
Some(VaultDepositWitness {
input_asset: NATIVE_ASSET,
output_asset: MOCK_SWAP_PARAMS.output_asset,
deposit_amount: DEPOSIT_AMOUNT,
destination_address: MOCK_SWAP_PARAMS.output_address.clone(),
tx_id: tx.txid.to_byte_array().into(),
deposit_details: Box::new(Utxo {
deposit_details: Utxo {
id: UtxoId { tx_id: tx.txid.to_byte_array().into(), vout: 0 },
amount: DEPOSIT_AMOUNT,
deposit_address: vault_deposit_address,
}),
deposit_address: vault_deposit_address.clone(),
},
broker_fee: Beneficiary {
account: BROKER,
bps: MOCK_SWAP_PARAMS.parameters.broker_fee.into()
},
affiliate_fees: bounded_vec![MOCK_SWAP_PARAMS.parameters.affiliates[0].into()],
deposit_metadata: None,
refund_params: Box::new(ChannelRefundParameters {
refund_params: ChannelRefundParameters {
retry_duration: MOCK_SWAP_PARAMS.parameters.retry_duration.into(),
refund_address: ForeignChainAddress::Btc(refund_pubkey),
min_price: sqrt_price_to_price(bounded_sqrt_price(
MOCK_SWAP_PARAMS.parameters.min_output_amount.into(),
DEPOSIT_AMOUNT.into(),
)),
}),
},
dca_params: Some(DcaParameters {
number_of_chunks: MOCK_SWAP_PARAMS.parameters.number_of_chunks.into(),
chunk_interval: MOCK_SWAP_PARAMS.parameters.chunk_interval.into(),
}),
boost_fee: MOCK_SWAP_PARAMS.parameters.boost_fee.into(),
deposit_address: Some(vault_deposit_address.script_pubkey()),
channel_id: Some(CHANNEL_ID),
})
);
}
Expand Down
36 changes: 17 additions & 19 deletions engine/src/witness/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use cf_primitives::{chains::assets::eth::Asset as EthAsset, Asset, AssetAmount,
use cf_utilities::task_scope::Scope;
use futures_core::Future;
use itertools::Itertools;
use pallet_cf_ingress_egress::VaultDepositWitness;
use sp_core::H160;

use crate::{
Expand All @@ -30,7 +31,10 @@ use crate::{
},
};

use super::{common::epoch_source::EpochSourceBuilder, evm::source::EvmSource};
use super::{
common::epoch_source::EpochSourceBuilder,
evm::{source::EvmSource, vault::vault_deposit_witness},
};
use crate::witness::common::chain_source::extension::ChainSourceExt;

use anyhow::{Context, Result};
Expand Down Expand Up @@ -232,6 +236,7 @@ impl super::evm::vault::IngressCallBuilder for EthCallBuilder {
type Chain = Ethereum;

fn vault_swap_request(
block_height: u64,
source_asset: Asset,
deposit_amount: AssetAmount,
destination_asset: Asset,
Expand All @@ -240,26 +245,19 @@ impl super::evm::vault::IngressCallBuilder for EthCallBuilder {
tx_id: H256,
vault_swap_parameters: VaultSwapParameters,
) -> state_chain_runtime::RuntimeCall {
let deposit = vault_deposit_witness!(
source_asset,
deposit_amount,
destination_asset,
destination_address,
deposit_metadata,
tx_id,
vault_swap_parameters
);
state_chain_runtime::RuntimeCall::EthereumIngressEgress(
pallet_cf_ingress_egress::Call::vault_swap_request {
input_asset: source_asset.try_into().expect("invalid asset for chain"),
output_asset: destination_asset,
deposit_amount,
destination_address,
deposit_metadata,
tx_id,
deposit_details: Box::new(DepositDetails { tx_hashes: Some(vec![tx_id]) }),
broker_fee: vault_swap_parameters.broker_fee,
affiliate_fees: vault_swap_parameters
.affiliate_fees
.into_iter()
.map(Into::into)
.collect_vec()
.try_into()
.expect("runtime supports at least as many affiliates as we allow in cf_parameters encoding"),
boost_fee: vault_swap_parameters.boost_fee.into(),
dca_params: vault_swap_parameters.dca_params,
refund_params: Box::new(vault_swap_parameters.refund_params),
block_height,
deposit: Box::new(deposit),
},
)
}
Expand Down
Loading

0 comments on commit 74e50be

Please sign in to comment.