From 6f26b199d988bbd13a0f53accfdfbbcd77cb0c73 Mon Sep 17 00:00:00 2001 From: Maxim Shishmarev Date: Tue, 15 Oct 2024 15:10:36 +1100 Subject: [PATCH 01/36] feat: witnessing btc smart contract swaps --- engine/src/witness/arb.rs | 7 +- engine/src/witness/btc.rs | 2 +- engine/src/witness/btc/deposits.rs | 66 +++++++--- engine/src/witness/btc/smart_contract.rs | 123 ++++++++++-------- engine/src/witness/eth.rs | 7 +- engine/src/witness/evm/evm_deposits.rs | 2 +- .../cf-integration-tests/src/swapping.rs | 5 + state-chain/chains/src/benchmarking_value.rs | 11 ++ state-chain/chains/src/btc.rs | 8 +- .../cf-ingress-egress/src/benchmarking.rs | 8 +- .../pallets/cf-ingress-egress/src/lib.rs | 27 ++-- .../pallets/cf-ingress-egress/src/tests.rs | 15 ++- state-chain/runtime/src/chainflip.rs | 17 ++- state-chain/traits/src/lib.rs | 9 +- 14 files changed, 203 insertions(+), 104 deletions(-) diff --git a/engine/src/witness/arb.rs b/engine/src/witness/arb.rs index 8dd4f6ce7b..8eaf700d32 100644 --- a/engine/src/witness/arb.rs +++ b/engine/src/witness/arb.rs @@ -2,7 +2,7 @@ mod chain_tracking; use std::{collections::HashMap, sync::Arc}; -use cf_chains::Arbitrum; +use cf_chains::{evm::DepositDetails, Arbitrum}; use cf_primitives::EpochIndex; use futures_core::Future; use sp_core::H160; @@ -207,6 +207,11 @@ impl super::evm::vault::IngressCallBuilder for ArbCallBuilder { deposit_amount, destination_address, tx_hash, + deposit_details: DepositDetails { tx_hashes: Some(vec![tx_hash.into()]) }, + // TODO: use real parameters when we can decode them + boost_fee: 0, + dca_params: None, + refund_params: None, } }, ) diff --git a/engine/src/witness/btc.rs b/engine/src/witness/btc.rs index b78a3cfca6..1963a4ecb0 100644 --- a/engine/src/witness/btc.rs +++ b/engine/src/witness/btc.rs @@ -1,6 +1,6 @@ mod chain_tracking; mod deposits; -mod smart_contract; +pub mod smart_contract; pub mod source; use crate::{ diff --git a/engine/src/witness/btc/deposits.rs b/engine/src/witness/btc/deposits.rs index 02d42d2f0b..4b35c2134b 100644 --- a/engine/src/witness/btc/deposits.rs +++ b/engine/src/witness/btc/deposits.rs @@ -20,7 +20,7 @@ use crate::{ use bitcoin::BlockHash; use cf_chains::{ assets::btc, - btc::{ScriptPubkey, UtxoId}, + btc::{deposit_address::DepositAddress, BtcDepositDetails, UtxoId}, Bitcoin, }; @@ -56,12 +56,37 @@ impl ChunkedByVaultBuilder { self.then(move |epoch, header| { let process_call = process_call.clone(); async move { + let vault_addresses = { + use cf_chains::btc::{ + deposit_address::DepositAddress, AggKey, CHANGE_ADDRESS_SALT, + }; + + let key: &AggKey = &epoch.info.0; + + let maybe_previous_vault_address = + key.previous.map(|key| DepositAddress::new(key, CHANGE_ADDRESS_SALT)); + let current_vault_address = + DepositAddress::new(key.current, CHANGE_ADDRESS_SALT); + + [current_vault_address].into_iter().chain(maybe_previous_vault_address) + }; + // TODO: Make addresses a Map of some kind? - let (((), txs), addresses) = header.data; + let (((), txs), deposit_channels) = header.data; + + for vault_address in vault_addresses { + for tx in &txs { + if let Some(call) = + super::smart_contract::try_extract_contract_call(tx, &vault_address) + { + process_call(call.into(), epoch.index).await; + } + } + } - let script_addresses = script_addresses(addresses); + let deposit_addresses = map_script_addresses(deposit_channels); - let deposit_witnesses = deposit_witnesses(&txs, &script_addresses); + let deposit_witnesses = deposit_witnesses(&txs, &deposit_addresses); // Submit all deposit witnesses for the block. if !deposit_witnesses.is_empty() { @@ -83,19 +108,22 @@ impl ChunkedByVaultBuilder { fn deposit_witnesses( txs: &[VerboseTransaction], - script_addresses: &HashMap, ScriptPubkey>, + deposit_addresses: &HashMap, DepositAddress>, ) -> Vec> { txs.iter() .flat_map(|tx| { Iterator::zip(0.., &tx.vout) .filter(|(_vout, tx_out)| tx_out.value.to_sat() > 0) .filter_map(|(vout, tx_out)| { - script_addresses.get(tx_out.script_pubkey.as_bytes()).map(|bitcoin_script| { + deposit_addresses.get(tx_out.script_pubkey.as_bytes()).map(|deposit_address| { DepositWitness:: { - deposit_address: bitcoin_script.clone(), + deposit_address: deposit_address.script_pubkey(), asset: btc::Asset::Btc, amount: tx_out.value.to_sat(), - deposit_details: UtxoId { tx_id: tx.txid.to_byte_array().into(), vout }, + deposit_details: BtcDepositDetails { + utxo_id: UtxoId { tx_id: tx.txid.to_byte_array().into(), vout }, + deposit_address: deposit_address.clone(), + }, } }) }) @@ -115,15 +143,17 @@ fn deposit_witnesses( .collect() } -fn script_addresses( +fn map_script_addresses( addresses: Vec>, -) -> HashMap, ScriptPubkey> { +) -> HashMap, DepositAddress> { addresses .into_iter() .map(|channel| { assert_eq!(channel.deposit_channel.asset, btc::Asset::Btc); + let deposit_address = channel.deposit_channel.state; let script_pubkey = channel.deposit_channel.address; - (script_pubkey.bytes(), script_pubkey) + + (script_pubkey.bytes(), deposit_address) }) .collect() } @@ -216,8 +246,10 @@ pub mod tests { None, )]; - let deposit_witnesses = - deposit_witnesses(&txs, &script_addresses(vec![(fake_details(btc_deposit_script))])); + let deposit_witnesses = deposit_witnesses( + &txs, + &map_script_addresses(vec![(fake_details(btc_deposit_script))]), + ); assert_eq!(deposit_witnesses.len(), 1); assert_eq!(deposit_witnesses[0].amount, UTXO_WITNESSED_1); } @@ -244,7 +276,7 @@ pub mod tests { ]; let deposit_witnesses = - deposit_witnesses(&txs, &script_addresses(vec![fake_details(btc_deposit_script)])); + deposit_witnesses(&txs, &map_script_addresses(vec![fake_details(btc_deposit_script)])); assert_eq!(deposit_witnesses.len(), 1); assert_eq!(deposit_witnesses[0].amount, LARGEST_UTXO_TO_DEPOSIT); } @@ -274,7 +306,7 @@ pub mod tests { let deposit_witnesses = deposit_witnesses( &txs, // watching 2 addresses - &script_addresses(vec![ + &map_script_addresses(vec![ fake_details(btc_deposit_script_1.clone()), fake_details(btc_deposit_script_2.clone()), ]), @@ -293,7 +325,7 @@ pub mod tests { let btc_deposit_script_1: ScriptPubkey = DepositAddress::new([0; 32], 9).script_pubkey(); let btc_deposit_script_2: ScriptPubkey = DepositAddress::new([0; 32], 1232).script_pubkey(); - let script_addresses = script_addresses(vec![ + let script_addresses = map_script_addresses(vec![ fake_details(btc_deposit_script_1.clone()), fake_details(btc_deposit_script_2.clone()), ]); @@ -382,7 +414,7 @@ pub mod tests { ]; let deposit_witnesses = - deposit_witnesses(&txs, &script_addresses(vec![fake_details(btc_deposit_script)])); + deposit_witnesses(&txs, &map_script_addresses(vec![fake_details(btc_deposit_script)])); assert_eq!(deposit_witnesses.len(), 2); assert_eq!(deposit_witnesses[0].amount, UTXO_WITNESSED_1); assert_eq!(deposit_witnesses[1].amount, UTXO_WITNESSED_2); diff --git a/engine/src/witness/btc/smart_contract.rs b/engine/src/witness/btc/smart_contract.rs index 76f2ddf387..3bcc01ec6a 100644 --- a/engine/src/witness/btc/smart_contract.rs +++ b/engine/src/witness/btc/smart_contract.rs @@ -1,12 +1,16 @@ use bitcoin::{opcodes::all::OP_RETURN, ScriptBuf}; use cf_amm::common::{bounded_sqrt_price, sqrt_price_to_price}; use cf_chains::{ - address::EncodedAddress, - btc::{smart_contract_encoding::UtxoEncodedData, ScriptPubkey}, + btc::{ + deposit_address::DepositAddress, smart_contract_encoding::UtxoEncodedData, + BtcDepositDetails, ScriptPubkey, UtxoId, + }, + ChannelRefundParameters, ForeignChainAddress, }; -use cf_primitives::{Asset, AssetAmount, Price}; +use cf_primitives::{Asset, DcaParameters}; use codec::Decode; use itertools::Itertools; +use state_chain_runtime::BitcoinInstance; use utilities::SliceToArray; use crate::btc::rpc::VerboseTransaction; @@ -14,22 +18,6 @@ use crate::btc::rpc::VerboseTransaction; const OP_PUSHBYTES_75: u8 = 0x4b; const OP_PUSHDATA1: u8 = 0x4c; -#[derive(PartialEq, Debug)] -pub struct BtcContractCall { - output_asset: Asset, - deposit_amount: AssetAmount, - output_address: EncodedAddress, - // --- FoK --- - retry_duration: u16, - refund_address: ScriptPubkey, - min_price: Price, - // --- DCA --- - number_of_chunks: u16, - chunk_interval: u16, - // --- Boost --- - boost_fee: u8, -} - fn try_extract_utxo_encoded_data(script: &bitcoin::ScriptBuf) -> Option<&[u8]> { let bytes = script.as_script().as_bytes(); @@ -86,19 +74,21 @@ fn script_buf_to_script_pubkey(script: &ScriptBuf) -> Option { Some(pubkey) } +type BtcIngressEgressCall = + pallet_cf_ingress_egress::Call; + // Currently unused, but will be used by the deposit wintesser: -#[allow(dead_code)] pub fn try_extract_contract_call( tx: &VerboseTransaction, - vault_address: ScriptPubkey, -) -> Option { + vault_address: &DepositAddress, +) -> Option { // 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; }; // First output must be a deposit into our vault: - if utxo_to_vault.script_pubkey.as_bytes() != vault_address.bytes() { + if utxo_to_vault.script_pubkey.as_bytes() != vault_address.script_pubkey().bytes() { return None; } @@ -135,16 +125,32 @@ pub fn try_extract_contract_call( deposit_amount.into(), )); - Some(BtcContractCall { - output_asset: data.output_asset, - deposit_amount: deposit_amount as AssetAmount, - output_address: data.output_address, - retry_duration: data.parameters.retry_duration, - refund_address, - min_price, - number_of_chunks: data.parameters.number_of_chunks, - chunk_interval: data.parameters.chunk_interval, - boost_fee: data.parameters.boost_fee, + use secp256k1::hashes::Hash as secp256k1Hash; + + let tx_id: [u8; 32] = tx.txid.to_byte_array(); + + Some(BtcIngressEgressCall::contract_swap_request { + from: Asset::Btc, + to: data.output_asset, + deposit_amount, + destination_address: data.output_address, + tx_hash: tx_id, + deposit_details: BtcDepositDetails { + // we require the deposit to be the first UTXO + utxo_id: UtxoId { tx_id: tx_id.into(), vout: 0 }, + deposit_address: vault_address.clone(), + }, + refund_params: Some(ChannelRefundParameters { + retry_duration: data.parameters.retry_duration as u32, + refund_address: ForeignChainAddress::Btc(refund_address), + min_price, + }), + dca_params: Some(DcaParameters { + number_of_chunks: data.parameters.number_of_chunks as u32, + chunk_interval: data.parameters.chunk_interval as u32, + }), + // This is only to be checked in the pre-witnessed version + boost_fee: data.parameters.boost_fee as u16, }) } @@ -220,13 +226,12 @@ mod tests { fn test_extract_contract_call_from_tx() { use bitcoin::Amount; - const VAULT_PK_HASH: [u8; 20] = [7; 20]; const REFUND_PK_HASH: [u8; 20] = [8; 20]; + const DEPOSIT_AMOUNT: u64 = 1000; - // Addresses represented in both `ScriptPubkey` and `ScriptBuf` to satisfy interfaces: - let vault_pubkey = ScriptPubkey::P2PKH(VAULT_PK_HASH); - let vault_script = ScriptBuf::new_p2pkh(&PubkeyHash::from_byte_array(VAULT_PK_HASH)); - assert_eq!(vault_pubkey.bytes(), vault_script.to_bytes()); + // Addresses have different representations to satisfy interfaces: + let vault_deposit_address = DepositAddress::new([7; 32], 0); + let vault_script = ScriptBuf::from_bytes(vault_deposit_address.script_pubkey().bytes()); let refund_pubkey = ScriptPubkey::P2PKH(REFUND_PK_HASH); let refund_script = ScriptBuf::new_p2pkh(&PubkeyHash::from_byte_array(REFUND_PK_HASH)); @@ -236,7 +241,7 @@ mod tests { vec![ // A UTXO spending into our vault; VerboseTxOut { - value: Amount::from_sat(1000), + value: Amount::from_sat(DEPOSIT_AMOUNT), n: 0, script_pubkey: vault_script.clone(), }, @@ -259,21 +264,31 @@ mod tests { ); assert_eq!( - try_extract_contract_call(&tx, vault_pubkey).unwrap(), - BtcContractCall { - output_asset: MOCK_SWAP_PARAMS.output_asset, - deposit_amount: 1000, - output_address: MOCK_SWAP_PARAMS.output_address.clone(), - retry_duration: MOCK_SWAP_PARAMS.parameters.retry_duration, - refund_address: refund_pubkey, - min_price: sqrt_price_to_price(bounded_sqrt_price( - MOCK_SWAP_PARAMS.parameters.min_output_amount.into(), - 1000.into(), - )), - number_of_chunks: MOCK_SWAP_PARAMS.parameters.number_of_chunks, - chunk_interval: MOCK_SWAP_PARAMS.parameters.chunk_interval, - boost_fee: MOCK_SWAP_PARAMS.parameters.boost_fee, - } + try_extract_contract_call(&tx, &vault_deposit_address), + Some(BtcIngressEgressCall::contract_swap_request { + from: Asset::Btc, + to: MOCK_SWAP_PARAMS.output_asset, + deposit_amount: DEPOSIT_AMOUNT, + destination_address: MOCK_SWAP_PARAMS.output_address.clone(), + tx_hash: tx.hash.to_byte_array(), + deposit_details: BtcDepositDetails { + utxo_id: UtxoId { tx_id: tx.txid.to_byte_array().into(), vout: 0 }, + deposit_address: vault_deposit_address, + }, + refund_params: Some(ChannelRefundParameters { + retry_duration: MOCK_SWAP_PARAMS.parameters.retry_duration as u32, + 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 as u32, + chunk_interval: MOCK_SWAP_PARAMS.parameters.chunk_interval as u32, + }), + boost_fee: MOCK_SWAP_PARAMS.parameters.boost_fee as u16, + }) ); } diff --git a/engine/src/witness/eth.rs b/engine/src/witness/eth.rs index 0ef1de22e0..8fe452fd22 100644 --- a/engine/src/witness/eth.rs +++ b/engine/src/witness/eth.rs @@ -3,7 +3,7 @@ mod state_chain_gateway; use std::{collections::HashMap, sync::Arc}; -use cf_chains::Ethereum; +use cf_chains::{evm::DepositDetails, Ethereum}; use cf_primitives::{chains::assets::eth, EpochIndex}; use futures_core::Future; use sp_core::H160; @@ -252,6 +252,11 @@ impl super::evm::vault::IngressCallBuilder for EthCallBuilder { deposit_amount, destination_address, tx_hash, + deposit_details: DepositDetails { tx_hashes: Some(vec![tx_hash.into()]) }, + // TODO: use real parameters when we can decode them + boost_fee: 0, + dca_params: None, + refund_params: None, } }, ) diff --git a/engine/src/witness/evm/evm_deposits.rs b/engine/src/witness/evm/evm_deposits.rs index bd23a763bd..4ce7786748 100644 --- a/engine/src/witness/evm/evm_deposits.rs +++ b/engine/src/witness/evm/evm_deposits.rs @@ -179,7 +179,7 @@ where } /// To ensure we don't double witness deposits, we use the following pseudo-code, implemented by -/// `eth_ingresses_at_block`. +/// [eth_ingresses_at_block]. /// /// if !address.hasContract: /// swap = address.balanceAtCurrentBlock - address.balanceAtPreviousBlock diff --git a/state-chain/cf-integration-tests/src/swapping.rs b/state-chain/cf-integration-tests/src/swapping.rs index 8ec0ed2eaa..40bd15e5af 100644 --- a/state-chain/cf-integration-tests/src/swapping.rs +++ b/state-chain/cf-integration-tests/src/swapping.rs @@ -17,6 +17,7 @@ use cf_chains::{ address::{AddressConverter, AddressDerivationApi, EncodedAddress}, assets::eth::Asset as EthAsset, eth::{api::EthereumApi, EthereumTrackedData}, + evm::DepositDetails, CcmChannelMetadata, CcmDepositMetadata, Chain, ChainState, DefaultRetryPolicy, Ethereum, ExecutexSwapAndCall, ForeignChain, ForeignChainAddress, RetryPolicy, SwapOrigin, TransactionBuilder, TransferAssetParams, @@ -622,6 +623,10 @@ fn failed_swaps_are_rolled_back() { deposit_amount: 10_000 * DECIMALS, destination_address: EncodedAddress::Eth(Default::default()), tx_hash: Default::default(), + deposit_details: DepositDetails { tx_hashes: None }, + refund_params: None, + dca_params: None, + boost_fee: 0, }, )); diff --git a/state-chain/chains/src/benchmarking_value.rs b/state-chain/chains/src/benchmarking_value.rs index a7cc2da8f9..0fb0fabf5f 100644 --- a/state-chain/chains/src/benchmarking_value.rs +++ b/state-chain/chains/src/benchmarking_value.rs @@ -15,6 +15,7 @@ use sp_std::vec; #[cfg(feature = "runtime-benchmarks")] use crate::{ address::{EncodedAddress, ForeignChainAddress}, + btc::{BtcDepositDetails, UtxoId}, dot::PolkadotTransactionId, evm::{DepositDetails, EvmFetchId, EvmTransactionMetadata}, }; @@ -223,6 +224,16 @@ impl BenchmarkValue for DepositDetails { } } +#[cfg(feature = "runtime-benchmarks")] +impl BenchmarkValue for BtcDepositDetails { + fn benchmark_value() -> Self { + BtcDepositDetails { + utxo_id: UtxoId::benchmark_value(), + deposit_address: crate::btc::deposit_address::DepositAddress::new([0; 32], 0), + } + } +} + impl_default_benchmark_value!(()); impl_default_benchmark_value!(u32); impl_default_benchmark_value!(u64); diff --git a/state-chain/chains/src/btc.rs b/state-chain/chains/src/btc.rs index 7999af390e..1234b43dba 100644 --- a/state-chain/chains/src/btc.rs +++ b/state-chain/chains/src/btc.rs @@ -227,6 +227,12 @@ impl BitcoinFeeInfo { } } +#[derive(Encode, Decode, TypeInfo, Clone, RuntimeDebug, PartialEq, Eq, MaxEncodedLen)] +pub struct BtcDepositDetails { + pub utxo_id: UtxoId, + pub deposit_address: DepositAddress, +} + impl Chain for Bitcoin { const NAME: &'static str = "Bitcoin"; const GAS_ASSET: Self::ChainAsset = assets::btc::Asset::Btc; @@ -244,7 +250,7 @@ impl Chain for Bitcoin { type ChainAccount = ScriptPubkey; type DepositFetchId = BitcoinFetchId; type DepositChannelState = DepositAddress; - type DepositDetails = UtxoId; + type DepositDetails = BtcDepositDetails; type Transaction = BitcoinTransactionData; type TransactionMetadata = (); type TransactionRef = Hash; diff --git a/state-chain/pallets/cf-ingress-egress/src/benchmarking.rs b/state-chain/pallets/cf-ingress-egress/src/benchmarking.rs index 5f8d853d7b..04f69be3bf 100644 --- a/state-chain/pallets/cf-ingress-egress/src/benchmarking.rs +++ b/state-chain/pallets/cf-ingress-egress/src/benchmarking.rs @@ -288,15 +288,19 @@ mod benchmarks { #[benchmark] fn contract_swap_request() { - let deposit_amount = 1_000; + let deposit_amount = 1_000u32; let witness_origin = T::EnsureWitnessed::try_successful_origin().unwrap(); let call = Call::::contract_swap_request { from: Asset::Usdc, to: Asset::Eth, - deposit_amount, + deposit_amount: deposit_amount.into(), destination_address: EncodedAddress::benchmark_value(), tx_hash: [0; 32], + deposit_details: BenchmarkValue::benchmark_value(), + refund_params: None, + dca_params: None, + boost_fee: 0, }; #[block] diff --git a/state-chain/pallets/cf-ingress-egress/src/lib.rs b/state-chain/pallets/cf-ingress-egress/src/lib.rs index 072013cf10..691c9d7cd6 100644 --- a/state-chain/pallets/cf-ingress-egress/src/lib.rs +++ b/state-chain/pallets/cf-ingress-egress/src/lib.rs @@ -1100,9 +1100,14 @@ pub mod pallet { origin: OriginFor, from: Asset, to: Asset, - deposit_amount: AssetAmount, + deposit_amount: ::ChainAmount, destination_address: EncodedAddress, tx_hash: TransactionHash, + deposit_details: ::DepositDetails, + refund_params: Option, + dca_params: Option, + // This is only to be checked in the pre-witnessed version (not implemented yet) + _boost_fee: BasisPoints, ) -> DispatchResult { T::EnsureWitnessed::ensure_origin(origin)?; @@ -1118,16 +1123,20 @@ pub mod pallet { }, }; + T::DepositHandler::on_deposit_made(deposit_details, deposit_amount); + + // TODO: ensure minimum deposit? + + // TODO: validate dca_params and refund_params + T::SwapRequestHandler::init_swap_request( from, - deposit_amount, + deposit_amount.into(), to, SwapRequestType::Regular { output_address: destination_address_internal.clone() }, Default::default(), - // NOTE: FoK not yet supported for swaps from the contract - None, - // NOTE: DCA not yet supported for swaps from the contract - None, + refund_params, + dca_params, SwapOrigin::Vault { tx_hash }, ); @@ -1819,11 +1828,7 @@ impl, I: 'static> Pallet { Self::deposit_event(Event::::DepositFetchesScheduled { channel_id, asset }); // Add the deposit to the balance. - T::DepositHandler::on_deposit_made( - deposit_details.clone(), - deposit_amount, - &deposit_channel_details.deposit_channel, - ); + T::DepositHandler::on_deposit_made(deposit_details.clone(), deposit_amount); // We received a deposit on a channel. If channel has been boosted earlier // (i.e. awaiting finalisation), *and* the boosted amount matches the amount diff --git a/state-chain/pallets/cf-ingress-egress/src/tests.rs b/state-chain/pallets/cf-ingress-egress/src/tests.rs index 4c8ca43572..45bf3cb74a 100644 --- a/state-chain/pallets/cf-ingress-egress/src/tests.rs +++ b/state-chain/pallets/cf-ingress-egress/src/tests.rs @@ -1851,6 +1851,10 @@ fn can_request_swap_via_extrinsic() { INPUT_AMOUNT, MockAddressConverter::to_encoded_address(output_address.clone()), TX_HASH, + DepositDetails { tx_hashes: None }, + None, + None, + 0, )); assert_eq!( @@ -1935,18 +1939,27 @@ fn rejects_invalid_swap_by_witnesser() { 10000, btc_encoded_address, Default::default(), + DepositDetails { tx_hashes: None }, + None, + None, + 0 ),); // No swap request created -> the call was ignored assert!(MockSwapRequestHandler::::get_swap_requests().is_empty()); + // Invalid BTC address: assert_ok!(IngressEgress::contract_swap_request( RuntimeOrigin::root(), Asset::Eth, Asset::Btc, 10000, EncodedAddress::Btc(vec![0x41, 0x80, 0x41]), - Default::default() + Default::default(), + DepositDetails { tx_hashes: None }, + None, + None, + 0 ),); assert!(MockSwapRequestHandler::::get_swap_requests().is_empty()); diff --git a/state-chain/runtime/src/chainflip.rs b/state-chain/runtime/src/chainflip.rs index 6226784623..5f0e1dfcc0 100644 --- a/state-chain/runtime/src/chainflip.rs +++ b/state-chain/runtime/src/chainflip.rs @@ -31,7 +31,7 @@ use cf_chains::{ assets::any::ForeignChainAndAsset, btc::{ api::{BitcoinApi, SelectedUtxosAndChangeAmount, UtxoSelectionType}, - Bitcoin, BitcoinCrypto, BitcoinFeeInfo, BitcoinTransactionData, UtxoId, + Bitcoin, BitcoinCrypto, BitcoinFeeInfo, BitcoinTransactionData, BtcDepositDetails, UtxoId, }, dot::{ api::PolkadotApi, Polkadot, PolkadotAccountId, PolkadotCrypto, PolkadotReplayProtection, @@ -55,9 +55,9 @@ use cf_chains::{ SolAddress, SolAmount, SolApiEnvironment, SolanaCrypto, SolanaTransactionData, }, AnyChain, ApiCall, Arbitrum, CcmChannelMetadata, CcmDepositMetadata, Chain, ChainCrypto, - ChainEnvironment, ChainState, ChannelRefundParameters, DepositChannel, ForeignChain, - ReplayProtectionProvider, RequiresSignatureRefresh, SetCommKeyWithAggKey, SetGovKeyWithAggKey, - Solana, TransactionBuilder, + ChainEnvironment, ChainState, ChannelRefundParameters, ForeignChain, ReplayProtectionProvider, + RequiresSignatureRefresh, SetCommKeyWithAggKey, SetGovKeyWithAggKey, Solana, + TransactionBuilder, }; use cf_primitives::{ chains::assets, AccountRole, Asset, BasisPoints, Beneficiaries, ChannelId, DcaParameters, @@ -766,11 +766,14 @@ impl OnDeposit for DepositHandler {} impl OnDeposit for DepositHandler {} impl OnDeposit for DepositHandler { fn on_deposit_made( - utxo_id: ::DepositDetails, + deposit_details: BtcDepositDetails, amount: ::ChainAmount, - channel: &DepositChannel, ) { - Environment::add_bitcoin_utxo_to_list(amount, utxo_id, channel.state.clone()) + Environment::add_bitcoin_utxo_to_list( + amount, + deposit_details.utxo_id, + deposit_details.deposit_address, + ) } } impl OnDeposit for DepositHandler {} diff --git a/state-chain/traits/src/lib.rs b/state-chain/traits/src/lib.rs index 8a8e73869f..c6a7ae89d2 100644 --- a/state-chain/traits/src/lib.rs +++ b/state-chain/traits/src/lib.rs @@ -23,7 +23,7 @@ use cf_chains::{ assets::any::AssetMap, sol::{SolAddress, SolHash}, ApiCall, CcmChannelMetadata, CcmDepositMetadata, Chain, ChainCrypto, ChannelRefundParameters, - DepositChannel, Ethereum, + Ethereum, }; use cf_primitives::{ AccountRole, Asset, AssetAmount, AuthorityCount, BasisPoints, Beneficiaries, BlockNumber, @@ -897,12 +897,7 @@ pub trait FlipBurnInfo { /// The trait implementation is intentionally no-op by default pub trait OnDeposit { - fn on_deposit_made( - _deposit_details: C::DepositDetails, - _amount: C::ChainAmount, - _channel: &DepositChannel, - ) { - } + fn on_deposit_made(_deposit_details: C::DepositDetails, _amount: C::ChainAmount) {} } pub trait NetworkEnvironmentProvider { From d0446aee8d748ec5c52e3a64f330093e0a0da593 Mon Sep 17 00:00:00 2001 From: Maxim Shishmarev Date: Wed, 16 Oct 2024 14:03:29 +1100 Subject: [PATCH 02/36] chore: address minor review comments --- engine/src/witness/btc/deposits.rs | 4 ++-- engine/src/witness/btc/smart_contract.rs | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/engine/src/witness/btc/deposits.rs b/engine/src/witness/btc/deposits.rs index 4b35c2134b..5d5fdb686d 100644 --- a/engine/src/witness/btc/deposits.rs +++ b/engine/src/witness/btc/deposits.rs @@ -144,9 +144,9 @@ fn deposit_witnesses( } fn map_script_addresses( - addresses: Vec>, + deposit_channels: Vec>, ) -> HashMap, DepositAddress> { - addresses + deposit_channels .into_iter() .map(|channel| { assert_eq!(channel.deposit_channel.asset, btc::Asset::Btc); diff --git a/engine/src/witness/btc/smart_contract.rs b/engine/src/witness/btc/smart_contract.rs index 3bcc01ec6a..358b4706b3 100644 --- a/engine/src/witness/btc/smart_contract.rs +++ b/engine/src/witness/btc/smart_contract.rs @@ -77,7 +77,6 @@ fn script_buf_to_script_pubkey(script: &ScriptBuf) -> Option { type BtcIngressEgressCall = pallet_cf_ingress_egress::Call; -// Currently unused, but will be used by the deposit wintesser: pub fn try_extract_contract_call( tx: &VerboseTransaction, vault_address: &DepositAddress, From 9c2e4c3ee79a7434c8f3fb84f53b2bd8e1511af5 Mon Sep 17 00:00:00 2001 From: albert Date: Wed, 16 Oct 2024 14:25:27 +0200 Subject: [PATCH 03/36] chore: start implementation --- engine/src/witness/arb.rs | 20 +- engine/src/witness/eth.rs | 41 +++- engine/src/witness/evm/vault.rs | 191 ++++++++++++++---- .../cf-integration-tests/src/solana.rs | 10 +- .../cf-integration-tests/src/swapping.rs | 10 +- state-chain/chains/src/arb/api.rs | 2 +- state-chain/chains/src/btc/api.rs | 2 +- state-chain/chains/src/ccm_checker.rs | 12 +- state-chain/chains/src/dot/api.rs | 2 +- state-chain/chains/src/eth/api.rs | 2 +- state-chain/chains/src/lib.rs | 4 +- state-chain/chains/src/sol/api.rs | 10 +- state-chain/chains/src/sol/sol_tx_core.rs | 2 +- .../cf-ingress-egress/src/benchmarking.rs | 5 +- .../pallets/cf-ingress-egress/src/lib.rs | 18 +- .../pallets/cf-ingress-egress/src/tests.rs | 23 ++- state-chain/pallets/cf-swapping/src/tests.rs | 2 +- .../pallets/cf-swapping/src/tests/ccm.rs | 2 +- state-chain/primitives/src/lib.rs | 13 +- state-chain/traits/src/mocks/api_call.rs | 4 +- .../traits/src/mocks/egress_handler.rs | 4 +- 21 files changed, 287 insertions(+), 92 deletions(-) diff --git a/engine/src/witness/arb.rs b/engine/src/witness/arb.rs index 8eaf700d32..08d6ad2972 100644 --- a/engine/src/witness/arb.rs +++ b/engine/src/witness/arb.rs @@ -176,8 +176,8 @@ where struct ArbCallBuilder {} -use cf_chains::{address::EncodedAddress, CcmDepositMetadata}; -use cf_primitives::{Asset, AssetAmount, TransactionHash}; +use cf_chains::{address::EncodedAddress, CcmDepositMetadata, ChannelRefundParameters}; +use cf_primitives::{Asset, AssetAmount, BasisPoints, DcaParameters, TransactionHash}; impl super::evm::vault::IngressCallBuilder for ArbCallBuilder { type Chain = Arbitrum; @@ -189,8 +189,12 @@ impl super::evm::vault::IngressCallBuilder for ArbCallBuilder { destination_address: EncodedAddress, deposit_metadata: Option, tx_hash: TransactionHash, + refund_params: Option, + dca_params: Option, + // This is only to be checked in the pre-witnessed version + boost_fee: Option, ) -> state_chain_runtime::RuntimeCall { - state_chain_runtime::RuntimeCall::ArbitrumIngressEgress( + state_chain_runtime::RuntimeCall::EthereumIngressEgress( if let Some(deposit_metadata) = deposit_metadata { pallet_cf_ingress_egress::Call::contract_ccm_swap_request { source_asset, @@ -199,6 +203,9 @@ impl super::evm::vault::IngressCallBuilder for ArbCallBuilder { destination_address, deposit_metadata, tx_hash, + boost_fee, + dca_params, + refund_params, } } else { pallet_cf_ingress_egress::Call::contract_swap_request { @@ -208,10 +215,9 @@ impl super::evm::vault::IngressCallBuilder for ArbCallBuilder { destination_address, tx_hash, deposit_details: DepositDetails { tx_hashes: Some(vec![tx_hash.into()]) }, - // TODO: use real parameters when we can decode them - boost_fee: 0, - dca_params: None, - refund_params: None, + boost_fee: boost_fee.unwrap_or_default(), + dca_params, + refund_params, } }, ) diff --git a/engine/src/witness/eth.rs b/engine/src/witness/eth.rs index 8fe452fd22..572554689a 100644 --- a/engine/src/witness/eth.rs +++ b/engine/src/witness/eth.rs @@ -1,6 +1,8 @@ mod chain_tracking; mod state_chain_gateway; +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; use std::{collections::HashMap, sync::Arc}; use cf_chains::{evm::DepositDetails, Ethereum}; @@ -219,8 +221,29 @@ where Ok(()) } -use cf_chains::{address::EncodedAddress, CcmDepositMetadata}; -use cf_primitives::{Asset, AssetAmount, TransactionHash}; +use cf_chains::{ + address::EncodedAddress, CcmCfParameters, CcmDepositMetadata, ChannelRefundParameters, +}; +use cf_primitives::{Asset, AssetAmount, BasisPoints, DcaParameters, TransactionHash}; + +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] +pub struct ChannellessCfParameters { + pub ccm_cf_parameters: Option, + // TODO: Consider if we want use the BTC SharedCfParameters. It's done like that to save on + // bytes but in EVM/SOL we have more bytes to work with. At the same time the optional types + // allow the user to not have to pass an unnecessary amount of bytes as parameters on-chain. + // We might have to do it if we need to convert internal parameters such as foreign addresses + // either in order to decode properly or to pass them correctly to the ingress pallet's + // contract_swap_request. + pub shared_cf_parameters: Option, +} + +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] +pub struct SharedCfParametersContract { + pub refund_params: Option, + pub dca_params: Option, + pub boost_fee: Option, +} pub struct EthCallBuilder {} @@ -234,6 +257,10 @@ impl super::evm::vault::IngressCallBuilder for EthCallBuilder { destination_address: EncodedAddress, deposit_metadata: Option, tx_hash: TransactionHash, + refund_params: Option, + dca_params: Option, + // This is only to be checked in the pre-witnessed version + boost_fee: Option, ) -> state_chain_runtime::RuntimeCall { state_chain_runtime::RuntimeCall::EthereumIngressEgress( if let Some(deposit_metadata) = deposit_metadata { @@ -244,6 +271,9 @@ impl super::evm::vault::IngressCallBuilder for EthCallBuilder { destination_address, deposit_metadata, tx_hash, + boost_fee, + dca_params, + refund_params, } } else { pallet_cf_ingress_egress::Call::contract_swap_request { @@ -253,10 +283,9 @@ impl super::evm::vault::IngressCallBuilder for EthCallBuilder { destination_address, tx_hash, deposit_details: DepositDetails { tx_hashes: Some(vec![tx_hash.into()]) }, - // TODO: use real parameters when we can decode them - boost_fee: 0, - dca_params: None, - refund_params: None, + boost_fee: boost_fee.unwrap_or_default(), + dca_params, + refund_params, } }, ) diff --git a/engine/src/witness/evm/vault.rs b/engine/src/witness/evm/vault.rs index 206679638d..f179057fec 100644 --- a/engine/src/witness/evm/vault.rs +++ b/engine/src/witness/evm/vault.rs @@ -1,8 +1,12 @@ +use codec::Decode; use ethers::types::Bloom; -use sp_core::H256; +use sp_core::{ConstU32, H256}; use std::collections::HashMap; -use crate::evm::retry_rpc::EvmRetryRpcApi; +use crate::{ + evm::retry_rpc::EvmRetryRpcApi, + witness::eth::{ChannellessCfParameters, SharedCfParametersContract}, +}; use super::{ super::common::{ @@ -19,14 +23,18 @@ use cf_chains::{ address::{EncodedAddress, IntoForeignChainAddress}, eth::Address as EthereumAddress, evm::DepositDetails, - CcmChannelMetadata, CcmDepositMetadata, Chain, + CcmCfParameters, CcmChannelMetadata, CcmDepositMetadata, Chain, ChannelRefundParameters, }; -use cf_primitives::{Asset, ForeignChain}; +use cf_primitives::{Asset, BasisPoints, DcaParameters, ForeignChain}; use ethers::prelude::*; +use frame_support::sp_runtime::BoundedVec; use state_chain_runtime::{EthereumInstance, Runtime, RuntimeCall}; abigen!(Vault, "$CF_ETH_CONTRACT_ABI_ROOT/$CF_ETH_CONTRACT_ABI_TAG/IVault.json"); +pub const MAX_CF_PARAM_LENGTH: u32 = 1_000; +pub type CfParameters = BoundedVec>; + pub fn call_from_event< C: cf_chains::Chain, CallBuilder: IngressCallBuilder, @@ -56,6 +64,69 @@ where }) } + fn decode_shared_cf_parameters( + cf_parameters_vec: CfParameters, + ) -> Result<(Option, Option, Option)> { + println!("DEBUGDEBUG cf_parameters_vec {:?}", cf_parameters_vec); + + if cf_parameters_vec.is_empty() { + println!("DEBUGDEBUG Emtpy cf_parameters_vec"); + + Ok((None, None, None)) + } else { + let shared_cf_parameters: SharedCfParametersContract = + SharedCfParametersContract::decode(&mut &cf_parameters_vec[..]) + .map_err(|_| anyhow!("Failed to decode to `SharedCfParametersContract`"))?; + + println!("DEBUGDEBUG shared_cf_parameters {:?}", shared_cf_parameters); + + Ok(( + shared_cf_parameters.refund_params, + shared_cf_parameters.dca_params, + shared_cf_parameters.boost_fee, + )) + } + } + + fn decode_channelless_cf_parameters( + cf_parameters_vec: CfParameters, + ) -> Result<( + CcmCfParameters, + (Option, Option, Option), + )> { + println!("DEBUGDEBUG cf_parameters_vec {:?}", cf_parameters_vec); + + if cf_parameters_vec.is_empty() { + println!("DEBUGDEBUG Emtpy cf_parameters_vec"); + + Ok((cf_parameters_vec, (None, None, None))) + } else { + let channelless_cf_parameters: ChannellessCfParameters = + ChannellessCfParameters::decode(&mut &cf_parameters_vec[..]) + .map_err(|_| anyhow!("Failed to decode to `ChannellessCfParameters`"))?; + + println!("DEBUGDEBUG channelless_cf_parameters {:?}", channelless_cf_parameters); + + let (refund_params, dca_params, boost_fee) = if let Some(shared_cf_parameters) = + channelless_cf_parameters.shared_cf_parameters + { + ( + shared_cf_parameters.refund_params, + shared_cf_parameters.dca_params, + shared_cf_parameters.boost_fee, + ) + } else { + (None, None, None) + }; + + Ok(( + // Default to empty CcmCfParameters if not present + channelless_cf_parameters.ccm_cf_parameters.unwrap_or_default(), + (refund_params, dca_params, boost_fee), + )) + } + } + Ok(match event.event_parameters { VaultEvents::SwapNativeFilter(SwapNativeFilter { dst_chain, @@ -63,15 +134,28 @@ where dst_token, amount, sender: _, - cf_parameters: _, - }) => Some(CallBuilder::contract_swap_request( - native_asset, - try_into_primitive(amount)?, - try_into_primitive(dst_token)?, - try_into_encoded_address(try_into_primitive(dst_chain)?, dst_address.to_vec())?, - None, - event.tx_hash.into(), - )), + cf_parameters, + }) => { + println!("DEBUGDEBUG cf_parameters {:?}", cf_parameters); + let cf_parameters_vec: CfParameters = cf_parameters + .to_vec() + .try_into() + .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; + let (refund_params, dca_params, boost_fee) = + decode_shared_cf_parameters(cf_parameters_vec)?; + + Some(CallBuilder::contract_swap_request( + native_asset, + try_into_primitive(amount)?, + try_into_primitive(dst_token)?, + try_into_encoded_address(try_into_primitive(dst_chain)?, dst_address.to_vec())?, + None, + event.tx_hash.into(), + refund_params, + dca_params, + boost_fee, + )) + }, VaultEvents::SwapTokenFilter(SwapTokenFilter { dst_chain, dst_address, @@ -79,17 +163,31 @@ where src_token, amount, sender: _, - cf_parameters: _, - }) => Some(CallBuilder::contract_swap_request( - *(supported_assets - .get(&src_token) - .ok_or(anyhow!("Source token {src_token:?} not found"))?), - try_into_primitive(amount)?, - try_into_primitive(dst_token)?, - try_into_encoded_address(try_into_primitive(dst_chain)?, dst_address.to_vec())?, - None, - event.tx_hash.into(), - )), + cf_parameters, + }) => { + println!("DEBUGDEBUG cf_parameters {:?}", cf_parameters); + + let cf_parameters_vec: CfParameters = cf_parameters + .to_vec() + .try_into() + .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; + let (refund_params, dca_params, boost_fee) = + decode_shared_cf_parameters(cf_parameters_vec)?; + + Some(CallBuilder::contract_swap_request( + *(supported_assets + .get(&src_token) + .ok_or(anyhow!("Source token {src_token:?} not found"))?), + try_into_primitive(amount)?, + try_into_primitive(dst_token)?, + try_into_encoded_address(try_into_primitive(dst_chain)?, dst_address.to_vec())?, + None, + event.tx_hash.into(), + refund_params, + dca_params, + boost_fee, + )) + }, VaultEvents::XcallNativeFilter(XcallNativeFilter { dst_chain, dst_address, @@ -99,7 +197,16 @@ where message, gas_amount, cf_parameters, - }) => + }) => { + println!("DEBUGDEBUG cf_parameters {:?}", cf_parameters); + + let cf_parameters_vec: CfParameters = cf_parameters + .to_vec() + .try_into() + .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; + let (ccm_cf_parameters, (refund_params, dca_params, boost_fee)) = + decode_channelless_cf_parameters(cf_parameters_vec)?; + Some(CallBuilder::contract_swap_request( native_asset, try_into_primitive(amount)?, @@ -118,13 +225,15 @@ where .try_into() .map_err(|_| anyhow!("Failed to deposit CCM: `message` too long."))?, gas_budget: try_into_primitive(gas_amount)?, - cf_parameters: cf_parameters.0.to_vec().try_into().map_err(|_| { - anyhow!("Failed to deposit CCM: `cf_parameters` too long.") - })?, + ccm_cf_parameters, }, }), event.tx_hash.into(), - )), + refund_params, + dca_params, + boost_fee, + )) + }, VaultEvents::XcallTokenFilter(XcallTokenFilter { dst_chain, dst_address, @@ -135,7 +244,16 @@ where message, gas_amount, cf_parameters, - }) => + }) => { + println!("DEBUGDEBUG cf_parameters {:?}", cf_parameters); + + let cf_parameters_vec: CfParameters = cf_parameters + .to_vec() + .try_into() + .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; + let (ccm_cf_parameters, (refund_params, dca_params, boost_fee)) = + decode_channelless_cf_parameters(cf_parameters_vec)?; + Some(CallBuilder::contract_swap_request( *(supported_assets .get(&src_token) @@ -156,13 +274,15 @@ where .try_into() .map_err(|_| anyhow!("Failed to deposit CCM. Message too long."))?, gas_budget: try_into_primitive(gas_amount)?, - cf_parameters: cf_parameters.0.to_vec().try_into().map_err(|_| { - anyhow!("Failed to deposit CCM. cf_parameters too long.") - })?, + ccm_cf_parameters, }, }), event.tx_hash.into(), - )), + refund_params, + dca_params, + boost_fee, + )) + }, VaultEvents::TransferNativeFailedFilter(TransferNativeFailedFilter { recipient, amount, @@ -204,6 +324,9 @@ pub trait IngressCallBuilder { destination_address: EncodedAddress, deposit_metadata: Option, tx_hash: cf_primitives::TransactionHash, + refund_params: Option, + dca_params: Option, + boost_fee: Option, ) -> state_chain_runtime::RuntimeCall; fn vault_transfer_failed( diff --git a/state-chain/cf-integration-tests/src/solana.rs b/state-chain/cf-integration-tests/src/solana.rs index 3af8d2f7bc..2850d06da5 100644 --- a/state-chain/cf-integration-tests/src/solana.rs +++ b/state-chain/cf-integration-tests/src/solana.rs @@ -374,7 +374,7 @@ fn solana_ccm_fails_with_invalid_input() { channel_metadata: CcmChannelMetadata { message: vec![0u8, 1u8, 2u8, 3u8].try_into().unwrap(), gas_budget: 0u128, - cf_parameters: vec![0u8, 1u8, 2u8, 3u8].try_into().unwrap(), + ccm_cf_parameters: vec![0u8, 1u8, 2u8, 3u8].try_into().unwrap(), }, }; @@ -416,6 +416,9 @@ fn solana_ccm_fails_with_invalid_input() { destination_address: EncodedAddress::Sol([1u8; 32]), deposit_metadata: invalid_ccm, tx_hash: Default::default(), + refund_params: None, + dca_params: None, + boost_fee: None, } ) .dispatch_bypass_filter( @@ -443,7 +446,7 @@ fn solana_ccm_fails_with_invalid_input() { channel_metadata: CcmChannelMetadata { message: vec![0u8, 1u8, 2u8, 3u8].try_into().unwrap(), gas_budget: 0u128, - cf_parameters: SolCcmAccounts { + ccm_cf_parameters: SolCcmAccounts { cf_receiver: SolCcmAddress { pubkey: receiver.into(), is_writable: true }, remaining_accounts: vec![ SolCcmAddress { pubkey: SolPubkey([0x01; 32]), is_writable: false }, @@ -464,6 +467,9 @@ fn solana_ccm_fails_with_invalid_input() { destination_address: EncodedAddress::Sol([1u8; 32]), deposit_metadata: ccm, tx_hash: Default::default(), + refund_params: None, + dca_params: None, + boost_fee: None, }, )); // Setting the current agg key will invalidate the CCM. diff --git a/state-chain/cf-integration-tests/src/swapping.rs b/state-chain/cf-integration-tests/src/swapping.rs index 40bd15e5af..28db1b8dba 100644 --- a/state-chain/cf-integration-tests/src/swapping.rs +++ b/state-chain/cf-integration-tests/src/swapping.rs @@ -374,7 +374,7 @@ fn can_process_ccm_via_swap_deposit_address() { let message = CcmChannelMetadata { message: vec![0u8, 1u8, 2u8, 3u8, 4u8].try_into().unwrap(), gas_budget: GAS_BUDGET, - cf_parameters: Default::default(), + ccm_cf_parameters: Default::default(), }; assert_ok!(Swapping::request_swap_deposit_address_with_affiliates( @@ -559,7 +559,7 @@ fn ccm_deposit_metadata_mock() -> CcmDepositMetadata { channel_metadata: CcmChannelMetadata { message: vec![0u8, 1u8, 2u8, 3u8, 4u8].try_into().unwrap(), gas_budget: 100_000_000, - cf_parameters: Default::default(), + ccm_cf_parameters: Default::default(), }, } } @@ -579,6 +579,9 @@ fn can_process_ccm_via_direct_deposit() { destination_address: EncodedAddress::Eth([0x02; 20]), deposit_metadata: ccm_deposit_metadata_mock(), tx_hash: Default::default(), + refund_params: None, + dca_params: None, + boost_fee: None, }, )); @@ -785,6 +788,9 @@ fn can_resign_failed_ccm() { deposit_metadata: ccm_deposit_metadata_mock(), // deposit_metadata, tx_hash: Default::default(), + refund_params: None, + dca_params: None, + boost_fee: None, }, )); diff --git a/state-chain/chains/src/arb/api.rs b/state-chain/chains/src/arb/api.rs index 053827d9ee..78b58d7f24 100644 --- a/state-chain/chains/src/arb/api.rs +++ b/state-chain/chains/src/arb/api.rs @@ -70,7 +70,7 @@ where source_address: Option, gas_budget: ::ChainAmount, message: Vec, - _cf_parameters: Vec, + _ccm_cf_parameters: Vec, ) -> Result { let transfer_param = EncodableTransferAssetParams { asset: E::token_address(transfer_param.asset) diff --git a/state-chain/chains/src/btc/api.rs b/state-chain/chains/src/btc/api.rs index c60401de79..4cf47ea1bf 100644 --- a/state-chain/chains/src/btc/api.rs +++ b/state-chain/chains/src/btc/api.rs @@ -140,7 +140,7 @@ impl> ExecutexSwapAndCall for Bitc _source_address: Option, _gas_budget: ::ChainAmount, _message: Vec, - _cf_parameters: Vec, + _ccm_cf_parameters: Vec, ) -> Result { Err(ExecutexSwapAndCallError::Unsupported) } diff --git a/state-chain/chains/src/ccm_checker.rs b/state-chain/chains/src/ccm_checker.rs index 13ccc8cd47..3ff687869c 100644 --- a/state-chain/chains/src/ccm_checker.rs +++ b/state-chain/chains/src/ccm_checker.rs @@ -44,7 +44,7 @@ impl CcmValidityCheck for CcmValidityChecker { ) -> Result { if ForeignChain::from(egress_asset) == ForeignChain::Solana { // Check if the cf_parameter can be decoded - let ccm_accounts = SolCcmAccounts::decode(&mut &ccm.cf_parameters.clone()[..]) + let ccm_accounts = SolCcmAccounts::decode(&mut &ccm.ccm_cf_parameters.clone()[..]) .map_err(|_| CcmValidityError::CannotDecodeCfParameters)?; let asset: SolAsset = egress_asset .try_into() @@ -107,7 +107,7 @@ mod test { let ccm = CcmChannelMetadata { message: vec![0x01, 0x02, 0x03, 0x04, 0x05].try_into().unwrap(), gas_budget: 1, - cf_parameters: vec![0x01, 0x02, 0x03, 0x04, 0x05].try_into().unwrap(), + ccm_cf_parameters: vec![0x01, 0x02, 0x03, 0x04, 0x05].try_into().unwrap(), }; assert_err!( @@ -121,7 +121,7 @@ mod test { let ccm = || CcmChannelMetadata { message: vec![0x01; MAX_CCM_BYTES_SOL].try_into().unwrap(), gas_budget: 0, - cf_parameters: SolCcmAccounts { + ccm_cf_parameters: SolCcmAccounts { cf_receiver: SolCcmAddress { pubkey: SolPubkey([0x01; 32]), is_writable: true }, remaining_accounts: vec![], } @@ -140,7 +140,7 @@ mod test { ); let mut invalid_ccm = ccm(); - invalid_ccm.cf_parameters = SolCcmAccounts { + invalid_ccm.ccm_cf_parameters = SolCcmAccounts { cf_receiver: SolCcmAddress { pubkey: SolPubkey([0x01; 32]), is_writable: true }, remaining_accounts: vec![SolCcmAddress { pubkey: SolPubkey([0x01; 32]), @@ -161,7 +161,7 @@ mod test { let ccm = || CcmChannelMetadata { message: vec![0x01; MAX_CCM_BYTES_USDC].try_into().unwrap(), gas_budget: 0, - cf_parameters: SolCcmAccounts { + ccm_cf_parameters: SolCcmAccounts { cf_receiver: SolCcmAddress { pubkey: SolPubkey([0x01; 32]), is_writable: true }, remaining_accounts: vec![], } @@ -180,7 +180,7 @@ mod test { ); let mut invalid_ccm = ccm(); - invalid_ccm.cf_parameters = SolCcmAccounts { + invalid_ccm.ccm_cf_parameters = SolCcmAccounts { cf_receiver: SolCcmAddress { pubkey: SolPubkey([0x01; 32]), is_writable: true }, remaining_accounts: vec![SolCcmAddress { pubkey: SolPubkey([0x01; 32]), diff --git a/state-chain/chains/src/dot/api.rs b/state-chain/chains/src/dot/api.rs index d42186f812..3b38109d0e 100644 --- a/state-chain/chains/src/dot/api.rs +++ b/state-chain/chains/src/dot/api.rs @@ -128,7 +128,7 @@ where _source_address: Option, _gas_budget: ::ChainAmount, _message: Vec, - _cf_parameters: Vec, + _ccm_cf_parameters: Vec, ) -> Result { Err(ExecutexSwapAndCallError::Unsupported) } diff --git a/state-chain/chains/src/eth/api.rs b/state-chain/chains/src/eth/api.rs index 1244ac31b2..f7df478ebc 100644 --- a/state-chain/chains/src/eth/api.rs +++ b/state-chain/chains/src/eth/api.rs @@ -194,7 +194,7 @@ where source_address: Option, gas_budget: ::ChainAmount, message: Vec, - _cf_parameters: Vec, + _ccm_cf_parameters: Vec, ) -> Result { let transfer_param = EncodableTransferAssetParams { asset: E::token_address(transfer_param.asset) diff --git a/state-chain/chains/src/lib.rs b/state-chain/chains/src/lib.rs index 7fc4c80909..b882c6b15b 100644 --- a/state-chain/chains/src/lib.rs +++ b/state-chain/chains/src/lib.rs @@ -549,7 +549,7 @@ pub trait ExecutexSwapAndCall: ApiCall { source_address: Option, gas_budget: C::ChainAmount, message: Vec, - cf_parameters: Vec, + ccm_cf_parameters: Vec, ) -> Result; } @@ -636,7 +636,7 @@ pub struct CcmChannelMetadata { feature = "std", serde(with = "bounded_hex", default, skip_serializing_if = "Vec::is_empty") )] - pub cf_parameters: CcmCfParameters, + pub ccm_cf_parameters: CcmCfParameters, } #[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)] diff --git a/state-chain/chains/src/sol/api.rs b/state-chain/chains/src/sol/api.rs index ff1b9442bf..4bbd81db81 100644 --- a/state-chain/chains/src/sol/api.rs +++ b/state-chain/chains/src/sol/api.rs @@ -260,10 +260,10 @@ impl SolanaApi { source_address: Option, gas_budget: ::ChainAmount, message: Vec, - cf_parameters: Vec, + ccm_cf_parameters: Vec, ) -> Result { // For extra safety, re-verify the validity of the CCM message here - // and extract the decoded `ccm_accounts` from `cf_parameters`. + // and extract the decoded `ccm_accounts` from `ccm_cf_parameters`. let decoded_cf_params = CcmValidityChecker::check_and_decode( &CcmChannelMetadata { message: message @@ -271,7 +271,7 @@ impl SolanaApi { .try_into() .expect("This is parsed from bounded vec, therefore the size must fit"), gas_budget: 0, // This value is un-used by Solana - cf_parameters: cf_parameters + ccm_cf_parameters: ccm_cf_parameters .clone() .try_into() .expect("This is parsed from bounded vec, therefore the size must fit"), @@ -439,7 +439,7 @@ impl ExecutexSwapAndCall for SolanaApi source_address: Option, gas_budget: ::ChainAmount, message: Vec, - cf_parameters: Vec, + ccm_cf_parameters: Vec, ) -> Result { Self::ccm_transfer( transfer_param, @@ -447,7 +447,7 @@ impl ExecutexSwapAndCall for SolanaApi source_address, gas_budget, message, - cf_parameters, + ccm_cf_parameters, ) .map_err(|e| { log::error!("Failed to construct Solana CCM transfer transaction! \nError: {:?}", e); diff --git a/state-chain/chains/src/sol/sol_tx_core.rs b/state-chain/chains/src/sol/sol_tx_core.rs index 87c249fa18..f3a6c1d370 100644 --- a/state-chain/chains/src/sol/sol_tx_core.rs +++ b/state-chain/chains/src/sol/sol_tx_core.rs @@ -946,7 +946,7 @@ pub mod sol_test_values { channel_metadata: CcmChannelMetadata { message: vec![124u8, 29u8, 15u8, 7u8].try_into().unwrap(), // CCM message gas_budget: 0u128, // unused - cf_parameters: codec::Encode::encode(&ccm_accounts()) + ccm_cf_parameters: codec::Encode::encode(&ccm_accounts()) .try_into() .expect("Test data cannot be too long"), // Extra addresses }, diff --git a/state-chain/pallets/cf-ingress-egress/src/benchmarking.rs b/state-chain/pallets/cf-ingress-egress/src/benchmarking.rs index 04f69be3bf..b10aa6e3b0 100644 --- a/state-chain/pallets/cf-ingress-egress/src/benchmarking.rs +++ b/state-chain/pallets/cf-ingress-egress/src/benchmarking.rs @@ -318,7 +318,7 @@ mod benchmarks { channel_metadata: CcmChannelMetadata { message: vec![0x00].try_into().unwrap(), gas_budget: 1, - cf_parameters: Default::default(), + ccm_cf_parameters: Default::default(), }, }; let call = Call::::contract_ccm_swap_request { @@ -328,6 +328,9 @@ mod benchmarks { destination_address: EncodedAddress::benchmark_value(), deposit_metadata, tx_hash: Default::default(), + refund_params: None, + dca_params: None, + boost_fee: None, }; #[block] diff --git a/state-chain/pallets/cf-ingress-egress/src/lib.rs b/state-chain/pallets/cf-ingress-egress/src/lib.rs index 691c9d7cd6..6121bc9816 100644 --- a/state-chain/pallets/cf-ingress-egress/src/lib.rs +++ b/state-chain/pallets/cf-ingress-egress/src/lib.rs @@ -134,7 +134,7 @@ pub(crate) struct CrossChainMessage { pub source_chain: ForeignChain, pub source_address: Option, // Where funds might be returned to if the message fails. - pub cf_parameters: CcmCfParameters, + pub ccm_cf_parameters: CcmCfParameters, pub gas_budget: C::ChainAmount, } @@ -1153,6 +1153,10 @@ pub mod pallet { destination_address: EncodedAddress, deposit_metadata: CcmDepositMetadata, tx_hash: TransactionHash, + refund_params: Option, + dca_params: Option, + // This is only to be checked in the pre-witnessed version (not implemented yet) + _boost_fee: Option, ) -> DispatchResult { T::EnsureWitnessed::ensure_origin(origin)?; @@ -1212,10 +1216,8 @@ pub mod pallet { output_address: destination_address_internal.clone(), }, Default::default(), - // NOTE: FoK not yet supported for swaps from the contract - None, - // NOTE: DCA not yet supported for swaps from the contract - None, + refund_params, + dca_params, swap_origin, ); @@ -1472,7 +1474,7 @@ impl, I: 'static> Pallet { ccm.source_address, ccm.gas_budget, ccm.message.to_vec(), - ccm.cf_parameters.to_vec(), + ccm.ccm_cf_parameters.to_vec(), ) { Ok(api_call) => { let broadcast_id = T::Broadcaster::threshold_sign_and_broadcast_with_callback( @@ -2116,7 +2118,7 @@ impl, I: 'static> EgressApi for Pallet { match maybe_ccm_with_gas_budget { Some(( CcmDepositMetadata { - channel_metadata: CcmChannelMetadata { message, cf_parameters, .. }, + channel_metadata: CcmChannelMetadata { message, ccm_cf_parameters, .. }, source_chain, source_address, .. @@ -2129,7 +2131,7 @@ impl, I: 'static> EgressApi for Pallet { amount, destination_address: destination_address.clone(), message, - cf_parameters, + ccm_cf_parameters, source_chain, source_address, gas_budget, diff --git a/state-chain/pallets/cf-ingress-egress/src/tests.rs b/state-chain/pallets/cf-ingress-egress/src/tests.rs index 45bf3cb74a..05ca749043 100644 --- a/state-chain/pallets/cf-ingress-egress/src/tests.rs +++ b/state-chain/pallets/cf-ingress-egress/src/tests.rs @@ -115,7 +115,7 @@ fn blacklisted_asset_will_not_egress_via_ccm() { channel_metadata: CcmChannelMetadata { message: vec![0x00, 0x01, 0x02].try_into().unwrap(), gas_budget: 1_000, - cf_parameters: vec![].try_into().unwrap(), + ccm_cf_parameters: vec![].try_into().unwrap(), }, }; @@ -149,7 +149,7 @@ fn blacklisted_asset_will_not_egress_via_ccm() { message: ccm.channel_metadata.message.clone(), source_chain: ForeignChain::Ethereum, source_address: ccm.source_address.clone(), - cf_parameters: ccm.channel_metadata.cf_parameters, + ccm_cf_parameters: ccm.channel_metadata.ccm_cf_parameters, gas_budget, }] ); @@ -578,7 +578,7 @@ fn can_egress_ccm() { channel_metadata: CcmChannelMetadata { message: vec![0x00, 0x01, 0x02].try_into().unwrap(), gas_budget: GAS_BUDGET, - cf_parameters: vec![].try_into().unwrap(), + ccm_cf_parameters: vec![].try_into().unwrap(), } }; @@ -598,7 +598,7 @@ fn can_egress_ccm() { amount, destination_address, message: ccm.channel_metadata.message.clone(), - cf_parameters: vec![].try_into().unwrap(), + ccm_cf_parameters: vec![].try_into().unwrap(), source_chain: ForeignChain::Ethereum, source_address: Some(ForeignChainAddress::Eth([0xcf; 20].into())), gas_budget: GAS_BUDGET, @@ -1798,7 +1798,7 @@ fn do_not_process_more_ccm_swaps_than_allowed_by_limit() { channel_metadata: CcmChannelMetadata { message: vec![0x00, 0x01, 0x02].try_into().unwrap(), gas_budget: 1_000, - cf_parameters: vec![].try_into().unwrap(), + ccm_cf_parameters: vec![].try_into().unwrap(), }, }; @@ -1884,7 +1884,7 @@ fn can_request_ccm_swap_via_extrinsic() { channel_metadata: CcmChannelMetadata { message: vec![0x01].try_into().unwrap(), gas_budget: 1_000, - cf_parameters: Default::default(), + ccm_cf_parameters: Default::default(), }, }; @@ -1899,6 +1899,9 @@ fn can_request_ccm_swap_via_extrinsic() { MockAddressConverter::to_encoded_address(output_address.clone()), ccm_deposit_metadata.clone(), TX_HASH, + None, + None, + None, )); assert_eq!( @@ -1976,7 +1979,7 @@ fn failed_ccm_deposit_can_deposit_event() { channel_metadata: CcmChannelMetadata { message: vec![0x01].try_into().unwrap(), gas_budget: GAS_BUDGET, - cf_parameters: Default::default(), + ccm_cf_parameters: Default::default(), }, }; @@ -1990,6 +1993,9 @@ fn failed_ccm_deposit_can_deposit_event() { EncodedAddress::Dot(Default::default()), ccm_deposit_metadata.clone(), Default::default(), + None, + None, + None, )); assert_has_matching_event!( @@ -2011,6 +2017,9 @@ fn failed_ccm_deposit_can_deposit_event() { EncodedAddress::Eth(Default::default()), ccm_deposit_metadata, Default::default(), + None, + None, + None, )); assert_has_matching_event!( diff --git a/state-chain/pallets/cf-swapping/src/tests.rs b/state-chain/pallets/cf-swapping/src/tests.rs index deaa23c184..08ef7d7c35 100644 --- a/state-chain/pallets/cf-swapping/src/tests.rs +++ b/state-chain/pallets/cf-swapping/src/tests.rs @@ -216,7 +216,7 @@ fn generate_ccm_channel() -> CcmChannelMetadata { CcmChannelMetadata { message: vec![0x01].try_into().unwrap(), gas_budget: GAS_BUDGET, - cf_parameters: Default::default(), + ccm_cf_parameters: Default::default(), } } fn generate_ccm_deposit() -> CcmDepositMetadata { diff --git a/state-chain/pallets/cf-swapping/src/tests/ccm.rs b/state-chain/pallets/cf-swapping/src/tests/ccm.rs index 7b2c9712d8..b8aa60c018 100644 --- a/state-chain/pallets/cf-swapping/src/tests/ccm.rs +++ b/state-chain/pallets/cf-swapping/src/tests/ccm.rs @@ -66,7 +66,7 @@ pub(super) fn assert_ccm_egressed( amount: principal_amount, destination_address: (*EVM_OUTPUT_ADDRESS).clone(), message: vec![0x01].try_into().unwrap(), - cf_parameters: vec![].try_into().unwrap(), + ccm_cf_parameters: vec![].try_into().unwrap(), gas_budget, }, ); diff --git a/state-chain/primitives/src/lib.rs b/state-chain/primitives/src/lib.rs index 6daa6b210e..6efde071d2 100644 --- a/state-chain/primitives/src/lib.rs +++ b/state-chain/primitives/src/lib.rs @@ -405,7 +405,18 @@ pub struct Beneficiary { pub bps: BasisPoints, } -#[derive(Clone, RuntimeDebug, PartialEq, Eq, Encode, Decode, TypeInfo, Serialize, Deserialize)] +#[derive( + Clone, + RuntimeDebug, + PartialEq, + Eq, + Encode, + Decode, + MaxEncodedLen, + TypeInfo, + Serialize, + Deserialize, +)] pub struct DcaParameters { /// The number of individual swaps to be executed pub number_of_chunks: u32, diff --git a/state-chain/traits/src/mocks/api_call.rs b/state-chain/traits/src/mocks/api_call.rs index 095b58c28f..6d8834f772 100644 --- a/state-chain/traits/src/mocks/api_call.rs +++ b/state-chain/traits/src/mocks/api_call.rs @@ -149,7 +149,7 @@ impl ExecutexSwapAndCall for MockEthereumApiCall { source_address: Option, gas_budget: ::ChainAmount, message: Vec, - _cf_parameters: Vec, + _ccm_cf_parameters: Vec, ) -> Result { if MockEvmEnvironment::lookup(transfer_param.asset).is_none() { Err(ExecutexSwapAndCallError::DispatchError(DispatchError::CannotLookup)) @@ -285,7 +285,7 @@ impl ExecutexSwapAndCall for MockBitcoinApiCall { source_address: Option, gas_budget: ::ChainAmount, message: Vec, - _cf_parameters: Vec, + _ccm_cf_parameters: Vec, ) -> Result { if MockBtcEnvironment::lookup(transfer_param.asset).is_none() { Err(ExecutexSwapAndCallError::DispatchError(DispatchError::CannotLookup)) diff --git a/state-chain/traits/src/mocks/egress_handler.rs b/state-chain/traits/src/mocks/egress_handler.rs index b150ef96e4..50033461fd 100644 --- a/state-chain/traits/src/mocks/egress_handler.rs +++ b/state-chain/traits/src/mocks/egress_handler.rs @@ -29,7 +29,7 @@ pub enum MockEgressParameter { amount: C::ChainAmount, destination_address: C::ChainAccount, message: CcmMessage, - cf_parameters: CcmCfParameters, + ccm_cf_parameters: CcmCfParameters, gas_budget: C::ChainAmount, }, } @@ -95,7 +95,7 @@ impl EgressApi for MockEgressHandler { amount, destination_address, message: message.channel_metadata.message.clone(), - cf_parameters: message.channel_metadata.cf_parameters.clone(), + ccm_cf_parameters: message.channel_metadata.ccm_cf_parameters.clone(), gas_budget: *gas_budget, }, None => MockEgressParameter::::Swap { From 6557606c6cbe494017c39eb61da4c65e8faa5775 Mon Sep 17 00:00:00 2001 From: Maxim Shishmarev Date: Thu, 17 Oct 2024 16:13:58 +1100 Subject: [PATCH 04/36] test: fix deposit witnessing tests --- engine/src/witness/btc.rs | 6 +- engine/src/witness/btc/deposits.rs | 134 ++++++++++++++--------------- 2 files changed, 69 insertions(+), 71 deletions(-) diff --git a/engine/src/witness/btc.rs b/engine/src/witness/btc.rs index 1963a4ecb0..4f3b3ed31b 100644 --- a/engine/src/witness/btc.rs +++ b/engine/src/witness/btc.rs @@ -213,15 +213,15 @@ mod tests { let txs = vec![ fake_transaction(vec![], Some(Amount::from_sat(FEE_0))), fake_transaction( - fake_verbose_vouts(vec![(2324, vec![0, 32, 121, 9])]), + fake_verbose_vouts(vec![(2324, &DepositAddress::new([0; 32], 0))]), Some(Amount::from_sat(FEE_1)), ), fake_transaction( - fake_verbose_vouts(vec![(232232, vec![32, 32, 121, 9])]), + fake_verbose_vouts(vec![(232232, &DepositAddress::new([32; 32], 0))]), Some(Amount::from_sat(FEE_2)), ), fake_transaction( - fake_verbose_vouts(vec![(232232, vec![32, 32, 121, 9])]), + fake_verbose_vouts(vec![(232232, &DepositAddress::new([32; 32], 0))]), Some(Amount::from_sat(FEE_3)), ), ]; diff --git a/engine/src/witness/btc/deposits.rs b/engine/src/witness/btc/deposits.rs index 5d5fdb686d..aac36ff971 100644 --- a/engine/src/witness/btc/deposits.rs +++ b/engine/src/witness/btc/deposits.rs @@ -168,10 +168,7 @@ pub mod tests { absolute::{Height, LockTime}, Amount, ScriptBuf, Txid, }; - use cf_chains::{ - btc::{deposit_address::DepositAddress, ScriptPubkey}, - DepositChannel, - }; + use cf_chains::{btc::deposit_address::DepositAddress, DepositChannel}; use pallet_cf_ingress_egress::{BoostStatus, ChannelAction}; use rand::{seq::SliceRandom, Rng, SeedableRng}; use sp_runtime::AccountId32; @@ -195,16 +192,16 @@ pub mod tests { } fn fake_details( - address: ScriptPubkey, + deposit_address: DepositAddress, ) -> DepositChannelDetails { DepositChannelDetails::<_, BitcoinInstance> { opened_at: 1, expires_at: 10, deposit_channel: DepositChannel { channel_id: 1, - address, + address: deposit_address.script_pubkey(), asset: btc::Asset::Btc, - state: DepositAddress::new([0; 32], 1), + state: deposit_address, }, action: ChannelAction::::LiquidityProvision { lp_account: AccountId32::new([0xab; 32]), @@ -214,14 +211,16 @@ pub mod tests { } } - pub fn fake_verbose_vouts(vals_and_scripts: Vec<(u64, Vec)>) -> Vec { - vals_and_scripts + pub fn fake_verbose_vouts( + amounts_and_addresses: Vec<(u64, &DepositAddress)>, + ) -> Vec { + amounts_and_addresses .into_iter() .enumerate() - .map(|(n, (value, script_bytes))| VerboseTxOut { - value: Amount::from_sat(value), + .map(|(n, (amount, address))| VerboseTxOut { + value: Amount::from_sat(amount), n: n as u64, - script_pubkey: ScriptBuf::from(script_bytes), + script_pubkey: ScriptBuf::from(address.script_pubkey().bytes()), }) .collect() } @@ -235,21 +234,16 @@ pub mod tests { #[test] fn filter_out_value_0() { - let btc_deposit_script: ScriptPubkey = DepositAddress::new([0; 32], 9).script_pubkey(); + let deposit_address = DepositAddress::new([0; 32], 9); const UTXO_WITNESSED_1: u64 = 2324; let txs = vec![fake_transaction( - fake_verbose_vouts(vec![ - (2324, btc_deposit_script.bytes()), - (0, btc_deposit_script.bytes()), - ]), + fake_verbose_vouts(vec![(2324, &deposit_address), (0, &deposit_address)]), None, )]; - let deposit_witnesses = deposit_witnesses( - &txs, - &map_script_addresses(vec![(fake_details(btc_deposit_script))]), - ); + let deposit_witnesses = + deposit_witnesses(&txs, &map_script_addresses(vec![(fake_details(deposit_address))])); assert_eq!(deposit_witnesses.len(), 1); assert_eq!(deposit_witnesses[0].amount, UTXO_WITNESSED_1); } @@ -260,15 +254,15 @@ pub mod tests { const UTXO_TO_DEPOSIT_2: u64 = 1234; const UTXO_TO_DEPOSIT_3: u64 = 2000; - let btc_deposit_script: ScriptPubkey = DepositAddress::new([0; 32], 9).script_pubkey(); + let deposit_address = DepositAddress::new([0; 32], 9); let txs = vec![ fake_transaction( fake_verbose_vouts(vec![ - (UTXO_TO_DEPOSIT_2, btc_deposit_script.bytes()), - (12223, vec![0, 32, 121, 9]), - (LARGEST_UTXO_TO_DEPOSIT, btc_deposit_script.bytes()), - (UTXO_TO_DEPOSIT_3, btc_deposit_script.bytes()), + (UTXO_TO_DEPOSIT_2, &deposit_address), + (12223, &DepositAddress::new([0; 32], 10)), + (LARGEST_UTXO_TO_DEPOSIT, &deposit_address), + (UTXO_TO_DEPOSIT_3, &deposit_address), ]), None, ), @@ -276,7 +270,7 @@ pub mod tests { ]; let deposit_witnesses = - deposit_witnesses(&txs, &map_script_addresses(vec![fake_details(btc_deposit_script)])); + deposit_witnesses(&txs, &map_script_addresses(vec![fake_details(deposit_address)])); assert_eq!(deposit_witnesses.len(), 1); assert_eq!(deposit_witnesses[0].amount, LARGEST_UTXO_TO_DEPOSIT); } @@ -287,16 +281,16 @@ pub mod tests { const UTXO_TO_DEPOSIT_2: u64 = 1234; const UTXO_FOR_SECOND_DEPOSIT: u64 = 2000; - let btc_deposit_script_1: ScriptPubkey = DepositAddress::new([0; 32], 9).script_pubkey(); - let btc_deposit_script_2: ScriptPubkey = DepositAddress::new([0; 32], 1232).script_pubkey(); + let deposit_address_1 = DepositAddress::new([0; 32], 9); + let deposit_address_2 = DepositAddress::new([0; 32], 1232); let txs = vec![ fake_transaction( fake_verbose_vouts(vec![ - (UTXO_TO_DEPOSIT_2, btc_deposit_script_1.bytes()), - (12223, vec![0, 32, 121, 9]), - (LARGEST_UTXO_TO_DEPOSIT, btc_deposit_script_1.bytes()), - (UTXO_FOR_SECOND_DEPOSIT, btc_deposit_script_2.bytes()), + (UTXO_TO_DEPOSIT_2, &deposit_address_1), + (12223, &DepositAddress::new([0; 32], 999)), + (LARGEST_UTXO_TO_DEPOSIT, &deposit_address_1), + (UTXO_FOR_SECOND_DEPOSIT, &deposit_address_2), ]), None, ), @@ -307,77 +301,81 @@ pub mod tests { &txs, // watching 2 addresses &map_script_addresses(vec![ - fake_details(btc_deposit_script_1.clone()), - fake_details(btc_deposit_script_2.clone()), + fake_details(deposit_address_1.clone()), + fake_details(deposit_address_2.clone()), ]), ); // We should have one deposit per address. assert_eq!(deposit_witnesses.len(), 2); assert_eq!(deposit_witnesses[0].amount, UTXO_FOR_SECOND_DEPOSIT); - assert_eq!(deposit_witnesses[0].deposit_address, btc_deposit_script_2); + assert_eq!(deposit_witnesses[0].deposit_address, deposit_address_2.script_pubkey()); assert_eq!(deposit_witnesses[1].amount, LARGEST_UTXO_TO_DEPOSIT); - assert_eq!(deposit_witnesses[1].deposit_address, btc_deposit_script_1); + assert_eq!(deposit_witnesses[1].deposit_address, deposit_address_1.script_pubkey()); } #[test] fn deposit_witnesses_ordering_is_consistent() { - let btc_deposit_script_1: ScriptPubkey = DepositAddress::new([0; 32], 9).script_pubkey(); - let btc_deposit_script_2: ScriptPubkey = DepositAddress::new([0; 32], 1232).script_pubkey(); + let address_1 = DepositAddress::new([0; 32], 9); + let address_2 = DepositAddress::new([0; 32], 1232); + DepositAddress::new([0; 32], 0); - let script_addresses = map_script_addresses(vec![ - fake_details(btc_deposit_script_1.clone()), - fake_details(btc_deposit_script_2.clone()), + let addresses = map_script_addresses(vec![ + fake_details(address_1.clone()), + fake_details(address_2.clone()), ]); let txs: Vec = vec![ fake_transaction( fake_verbose_vouts(vec![ - (3, btc_deposit_script_1.bytes()), - (5, vec![3]), - (7, btc_deposit_script_1.bytes()), - (11, btc_deposit_script_2.bytes()), + (3, &address_1), + (5, &DepositAddress::new([3; 32], 0)), + (7, &address_1), + (11, &address_2), ]), None, ), fake_transaction( fake_verbose_vouts(vec![ - (13, btc_deposit_script_2.bytes()), - (17, btc_deposit_script_2.bytes()), - (19, vec![5]), - (23, btc_deposit_script_1.bytes()), + (13, &address_2), + (17, &address_2), + (19, &DepositAddress::new([5; 32], 0)), + (23, &address_1), ]), None, ), fake_transaction( fake_verbose_vouts(vec![ - (13, btc_deposit_script_2.bytes()), - (19, vec![7]), - (23, btc_deposit_script_1.bytes()), + (13, &address_2), + (19, &DepositAddress::new([7; 32], 0)), + (23, &address_1), ]), None, ), fake_transaction( fake_verbose_vouts(vec![ - (29, btc_deposit_script_1.bytes()), - (31, btc_deposit_script_2.bytes()), - (37, vec![11]), + (29, &address_1), + (31, &address_2), + (37, &DepositAddress::new([11; 32], 0)), ]), None, ), fake_transaction( - fake_verbose_vouts(vec![(41, btc_deposit_script_2.bytes()), (43, vec![17])]), + fake_verbose_vouts(vec![(41, &address_2), (43, &DepositAddress::new([17; 32], 0))]), + None, + ), + fake_transaction( + fake_verbose_vouts(vec![(47, &address_1), (53, &DepositAddress::new([19; 32], 0))]), None, ), fake_transaction( - fake_verbose_vouts(vec![(47, btc_deposit_script_1.bytes()), (53, vec![19])]), + fake_verbose_vouts(vec![(61, &DepositAddress::new([23; 32], 0)), (59, &address_2)]), None, ), fake_transaction( - fake_verbose_vouts(vec![(61, vec![23]), (59, btc_deposit_script_2.bytes())]), + fake_verbose_vouts(vec![(67, &DepositAddress::new([29; 32], 0))]), None, ), - fake_transaction(fake_verbose_vouts(vec![(67, vec![29])]), None), ]; let mut rng = rand::rngs::StdRng::from_seed([3; 32]); @@ -385,36 +383,36 @@ pub mod tests { for _i in 0..10 { let n = rng.gen_range(0..txs.len()); let test_txs = txs.as_slice().choose_multiple(&mut rng, n).cloned().collect::>(); - assert!((0..10).map(|_| deposit_witnesses(&test_txs, &script_addresses)).all_equal()); + assert!((0..10).map(|_| deposit_witnesses(&test_txs, &addresses)).all_equal()); } } #[test] fn deposit_witnesses_several_diff_tx() { - let btc_deposit_script: ScriptPubkey = DepositAddress::new([0; 32], 9).script_pubkey(); + let address = DepositAddress::new([0; 32], 9); const UTXO_WITNESSED_1: u64 = 2324; const UTXO_WITNESSED_2: u64 = 1234; let txs = vec![ fake_transaction( fake_verbose_vouts(vec![ - (UTXO_WITNESSED_1, btc_deposit_script.bytes()), - (12223, vec![0, 32, 121, 9]), - (UTXO_WITNESSED_1 - 1, btc_deposit_script.bytes()), + (UTXO_WITNESSED_1, &address), + (12223, &DepositAddress::new([0; 32], 11)), + (UTXO_WITNESSED_1 - 1, &address), ]), None, ), fake_transaction( fake_verbose_vouts(vec![ - (UTXO_WITNESSED_2 - 10, btc_deposit_script.bytes()), - (UTXO_WITNESSED_2, btc_deposit_script.bytes()), + (UTXO_WITNESSED_2 - 10, &address), + (UTXO_WITNESSED_2, &address), ]), None, ), ]; let deposit_witnesses = - deposit_witnesses(&txs, &map_script_addresses(vec![fake_details(btc_deposit_script)])); + deposit_witnesses(&txs, &map_script_addresses(vec![fake_details(address)])); assert_eq!(deposit_witnesses.len(), 2); assert_eq!(deposit_witnesses[0].amount, UTXO_WITNESSED_1); assert_eq!(deposit_witnesses[1].amount, UTXO_WITNESSED_2); From e682f164a3bb715e22b68b927fb8aacf906005cf Mon Sep 17 00:00:00 2001 From: albert Date: Thu, 17 Oct 2024 13:06:53 +0200 Subject: [PATCH 05/36] chore: add intial scale encoding for cfParameters --- bouncer/package.json | 1 + bouncer/pnpm-lock.yaml | 6 +- bouncer/shared/contract_swap.ts | 50 +++++++++++- bouncer/shared/swapping.ts | 67 ++++++++++++++-- engine/src/witness/arb.rs | 2 +- engine/src/witness/eth.rs | 16 ++-- engine/src/witness/evm/vault.rs | 80 +++++++++---------- .../cf-integration-tests/src/solana.rs | 6 +- .../cf-integration-tests/src/swapping.rs | 4 +- state-chain/chains/src/arb/api.rs | 2 +- state-chain/chains/src/btc/api.rs | 2 +- state-chain/chains/src/ccm_checker.rs | 58 +++++++------- state-chain/chains/src/dot/api.rs | 2 +- state-chain/chains/src/eth/api.rs | 2 +- state-chain/chains/src/lib.rs | 8 +- state-chain/chains/src/sol/api.rs | 20 ++--- state-chain/chains/src/sol/sol_tx_core.rs | 2 +- .../cf-ingress-egress/src/benchmarking.rs | 2 +- .../pallets/cf-ingress-egress/src/lib.rs | 10 +-- .../pallets/cf-ingress-egress/src/tests.rs | 14 ++-- state-chain/pallets/cf-swapping/src/tests.rs | 2 +- .../pallets/cf-swapping/src/tests/ccm.rs | 2 +- state-chain/traits/src/mocks/api_call.rs | 4 +- .../traits/src/mocks/egress_handler.rs | 6 +- 24 files changed, 233 insertions(+), 135 deletions(-) diff --git a/bouncer/package.json b/bouncer/package.json index 5b107e2d97..d41a0d3f9c 100644 --- a/bouncer/package.json +++ b/bouncer/package.json @@ -30,6 +30,7 @@ "md5": "^2.3.0", "minimist": "^1.2.8", "rxjs": "^7.8.1", + "scale-ts": "1.6.0", "tiny-secp256k1": "^2.2.1", "toml": "^3.0.0", "web3": "^1.9.0", diff --git a/bouncer/pnpm-lock.yaml b/bouncer/pnpm-lock.yaml index 92661a523b..1b3b56eaa3 100644 --- a/bouncer/pnpm-lock.yaml +++ b/bouncer/pnpm-lock.yaml @@ -80,6 +80,9 @@ importers: rxjs: specifier: ^7.8.1 version: 7.8.1 + scale-ts: + specifier: 1.6.0 + version: 1.6.0 tiny-secp256k1: specifier: ^2.2.1 version: 2.2.3 @@ -6224,8 +6227,7 @@ snapshots: safer-buffer@2.1.2: {} - scale-ts@1.6.0: - optional: true + scale-ts@1.6.0: {} scrypt-js@3.0.1: {} diff --git a/bouncer/shared/contract_swap.ts b/bouncer/shared/contract_swap.ts index fa3f70c94c..6f41cf0b4f 100644 --- a/bouncer/shared/contract_swap.ts +++ b/bouncer/shared/contract_swap.ts @@ -8,6 +8,8 @@ import { InternalAsset, Chain, } from '@chainflip/cli'; +import { u8aToHex, hexToU8a } from '@polkadot/util'; + import { HDNodeWallet, Wallet, getDefaultProvider } from 'ethers'; import { observeBalanceIncrease, @@ -20,11 +22,15 @@ import { assetDecimals, stateChainAssetFromAsset, chainGasAsset, + shortChainFromAsset, } from './utils'; import { getBalance } from './get_balance'; import { CcmDepositMetadata } from '../shared/new_swap'; import { send } from './send'; import { SwapContext, SwapStatus } from './swap_context'; +import { vaultSwapCfParametersCodec } from './swapping'; +import { newEvmAddress } from './new_evm_address'; +import { newSolAddress } from './new_sol_address'; const erc20Assets: Asset[] = ['Flip', 'Usdc', 'Usdt', 'ArbUsdc']; @@ -49,6 +55,47 @@ export async function executeContractSwap( gasLimit: srcChain === Chains.Arbitrum ? 10000000n : 200000n, } as const; + console.log('messageMetadata?.cfParameters', messageMetadata?.cfParameters); + console.log('hexTou8(messageMetadata?.cfParameters)', hexToU8a(messageMetadata?.cfParameters)); + + // const refundAddressTest = hexToU8a('0x41aD2bc63A2059f9b623533d87fe99887D794847'); + + let refundAddress; + switch (srcChain) { + case Chains.Ethereum: + case Chains.Arbitrum: + refundAddress = newEvmAddress('refundAddress'); + break; + case Chains.Solana: + refundAddress = newSolAddress('refundAddress'); + break; + default: + throw new Error(`Unsupported chain: ${srcChain}`); + } + console.log('refundAddress', refundAddress); + console.log('refundAddress', hexToU8a(refundAddress)); + + const ccmAdditionalData = u8aToHex( + vaultSwapCfParametersCodec.enc({ + ccmAdditionalData: hexToU8a(messageMetadata?.cfParameters), + // vaultSwapAttributes: undefined, + vaultSwapAttributes: { + // refundParams: undefined, + refundParams: { + retryDuration: 2, + refundAddress: { tag: shortChainFromAsset(srcAsset), value: hexToU8a(refundAddress) }, + minPriceX128: BigInt(3), + }, + dcaParams: { + numberOfChunks: 4, + chunkIntervalBlocks: 5, + }, + boostFee: 1, + }, + }), + ); + console.log('ccmAdditionalData passed to the SDK in contractCall', ccmAdditionalData); + const receipt = await executeSwap( { destChain, @@ -62,7 +109,8 @@ export async function executeContractSwap( ccmParams: messageMetadata && { gasBudget: messageMetadata.gasBudget.toString(), message: messageMetadata.message, - cfParameters: messageMetadata.cfParameters, + cfParameters: ccmAdditionalData, + // ccmAdditionalData: ccmAdditionalData, }, } as ExecuteSwapParams, networkOptions, diff --git a/bouncer/shared/swapping.ts b/bouncer/shared/swapping.ts index ba65c7728f..ee5b1915be 100644 --- a/bouncer/shared/swapping.ts +++ b/bouncer/shared/swapping.ts @@ -1,6 +1,8 @@ import { InternalAsset as Asset } from '@chainflip/cli'; import { Keypair, PublicKey } from '@solana/web3.js'; import Web3 from 'web3'; +import { u8aToHex } from '@polkadot/util'; +import { str, u32, Struct, Option, u16, u256, Bytes as TsBytes, Enum } from 'scale-ts'; import { randomAsHex, randomAsNumber } from '../polkadot/util-crypto'; import { performSwap } from '../shared/perform_swap'; import { @@ -13,9 +15,10 @@ import { assetDecimals, } from '../shared/utils'; import { BtcAddressType } from '../shared/new_btc_address'; -import { CcmDepositMetadata } from '../shared/new_swap'; +import { CcmDepositMetadata, DcaParams, FillOrKillParamsX128 } from '../shared/new_swap'; import { performSwapViaContract } from '../shared/contract_swap'; import { SwapContext, SwapStatus } from './swap_context'; +import { U256 } from '@polkadot/types'; enum SolidityType { Uint256 = 'uint256', @@ -67,7 +70,7 @@ function newAbiEncodedMessage(types?: SolidityType[]): string { return web3.eth.abi.encodeParameters(typesArray, variables); } -function newSolanaCfParameters(maxAccounts: number) { +function newSolanaCcmAdditionalData(maxAccounts: number) { function arrayToHexString(byteArray: Uint8Array): string { return ( '0x' + @@ -120,7 +123,7 @@ function newCcmArbitraryBytes(maxLength: number): string { return randomAsHex(Math.floor(Math.random() * Math.max(0, maxLength - 10)) + 10); } -function newCfParameters(destAsset: Asset, message?: string): string { +function newCcmAdditionalData(destAsset: Asset, message?: string): string { const destChain = chainFromAsset(destAsset); switch (destChain) { case 'Ethereum': @@ -136,7 +139,7 @@ function newCfParameters(destAsset: Asset, message?: string): string { // The maximum number of extra accounts that can be passed is limited by the tx size // and therefore also depends on the message length. - return newSolanaCfParameters(maxAccounts); + return newSolanaCcmAdditionalData(maxAccounts); } default: throw new Error(`Unsupported chain: ${destChain}`); @@ -156,6 +159,29 @@ function newCcmMessage(destAsset: Asset): string { } } +export const vaultSwapCfParametersCodec = Struct({ + ccmAdditionalData: Option(TsBytes()), + vaultSwapAttributes: Option( + Struct({ + refundParams: Option( + Struct({ + retryDuration: u32, + refundAddress: Enum({ + Eth: TsBytes(20), + Dot: TsBytes(32), + Btc: TsBytes(), // not supported anyway + Arb: TsBytes(20), + Sol: TsBytes(32), + }), + minPriceX128: u256, + }), + ), + dcaParams: Option(Struct({ numberOfChunks: u32, chunkIntervalBlocks: u32 })), + boostFee: Option(u16), + }), + ), +}); + export function newCcmMetadata( sourceAsset: Asset, destAsset: Asset, @@ -164,7 +190,7 @@ export function newCcmMetadata( cfParamsArray?: string, ): CcmDepositMetadata { const message = ccmMessage ?? newCcmMessage(destAsset); - const cfParameters = cfParamsArray ?? newCfParameters(destAsset, message); + const cfParameters = cfParamsArray ?? newCcmAdditionalData(destAsset, message); const gasDiv = gasBudgetFraction ?? 2; const gasBudget = Math.floor( @@ -175,10 +201,41 @@ export function newCcmMetadata( return { message, gasBudget, + // TODO: To rename to ccmAdditionalData cfParameters, }; } +export function newVaultSwapCfParameters( + sourceAsset: Asset, + destAsset: Asset, + ccmMessage?: string, + gasBudgetFraction?: number, + cfParamsArray?: string, + boostFeeBps?: number, + fillOrKillParams?: FillOrKillParamsX128, + dcaParams?: DcaParams, +): string { + const ccmMetadata = newCcmMetadata( + sourceAsset, + destAsset, + ccmMessage, + gasBudgetFraction, + cfParamsArray, + ); + + return u8aToHex( + vaultSwapCfParametersCodec.enc({ + ccmAdditionalData: ccmMetadata.cfParameters, + vaultSwapAttributes: { + boostFeeBps, + fillOrKillParams, + dcaParams, + }, + }), + ); +} + export async function prepareSwap( sourceAsset: Asset, destAsset: Asset, diff --git a/engine/src/witness/arb.rs b/engine/src/witness/arb.rs index 08d6ad2972..60130d3ae4 100644 --- a/engine/src/witness/arb.rs +++ b/engine/src/witness/arb.rs @@ -194,7 +194,7 @@ impl super::evm::vault::IngressCallBuilder for ArbCallBuilder { // This is only to be checked in the pre-witnessed version boost_fee: Option, ) -> state_chain_runtime::RuntimeCall { - state_chain_runtime::RuntimeCall::EthereumIngressEgress( + state_chain_runtime::RuntimeCall::ArbitrumIngressEgress( if let Some(deposit_metadata) = deposit_metadata { pallet_cf_ingress_egress::Call::contract_ccm_swap_request { source_asset, diff --git a/engine/src/witness/eth.rs b/engine/src/witness/eth.rs index 572554689a..8f7d946b3d 100644 --- a/engine/src/witness/eth.rs +++ b/engine/src/witness/eth.rs @@ -222,24 +222,18 @@ where } use cf_chains::{ - address::EncodedAddress, CcmCfParameters, CcmDepositMetadata, ChannelRefundParameters, + address::EncodedAddress, CcmAdditionalData, CcmDepositMetadata, ChannelRefundParameters, }; use cf_primitives::{Asset, AssetAmount, BasisPoints, DcaParameters, TransactionHash}; #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] -pub struct ChannellessCfParameters { - pub ccm_cf_parameters: Option, - // TODO: Consider if we want use the BTC SharedCfParameters. It's done like that to save on - // bytes but in EVM/SOL we have more bytes to work with. At the same time the optional types - // allow the user to not have to pass an unnecessary amount of bytes as parameters on-chain. - // We might have to do it if we need to convert internal parameters such as foreign addresses - // either in order to decode properly or to pass them correctly to the ingress pallet's - // contract_swap_request. - pub shared_cf_parameters: Option, +pub struct VaultSwapCfParameters { + pub ccm_additional_data: Option, + pub vault_swap_attributes: Option, } #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] -pub struct SharedCfParametersContract { +pub struct VaultSwapAttributes { pub refund_params: Option, pub dca_params: Option, pub boost_fee: Option, diff --git a/engine/src/witness/evm/vault.rs b/engine/src/witness/evm/vault.rs index f179057fec..d3f9c689b7 100644 --- a/engine/src/witness/evm/vault.rs +++ b/engine/src/witness/evm/vault.rs @@ -5,7 +5,7 @@ use std::collections::HashMap; use crate::{ evm::retry_rpc::EvmRetryRpcApi, - witness::eth::{ChannellessCfParameters, SharedCfParametersContract}, + witness::eth::{VaultSwapAttributes, VaultSwapCfParameters}, }; use super::{ @@ -23,7 +23,7 @@ use cf_chains::{ address::{EncodedAddress, IntoForeignChainAddress}, eth::Address as EthereumAddress, evm::DepositDetails, - CcmCfParameters, CcmChannelMetadata, CcmDepositMetadata, Chain, ChannelRefundParameters, + CcmAdditionalData, CcmChannelMetadata, CcmDepositMetadata, Chain, ChannelRefundParameters, MAX_CCM_ADDITIONAL_DATA_LENGTH }; use cf_primitives::{Asset, BasisPoints, DcaParameters, ForeignChain}; use ethers::prelude::*; @@ -32,7 +32,8 @@ use state_chain_runtime::{EthereumInstance, Runtime, RuntimeCall}; abigen!(Vault, "$CF_ETH_CONTRACT_ABI_ROOT/$CF_ETH_CONTRACT_ABI_TAG/IVault.json"); -pub const MAX_CF_PARAM_LENGTH: u32 = 1_000; +// MAX_CF_PARAM_LENGTH ~== MAX_CCM_ADDITIONAL_DATA_LENGTH + MAX_VAULT_SWAP_ATTRIBUTES_LENGTH +pub const MAX_CF_PARAM_LENGTH: u32 = MAX_CCM_ADDITIONAL_DATA_LENGTH + 1_000; pub type CfParameters = BoundedVec>; pub fn call_from_event< @@ -64,7 +65,7 @@ where }) } - fn decode_shared_cf_parameters( + fn decode_vault_swap_attributes( cf_parameters_vec: CfParameters, ) -> Result<(Option, Option, Option)> { println!("DEBUGDEBUG cf_parameters_vec {:?}", cf_parameters_vec); @@ -74,24 +75,21 @@ where Ok((None, None, None)) } else { - let shared_cf_parameters: SharedCfParametersContract = - SharedCfParametersContract::decode(&mut &cf_parameters_vec[..]) - .map_err(|_| anyhow!("Failed to decode to `SharedCfParametersContract`"))?; + let attributes: VaultSwapAttributes = + VaultSwapAttributes::decode(&mut &cf_parameters_vec[..]) + .map_err(|_| anyhow!("Failed to decode to `VaultSwapAttributes`"))?; - println!("DEBUGDEBUG shared_cf_parameters {:?}", shared_cf_parameters); + println!("DEBUGDEBUG attributes {:?}", attributes); - Ok(( - shared_cf_parameters.refund_params, - shared_cf_parameters.dca_params, - shared_cf_parameters.boost_fee, - )) + Ok((attributes.refund_params, attributes.dca_params, attributes.boost_fee)) } } - fn decode_channelless_cf_parameters( + #[allow(clippy::type_complexity)] + fn decode_vault_swap_cf_parameters( cf_parameters_vec: CfParameters, ) -> Result<( - CcmCfParameters, + CcmAdditionalData, (Option, Option, Option), )> { println!("DEBUGDEBUG cf_parameters_vec {:?}", cf_parameters_vec); @@ -99,29 +97,25 @@ where if cf_parameters_vec.is_empty() { println!("DEBUGDEBUG Emtpy cf_parameters_vec"); - Ok((cf_parameters_vec, (None, None, None))) + // Return the empty vector since the CCM additional data is required + Ok((CcmAdditionalData::default(), (None, None, None))) } else { - let channelless_cf_parameters: ChannellessCfParameters = - ChannellessCfParameters::decode(&mut &cf_parameters_vec[..]) - .map_err(|_| anyhow!("Failed to decode to `ChannellessCfParameters`"))?; - - println!("DEBUGDEBUG channelless_cf_parameters {:?}", channelless_cf_parameters); - - let (refund_params, dca_params, boost_fee) = if let Some(shared_cf_parameters) = - channelless_cf_parameters.shared_cf_parameters - { - ( - shared_cf_parameters.refund_params, - shared_cf_parameters.dca_params, - shared_cf_parameters.boost_fee, - ) - } else { - (None, None, None) - }; + let vault_swap_cf_parameters: VaultSwapCfParameters = + VaultSwapCfParameters::decode(&mut &cf_parameters_vec[..]) + .map_err(|_| anyhow!("Failed to decode to `VaultSwapCfParameters`"))?; + + println!("DEBUGDEBUG vault_swap_cf_parameters {:?}", vault_swap_cf_parameters); + + let (refund_params, dca_params, boost_fee) = + if let Some(attributes) = vault_swap_cf_parameters.vault_swap_attributes { + (attributes.refund_params, attributes.dca_params, attributes.boost_fee) + } else { + (None, None, None) + }; Ok(( - // Default to empty CcmCfParameters if not present - channelless_cf_parameters.ccm_cf_parameters.unwrap_or_default(), + // Default to empty CcmAdditionalData if not present + vault_swap_cf_parameters.ccm_additional_data.unwrap_or_default(), (refund_params, dca_params, boost_fee), )) } @@ -142,7 +136,7 @@ where .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; let (refund_params, dca_params, boost_fee) = - decode_shared_cf_parameters(cf_parameters_vec)?; + decode_vault_swap_attributes(cf_parameters_vec)?; Some(CallBuilder::contract_swap_request( native_asset, @@ -172,7 +166,7 @@ where .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; let (refund_params, dca_params, boost_fee) = - decode_shared_cf_parameters(cf_parameters_vec)?; + decode_vault_swap_attributes(cf_parameters_vec)?; Some(CallBuilder::contract_swap_request( *(supported_assets @@ -204,8 +198,8 @@ where .to_vec() .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; - let (ccm_cf_parameters, (refund_params, dca_params, boost_fee)) = - decode_channelless_cf_parameters(cf_parameters_vec)?; + let (ccm_additional_data, (refund_params, dca_params, boost_fee)) = + decode_vault_swap_cf_parameters(cf_parameters_vec)?; Some(CallBuilder::contract_swap_request( native_asset, @@ -225,7 +219,7 @@ where .try_into() .map_err(|_| anyhow!("Failed to deposit CCM: `message` too long."))?, gas_budget: try_into_primitive(gas_amount)?, - ccm_cf_parameters, + ccm_additional_data, }, }), event.tx_hash.into(), @@ -251,8 +245,8 @@ where .to_vec() .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; - let (ccm_cf_parameters, (refund_params, dca_params, boost_fee)) = - decode_channelless_cf_parameters(cf_parameters_vec)?; + let (ccm_additional_data, (refund_params, dca_params, boost_fee)) = + decode_vault_swap_cf_parameters(cf_parameters_vec)?; Some(CallBuilder::contract_swap_request( *(supported_assets @@ -274,7 +268,7 @@ where .try_into() .map_err(|_| anyhow!("Failed to deposit CCM. Message too long."))?, gas_budget: try_into_primitive(gas_amount)?, - ccm_cf_parameters, + ccm_additional_data, }, }), event.tx_hash.into(), diff --git a/state-chain/cf-integration-tests/src/solana.rs b/state-chain/cf-integration-tests/src/solana.rs index 2850d06da5..012a4fe5b1 100644 --- a/state-chain/cf-integration-tests/src/solana.rs +++ b/state-chain/cf-integration-tests/src/solana.rs @@ -374,7 +374,7 @@ fn solana_ccm_fails_with_invalid_input() { channel_metadata: CcmChannelMetadata { message: vec![0u8, 1u8, 2u8, 3u8].try_into().unwrap(), gas_budget: 0u128, - ccm_cf_parameters: vec![0u8, 1u8, 2u8, 3u8].try_into().unwrap(), + ccm_additional_data: vec![0u8, 1u8, 2u8, 3u8].try_into().unwrap(), }, }; @@ -446,7 +446,7 @@ fn solana_ccm_fails_with_invalid_input() { channel_metadata: CcmChannelMetadata { message: vec![0u8, 1u8, 2u8, 3u8].try_into().unwrap(), gas_budget: 0u128, - ccm_cf_parameters: SolCcmAccounts { + ccm_additional_data: SolCcmAccounts { cf_receiver: SolCcmAddress { pubkey: receiver.into(), is_writable: true }, remaining_accounts: vec![ SolCcmAddress { pubkey: SolPubkey([0x01; 32]), is_writable: false }, @@ -492,7 +492,7 @@ fn solana_ccm_fails_with_invalid_input() { egress_id: (ForeignChain::Solana, 1u64), error: ExecutexSwapAndCallError::FailedToBuildCcmForSolana( SolanaTransactionBuildingError::InvalidCcm( - CcmValidityError::CfParametersContainsInvalidAccounts + CcmValidityError::CcmAdditionalDataContainsInvalidAccounts ) ), }), diff --git a/state-chain/cf-integration-tests/src/swapping.rs b/state-chain/cf-integration-tests/src/swapping.rs index 28db1b8dba..8664ca5bc1 100644 --- a/state-chain/cf-integration-tests/src/swapping.rs +++ b/state-chain/cf-integration-tests/src/swapping.rs @@ -374,7 +374,7 @@ fn can_process_ccm_via_swap_deposit_address() { let message = CcmChannelMetadata { message: vec![0u8, 1u8, 2u8, 3u8, 4u8].try_into().unwrap(), gas_budget: GAS_BUDGET, - ccm_cf_parameters: Default::default(), + ccm_additional_data: Default::default(), }; assert_ok!(Swapping::request_swap_deposit_address_with_affiliates( @@ -559,7 +559,7 @@ fn ccm_deposit_metadata_mock() -> CcmDepositMetadata { channel_metadata: CcmChannelMetadata { message: vec![0u8, 1u8, 2u8, 3u8, 4u8].try_into().unwrap(), gas_budget: 100_000_000, - ccm_cf_parameters: Default::default(), + ccm_additional_data: Default::default(), }, } } diff --git a/state-chain/chains/src/arb/api.rs b/state-chain/chains/src/arb/api.rs index 78b58d7f24..e6a177a44d 100644 --- a/state-chain/chains/src/arb/api.rs +++ b/state-chain/chains/src/arb/api.rs @@ -70,7 +70,7 @@ where source_address: Option, gas_budget: ::ChainAmount, message: Vec, - _ccm_cf_parameters: Vec, + _ccm_additional_data: Vec, ) -> Result { let transfer_param = EncodableTransferAssetParams { asset: E::token_address(transfer_param.asset) diff --git a/state-chain/chains/src/btc/api.rs b/state-chain/chains/src/btc/api.rs index 4cf47ea1bf..97a1f3d2d9 100644 --- a/state-chain/chains/src/btc/api.rs +++ b/state-chain/chains/src/btc/api.rs @@ -140,7 +140,7 @@ impl> ExecutexSwapAndCall for Bitc _source_address: Option, _gas_budget: ::ChainAmount, _message: Vec, - _ccm_cf_parameters: Vec, + _ccm_additional_data: Vec, ) -> Result { Err(ExecutexSwapAndCallError::Unsupported) } diff --git a/state-chain/chains/src/ccm_checker.rs b/state-chain/chains/src/ccm_checker.rs index 3ff687869c..122a3bb723 100644 --- a/state-chain/chains/src/ccm_checker.rs +++ b/state-chain/chains/src/ccm_checker.rs @@ -12,22 +12,22 @@ use sp_std::vec::Vec; #[derive(Copy, Clone, Debug, PartialEq, Eq, Encode, Decode, TypeInfo)] pub enum CcmValidityError { - CannotDecodeCfParameters, + CannotDecodeCcmAdditionalData, CcmIsTooLong, - CfParametersContainsInvalidAccounts, + CcmAdditionalDataContainsInvalidAccounts, } pub trait CcmValidityCheck { fn check_and_decode( _ccm: &CcmChannelMetadata, _egress_asset: cf_primitives::Asset, - ) -> Result { - Ok(DecodedCfParameters::NotRequired) + ) -> Result { + Ok(DecodedCcmAdditionalData::NotRequired) } } #[derive(Clone, Debug, PartialEq, Eq)] -pub enum DecodedCfParameters { +pub enum DecodedCcmAdditionalData { Solana(SolCcmAccounts), NotRequired, } @@ -41,11 +41,11 @@ impl CcmValidityCheck for CcmValidityChecker { fn check_and_decode( ccm: &CcmChannelMetadata, egress_asset: Asset, - ) -> Result { + ) -> Result { if ForeignChain::from(egress_asset) == ForeignChain::Solana { // Check if the cf_parameter can be decoded - let ccm_accounts = SolCcmAccounts::decode(&mut &ccm.ccm_cf_parameters.clone()[..]) - .map_err(|_| CcmValidityError::CannotDecodeCfParameters)?; + let ccm_accounts = SolCcmAccounts::decode(&mut &ccm.ccm_additional_data.clone()[..]) + .map_err(|_| CcmValidityError::CannotDecodeCcmAdditionalData)?; let asset: SolAsset = egress_asset .try_into() .expect("Only Solana chain's asset will be checked. This conversion must succeed."); @@ -61,9 +61,9 @@ impl CcmValidityCheck for CcmValidityChecker { return Err(CcmValidityError::CcmIsTooLong) } - Ok(DecodedCfParameters::Solana(ccm_accounts)) + Ok(DecodedCcmAdditionalData::Solana(ccm_accounts)) } else { - Ok(DecodedCfParameters::NotRequired) + Ok(DecodedCcmAdditionalData::NotRequired) } } } @@ -80,7 +80,7 @@ pub fn check_ccm_for_blacklisted_accounts( .iter() .any(|acc| acc.pubkey == blacklisted_account)) .then_some(()) - .ok_or(CcmValidityError::CfParametersContainsInvalidAccounts) + .ok_or(CcmValidityError::CcmAdditionalDataContainsInvalidAccounts) }) } @@ -98,7 +98,7 @@ mod test { let ccm = sol_test_values::ccm_parameter().channel_metadata; assert_eq!( CcmValidityChecker::check_and_decode(&ccm, Asset::Sol), - Ok(DecodedCfParameters::Solana(sol_test_values::ccm_accounts())) + Ok(DecodedCcmAdditionalData::Solana(sol_test_values::ccm_accounts())) ); } @@ -107,12 +107,12 @@ mod test { let ccm = CcmChannelMetadata { message: vec![0x01, 0x02, 0x03, 0x04, 0x05].try_into().unwrap(), gas_budget: 1, - ccm_cf_parameters: vec![0x01, 0x02, 0x03, 0x04, 0x05].try_into().unwrap(), + ccm_additional_data: vec![0x01, 0x02, 0x03, 0x04, 0x05].try_into().unwrap(), }; assert_err!( CcmValidityChecker::check_and_decode(&ccm, Asset::Sol), - CcmValidityError::CannotDecodeCfParameters + CcmValidityError::CannotDecodeCcmAdditionalData ); } @@ -121,7 +121,7 @@ mod test { let ccm = || CcmChannelMetadata { message: vec![0x01; MAX_CCM_BYTES_SOL].try_into().unwrap(), gas_budget: 0, - ccm_cf_parameters: SolCcmAccounts { + ccm_additional_data: SolCcmAccounts { cf_receiver: SolCcmAddress { pubkey: SolPubkey([0x01; 32]), is_writable: true }, remaining_accounts: vec![], } @@ -140,7 +140,7 @@ mod test { ); let mut invalid_ccm = ccm(); - invalid_ccm.ccm_cf_parameters = SolCcmAccounts { + invalid_ccm.ccm_additional_data = SolCcmAccounts { cf_receiver: SolCcmAddress { pubkey: SolPubkey([0x01; 32]), is_writable: true }, remaining_accounts: vec![SolCcmAddress { pubkey: SolPubkey([0x01; 32]), @@ -161,7 +161,7 @@ mod test { let ccm = || CcmChannelMetadata { message: vec![0x01; MAX_CCM_BYTES_USDC].try_into().unwrap(), gas_budget: 0, - ccm_cf_parameters: SolCcmAccounts { + ccm_additional_data: SolCcmAccounts { cf_receiver: SolCcmAddress { pubkey: SolPubkey([0x01; 32]), is_writable: true }, remaining_accounts: vec![], } @@ -180,7 +180,7 @@ mod test { ); let mut invalid_ccm = ccm(); - invalid_ccm.ccm_cf_parameters = SolCcmAccounts { + invalid_ccm.ccm_additional_data = SolCcmAccounts { cf_receiver: SolCcmAddress { pubkey: SolPubkey([0x01; 32]), is_writable: true }, remaining_accounts: vec![SolCcmAddress { pubkey: SolPubkey([0x01; 32]), @@ -215,31 +215,31 @@ mod test { // Always valid on other chains. assert_ok!( CcmValidityChecker::check_and_decode(&ccm, Asset::Eth), - DecodedCfParameters::NotRequired + DecodedCcmAdditionalData::NotRequired ); assert_ok!( CcmValidityChecker::check_and_decode(&ccm, Asset::Btc), - DecodedCfParameters::NotRequired + DecodedCcmAdditionalData::NotRequired ); assert_ok!( CcmValidityChecker::check_and_decode(&ccm, Asset::Flip), - DecodedCfParameters::NotRequired + DecodedCcmAdditionalData::NotRequired ); assert_ok!( CcmValidityChecker::check_and_decode(&ccm, Asset::Usdt), - DecodedCfParameters::NotRequired + DecodedCcmAdditionalData::NotRequired ); assert_ok!( CcmValidityChecker::check_and_decode(&ccm, Asset::Usdc), - DecodedCfParameters::NotRequired + DecodedCcmAdditionalData::NotRequired ); assert_ok!( CcmValidityChecker::check_and_decode(&ccm, Asset::ArbUsdc), - DecodedCfParameters::NotRequired + DecodedCcmAdditionalData::NotRequired ); assert_ok!( CcmValidityChecker::check_and_decode(&ccm, Asset::ArbEth), - DecodedCfParameters::NotRequired + DecodedCcmAdditionalData::NotRequired ); } @@ -262,7 +262,7 @@ mod test { }; assert_err!( check_ccm_for_blacklisted_accounts(&ccm_accounts, blacklisted_accounts()), - CcmValidityError::CfParametersContainsInvalidAccounts + CcmValidityError::CcmAdditionalDataContainsInvalidAccounts ); let ccm_accounts = SolCcmAccounts { @@ -280,7 +280,7 @@ mod test { }; assert_err!( check_ccm_for_blacklisted_accounts(&ccm_accounts, blacklisted_accounts()), - CcmValidityError::CfParametersContainsInvalidAccounts + CcmValidityError::CcmAdditionalDataContainsInvalidAccounts ); // Agg key is blacklisted @@ -296,7 +296,7 @@ mod test { }; assert_err!( check_ccm_for_blacklisted_accounts(&ccm_accounts, blacklisted_accounts()), - CcmValidityError::CfParametersContainsInvalidAccounts + CcmValidityError::CcmAdditionalDataContainsInvalidAccounts ); let ccm_accounts = SolCcmAccounts { @@ -311,7 +311,7 @@ mod test { }; assert_err!( check_ccm_for_blacklisted_accounts(&ccm_accounts, blacklisted_accounts()), - CcmValidityError::CfParametersContainsInvalidAccounts + CcmValidityError::CcmAdditionalDataContainsInvalidAccounts ); } } diff --git a/state-chain/chains/src/dot/api.rs b/state-chain/chains/src/dot/api.rs index 3b38109d0e..5cd8443f2e 100644 --- a/state-chain/chains/src/dot/api.rs +++ b/state-chain/chains/src/dot/api.rs @@ -128,7 +128,7 @@ where _source_address: Option, _gas_budget: ::ChainAmount, _message: Vec, - _ccm_cf_parameters: Vec, + _ccm_additional_data: Vec, ) -> Result { Err(ExecutexSwapAndCallError::Unsupported) } diff --git a/state-chain/chains/src/eth/api.rs b/state-chain/chains/src/eth/api.rs index f7df478ebc..9eb4121f57 100644 --- a/state-chain/chains/src/eth/api.rs +++ b/state-chain/chains/src/eth/api.rs @@ -194,7 +194,7 @@ where source_address: Option, gas_budget: ::ChainAmount, message: Vec, - _ccm_cf_parameters: Vec, + _ccm_additional_data: Vec, ) -> Result { let transfer_param = EncodableTransferAssetParams { asset: E::token_address(transfer_param.asset) diff --git a/state-chain/chains/src/lib.rs b/state-chain/chains/src/lib.rs index b882c6b15b..b1cb04ebbc 100644 --- a/state-chain/chains/src/lib.rs +++ b/state-chain/chains/src/lib.rs @@ -549,7 +549,7 @@ pub trait ExecutexSwapAndCall: ApiCall { source_address: Option, gas_budget: C::ChainAmount, message: Vec, - ccm_cf_parameters: Vec, + ccm_additional_data: Vec, ) -> Result; } @@ -588,10 +588,10 @@ pub enum SwapOrigin { } pub const MAX_CCM_MSG_LENGTH: u32 = 10_000; -pub const MAX_CCM_CF_PARAM_LENGTH: u32 = 1_000; +pub const MAX_CCM_ADDITIONAL_DATA_LENGTH: u32 = 1_000; pub type CcmMessage = BoundedVec>; -pub type CcmCfParameters = BoundedVec>; +pub type CcmAdditionalData = BoundedVec>; #[cfg(feature = "std")] mod bounded_hex { @@ -636,7 +636,7 @@ pub struct CcmChannelMetadata { feature = "std", serde(with = "bounded_hex", default, skip_serializing_if = "Vec::is_empty") )] - pub ccm_cf_parameters: CcmCfParameters, + pub ccm_additional_data: CcmAdditionalData, } #[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)] diff --git a/state-chain/chains/src/sol/api.rs b/state-chain/chains/src/sol/api.rs index 4bbd81db81..40aecee43a 100644 --- a/state-chain/chains/src/sol/api.rs +++ b/state-chain/chains/src/sol/api.rs @@ -10,7 +10,7 @@ use sp_std::{vec, vec::Vec}; use crate::{ ccm_checker::{ check_ccm_for_blacklisted_accounts, CcmValidityCheck, CcmValidityChecker, CcmValidityError, - DecodedCfParameters, + DecodedCcmAdditionalData, }, sol::{ transaction_builder::SolanaTransactionBuilder, SolAddress, SolAmount, SolApiEnvironment, @@ -260,10 +260,10 @@ impl SolanaApi { source_address: Option, gas_budget: ::ChainAmount, message: Vec, - ccm_cf_parameters: Vec, + ccm_additional_data: Vec, ) -> Result { // For extra safety, re-verify the validity of the CCM message here - // and extract the decoded `ccm_accounts` from `ccm_cf_parameters`. + // and extract the decoded `ccm_accounts` from `ccm_additional_data`. let decoded_cf_params = CcmValidityChecker::check_and_decode( &CcmChannelMetadata { message: message @@ -271,7 +271,7 @@ impl SolanaApi { .try_into() .expect("This is parsed from bounded vec, therefore the size must fit"), gas_budget: 0, // This value is un-used by Solana - ccm_cf_parameters: ccm_cf_parameters + ccm_additional_data: ccm_additional_data .clone() .try_into() .expect("This is parsed from bounded vec, therefore the size must fit"), @@ -280,12 +280,14 @@ impl SolanaApi { ) .map_err(SolanaTransactionBuildingError::InvalidCcm)?; - // Always expects the `DecodedCfParameters::Solana(..)` variant of the decoded cf params. - let ccm_accounts = if let DecodedCfParameters::Solana(ccm_accounts) = decoded_cf_params { + // Always expects the `DecodedCcmAdditionalData::Solana(..)` variant of the decoded cf + // params. + let ccm_accounts = if let DecodedCcmAdditionalData::Solana(ccm_accounts) = decoded_cf_params + { Ok(ccm_accounts) } else { Err(SolanaTransactionBuildingError::InvalidCcm( - CcmValidityError::CannotDecodeCfParameters, + CcmValidityError::CannotDecodeCcmAdditionalData, )) }?; @@ -439,7 +441,7 @@ impl ExecutexSwapAndCall for SolanaApi source_address: Option, gas_budget: ::ChainAmount, message: Vec, - ccm_cf_parameters: Vec, + ccm_additional_data: Vec, ) -> Result { Self::ccm_transfer( transfer_param, @@ -447,7 +449,7 @@ impl ExecutexSwapAndCall for SolanaApi source_address, gas_budget, message, - ccm_cf_parameters, + ccm_additional_data, ) .map_err(|e| { log::error!("Failed to construct Solana CCM transfer transaction! \nError: {:?}", e); diff --git a/state-chain/chains/src/sol/sol_tx_core.rs b/state-chain/chains/src/sol/sol_tx_core.rs index f3a6c1d370..887a30a96c 100644 --- a/state-chain/chains/src/sol/sol_tx_core.rs +++ b/state-chain/chains/src/sol/sol_tx_core.rs @@ -946,7 +946,7 @@ pub mod sol_test_values { channel_metadata: CcmChannelMetadata { message: vec![124u8, 29u8, 15u8, 7u8].try_into().unwrap(), // CCM message gas_budget: 0u128, // unused - ccm_cf_parameters: codec::Encode::encode(&ccm_accounts()) + ccm_additional_data: codec::Encode::encode(&ccm_accounts()) .try_into() .expect("Test data cannot be too long"), // Extra addresses }, diff --git a/state-chain/pallets/cf-ingress-egress/src/benchmarking.rs b/state-chain/pallets/cf-ingress-egress/src/benchmarking.rs index b10aa6e3b0..ff2e254830 100644 --- a/state-chain/pallets/cf-ingress-egress/src/benchmarking.rs +++ b/state-chain/pallets/cf-ingress-egress/src/benchmarking.rs @@ -318,7 +318,7 @@ mod benchmarks { channel_metadata: CcmChannelMetadata { message: vec![0x00].try_into().unwrap(), gas_budget: 1, - ccm_cf_parameters: Default::default(), + ccm_additional_data: Default::default(), }, }; let call = Call::::contract_ccm_swap_request { diff --git a/state-chain/pallets/cf-ingress-egress/src/lib.rs b/state-chain/pallets/cf-ingress-egress/src/lib.rs index 6121bc9816..d42c99e341 100644 --- a/state-chain/pallets/cf-ingress-egress/src/lib.rs +++ b/state-chain/pallets/cf-ingress-egress/src/lib.rs @@ -26,7 +26,7 @@ use cf_chains::{ }, assets::any::GetChainAssetMap, ccm_checker::CcmValidityCheck, - AllBatch, AllBatchError, CcmCfParameters, CcmChannelMetadata, CcmDepositMetadata, + AllBatch, AllBatchError, CcmAdditionalData, CcmChannelMetadata, CcmDepositMetadata, CcmFailReason, CcmMessage, Chain, ChannelLifecycleHooks, ChannelRefundParameters, ConsolidateCall, DepositChannel, ExecutexSwapAndCall, FetchAssetParams, ForeignChainAddress, SwapOrigin, TransferAssetParams, @@ -134,7 +134,7 @@ pub(crate) struct CrossChainMessage { pub source_chain: ForeignChain, pub source_address: Option, // Where funds might be returned to if the message fails. - pub ccm_cf_parameters: CcmCfParameters, + pub ccm_additional_data: CcmAdditionalData, pub gas_budget: C::ChainAmount, } @@ -1474,7 +1474,7 @@ impl, I: 'static> Pallet { ccm.source_address, ccm.gas_budget, ccm.message.to_vec(), - ccm.ccm_cf_parameters.to_vec(), + ccm.ccm_additional_data.to_vec(), ) { Ok(api_call) => { let broadcast_id = T::Broadcaster::threshold_sign_and_broadcast_with_callback( @@ -2118,7 +2118,7 @@ impl, I: 'static> EgressApi for Pallet { match maybe_ccm_with_gas_budget { Some(( CcmDepositMetadata { - channel_metadata: CcmChannelMetadata { message, ccm_cf_parameters, .. }, + channel_metadata: CcmChannelMetadata { message, ccm_additional_data, .. }, source_chain, source_address, .. @@ -2131,7 +2131,7 @@ impl, I: 'static> EgressApi for Pallet { amount, destination_address: destination_address.clone(), message, - ccm_cf_parameters, + ccm_additional_data, source_chain, source_address, gas_budget, diff --git a/state-chain/pallets/cf-ingress-egress/src/tests.rs b/state-chain/pallets/cf-ingress-egress/src/tests.rs index 05ca749043..5a18097034 100644 --- a/state-chain/pallets/cf-ingress-egress/src/tests.rs +++ b/state-chain/pallets/cf-ingress-egress/src/tests.rs @@ -115,7 +115,7 @@ fn blacklisted_asset_will_not_egress_via_ccm() { channel_metadata: CcmChannelMetadata { message: vec![0x00, 0x01, 0x02].try_into().unwrap(), gas_budget: 1_000, - ccm_cf_parameters: vec![].try_into().unwrap(), + ccm_additional_data: vec![].try_into().unwrap(), }, }; @@ -149,7 +149,7 @@ fn blacklisted_asset_will_not_egress_via_ccm() { message: ccm.channel_metadata.message.clone(), source_chain: ForeignChain::Ethereum, source_address: ccm.source_address.clone(), - ccm_cf_parameters: ccm.channel_metadata.ccm_cf_parameters, + ccm_additional_data: ccm.channel_metadata.ccm_additional_data, gas_budget, }] ); @@ -578,7 +578,7 @@ fn can_egress_ccm() { channel_metadata: CcmChannelMetadata { message: vec![0x00, 0x01, 0x02].try_into().unwrap(), gas_budget: GAS_BUDGET, - ccm_cf_parameters: vec![].try_into().unwrap(), + ccm_additional_data: vec![].try_into().unwrap(), } }; @@ -598,7 +598,7 @@ fn can_egress_ccm() { amount, destination_address, message: ccm.channel_metadata.message.clone(), - ccm_cf_parameters: vec![].try_into().unwrap(), + ccm_additional_data: vec![].try_into().unwrap(), source_chain: ForeignChain::Ethereum, source_address: Some(ForeignChainAddress::Eth([0xcf; 20].into())), gas_budget: GAS_BUDGET, @@ -1798,7 +1798,7 @@ fn do_not_process_more_ccm_swaps_than_allowed_by_limit() { channel_metadata: CcmChannelMetadata { message: vec![0x00, 0x01, 0x02].try_into().unwrap(), gas_budget: 1_000, - ccm_cf_parameters: vec![].try_into().unwrap(), + ccm_additional_data: vec![].try_into().unwrap(), }, }; @@ -1884,7 +1884,7 @@ fn can_request_ccm_swap_via_extrinsic() { channel_metadata: CcmChannelMetadata { message: vec![0x01].try_into().unwrap(), gas_budget: 1_000, - ccm_cf_parameters: Default::default(), + ccm_additional_data: Default::default(), }, }; @@ -1979,7 +1979,7 @@ fn failed_ccm_deposit_can_deposit_event() { channel_metadata: CcmChannelMetadata { message: vec![0x01].try_into().unwrap(), gas_budget: GAS_BUDGET, - ccm_cf_parameters: Default::default(), + ccm_additional_data: Default::default(), }, }; diff --git a/state-chain/pallets/cf-swapping/src/tests.rs b/state-chain/pallets/cf-swapping/src/tests.rs index 08ef7d7c35..ac79413503 100644 --- a/state-chain/pallets/cf-swapping/src/tests.rs +++ b/state-chain/pallets/cf-swapping/src/tests.rs @@ -216,7 +216,7 @@ fn generate_ccm_channel() -> CcmChannelMetadata { CcmChannelMetadata { message: vec![0x01].try_into().unwrap(), gas_budget: GAS_BUDGET, - ccm_cf_parameters: Default::default(), + ccm_additional_data: Default::default(), } } fn generate_ccm_deposit() -> CcmDepositMetadata { diff --git a/state-chain/pallets/cf-swapping/src/tests/ccm.rs b/state-chain/pallets/cf-swapping/src/tests/ccm.rs index b8aa60c018..f06002224a 100644 --- a/state-chain/pallets/cf-swapping/src/tests/ccm.rs +++ b/state-chain/pallets/cf-swapping/src/tests/ccm.rs @@ -66,7 +66,7 @@ pub(super) fn assert_ccm_egressed( amount: principal_amount, destination_address: (*EVM_OUTPUT_ADDRESS).clone(), message: vec![0x01].try_into().unwrap(), - ccm_cf_parameters: vec![].try_into().unwrap(), + ccm_additional_data: vec![].try_into().unwrap(), gas_budget, }, ); diff --git a/state-chain/traits/src/mocks/api_call.rs b/state-chain/traits/src/mocks/api_call.rs index 6d8834f772..05ee49ecdc 100644 --- a/state-chain/traits/src/mocks/api_call.rs +++ b/state-chain/traits/src/mocks/api_call.rs @@ -149,7 +149,7 @@ impl ExecutexSwapAndCall for MockEthereumApiCall { source_address: Option, gas_budget: ::ChainAmount, message: Vec, - _ccm_cf_parameters: Vec, + _ccm_additional_data: Vec, ) -> Result { if MockEvmEnvironment::lookup(transfer_param.asset).is_none() { Err(ExecutexSwapAndCallError::DispatchError(DispatchError::CannotLookup)) @@ -285,7 +285,7 @@ impl ExecutexSwapAndCall for MockBitcoinApiCall { source_address: Option, gas_budget: ::ChainAmount, message: Vec, - _ccm_cf_parameters: Vec, + _ccm_additional_data: Vec, ) -> Result { if MockBtcEnvironment::lookup(transfer_param.asset).is_none() { Err(ExecutexSwapAndCallError::DispatchError(DispatchError::CannotLookup)) diff --git a/state-chain/traits/src/mocks/egress_handler.rs b/state-chain/traits/src/mocks/egress_handler.rs index 50033461fd..d6fdc50160 100644 --- a/state-chain/traits/src/mocks/egress_handler.rs +++ b/state-chain/traits/src/mocks/egress_handler.rs @@ -1,6 +1,6 @@ use super::{MockPallet, MockPalletStorage}; use crate::{EgressApi, ScheduledEgressDetails}; -use cf_chains::{CcmCfParameters, CcmDepositMetadata, CcmMessage, Chain}; +use cf_chains::{CcmAdditionalData, CcmDepositMetadata, CcmMessage, Chain}; use cf_primitives::{AssetAmount, EgressCounter}; use codec::{Decode, Encode}; use frame_support::sp_runtime::{ @@ -29,7 +29,7 @@ pub enum MockEgressParameter { amount: C::ChainAmount, destination_address: C::ChainAccount, message: CcmMessage, - ccm_cf_parameters: CcmCfParameters, + ccm_additional_data: CcmAdditionalData, gas_budget: C::ChainAmount, }, } @@ -95,7 +95,7 @@ impl EgressApi for MockEgressHandler { amount, destination_address, message: message.channel_metadata.message.clone(), - ccm_cf_parameters: message.channel_metadata.ccm_cf_parameters.clone(), + ccm_additional_data: message.channel_metadata.ccm_additional_data.clone(), gas_budget: *gas_budget, }, None => MockEgressParameter::::Swap { From 115342e92cdf3539326d28dc01a7b388a96fc601 Mon Sep 17 00:00:00 2001 From: albert Date: Thu, 17 Oct 2024 16:27:45 +0200 Subject: [PATCH 06/36] chore: improve logic --- bouncer/shared/contract_swap.ts | 87 +++++++++++++++++---------------- 1 file changed, 45 insertions(+), 42 deletions(-) diff --git a/bouncer/shared/contract_swap.ts b/bouncer/shared/contract_swap.ts index 6f41cf0b4f..854d7310ae 100644 --- a/bouncer/shared/contract_swap.ts +++ b/bouncer/shared/contract_swap.ts @@ -25,12 +25,10 @@ import { shortChainFromAsset, } from './utils'; import { getBalance } from './get_balance'; -import { CcmDepositMetadata } from '../shared/new_swap'; +import { CcmDepositMetadata, DcaParams, FillOrKillParamsX128 } from '../shared/new_swap'; import { send } from './send'; import { SwapContext, SwapStatus } from './swap_context'; import { vaultSwapCfParametersCodec } from './swapping'; -import { newEvmAddress } from './new_evm_address'; -import { newSolAddress } from './new_sol_address'; const erc20Assets: Asset[] = ['Flip', 'Usdc', 'Usdt', 'ArbUsdc']; @@ -40,6 +38,9 @@ export async function executeContractSwap( destAddress: string, wallet: HDNodeWallet, messageMetadata?: CcmDepositMetadata, + boostFeeBps?: number, + fillOrKillParams?: FillOrKillParamsX128, + dcaParams?: DcaParams, ): ReturnType { const srcChain = chainFromAsset(srcAsset); const destChain = chainFromAsset(destAsset); @@ -55,45 +56,37 @@ export async function executeContractSwap( gasLimit: srcChain === Chains.Arbitrum ? 10000000n : 200000n, } as const; - console.log('messageMetadata?.cfParameters', messageMetadata?.cfParameters); - console.log('hexTou8(messageMetadata?.cfParameters)', hexToU8a(messageMetadata?.cfParameters)); - - // const refundAddressTest = hexToU8a('0x41aD2bc63A2059f9b623533d87fe99887D794847'); - - let refundAddress; - switch (srcChain) { - case Chains.Ethereum: - case Chains.Arbitrum: - refundAddress = newEvmAddress('refundAddress'); - break; - case Chains.Solana: - refundAddress = newSolAddress('refundAddress'); - break; - default: - throw new Error(`Unsupported chain: ${srcChain}`); - } - console.log('refundAddress', refundAddress); - console.log('refundAddress', hexToU8a(refundAddress)); - - const ccmAdditionalData = u8aToHex( - vaultSwapCfParametersCodec.enc({ - ccmAdditionalData: hexToU8a(messageMetadata?.cfParameters), - // vaultSwapAttributes: undefined, - vaultSwapAttributes: { - // refundParams: undefined, - refundParams: { - retryDuration: 2, - refundAddress: { tag: shortChainFromAsset(srcAsset), value: hexToU8a(refundAddress) }, - minPriceX128: BigInt(3), - }, - dcaParams: { - numberOfChunks: 4, - chunkIntervalBlocks: 5, - }, - boostFee: 1, - }, - }), - ); + // messageMetadata.cfParameters = undefined; + // boostFeeBps = 1; + + const ccmAdditionalData = + messageMetadata?.cfParameters || fillOrKillParams || dcaParams || boostFeeBps + ? u8aToHex( + vaultSwapCfParametersCodec.enc({ + ccmAdditionalData: messageMetadata?.cfParameters + ? hexToU8a(messageMetadata.cfParameters) + : undefined, + vaultSwapAttributes: + fillOrKillParams || dcaParams || boostFeeBps + ? { + refundParams: fillOrKillParams && { + retryDuration: fillOrKillParams.retryDurationBlocks, + // refundAddress: { tag: shortChainFromAsset(srcAsset), value: hexToU8a(refundAddress) }, + refundAddress: { + tag: shortChainFromAsset(srcAsset), + // value: fillOrKillParams.refundAddress, + value: hexToU8a(fillOrKillParams.refundAddress), + }, + minPriceX128: BigInt(fillOrKillParams.minPriceX128), + }, + dcaParams, + boostFee: boostFeeBps, + } + : undefined, + }), + ) + : undefined; + console.log('ccmAdditionalData passed to the SDK in contractCall', ccmAdditionalData); const receipt = await executeSwap( @@ -106,6 +99,10 @@ export async function executeContractSwap( destAddress, srcAsset: stateChainAssetFromAsset(srcAsset), srcChain, + // TODO: This will need some refactoring either putting the cfParameters outside the + // ccmParams and the user should encode it as done here or, probably better, we just + // add the SwapAttributes support (Fok/Dca/Boost) as separate parameters, rename + // cfParameters to ccmAdditionalData and do the encoding within the SDK. ccmParams: messageMetadata && { gasBudget: messageMetadata.gasBudget.toString(), message: messageMetadata.message, @@ -134,6 +131,9 @@ export async function performSwapViaContract( messageMetadata?: CcmDepositMetadata, swapContext?: SwapContext, log = true, + boostFeeBps?: number, + fillOrKillParams?: FillOrKillParamsX128, + dcaParams?: DcaParams, ): Promise { const tag = swapTag ?? ''; @@ -183,6 +183,9 @@ export async function performSwapViaContract( destAddress, wallet, messageMetadata, + boostFeeBps, + fillOrKillParams, + dcaParams, ); swapContext?.updateStatus(swapTag, SwapStatus.ContractExecuted); From 4256a5b3f578731ac3dc73e5f68d4fd438afcb95 Mon Sep 17 00:00:00 2001 From: Maxim Shishmarev Date: Fri, 18 Oct 2024 13:00:47 +1100 Subject: [PATCH 07/36] fix: address RuntimeCall size limit --- engine/src/witness/arb.rs | 4 +++- engine/src/witness/btc/smart_contract.rs | 4 ++-- engine/src/witness/eth.rs | 4 +++- state-chain/pallets/cf-ingress-egress/src/lib.rs | 5 +++-- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/engine/src/witness/arb.rs b/engine/src/witness/arb.rs index 8eaf700d32..1c4e2433ad 100644 --- a/engine/src/witness/arb.rs +++ b/engine/src/witness/arb.rs @@ -207,7 +207,9 @@ impl super::evm::vault::IngressCallBuilder for ArbCallBuilder { deposit_amount, destination_address, tx_hash, - deposit_details: DepositDetails { tx_hashes: Some(vec![tx_hash.into()]) }, + deposit_details: Box::new(DepositDetails { + tx_hashes: Some(vec![tx_hash.into()]), + }), // TODO: use real parameters when we can decode them boost_fee: 0, dca_params: None, diff --git a/engine/src/witness/btc/smart_contract.rs b/engine/src/witness/btc/smart_contract.rs index 358b4706b3..ad7afb2f7f 100644 --- a/engine/src/witness/btc/smart_contract.rs +++ b/engine/src/witness/btc/smart_contract.rs @@ -134,11 +134,11 @@ pub fn try_extract_contract_call( deposit_amount, destination_address: data.output_address, tx_hash: tx_id, - deposit_details: BtcDepositDetails { + deposit_details: Box::new(BtcDepositDetails { // we require the deposit to be the first UTXO utxo_id: UtxoId { tx_id: tx_id.into(), vout: 0 }, deposit_address: vault_address.clone(), - }, + }), refund_params: Some(ChannelRefundParameters { retry_duration: data.parameters.retry_duration as u32, refund_address: ForeignChainAddress::Btc(refund_address), diff --git a/engine/src/witness/eth.rs b/engine/src/witness/eth.rs index 8fe452fd22..75e7dea2a4 100644 --- a/engine/src/witness/eth.rs +++ b/engine/src/witness/eth.rs @@ -252,7 +252,9 @@ impl super::evm::vault::IngressCallBuilder for EthCallBuilder { deposit_amount, destination_address, tx_hash, - deposit_details: DepositDetails { tx_hashes: Some(vec![tx_hash.into()]) }, + deposit_details: Box::new(DepositDetails { + tx_hashes: Some(vec![tx_hash.into()]), + }), // TODO: use real parameters when we can decode them boost_fee: 0, dca_params: None, diff --git a/state-chain/pallets/cf-ingress-egress/src/lib.rs b/state-chain/pallets/cf-ingress-egress/src/lib.rs index 691c9d7cd6..3bd3efe3f3 100644 --- a/state-chain/pallets/cf-ingress-egress/src/lib.rs +++ b/state-chain/pallets/cf-ingress-egress/src/lib.rs @@ -57,6 +57,7 @@ use scale_info::{ }; use sp_runtime::traits::UniqueSaturatedInto; use sp_std::{ + boxed::Box, collections::{btree_map::BTreeMap, btree_set::BTreeSet}, marker::PhantomData, vec, @@ -1103,7 +1104,7 @@ pub mod pallet { deposit_amount: ::ChainAmount, destination_address: EncodedAddress, tx_hash: TransactionHash, - deposit_details: ::DepositDetails, + deposit_details: Box<::DepositDetails>, refund_params: Option, dca_params: Option, // This is only to be checked in the pre-witnessed version (not implemented yet) @@ -1123,7 +1124,7 @@ pub mod pallet { }, }; - T::DepositHandler::on_deposit_made(deposit_details, deposit_amount); + T::DepositHandler::on_deposit_made(*deposit_details, deposit_amount); // TODO: ensure minimum deposit? From 4234046b7dea0dd4590b06dc7d9367ada6307303 Mon Sep 17 00:00:00 2001 From: Maxim Shishmarev Date: Fri, 18 Oct 2024 13:55:46 +1100 Subject: [PATCH 08/36] chore: address clippy --- .../src/witnessing/state_chain.rs | 4 ++-- engine/src/witness/btc/smart_contract.rs | 4 ++-- state-chain/cf-integration-tests/src/swapping.rs | 2 +- state-chain/pallets/cf-ingress-egress/src/benchmarking.rs | 2 +- state-chain/pallets/cf-ingress-egress/src/tests.rs | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/api/bin/chainflip-ingress-egress-tracker/src/witnessing/state_chain.rs b/api/bin/chainflip-ingress-egress-tracker/src/witnessing/state_chain.rs index 85818481de..5d9c6c553c 100644 --- a/api/bin/chainflip-ingress-egress-tracker/src/witnessing/state_chain.rs +++ b/api/bin/chainflip-ingress-egress-tracker/src/witnessing/state_chain.rs @@ -147,8 +147,8 @@ impl From> for WitnessInformation { amount: value.amount.into(), asset: value.asset.into(), deposit_details: Some(DepositDetails::Bitcoin { - tx_id: value.deposit_details.tx_id, - vout: value.deposit_details.vout, + tx_id: value.deposit_details.utxo_id.tx_id, + vout: value.deposit_details.utxo_id.vout, }), } } diff --git a/engine/src/witness/btc/smart_contract.rs b/engine/src/witness/btc/smart_contract.rs index ad7afb2f7f..7cf4931d7b 100644 --- a/engine/src/witness/btc/smart_contract.rs +++ b/engine/src/witness/btc/smart_contract.rs @@ -270,10 +270,10 @@ mod tests { deposit_amount: DEPOSIT_AMOUNT, destination_address: MOCK_SWAP_PARAMS.output_address.clone(), tx_hash: tx.hash.to_byte_array(), - deposit_details: BtcDepositDetails { + deposit_details: Box::new(BtcDepositDetails { utxo_id: UtxoId { tx_id: tx.txid.to_byte_array().into(), vout: 0 }, deposit_address: vault_deposit_address, - }, + }), refund_params: Some(ChannelRefundParameters { retry_duration: MOCK_SWAP_PARAMS.parameters.retry_duration as u32, refund_address: ForeignChainAddress::Btc(refund_pubkey), diff --git a/state-chain/cf-integration-tests/src/swapping.rs b/state-chain/cf-integration-tests/src/swapping.rs index 40bd15e5af..f71dd53698 100644 --- a/state-chain/cf-integration-tests/src/swapping.rs +++ b/state-chain/cf-integration-tests/src/swapping.rs @@ -623,7 +623,7 @@ fn failed_swaps_are_rolled_back() { deposit_amount: 10_000 * DECIMALS, destination_address: EncodedAddress::Eth(Default::default()), tx_hash: Default::default(), - deposit_details: DepositDetails { tx_hashes: None }, + deposit_details: Box::new(DepositDetails { tx_hashes: None }), refund_params: None, dca_params: None, boost_fee: 0, diff --git a/state-chain/pallets/cf-ingress-egress/src/benchmarking.rs b/state-chain/pallets/cf-ingress-egress/src/benchmarking.rs index 04f69be3bf..9af3401b1f 100644 --- a/state-chain/pallets/cf-ingress-egress/src/benchmarking.rs +++ b/state-chain/pallets/cf-ingress-egress/src/benchmarking.rs @@ -297,7 +297,7 @@ mod benchmarks { deposit_amount: deposit_amount.into(), destination_address: EncodedAddress::benchmark_value(), tx_hash: [0; 32], - deposit_details: BenchmarkValue::benchmark_value(), + deposit_details: Box::new(BenchmarkValue::benchmark_value()), refund_params: None, dca_params: None, boost_fee: 0, diff --git a/state-chain/pallets/cf-ingress-egress/src/tests.rs b/state-chain/pallets/cf-ingress-egress/src/tests.rs index 45bf3cb74a..f1906ac22f 100644 --- a/state-chain/pallets/cf-ingress-egress/src/tests.rs +++ b/state-chain/pallets/cf-ingress-egress/src/tests.rs @@ -1851,7 +1851,7 @@ fn can_request_swap_via_extrinsic() { INPUT_AMOUNT, MockAddressConverter::to_encoded_address(output_address.clone()), TX_HASH, - DepositDetails { tx_hashes: None }, + Box::new(DepositDetails { tx_hashes: None }), None, None, 0, @@ -1939,7 +1939,7 @@ fn rejects_invalid_swap_by_witnesser() { 10000, btc_encoded_address, Default::default(), - DepositDetails { tx_hashes: None }, + Box::new(DepositDetails { tx_hashes: None }), None, None, 0 @@ -1956,7 +1956,7 @@ fn rejects_invalid_swap_by_witnesser() { 10000, EncodedAddress::Btc(vec![0x41, 0x80, 0x41]), Default::default(), - DepositDetails { tx_hashes: None }, + Box::new(DepositDetails { tx_hashes: None }), None, None, 0 From bd67b361ae73097914536eab2b98e9edeefd8654 Mon Sep 17 00:00:00 2001 From: albert Date: Fri, 18 Oct 2024 09:05:32 +0200 Subject: [PATCH 09/36] chore: more cleanup and refactoring --- bouncer/shared/contract_swap.ts | 105 +++++++++++++++++--------------- bouncer/shared/send.ts | 4 +- bouncer/shared/swapping.ts | 44 ++----------- bouncer/tests/fill_or_kill.ts | 101 ++++++++++++++++++------------ 4 files changed, 127 insertions(+), 127 deletions(-) diff --git a/bouncer/shared/contract_swap.ts b/bouncer/shared/contract_swap.ts index 854d7310ae..8f92c6068a 100644 --- a/bouncer/shared/contract_swap.ts +++ b/bouncer/shared/contract_swap.ts @@ -32,62 +32,72 @@ import { vaultSwapCfParametersCodec } from './swapping'; const erc20Assets: Asset[] = ['Flip', 'Usdc', 'Usdt', 'ArbUsdc']; +export function encodeCfParameters( + sourceAsset: Asset, + ccmAdditionalData?: string | undefined, + boostFeeBps?: number, + fillOrKillParams?: FillOrKillParamsX128, + dcaParams?: DcaParams, +): string | undefined { + return ccmAdditionalData || fillOrKillParams || dcaParams || boostFeeBps + ? u8aToHex( + vaultSwapCfParametersCodec.enc({ + ccmAdditionalData: ccmAdditionalData ? hexToU8a(ccmAdditionalData) : undefined, + vaultSwapAttributes: + fillOrKillParams || dcaParams || boostFeeBps + ? { + refundParams: fillOrKillParams && { + retryDurationBlocks: fillOrKillParams.retryDurationBlocks, + refundAddress: { + tag: shortChainFromAsset(sourceAsset), + value: hexToU8a(fillOrKillParams.refundAddress), + }, + minPriceX128: BigInt(fillOrKillParams.minPriceX128), + }, + dcaParams, + boostFee: boostFeeBps, + } + : undefined, + }), + ) + : undefined; +} + export async function executeContractSwap( - srcAsset: Asset, + sourceAsset: Asset, destAsset: Asset, destAddress: string, wallet: HDNodeWallet, messageMetadata?: CcmDepositMetadata, + amount?: string, boostFeeBps?: number, fillOrKillParams?: FillOrKillParamsX128, dcaParams?: DcaParams, ): ReturnType { - const srcChain = chainFromAsset(srcAsset); + const srcChain = chainFromAsset(sourceAsset); const destChain = chainFromAsset(destAsset); + const amountToSwap = amount ?? defaultAssetAmounts(sourceAsset); const networkOptions = { signer: wallet, network: 'localnet', vaultContractAddress: getContractAddress(srcChain, 'VAULT'), - srcTokenContractAddress: getContractAddress(srcChain, srcAsset), + srcTokenContractAddress: getContractAddress(srcChain, sourceAsset), } as const; const txOptions = { // This is run with fresh addresses to prevent nonce issues. Will be 1 for ERC20s. gasLimit: srcChain === Chains.Arbitrum ? 10000000n : 200000n, } as const; - // messageMetadata.cfParameters = undefined; - // boostFeeBps = 1; - - const ccmAdditionalData = - messageMetadata?.cfParameters || fillOrKillParams || dcaParams || boostFeeBps - ? u8aToHex( - vaultSwapCfParametersCodec.enc({ - ccmAdditionalData: messageMetadata?.cfParameters - ? hexToU8a(messageMetadata.cfParameters) - : undefined, - vaultSwapAttributes: - fillOrKillParams || dcaParams || boostFeeBps - ? { - refundParams: fillOrKillParams && { - retryDuration: fillOrKillParams.retryDurationBlocks, - // refundAddress: { tag: shortChainFromAsset(srcAsset), value: hexToU8a(refundAddress) }, - refundAddress: { - tag: shortChainFromAsset(srcAsset), - // value: fillOrKillParams.refundAddress, - value: hexToU8a(fillOrKillParams.refundAddress), - }, - minPriceX128: BigInt(fillOrKillParams.minPriceX128), - }, - dcaParams, - boostFee: boostFeeBps, - } - : undefined, - }), - ) - : undefined; + const cfParameters = encodeCfParameters( + sourceAsset, + messageMetadata?.cfParameters, + boostFeeBps, + fillOrKillParams, + dcaParams, + ); - console.log('ccmAdditionalData passed to the SDK in contractCall', ccmAdditionalData); + console.log('cfParameters passed to the SDK in contractCall', cfParameters); const receipt = await executeSwap( { @@ -95,9 +105,9 @@ export async function executeContractSwap( destAsset: stateChainAssetFromAsset(destAsset), // It is important that this is large enough to result in // an amount larger than existential (e.g. on Polkadot): - amount: amountToFineAmount(defaultAssetAmounts(srcAsset), assetDecimals(srcAsset)), + amount: amountToFineAmount(amountToSwap, assetDecimals(sourceAsset)), destAddress, - srcAsset: stateChainAssetFromAsset(srcAsset), + srcAsset: stateChainAssetFromAsset(sourceAsset), srcChain, // TODO: This will need some refactoring either putting the cfParameters outside the // ccmParams and the user should encode it as done here or, probably better, we just @@ -106,8 +116,7 @@ export async function executeContractSwap( ccmParams: messageMetadata && { gasBudget: messageMetadata.gasBudget.toString(), message: messageMetadata.message, - cfParameters: ccmAdditionalData, - // ccmAdditionalData: ccmAdditionalData, + cfParameters, }, } as ExecuteSwapParams, networkOptions, @@ -131,11 +140,13 @@ export async function performSwapViaContract( messageMetadata?: CcmDepositMetadata, swapContext?: SwapContext, log = true, + amount?: string, boostFeeBps?: number, fillOrKillParams?: FillOrKillParamsX128, dcaParams?: DcaParams, ): Promise { const tag = swapTag ?? ''; + const amountToSwap = amount ?? defaultAssetAmounts(sourceAsset); const srcChain = chainFromAsset(sourceAsset); @@ -157,10 +168,7 @@ export async function performSwapViaContract( // eslint-disable-next-line @typescript-eslint/no-use-before-define await approveTokenVault( sourceAsset, - ( - BigInt(amountToFineAmount(defaultAssetAmounts(sourceAsset), assetDecimals(sourceAsset))) * - 100n - ).toString(), + (BigInt(amountToFineAmount(amountToSwap, assetDecimals(sourceAsset))) * 100n).toString(), wallet, ); } @@ -183,6 +191,7 @@ export async function performSwapViaContract( destAddress, wallet, messageMetadata, + amountToSwap, boostFeeBps, fillOrKillParams, dcaParams, @@ -222,24 +231,24 @@ export async function performSwapViaContract( throw new Error(`${tag} ${err}`); } } -export async function approveTokenVault(srcAsset: Asset, amount: string, wallet: HDNodeWallet) { - if (!erc20Assets.includes(srcAsset)) { - throw new Error(`Unsupported asset, not an ERC20: ${srcAsset}`); +export async function approveTokenVault(sourceAsset: Asset, amount: string, wallet: HDNodeWallet) { + if (!erc20Assets.includes(sourceAsset)) { + throw new Error(`Unsupported asset, not an ERC20: ${sourceAsset}`); } - const chain = chainFromAsset(srcAsset as Asset); + const chain = chainFromAsset(sourceAsset as Asset); await approveVault( { amount, srcChain: chain as Chain, - srcAsset: stateChainAssetFromAsset(srcAsset) as SCAsset, + srcAsset: stateChainAssetFromAsset(sourceAsset) as SCAsset, }, { signer: wallet, network: 'localnet', vaultContractAddress: getContractAddress(chain, 'VAULT'), - srcTokenContractAddress: getContractAddress(chain, srcAsset), + srcTokenContractAddress: getContractAddress(chain, sourceAsset), }, // This is run with fresh addresses to prevent nonce issues { diff --git a/bouncer/shared/send.ts b/bouncer/shared/send.ts index 984806351f..521f66fc34 100644 --- a/bouncer/shared/send.ts +++ b/bouncer/shared/send.ts @@ -20,9 +20,7 @@ import { sendSolUsdc } from './send_solusdc'; const cfTesterAbi = await getCFTesterAbi(); export async function send(asset: Asset, address: string, amount?: string, log = true) { - // TODO: Remove this any when we have Sol assets in the Asset type. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - switch (asset as any) { + switch (asset) { case 'Btc': await sendBtc(address, amount ?? defaultAssetAmounts(asset)); break; diff --git a/bouncer/shared/swapping.ts b/bouncer/shared/swapping.ts index ee5b1915be..c00d638d19 100644 --- a/bouncer/shared/swapping.ts +++ b/bouncer/shared/swapping.ts @@ -1,8 +1,7 @@ import { InternalAsset as Asset } from '@chainflip/cli'; import { Keypair, PublicKey } from '@solana/web3.js'; import Web3 from 'web3'; -import { u8aToHex } from '@polkadot/util'; -import { str, u32, Struct, Option, u16, u256, Bytes as TsBytes, Enum } from 'scale-ts'; +import { u32, Struct, Option, u16, u256, Bytes as TsBytes, Enum } from 'scale-ts'; import { randomAsHex, randomAsNumber } from '../polkadot/util-crypto'; import { performSwap } from '../shared/perform_swap'; import { @@ -15,10 +14,9 @@ import { assetDecimals, } from '../shared/utils'; import { BtcAddressType } from '../shared/new_btc_address'; -import { CcmDepositMetadata, DcaParams, FillOrKillParamsX128 } from '../shared/new_swap'; +import { CcmDepositMetadata } from '../shared/new_swap'; import { performSwapViaContract } from '../shared/contract_swap'; import { SwapContext, SwapStatus } from './swap_context'; -import { U256 } from '@polkadot/types'; enum SolidityType { Uint256 = 'uint256', @@ -165,10 +163,10 @@ export const vaultSwapCfParametersCodec = Struct({ Struct({ refundParams: Option( Struct({ - retryDuration: u32, + retryDurationBlocks: u32, refundAddress: Enum({ Eth: TsBytes(20), - Dot: TsBytes(32), + Dot: TsBytes(32), // not supported anyway Btc: TsBytes(), // not supported anyway Arb: TsBytes(20), Sol: TsBytes(32), @@ -190,7 +188,7 @@ export function newCcmMetadata( cfParamsArray?: string, ): CcmDepositMetadata { const message = ccmMessage ?? newCcmMessage(destAsset); - const cfParameters = cfParamsArray ?? newCcmAdditionalData(destAsset, message); + const ccmAdditionalData = cfParamsArray ?? newCcmAdditionalData(destAsset, message); const gasDiv = gasBudgetFraction ?? 2; const gasBudget = Math.floor( @@ -202,40 +200,10 @@ export function newCcmMetadata( message, gasBudget, // TODO: To rename to ccmAdditionalData - cfParameters, + cfParameters: ccmAdditionalData, }; } -export function newVaultSwapCfParameters( - sourceAsset: Asset, - destAsset: Asset, - ccmMessage?: string, - gasBudgetFraction?: number, - cfParamsArray?: string, - boostFeeBps?: number, - fillOrKillParams?: FillOrKillParamsX128, - dcaParams?: DcaParams, -): string { - const ccmMetadata = newCcmMetadata( - sourceAsset, - destAsset, - ccmMessage, - gasBudgetFraction, - cfParamsArray, - ); - - return u8aToHex( - vaultSwapCfParametersCodec.enc({ - ccmAdditionalData: ccmMetadata.cfParameters, - vaultSwapAttributes: { - boostFeeBps, - fillOrKillParams, - dcaParams, - }, - }), - ); -} - export async function prepareSwap( sourceAsset: Asset, destAsset: Asset, diff --git a/bouncer/tests/fill_or_kill.ts b/bouncer/tests/fill_or_kill.ts index bbdf7a6e3e..becc8b63d4 100644 --- a/bouncer/tests/fill_or_kill.ts +++ b/bouncer/tests/fill_or_kill.ts @@ -15,12 +15,14 @@ import { getBalance } from '../shared/get_balance'; import { observeEvent } from '../shared/utils/substrate'; import { FillOrKillParamsX128 } from '../shared/new_swap'; import { ExecutableTest } from '../shared/executable_test'; +import { performSwapViaContract } from '../shared/contract_swap'; +import { newCcmMetadata } from '../shared/swapping'; /* eslint-disable @typescript-eslint/no-use-before-define */ export const testFillOrKill = new ExecutableTest('FoK', main, 600); /// Do a swap with unrealistic minimum price so it gets refunded. -async function testMinPriceRefund(inputAsset: Asset, amount: number) { +async function testMinPriceRefund(inputAsset: Asset, amount: number, swapviaContract = false) { const destAsset = inputAsset === Assets.Usdc ? Assets.Flip : Assets.Usdc; const refundAddress = await newAddress(inputAsset, randomBytes(32).toString('hex')); const destAddress = await newAddress(destAsset, randomBytes(32).toString('hex')); @@ -39,56 +41,76 @@ async function testMinPriceRefund(inputAsset: Asset, amount: number) { ), }; - testFillOrKill.log( - `Requesting swap from ${inputAsset} to ${destAsset} with unrealistic min price`, - ); - const swapRequest = await requestNewSwap( - inputAsset, - destAsset, - destAddress, - 'FoK_Test', - undefined, // messageMetadata - 0, // brokerCommissionBps - false, // log - 0, // boostFeeBps - refundParameters, - ); - const depositAddress = swapRequest.depositAddress; - const depositChannelId = swapRequest.channelId; + let swapHandle; - const swapRequestedHandle = observeSwapRequested( - inputAsset, - destAsset, - depositChannelId, - SwapRequestType.Regular, - ); + if (!swapviaContract) { + testFillOrKill.log( + `Requesting swap from ${inputAsset} to ${destAsset} with unrealistic min price`, + ); + const swapRequest = await requestNewSwap( + inputAsset, + destAsset, + destAddress, + 'FoK_Test', + undefined, // messageMetadata + 0, // brokerCommissionBps + false, // log + 0, // boostFeeBps + refundParameters, + ); + const depositAddress = swapRequest.depositAddress; + const depositChannelId = swapRequest.channelId; - // Deposit the asset - await send(inputAsset, depositAddress, amount.toString()); - testFillOrKill.log(`Sent ${amount} ${inputAsset} to ${depositAddress}`); + const swapRequestedHandle = observeSwapRequested( + inputAsset, + destAsset, + depositChannelId, + SwapRequestType.Regular, + ); - const swapRequestedEvent = await swapRequestedHandle; - const swapRequestId = Number(swapRequestedEvent.data.swapRequestId.replaceAll(',', '')); - testFillOrKill.log(`${inputAsset} swap requested, swapRequestId: ${swapRequestId}`); + // Deposit the asset + await send(inputAsset, depositAddress, amount.toString()); + testFillOrKill.log(`Sent ${amount} ${inputAsset} to ${depositAddress}`); - const observeSwapExecuted = observeEvent(`swapping:SwapExecuted`, { - test: (event) => Number(event.data.swapRequestId.replaceAll(',', '')) === swapRequestId, - historicalCheckBlocks: 10, - }).event; + const swapRequestedEvent = await swapRequestedHandle; + const swapRequestId = Number(swapRequestedEvent.data.swapRequestId.replaceAll(',', '')); + testFillOrKill.log(`${inputAsset} swap requested, swapRequestId: ${swapRequestId}`); + + swapHandle = observeEvent(`swapping:SwapExecuted`, { + test: (event) => Number(event.data.swapRequestId.replaceAll(',', '')) === swapRequestId, + historicalCheckBlocks: 10, + }).event; + } else { + swapHandle = performSwapViaContract( + inputAsset, + destAsset, + destAddress, + 'test', + // Creating CCM metadata because we need a CCM metadata with the current SDK to be able + // to pass the ccmAdditionalData even if we dont' need it. Then if the gasBudget is + // very high the swap might fail so we force a lower gasBudget. + // TODO: Remove the entire CCM metadata. + newCcmMetadata(inputAsset, destAsset, undefined, 100), + undefined, + true, + amount.toString(), + undefined, + refundParameters, + undefined, + ); + } // Wait for the swap to execute or get refunded const executeOrRefund = await Promise.race([ - observeSwapExecuted, + swapHandle, observeBalanceIncrease(inputAsset, refundAddress, refundBalanceBefore), ]); if (typeof executeOrRefund !== 'number') { - throw new Error( - `${inputAsset} swap ${swapRequestId} was executed instead of failing and being refunded`, - ); + throw new Error(`${inputAsset} swap was executed instead of failing and being refunded`); } - testFillOrKill.log(`FoK ${inputAsset} swap refunded`); + testFillOrKill.log(`FoK ${inputAsset} ${swapviaContract ? ' via contract' : ''} swap refunded`); } async function main() { @@ -98,5 +120,8 @@ async function main() { testMinPriceRefund(Assets.Dot, 100), testMinPriceRefund(Assets.Btc, 0.1), testMinPriceRefund(Assets.Usdc, 1000), + testMinPriceRefund(Assets.Flip, 500, true), + testMinPriceRefund(Assets.Eth, 1, true), + testMinPriceRefund(Assets.ArbEth, 5, true), ]); } From b510b814327fb1312c6b0c39323f62ee44dbfc38 Mon Sep 17 00:00:00 2001 From: albert Date: Fri, 18 Oct 2024 10:51:23 +0200 Subject: [PATCH 10/36] chore: add contract swaps to dca test --- bouncer/shared/utils.ts | 9 +- bouncer/tests/DCA_test.ts | 150 ++++++++++++++++++++++++---------- bouncer/tests/fill_or_kill.ts | 7 +- 3 files changed, 119 insertions(+), 47 deletions(-) diff --git a/bouncer/shared/utils.ts b/bouncer/shared/utils.ts index 8ce6075902..d49324a391 100644 --- a/bouncer/shared/utils.ts +++ b/bouncer/shared/utils.ts @@ -469,7 +469,7 @@ function checkRequestTypeMatches(actual: object | string, expected: SwapRequestT export async function observeSwapRequested( sourceAsset: Asset, destAsset: Asset, - channelId: number, + id: number | string, swapRequestType: SwapRequestType, ) { // need to await this to prevent the chainflip api from being disposed prematurely @@ -477,9 +477,12 @@ export async function observeSwapRequested( test: (event) => { const data = event.data; - if (typeof data.origin === 'object' && 'DepositChannel' in data.origin) { + if (typeof data.origin === 'object') { const channelMatches = - Number(data.origin.DepositChannel.channelId.replaceAll(',', '')) === channelId; + (typeof id === 'number' && + 'DepositChannel' in data.origin && + Number(data.origin.DepositChannel.channelId.replaceAll(',', '')) === id) || + (typeof id === 'string' && 'Vault' in data.origin && data.origin.Vault.txHash === id); const sourceAssetMatches = sourceAsset === (data.inputAsset as Asset); const destAssetMatches = destAsset === (data.outputAsset as Asset); const requestTypeMatches = checkRequestTypeMatches(data.requestType, swapRequestType); diff --git a/bouncer/tests/DCA_test.ts b/bouncer/tests/DCA_test.ts index 43e14aad59..cfd1c0a0e9 100644 --- a/bouncer/tests/DCA_test.ts +++ b/bouncer/tests/DCA_test.ts @@ -1,7 +1,12 @@ -import { InternalAsset as Asset, InternalAssets as Assets } from '@chainflip/cli'; +import { InternalAsset as Asset, InternalAssets as Assets, InternalAsset } from '@chainflip/cli'; import { randomBytes } from 'crypto'; +import { getDefaultProvider, Wallet } from 'ethers'; import assert from 'assert'; import { + chainFromAsset, + chainGasAsset, + getContractAddress, + getEvmEndpoint, newAddress, observeBalanceIncrease, observeSwapRequested, @@ -12,7 +17,9 @@ import { observeEvent, observeEvents } from '../shared/utils/substrate'; import { getBalance } from '../shared/get_balance'; import { ExecutableTest } from '../shared/executable_test'; import { requestNewSwap } from '../shared/perform_swap'; -import { DcaParams } from '../shared/new_swap'; +import { DcaParams, FillOrKillParamsX128 } from '../shared/new_swap'; +import { newCcmMetadata } from '../shared/swapping'; +import { executeContractSwap } from '../shared/contract_swap'; /* eslint-disable @typescript-eslint/no-use-before-define */ export const testDCASwaps = new ExecutableTest('DCA-Swaps', main, 150); @@ -20,50 +27,104 @@ export const testDCASwaps = new ExecutableTest('DCA-Swaps', main, 150); // Requested number of blocks between each chunk const CHUNK_INTERVAL = 2; -async function testDCASwap(inputAsset: Asset, amount: number, numberOfChunks: number) { +async function testDCASwap( + inputAsset: Asset, + amount: number, + numberOfChunks: number, + swapviaContract = false, +) { assert(numberOfChunks > 1, 'Number of chunks must be greater than 1'); - const dcaParameters: DcaParams = { + const dcaParams: DcaParams = { numberOfChunks, chunkIntervalBlocks: CHUNK_INTERVAL, }; + const fillOrKillParams: FillOrKillParamsX128 = { + refundAddress: '0xa56A6be23b6Cf39D9448FF6e897C29c41c8fbDFF', + minPriceX128: '1', + retryDurationBlocks: 100, + }; const destAsset = inputAsset === Assets.Usdc ? Assets.Flip : Assets.Usdc; - const destAddress = await newAddress(destAsset, randomBytes(32).toString('hex')); + + // TODO: Temporary while we are forced to have CCM when passing VaultSwapAttributes + const destAddress = !swapviaContract + ? await newAddress(destAsset, randomBytes(32).toString('hex')) + : getContractAddress(chainFromAsset(destAsset), 'CFTESTER'); + const destBalanceBefore = await getBalance(inputAsset, destAddress); testDCASwaps.debugLog(`DCA destination address: ${destAddress}`); - const swapRequest = await requestNewSwap( - inputAsset, - destAsset, - destAddress, - 'DCA_Test', - undefined, // messageMetadata - 0, // brokerCommissionBps - false, // log - 0, // boostFeeBps - { - refundAddress: '0xa56A6be23b6Cf39D9448FF6e897C29c41c8fbDFF', - minPriceX128: '1', - retryDurationBlocks: 100, - }, // FoK parameters - dcaParameters, - ); + let swapRequestedHandle; - const depositChannelId = swapRequest.channelId; - const swapRequestedHandle = observeSwapRequested( - inputAsset, - destAsset, - depositChannelId, - SwapRequestType.Regular, - ); + if (!swapviaContract) { + const swapRequest = await requestNewSwap( + inputAsset, + destAsset, + destAddress, + 'DCA_Test', + undefined, // messageMetadata + 0, // brokerCommissionBps + false, // log + 0, // boostFeeBps + fillOrKillParams, + dcaParams, + ); + + const depositChannelId = swapRequest.channelId; + swapRequestedHandle = observeSwapRequested( + inputAsset, + destAsset, + depositChannelId, + SwapRequestType.Regular, + ); - // Deposit the asset - await send(inputAsset, swapRequest.depositAddress, amount.toString()); - testDCASwaps.log(`Sent ${amount} ${inputAsset} to ${swapRequest.depositAddress}`); + // Deposit the asset + await send(inputAsset, swapRequest.depositAddress, amount.toString()); + testDCASwaps.log(`Sent ${amount} ${inputAsset} to ${swapRequest.depositAddress}`); + } else { + const srcChain = chainFromAsset(inputAsset); + + // Probably refactor this into a function + const mnemonic = Wallet.createRandom().mnemonic?.phrase ?? ''; + if (mnemonic === '') { + throw new Error('Failed to create random mnemonic'); + } + const wallet = Wallet.fromPhrase(mnemonic).connect( + getDefaultProvider(getEvmEndpoint(srcChain)), + ); + await send(chainGasAsset(srcChain) as InternalAsset, wallet.address); + await send(inputAsset, wallet.address); + + const contractSwapParams = await executeContractSwap( + inputAsset, + destAsset, + destAddress, + wallet, + // Creating CCM metadata because we need a CCM metadata with the current SDK to be able + // to pass the ccmAdditionalData even if we dont' need it. Then if the gasBudget is + // very high the swap might fail so we force a lower gasBudget. + // TODO: Remove the entire CCM metadata. + newCcmMetadata(inputAsset, destAsset, undefined, 100), + amount.toString(), + undefined, + fillOrKillParams, + dcaParams, + ); + + // Look after Swap Requested of data.origin.Vault.tx_hash + swapRequestedHandle = observeSwapRequested( + inputAsset, + destAsset, + contractSwapParams.hash, + SwapRequestType.Ccm, + ); + } const swapRequestId = Number((await swapRequestedHandle).data.swapRequestId.replaceAll(',', '')); - testDCASwaps.debugLog(`${inputAsset} swap requested, swapRequestId: ${swapRequestId}`); + testDCASwaps.debugLog( + `${inputAsset} swap ${swapviaContract ? 'via contract' : ''}, swapRequestId: ${swapRequestId}`, + ); // Wait for the swap to complete await observeEvent(`swapping:SwapRequestCompleted`, { @@ -79,24 +140,29 @@ async function testDCASwap(inputAsset: Asset, amount: number, numberOfChunks: nu // Check that there were the correct number of SwapExecuted events, one for each chunk. assert.strictEqual( observeSwapExecutedEvents.length, - numberOfChunks, + // TODO: Temporary because of gas swap + !swapviaContract ? numberOfChunks : numberOfChunks + 1, 'Unexpected number of SwapExecuted events', ); - // Check the chunk interval of all chunks - for (let i = 1; i < numberOfChunks; i++) { - const interval = observeSwapExecutedEvents[i].block - observeSwapExecutedEvents[i - 1].block; - assert.strictEqual( - interval, - CHUNK_INTERVAL, - `Unexpected chunk interval between chunk ${i - 1} & ${i}`, - ); + // TODO: Temporary because of gas swap + if (!swapviaContract) { + // Check the chunk interval of all chunks + for (let i = 1; i < numberOfChunks; i++) { + const interval = observeSwapExecutedEvents[i].block - observeSwapExecutedEvents[i - 1].block; + assert.strictEqual( + interval, + CHUNK_INTERVAL, + `Unexpected chunk interval between chunk ${i - 1} & ${i}`, + ); + } } + testDCASwaps.log(`Chunk interval of ${CHUNK_INTERVAL} verified for all ${numberOfChunks} chunks`); await observeBalanceIncrease(destAsset, destAddress, destBalanceBefore); } export async function main() { - await testDCASwap(Assets.Eth, 1, 2); + await Promise.all([testDCASwap(Assets.Eth, 1, 2), testDCASwap(Assets.ArbEth, 1, 2, true)]); } diff --git a/bouncer/tests/fill_or_kill.ts b/bouncer/tests/fill_or_kill.ts index becc8b63d4..7a3b73a151 100644 --- a/bouncer/tests/fill_or_kill.ts +++ b/bouncer/tests/fill_or_kill.ts @@ -81,11 +81,14 @@ async function testMinPriceRefund(inputAsset: Asset, amount: number, swapviaCont historicalCheckBlocks: 10, }).event; } else { + testFillOrKill.log( + `Swapping via contract from ${inputAsset} to ${destAsset} with unrealistic min price`, + ); swapHandle = performSwapViaContract( inputAsset, destAsset, destAddress, - 'test', + undefined, // Creating CCM metadata because we need a CCM metadata with the current SDK to be able // to pass the ccmAdditionalData even if we dont' need it. Then if the gasBudget is // very high the swap might fail so we force a lower gasBudget. @@ -110,7 +113,7 @@ async function testMinPriceRefund(inputAsset: Asset, amount: number, swapviaCont throw new Error(`${inputAsset} swap was executed instead of failing and being refunded`); } - testFillOrKill.log(`FoK ${inputAsset} ${swapviaContract ? ' via contract' : ''} swap refunded`); + testFillOrKill.log(`FoK ${inputAsset} ${swapviaContract ? 'via contract' : ''} swap refunded`); } async function main() { From f4363937ae808ca56b3b03ab0722e740cfbe738e Mon Sep 17 00:00:00 2001 From: albert Date: Fri, 18 Oct 2024 13:28:38 +0200 Subject: [PATCH 11/36] chore: engine refactor --- bouncer/shared/contract_swap.ts | 2 - engine/src/witness/eth.rs | 19 +------ engine/src/witness/evm/vault.rs | 87 +++++++++++++++++---------------- 3 files changed, 47 insertions(+), 61 deletions(-) diff --git a/bouncer/shared/contract_swap.ts b/bouncer/shared/contract_swap.ts index 8f92c6068a..3b3c79b0e9 100644 --- a/bouncer/shared/contract_swap.ts +++ b/bouncer/shared/contract_swap.ts @@ -97,8 +97,6 @@ export async function executeContractSwap( dcaParams, ); - console.log('cfParameters passed to the SDK in contractCall', cfParameters); - const receipt = await executeSwap( { destChain, diff --git a/engine/src/witness/eth.rs b/engine/src/witness/eth.rs index d43d64c956..7d0b5cdd6d 100644 --- a/engine/src/witness/eth.rs +++ b/engine/src/witness/eth.rs @@ -1,8 +1,6 @@ mod chain_tracking; mod state_chain_gateway; -use codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; use std::{collections::HashMap, sync::Arc}; use cf_chains::{evm::DepositDetails, Ethereum}; @@ -221,24 +219,9 @@ where Ok(()) } -use cf_chains::{ - address::EncodedAddress, CcmAdditionalData, CcmDepositMetadata, ChannelRefundParameters, -}; +use cf_chains::{address::EncodedAddress, CcmDepositMetadata, ChannelRefundParameters}; use cf_primitives::{Asset, AssetAmount, BasisPoints, DcaParameters, TransactionHash}; -#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] -pub struct VaultSwapCfParameters { - pub ccm_additional_data: Option, - pub vault_swap_attributes: Option, -} - -#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] -pub struct VaultSwapAttributes { - pub refund_params: Option, - pub dca_params: Option, - pub boost_fee: Option, -} - pub struct EthCallBuilder {} impl super::evm::vault::IngressCallBuilder for EthCallBuilder { diff --git a/engine/src/witness/evm/vault.rs b/engine/src/witness/evm/vault.rs index 3827d50d68..bfa76b70cf 100644 --- a/engine/src/witness/evm/vault.rs +++ b/engine/src/witness/evm/vault.rs @@ -1,12 +1,10 @@ -use codec::Decode; +use codec::{Decode, Encode, MaxEncodedLen}; use ethers::types::Bloom; +use scale_info::TypeInfo; use sp_core::{ConstU32, H256}; use std::collections::HashMap; -use crate::{ - evm::retry_rpc::EvmRetryRpcApi, - witness::eth::{VaultSwapAttributes, VaultSwapCfParameters}, -}; +use crate::evm::retry_rpc::EvmRetryRpcApi; use super::{ super::common::{ @@ -37,6 +35,19 @@ abigen!(Vault, "$CF_ETH_CONTRACT_ABI_ROOT/$CF_ETH_CONTRACT_ABI_TAG/IVault.json") pub const MAX_CF_PARAM_LENGTH: u32 = MAX_CCM_ADDITIONAL_DATA_LENGTH + 1_000; pub type CfParameters = BoundedVec>; +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] +pub struct VaultSwapCfParameters { + pub ccm_additional_data: Option, + pub vault_swap_attributes: Option, +} + +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] +pub struct VaultSwapAttributes { + pub refund_params: Option, + pub dca_params: Option, + pub boost_fee: Option, +} + pub fn call_from_event< C: cf_chains::Chain, CallBuilder: IngressCallBuilder, @@ -68,13 +79,13 @@ where fn decode_vault_swap_attributes( cf_parameters_vec: CfParameters, - ) -> Result<(Option, Option, Option)> { + ) -> Result { println!("DEBUGDEBUG cf_parameters_vec {:?}", cf_parameters_vec); if cf_parameters_vec.is_empty() { println!("DEBUGDEBUG Emtpy cf_parameters_vec"); - Ok((None, None, None)) + Ok(VaultSwapAttributes { refund_params: None, dca_params: None, boost_fee: None }) } else { let attributes: VaultSwapAttributes = VaultSwapAttributes::decode(&mut &cf_parameters_vec[..]) @@ -82,24 +93,23 @@ where println!("DEBUGDEBUG attributes {:?}", attributes); - Ok((attributes.refund_params, attributes.dca_params, attributes.boost_fee)) + Ok(attributes) } } - #[allow(clippy::type_complexity)] fn decode_vault_swap_cf_parameters( cf_parameters_vec: CfParameters, - ) -> Result<( - CcmAdditionalData, - (Option, Option, Option), - )> { + ) -> Result<(CcmAdditionalData, VaultSwapAttributes)> { println!("DEBUGDEBUG cf_parameters_vec {:?}", cf_parameters_vec); if cf_parameters_vec.is_empty() { println!("DEBUGDEBUG Emtpy cf_parameters_vec"); // Return the empty vector since the CCM additional data is required - Ok((CcmAdditionalData::default(), (None, None, None))) + Ok(( + CcmAdditionalData::default(), + VaultSwapAttributes { refund_params: None, dca_params: None, boost_fee: None }, + )) } else { let vault_swap_cf_parameters: VaultSwapCfParameters = VaultSwapCfParameters::decode(&mut &cf_parameters_vec[..]) @@ -107,17 +117,14 @@ where println!("DEBUGDEBUG vault_swap_cf_parameters {:?}", vault_swap_cf_parameters); - let (refund_params, dca_params, boost_fee) = - if let Some(attributes) = vault_swap_cf_parameters.vault_swap_attributes { - (attributes.refund_params, attributes.dca_params, attributes.boost_fee) - } else { - (None, None, None) - }; - Ok(( - // Default to empty CcmAdditionalData if not present + // Default to empty CcmAdditionalData vector if not present vault_swap_cf_parameters.ccm_additional_data.unwrap_or_default(), - (refund_params, dca_params, boost_fee), + vault_swap_cf_parameters.vault_swap_attributes.unwrap_or(VaultSwapAttributes { + refund_params: None, + dca_params: None, + boost_fee: None, + }), )) } } @@ -136,8 +143,7 @@ where .to_vec() .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; - let (refund_params, dca_params, boost_fee) = - decode_vault_swap_attributes(cf_parameters_vec)?; + let vault_swap_attributes = decode_vault_swap_attributes(cf_parameters_vec)?; Some(CallBuilder::contract_swap_request( native_asset, @@ -146,9 +152,9 @@ where try_into_encoded_address(try_into_primitive(dst_chain)?, dst_address.to_vec())?, None, event.tx_hash.into(), - refund_params, - dca_params, - boost_fee, + vault_swap_attributes.refund_params, + vault_swap_attributes.dca_params, + vault_swap_attributes.boost_fee, )) }, VaultEvents::SwapTokenFilter(SwapTokenFilter { @@ -166,8 +172,7 @@ where .to_vec() .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; - let (refund_params, dca_params, boost_fee) = - decode_vault_swap_attributes(cf_parameters_vec)?; + let vault_swap_attributes = decode_vault_swap_attributes(cf_parameters_vec)?; Some(CallBuilder::contract_swap_request( *(supported_assets @@ -178,9 +183,9 @@ where try_into_encoded_address(try_into_primitive(dst_chain)?, dst_address.to_vec())?, None, event.tx_hash.into(), - refund_params, - dca_params, - boost_fee, + vault_swap_attributes.refund_params, + vault_swap_attributes.dca_params, + vault_swap_attributes.boost_fee, )) }, VaultEvents::XcallNativeFilter(XcallNativeFilter { @@ -199,7 +204,7 @@ where .to_vec() .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; - let (ccm_additional_data, (refund_params, dca_params, boost_fee)) = + let (ccm_additional_data, vault_swap_attributes) = decode_vault_swap_cf_parameters(cf_parameters_vec)?; Some(CallBuilder::contract_swap_request( @@ -224,9 +229,9 @@ where }, }), event.tx_hash.into(), - refund_params, - dca_params, - boost_fee, + vault_swap_attributes.refund_params, + vault_swap_attributes.dca_params, + vault_swap_attributes.boost_fee, )) }, VaultEvents::XcallTokenFilter(XcallTokenFilter { @@ -246,7 +251,7 @@ where .to_vec() .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; - let (ccm_additional_data, (refund_params, dca_params, boost_fee)) = + let (ccm_additional_data, vault_swap_attributes) = decode_vault_swap_cf_parameters(cf_parameters_vec)?; Some(CallBuilder::contract_swap_request( @@ -273,9 +278,9 @@ where }, }), event.tx_hash.into(), - refund_params, - dca_params, - boost_fee, + vault_swap_attributes.refund_params, + vault_swap_attributes.dca_params, + vault_swap_attributes.boost_fee, )) }, VaultEvents::TransferNativeFailedFilter(TransferNativeFailedFilter { From e27808c4b2df63168b85bbc0dbd9e03f67e6dbb3 Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 21 Oct 2024 07:30:10 +0200 Subject: [PATCH 12/36] chore: refactor createEvmWallet --- bouncer/shared/contract_swap.ts | 15 +++------------ bouncer/shared/utils.ts | 17 +++++++++++++++++ bouncer/tests/DCA_test.ts | 19 +++---------------- 3 files changed, 23 insertions(+), 28 deletions(-) diff --git a/bouncer/shared/contract_swap.ts b/bouncer/shared/contract_swap.ts index 3b3c79b0e9..e138e22ce3 100644 --- a/bouncer/shared/contract_swap.ts +++ b/bouncer/shared/contract_swap.ts @@ -5,12 +5,11 @@ import { approveVault, Asset as SCAsset, Chains, - InternalAsset, Chain, } from '@chainflip/cli'; import { u8aToHex, hexToU8a } from '@polkadot/util'; -import { HDNodeWallet, Wallet, getDefaultProvider } from 'ethers'; +import { HDNodeWallet, Wallet } from 'ethers'; import { observeBalanceIncrease, getContractAddress, @@ -18,15 +17,13 @@ import { amountToFineAmount, defaultAssetAmounts, chainFromAsset, - getEvmEndpoint, assetDecimals, stateChainAssetFromAsset, - chainGasAsset, shortChainFromAsset, + createEvmWalletAndFund, } from './utils'; import { getBalance } from './get_balance'; import { CcmDepositMetadata, DcaParams, FillOrKillParamsX128 } from '../shared/new_swap'; -import { send } from './send'; import { SwapContext, SwapStatus } from './swap_context'; import { vaultSwapCfParametersCodec } from './swapping'; @@ -146,21 +143,15 @@ export async function performSwapViaContract( const tag = swapTag ?? ''; const amountToSwap = amount ?? defaultAssetAmounts(sourceAsset); - const srcChain = chainFromAsset(sourceAsset); - // Generate a new wallet for each contract swap to prevent nonce issues when running in parallel // with other swaps via deposit channels. const mnemonic = Wallet.createRandom().mnemonic?.phrase ?? ''; if (mnemonic === '') { throw new Error('Failed to create random mnemonic'); } - const wallet = Wallet.fromPhrase(mnemonic).connect(getDefaultProvider(getEvmEndpoint(srcChain))); + const wallet = await createEvmWalletAndFund(sourceAsset); try { - // Fund new key with native asset and asset to swap. - await send(chainGasAsset(srcChain) as InternalAsset, wallet.address); - await send(sourceAsset, wallet.address); - if (erc20Assets.includes(sourceAsset)) { // Doing effectively infinite approvals to make sure it doesn't fail. // eslint-disable-next-line @typescript-eslint/no-use-before-define diff --git a/bouncer/shared/utils.ts b/bouncer/shared/utils.ts index d49324a391..11a41e0bb0 100644 --- a/bouncer/shared/utils.ts +++ b/bouncer/shared/utils.ts @@ -1,5 +1,6 @@ import { execSync } from 'child_process'; import * as crypto from 'crypto'; +import { HDNodeWallet, Wallet, getDefaultProvider } from 'ethers'; import { setTimeout as sleep } from 'timers/promises'; import Client from 'bitcoin-core'; import { ApiPromise, Keyring } from '@polkadot/api'; @@ -30,6 +31,7 @@ import { SwapParams } from './perform_swap'; import { newSolAddress } from './new_sol_address'; import { getChainflipApi, observeBadEvent, observeEvent } from './utils/substrate'; import { execWithLog } from './utils/exec_with_log'; +import { send } from './send'; const cfTesterAbi = await getCFTesterAbi(); const cfTesterIdl = await getCfTesterIdl(); @@ -1161,3 +1163,18 @@ export function getTimeStamp(): string { const seconds = now.getSeconds().toString().padStart(2, '0'); return `${hours}:${minutes}:${seconds}`; } + +export async function createEvmWalletAndFund(asset: Asset): Promise { + const chain = chainFromAsset(asset); + + const mnemonic = Wallet.createRandom().mnemonic?.phrase ?? ''; + if (mnemonic === '') { + throw new Error('Failed to create random mnemonic'); + } + const wallet = Wallet.fromPhrase(mnemonic).connect( + getDefaultProvider(getEvmEndpoint(chain)), + ); + await send(chainGasAsset(chain) as SDKAsset, wallet.address); + await send(asset, wallet.address); + return wallet; +} diff --git a/bouncer/tests/DCA_test.ts b/bouncer/tests/DCA_test.ts index cfd1c0a0e9..e02cd1c7bd 100644 --- a/bouncer/tests/DCA_test.ts +++ b/bouncer/tests/DCA_test.ts @@ -1,12 +1,10 @@ -import { InternalAsset as Asset, InternalAssets as Assets, InternalAsset } from '@chainflip/cli'; +import { InternalAsset as Asset, InternalAssets as Assets } from '@chainflip/cli'; import { randomBytes } from 'crypto'; -import { getDefaultProvider, Wallet } from 'ethers'; import assert from 'assert'; import { chainFromAsset, - chainGasAsset, + createEvmWalletAndFund, getContractAddress, - getEvmEndpoint, newAddress, observeBalanceIncrease, observeSwapRequested, @@ -83,18 +81,7 @@ async function testDCASwap( await send(inputAsset, swapRequest.depositAddress, amount.toString()); testDCASwaps.log(`Sent ${amount} ${inputAsset} to ${swapRequest.depositAddress}`); } else { - const srcChain = chainFromAsset(inputAsset); - - // Probably refactor this into a function - const mnemonic = Wallet.createRandom().mnemonic?.phrase ?? ''; - if (mnemonic === '') { - throw new Error('Failed to create random mnemonic'); - } - const wallet = Wallet.fromPhrase(mnemonic).connect( - getDefaultProvider(getEvmEndpoint(srcChain)), - ); - await send(chainGasAsset(srcChain) as InternalAsset, wallet.address); - await send(inputAsset, wallet.address); + const wallet = await createEvmWalletAndFund(inputAsset); const contractSwapParams = await executeContractSwap( inputAsset, From d14c40d087544c0ca72ce3983c16b72f9658e54d Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 21 Oct 2024 09:19:07 +0200 Subject: [PATCH 13/36] chore: cleanup --- engine/src/witness/evm/vault.rs | 20 ------------------- .../cf-integration-tests/src/solana.rs | 5 ++++- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/engine/src/witness/evm/vault.rs b/engine/src/witness/evm/vault.rs index bfa76b70cf..c6f0c1300b 100644 --- a/engine/src/witness/evm/vault.rs +++ b/engine/src/witness/evm/vault.rs @@ -80,19 +80,12 @@ where fn decode_vault_swap_attributes( cf_parameters_vec: CfParameters, ) -> Result { - println!("DEBUGDEBUG cf_parameters_vec {:?}", cf_parameters_vec); - if cf_parameters_vec.is_empty() { - println!("DEBUGDEBUG Emtpy cf_parameters_vec"); - Ok(VaultSwapAttributes { refund_params: None, dca_params: None, boost_fee: None }) } else { let attributes: VaultSwapAttributes = VaultSwapAttributes::decode(&mut &cf_parameters_vec[..]) .map_err(|_| anyhow!("Failed to decode to `VaultSwapAttributes`"))?; - - println!("DEBUGDEBUG attributes {:?}", attributes); - Ok(attributes) } } @@ -100,11 +93,7 @@ where fn decode_vault_swap_cf_parameters( cf_parameters_vec: CfParameters, ) -> Result<(CcmAdditionalData, VaultSwapAttributes)> { - println!("DEBUGDEBUG cf_parameters_vec {:?}", cf_parameters_vec); - if cf_parameters_vec.is_empty() { - println!("DEBUGDEBUG Emtpy cf_parameters_vec"); - // Return the empty vector since the CCM additional data is required Ok(( CcmAdditionalData::default(), @@ -115,8 +104,6 @@ where VaultSwapCfParameters::decode(&mut &cf_parameters_vec[..]) .map_err(|_| anyhow!("Failed to decode to `VaultSwapCfParameters`"))?; - println!("DEBUGDEBUG vault_swap_cf_parameters {:?}", vault_swap_cf_parameters); - Ok(( // Default to empty CcmAdditionalData vector if not present vault_swap_cf_parameters.ccm_additional_data.unwrap_or_default(), @@ -138,7 +125,6 @@ where sender: _, cf_parameters, }) => { - println!("DEBUGDEBUG cf_parameters {:?}", cf_parameters); let cf_parameters_vec: CfParameters = cf_parameters .to_vec() .try_into() @@ -166,8 +152,6 @@ where sender: _, cf_parameters, }) => { - println!("DEBUGDEBUG cf_parameters {:?}", cf_parameters); - let cf_parameters_vec: CfParameters = cf_parameters .to_vec() .try_into() @@ -198,8 +182,6 @@ where gas_amount, cf_parameters, }) => { - println!("DEBUGDEBUG cf_parameters {:?}", cf_parameters); - let cf_parameters_vec: CfParameters = cf_parameters .to_vec() .try_into() @@ -245,8 +227,6 @@ where gas_amount, cf_parameters, }) => { - println!("DEBUGDEBUG cf_parameters {:?}", cf_parameters); - let cf_parameters_vec: CfParameters = cf_parameters .to_vec() .try_into() diff --git a/state-chain/cf-integration-tests/src/solana.rs b/state-chain/cf-integration-tests/src/solana.rs index af3a5b7a2c..46b4b56610 100644 --- a/state-chain/cf-integration-tests/src/solana.rs +++ b/state-chain/cf-integration-tests/src/solana.rs @@ -687,7 +687,7 @@ fn solana_ccm_execution_error_can_trigger_fallback() { channel_metadata: CcmChannelMetadata { message: vec![0u8, 1u8, 2u8, 3u8].try_into().unwrap(), gas_budget: 1_000_000_000u128, - cf_parameters: SolCcmAccounts { + ccm_additional_data: SolCcmAccounts { cf_receiver: SolCcmAddress { pubkey: SolPubkey([0x10; 32]), is_writable: true }, remaining_accounts: vec![ SolCcmAddress { pubkey: SolPubkey([0x01; 32]), is_writable: false }, @@ -708,6 +708,9 @@ fn solana_ccm_execution_error_can_trigger_fallback() { destination_address: EncodedAddress::Sol([1u8; 32]), deposit_metadata: ccm, tx_hash: Default::default(), + boost_fee: None, + refund_params: None, + dca_params: None, }, )); From 7a80f89f701129dc5be7cabe14710472fee673c9 Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 21 Oct 2024 09:57:28 +0200 Subject: [PATCH 14/36] chore: add MAX_VAULT_SWAP_ATTRIBUTES_LENGTH --- engine/src/witness/evm/vault.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/engine/src/witness/evm/vault.rs b/engine/src/witness/evm/vault.rs index c6f0c1300b..6abec22725 100644 --- a/engine/src/witness/evm/vault.rs +++ b/engine/src/witness/evm/vault.rs @@ -31,8 +31,9 @@ use state_chain_runtime::{EthereumInstance, Runtime, RuntimeCall}; abigen!(Vault, "$CF_ETH_CONTRACT_ABI_ROOT/$CF_ETH_CONTRACT_ABI_TAG/IVault.json"); -// MAX_CF_PARAM_LENGTH ~== MAX_CCM_ADDITIONAL_DATA_LENGTH + MAX_VAULT_SWAP_ATTRIBUTES_LENGTH -pub const MAX_CF_PARAM_LENGTH: u32 = MAX_CCM_ADDITIONAL_DATA_LENGTH + 1_000; +pub const MAX_VAULT_SWAP_ATTRIBUTES_LENGTH: u32 = 1_000; +pub const MAX_CF_PARAM_LENGTH: u32 = + MAX_CCM_ADDITIONAL_DATA_LENGTH + MAX_VAULT_SWAP_ATTRIBUTES_LENGTH; pub type CfParameters = BoundedVec>; #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] From cd8fa682678b3c6ccb9bae315a8ad6da8ac22e81 Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 21 Oct 2024 10:02:15 +0200 Subject: [PATCH 15/36] chore: refactor bouncer --- bouncer/shared/contract_swap.ts | 26 ++++++++++++++++++++++++-- bouncer/shared/swapping.ts | 24 ------------------------ bouncer/shared/utils.ts | 4 +--- 3 files changed, 25 insertions(+), 29 deletions(-) diff --git a/bouncer/shared/contract_swap.ts b/bouncer/shared/contract_swap.ts index e138e22ce3..80415162d9 100644 --- a/bouncer/shared/contract_swap.ts +++ b/bouncer/shared/contract_swap.ts @@ -7,8 +7,8 @@ import { Chains, Chain, } from '@chainflip/cli'; +import { u32, Struct, Option, u16, u256, Bytes as TsBytes, Enum } from 'scale-ts'; import { u8aToHex, hexToU8a } from '@polkadot/util'; - import { HDNodeWallet, Wallet } from 'ethers'; import { observeBalanceIncrease, @@ -25,10 +25,32 @@ import { import { getBalance } from './get_balance'; import { CcmDepositMetadata, DcaParams, FillOrKillParamsX128 } from '../shared/new_swap'; import { SwapContext, SwapStatus } from './swap_context'; -import { vaultSwapCfParametersCodec } from './swapping'; const erc20Assets: Asset[] = ['Flip', 'Usdc', 'Usdt', 'ArbUsdc']; +export const vaultSwapCfParametersCodec = Struct({ + ccmAdditionalData: Option(TsBytes()), + vaultSwapAttributes: Option( + Struct({ + refundParams: Option( + Struct({ + retryDurationBlocks: u32, + refundAddress: Enum({ + Eth: TsBytes(20), + Dot: TsBytes(32), + Btc: TsBytes(), + Arb: TsBytes(20), + Sol: TsBytes(32), + }), + minPriceX128: u256, + }), + ), + dcaParams: Option(Struct({ numberOfChunks: u32, chunkIntervalBlocks: u32 })), + boostFee: Option(u16), + }), + ), +}); + export function encodeCfParameters( sourceAsset: Asset, ccmAdditionalData?: string | undefined, diff --git a/bouncer/shared/swapping.ts b/bouncer/shared/swapping.ts index 48bf3e9c17..73a3dd9850 100644 --- a/bouncer/shared/swapping.ts +++ b/bouncer/shared/swapping.ts @@ -1,7 +1,6 @@ import { InternalAsset as Asset } from '@chainflip/cli'; import { Keypair, PublicKey } from '@solana/web3.js'; import Web3 from 'web3'; -import { u32, Struct, Option, u16, u256, Bytes as TsBytes, Enum } from 'scale-ts'; import { randomAsHex, randomAsNumber } from '../polkadot/util-crypto'; import { performSwap } from '../shared/perform_swap'; import { @@ -160,29 +159,6 @@ function newCcmMessage(destAsset: Asset): string { } } -export const vaultSwapCfParametersCodec = Struct({ - ccmAdditionalData: Option(TsBytes()), - vaultSwapAttributes: Option( - Struct({ - refundParams: Option( - Struct({ - retryDurationBlocks: u32, - refundAddress: Enum({ - Eth: TsBytes(20), - Dot: TsBytes(32), // not supported anyway - Btc: TsBytes(), // not supported anyway - Arb: TsBytes(20), - Sol: TsBytes(32), - }), - minPriceX128: u256, - }), - ), - dcaParams: Option(Struct({ numberOfChunks: u32, chunkIntervalBlocks: u32 })), - boostFee: Option(u16), - }), - ), -}); - export function newCcmMetadata( sourceAsset: Asset, destAsset: Asset, diff --git a/bouncer/shared/utils.ts b/bouncer/shared/utils.ts index 048971e060..fd295e5551 100644 --- a/bouncer/shared/utils.ts +++ b/bouncer/shared/utils.ts @@ -1177,9 +1177,7 @@ export async function createEvmWalletAndFund(asset: Asset): Promise Date: Mon, 21 Oct 2024 11:06:38 +0200 Subject: [PATCH 16/36] chore: refactor into common for reusal --- engine/src/witness/common.rs | 1 + engine/src/witness/common/cf_parameters.rs | 71 +++++++++++++++++++++ engine/src/witness/evm/vault.rs | 74 ++-------------------- 3 files changed, 79 insertions(+), 67 deletions(-) create mode 100644 engine/src/witness/common/cf_parameters.rs diff --git a/engine/src/witness/common.rs b/engine/src/witness/common.rs index 60690923d6..56b2ba4857 100644 --- a/engine/src/witness/common.rs +++ b/engine/src/witness/common.rs @@ -1,3 +1,4 @@ +pub mod cf_parameters; pub mod chain_source; pub mod chunked_chain_source; pub mod epoch_source; diff --git a/engine/src/witness/common/cf_parameters.rs b/engine/src/witness/common/cf_parameters.rs new file mode 100644 index 0000000000..78c25be876 --- /dev/null +++ b/engine/src/witness/common/cf_parameters.rs @@ -0,0 +1,71 @@ +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_core::ConstU32; + +use anyhow::{anyhow, Result}; +use cf_chains::{CcmAdditionalData, ChannelRefundParameters, MAX_CCM_ADDITIONAL_DATA_LENGTH}; +use cf_primitives::{BasisPoints, DcaParameters}; +use frame_support::sp_runtime::BoundedVec; + +pub const MAX_VAULT_SWAP_ATTRIBUTES_LENGTH: u32 = 1_000; +pub const MAX_CF_PARAM_LENGTH: u32 = + MAX_CCM_ADDITIONAL_DATA_LENGTH + MAX_VAULT_SWAP_ATTRIBUTES_LENGTH; +pub type CfParameters = BoundedVec>; + +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] +pub struct VaultSwapCfParameters { + pub ccm_additional_data: Option, + pub vault_swap_attributes: Option, +} + +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] +pub struct VaultSwapAttributes { + pub refund_params: Option, + pub dca_params: Option, + pub boost_fee: Option, +} + +pub trait CfParametersDecode { + fn decode_vault_swap_attributes(self) -> Result; + fn decode_vault_swap_cf_parameters(self) -> Result<(CcmAdditionalData, VaultSwapAttributes)>; +} + +// CfParameters is swap data encoded in Vault Swaps that is to be decoded into the adequate +// parameters to pass to the State Chain along with the contract swap. This applies to EVM +// chains and Solana. BTC has it's own format for VaultSwapAttributes and does not +// support initiating CCM swaps via vault swaps. +impl CfParametersDecode for CfParameters { + fn decode_vault_swap_attributes(self) -> Result { + if self.is_empty() { + Ok(VaultSwapAttributes { refund_params: None, dca_params: None, boost_fee: None }) + } else { + let attributes: VaultSwapAttributes = VaultSwapAttributes::decode(&mut &self[..]) + .map_err(|_| anyhow!("Failed to decode to `VaultSwapAttributes`"))?; + Ok(attributes) + } + } + + fn decode_vault_swap_cf_parameters(self) -> Result<(CcmAdditionalData, VaultSwapAttributes)> { + if self.is_empty() { + // Return the empty vector since the CCM additional data is required + Ok(( + CcmAdditionalData::default(), + VaultSwapAttributes { refund_params: None, dca_params: None, boost_fee: None }, + )) + } else { + let vault_swap_cf_parameters: VaultSwapCfParameters = + VaultSwapCfParameters::decode(&mut &self[..]) + .map_err(|_| anyhow!("Failed to decode to `VaultSwapCfParameters`"))?; + + Ok(( + // Default to empty CcmAdditionalData vector if not present + vault_swap_cf_parameters.ccm_additional_data.unwrap_or_default(), + vault_swap_cf_parameters.vault_swap_attributes.unwrap_or(VaultSwapAttributes { + refund_params: None, + dca_params: None, + boost_fee: None, + }), + )) + } + } +} diff --git a/engine/src/witness/evm/vault.rs b/engine/src/witness/evm/vault.rs index 6abec22725..8573d9a0a1 100644 --- a/engine/src/witness/evm/vault.rs +++ b/engine/src/witness/evm/vault.rs @@ -1,13 +1,12 @@ -use codec::{Decode, Encode, MaxEncodedLen}; use ethers::types::Bloom; -use scale_info::TypeInfo; -use sp_core::{ConstU32, H256}; +use sp_core::H256; use std::collections::HashMap; use crate::evm::retry_rpc::EvmRetryRpcApi; use super::{ super::common::{ + cf_parameters::*, chain_source::ChainClient, chunked_chain_source::chunked_by_vault::{builder::ChunkedByVaultBuilder, ChunkedByVault}, }, @@ -21,34 +20,14 @@ use cf_chains::{ address::{EncodedAddress, IntoForeignChainAddress}, eth::Address as EthereumAddress, evm::DepositDetails, - CcmAdditionalData, CcmChannelMetadata, CcmDepositMetadata, Chain, ChannelRefundParameters, - MAX_CCM_ADDITIONAL_DATA_LENGTH, + CcmChannelMetadata, CcmDepositMetadata, Chain, ChannelRefundParameters, }; use cf_primitives::{Asset, BasisPoints, DcaParameters, ForeignChain}; use ethers::prelude::*; -use frame_support::sp_runtime::BoundedVec; use state_chain_runtime::{EthereumInstance, Runtime, RuntimeCall}; abigen!(Vault, "$CF_ETH_CONTRACT_ABI_ROOT/$CF_ETH_CONTRACT_ABI_TAG/IVault.json"); -pub const MAX_VAULT_SWAP_ATTRIBUTES_LENGTH: u32 = 1_000; -pub const MAX_CF_PARAM_LENGTH: u32 = - MAX_CCM_ADDITIONAL_DATA_LENGTH + MAX_VAULT_SWAP_ATTRIBUTES_LENGTH; -pub type CfParameters = BoundedVec>; - -#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] -pub struct VaultSwapCfParameters { - pub ccm_additional_data: Option, - pub vault_swap_attributes: Option, -} - -#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] -pub struct VaultSwapAttributes { - pub refund_params: Option, - pub dca_params: Option, - pub boost_fee: Option, -} - pub fn call_from_event< C: cf_chains::Chain, CallBuilder: IngressCallBuilder, @@ -78,45 +57,6 @@ where }) } - fn decode_vault_swap_attributes( - cf_parameters_vec: CfParameters, - ) -> Result { - if cf_parameters_vec.is_empty() { - Ok(VaultSwapAttributes { refund_params: None, dca_params: None, boost_fee: None }) - } else { - let attributes: VaultSwapAttributes = - VaultSwapAttributes::decode(&mut &cf_parameters_vec[..]) - .map_err(|_| anyhow!("Failed to decode to `VaultSwapAttributes`"))?; - Ok(attributes) - } - } - - fn decode_vault_swap_cf_parameters( - cf_parameters_vec: CfParameters, - ) -> Result<(CcmAdditionalData, VaultSwapAttributes)> { - if cf_parameters_vec.is_empty() { - // Return the empty vector since the CCM additional data is required - Ok(( - CcmAdditionalData::default(), - VaultSwapAttributes { refund_params: None, dca_params: None, boost_fee: None }, - )) - } else { - let vault_swap_cf_parameters: VaultSwapCfParameters = - VaultSwapCfParameters::decode(&mut &cf_parameters_vec[..]) - .map_err(|_| anyhow!("Failed to decode to `VaultSwapCfParameters`"))?; - - Ok(( - // Default to empty CcmAdditionalData vector if not present - vault_swap_cf_parameters.ccm_additional_data.unwrap_or_default(), - vault_swap_cf_parameters.vault_swap_attributes.unwrap_or(VaultSwapAttributes { - refund_params: None, - dca_params: None, - boost_fee: None, - }), - )) - } - } - Ok(match event.event_parameters { VaultEvents::SwapNativeFilter(SwapNativeFilter { dst_chain, @@ -130,7 +70,7 @@ where .to_vec() .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; - let vault_swap_attributes = decode_vault_swap_attributes(cf_parameters_vec)?; + let vault_swap_attributes = cf_parameters_vec.decode_vault_swap_attributes()?; Some(CallBuilder::contract_swap_request( native_asset, @@ -157,7 +97,7 @@ where .to_vec() .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; - let vault_swap_attributes = decode_vault_swap_attributes(cf_parameters_vec)?; + let vault_swap_attributes = cf_parameters_vec.decode_vault_swap_attributes()?; Some(CallBuilder::contract_swap_request( *(supported_assets @@ -188,7 +128,7 @@ where .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; let (ccm_additional_data, vault_swap_attributes) = - decode_vault_swap_cf_parameters(cf_parameters_vec)?; + cf_parameters_vec.decode_vault_swap_cf_parameters()?; Some(CallBuilder::contract_swap_request( native_asset, @@ -233,7 +173,7 @@ where .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; let (ccm_additional_data, vault_swap_attributes) = - decode_vault_swap_cf_parameters(cf_parameters_vec)?; + cf_parameters_vec.decode_vault_swap_cf_parameters()?; Some(CallBuilder::contract_swap_request( *(supported_assets From 1851094bae1a20fbdcf236a69afac094cbd8ed89 Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 21 Oct 2024 15:17:18 +0200 Subject: [PATCH 17/36] chore: rename attributes to parameters --- bouncer/shared/contract_swap.ts | 6 ++-- bouncer/tests/DCA_test.ts | 2 +- engine/src/witness/common/cf_parameters.rs | 30 ++++++++++---------- engine/src/witness/evm/vault.rs | 32 +++++++++++----------- 4 files changed, 35 insertions(+), 35 deletions(-) diff --git a/bouncer/shared/contract_swap.ts b/bouncer/shared/contract_swap.ts index 80415162d9..16a5e1c223 100644 --- a/bouncer/shared/contract_swap.ts +++ b/bouncer/shared/contract_swap.ts @@ -30,7 +30,7 @@ const erc20Assets: Asset[] = ['Flip', 'Usdc', 'Usdt', 'ArbUsdc']; export const vaultSwapCfParametersCodec = Struct({ ccmAdditionalData: Option(TsBytes()), - vaultSwapAttributes: Option( + vaultSwapParameters: Option( Struct({ refundParams: Option( Struct({ @@ -62,7 +62,7 @@ export function encodeCfParameters( ? u8aToHex( vaultSwapCfParametersCodec.enc({ ccmAdditionalData: ccmAdditionalData ? hexToU8a(ccmAdditionalData) : undefined, - vaultSwapAttributes: + vaultSwapParameters: fillOrKillParams || dcaParams || boostFeeBps ? { refundParams: fillOrKillParams && { @@ -128,7 +128,7 @@ export async function executeContractSwap( srcChain, // TODO: This will need some refactoring either putting the cfParameters outside the // ccmParams and the user should encode it as done here or, probably better, we just - // add the SwapAttributes support (Fok/Dca/Boost) as separate parameters, rename + // add the SwapParameters support (Fok/Dca/Boost) as separate parameters, rename // cfParameters to ccmAdditionalData and do the encoding within the SDK. ccmParams: messageMetadata && { gasBudget: messageMetadata.gasBudget.toString(), diff --git a/bouncer/tests/DCA_test.ts b/bouncer/tests/DCA_test.ts index e02cd1c7bd..2102f47671 100644 --- a/bouncer/tests/DCA_test.ts +++ b/bouncer/tests/DCA_test.ts @@ -45,7 +45,7 @@ async function testDCASwap( const destAsset = inputAsset === Assets.Usdc ? Assets.Flip : Assets.Usdc; - // TODO: Temporary while we are forced to have CCM when passing VaultSwapAttributes + // TODO: Temporary while we are forced to have CCM when passing VaultSwapParameters const destAddress = !swapviaContract ? await newAddress(destAsset, randomBytes(32).toString('hex')) : getContractAddress(chainFromAsset(destAsset), 'CFTESTER'); diff --git a/engine/src/witness/common/cf_parameters.rs b/engine/src/witness/common/cf_parameters.rs index 78c25be876..5e42693ee5 100644 --- a/engine/src/witness/common/cf_parameters.rs +++ b/engine/src/witness/common/cf_parameters.rs @@ -7,50 +7,50 @@ use cf_chains::{CcmAdditionalData, ChannelRefundParameters, MAX_CCM_ADDITIONAL_D use cf_primitives::{BasisPoints, DcaParameters}; use frame_support::sp_runtime::BoundedVec; -pub const MAX_VAULT_SWAP_ATTRIBUTES_LENGTH: u32 = 1_000; +pub const MAX_VAULT_SWAP_PARAMETERS_LENGTH: u32 = 1_000; pub const MAX_CF_PARAM_LENGTH: u32 = - MAX_CCM_ADDITIONAL_DATA_LENGTH + MAX_VAULT_SWAP_ATTRIBUTES_LENGTH; + MAX_CCM_ADDITIONAL_DATA_LENGTH + MAX_VAULT_SWAP_PARAMETERS_LENGTH; pub type CfParameters = BoundedVec>; #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] pub struct VaultSwapCfParameters { pub ccm_additional_data: Option, - pub vault_swap_attributes: Option, + pub vault_swap_parameters: Option, } #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] -pub struct VaultSwapAttributes { +pub struct VaultSwapParameters { pub refund_params: Option, pub dca_params: Option, pub boost_fee: Option, } pub trait CfParametersDecode { - fn decode_vault_swap_attributes(self) -> Result; - fn decode_vault_swap_cf_parameters(self) -> Result<(CcmAdditionalData, VaultSwapAttributes)>; + fn decode_vault_swap_parameters(self) -> Result; + fn decode_vault_swap_cf_parameters(self) -> Result<(CcmAdditionalData, VaultSwapParameters)>; } // CfParameters is swap data encoded in Vault Swaps that is to be decoded into the adequate // parameters to pass to the State Chain along with the contract swap. This applies to EVM -// chains and Solana. BTC has it's own format for VaultSwapAttributes and does not +// chains and Solana. BTC has it's own format for VaultSwapParameters and does not // support initiating CCM swaps via vault swaps. impl CfParametersDecode for CfParameters { - fn decode_vault_swap_attributes(self) -> Result { + fn decode_vault_swap_parameters(self) -> Result { if self.is_empty() { - Ok(VaultSwapAttributes { refund_params: None, dca_params: None, boost_fee: None }) + Ok(VaultSwapParameters { refund_params: None, dca_params: None, boost_fee: None }) } else { - let attributes: VaultSwapAttributes = VaultSwapAttributes::decode(&mut &self[..]) - .map_err(|_| anyhow!("Failed to decode to `VaultSwapAttributes`"))?; - Ok(attributes) + let parameters: VaultSwapParameters = VaultSwapParameters::decode(&mut &self[..]) + .map_err(|_| anyhow!("Failed to decode to `VaultSwapParameters`"))?; + Ok(parameters) } } - fn decode_vault_swap_cf_parameters(self) -> Result<(CcmAdditionalData, VaultSwapAttributes)> { + fn decode_vault_swap_cf_parameters(self) -> Result<(CcmAdditionalData, VaultSwapParameters)> { if self.is_empty() { // Return the empty vector since the CCM additional data is required Ok(( CcmAdditionalData::default(), - VaultSwapAttributes { refund_params: None, dca_params: None, boost_fee: None }, + VaultSwapParameters { refund_params: None, dca_params: None, boost_fee: None }, )) } else { let vault_swap_cf_parameters: VaultSwapCfParameters = @@ -60,7 +60,7 @@ impl CfParametersDecode for CfParameters { Ok(( // Default to empty CcmAdditionalData vector if not present vault_swap_cf_parameters.ccm_additional_data.unwrap_or_default(), - vault_swap_cf_parameters.vault_swap_attributes.unwrap_or(VaultSwapAttributes { + vault_swap_cf_parameters.vault_swap_parameters.unwrap_or(VaultSwapParameters { refund_params: None, dca_params: None, boost_fee: None, diff --git a/engine/src/witness/evm/vault.rs b/engine/src/witness/evm/vault.rs index 8573d9a0a1..a1dfb9127b 100644 --- a/engine/src/witness/evm/vault.rs +++ b/engine/src/witness/evm/vault.rs @@ -70,7 +70,7 @@ where .to_vec() .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; - let vault_swap_attributes = cf_parameters_vec.decode_vault_swap_attributes()?; + let vault_swap_parameters = cf_parameters_vec.decode_vault_swap_parameters()?; Some(CallBuilder::contract_swap_request( native_asset, @@ -79,9 +79,9 @@ where try_into_encoded_address(try_into_primitive(dst_chain)?, dst_address.to_vec())?, None, event.tx_hash.into(), - vault_swap_attributes.refund_params, - vault_swap_attributes.dca_params, - vault_swap_attributes.boost_fee, + vault_swap_parameters.refund_params, + vault_swap_parameters.dca_params, + vault_swap_parameters.boost_fee, )) }, VaultEvents::SwapTokenFilter(SwapTokenFilter { @@ -97,7 +97,7 @@ where .to_vec() .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; - let vault_swap_attributes = cf_parameters_vec.decode_vault_swap_attributes()?; + let vault_swap_parameters = cf_parameters_vec.decode_vault_swap_parameters()?; Some(CallBuilder::contract_swap_request( *(supported_assets @@ -108,9 +108,9 @@ where try_into_encoded_address(try_into_primitive(dst_chain)?, dst_address.to_vec())?, None, event.tx_hash.into(), - vault_swap_attributes.refund_params, - vault_swap_attributes.dca_params, - vault_swap_attributes.boost_fee, + vault_swap_parameters.refund_params, + vault_swap_parameters.dca_params, + vault_swap_parameters.boost_fee, )) }, VaultEvents::XcallNativeFilter(XcallNativeFilter { @@ -127,7 +127,7 @@ where .to_vec() .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; - let (ccm_additional_data, vault_swap_attributes) = + let (ccm_additional_data, vault_swap_parameters) = cf_parameters_vec.decode_vault_swap_cf_parameters()?; Some(CallBuilder::contract_swap_request( @@ -152,9 +152,9 @@ where }, }), event.tx_hash.into(), - vault_swap_attributes.refund_params, - vault_swap_attributes.dca_params, - vault_swap_attributes.boost_fee, + vault_swap_parameters.refund_params, + vault_swap_parameters.dca_params, + vault_swap_parameters.boost_fee, )) }, VaultEvents::XcallTokenFilter(XcallTokenFilter { @@ -172,7 +172,7 @@ where .to_vec() .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; - let (ccm_additional_data, vault_swap_attributes) = + let (ccm_additional_data, vault_swap_parameters) = cf_parameters_vec.decode_vault_swap_cf_parameters()?; Some(CallBuilder::contract_swap_request( @@ -199,9 +199,9 @@ where }, }), event.tx_hash.into(), - vault_swap_attributes.refund_params, - vault_swap_attributes.dca_params, - vault_swap_attributes.boost_fee, + vault_swap_parameters.refund_params, + vault_swap_parameters.dca_params, + vault_swap_parameters.boost_fee, )) }, VaultEvents::TransferNativeFailedFilter(TransferNativeFailedFilter { From 7305042ccf50e5d903164f056b9c6e90806fa4b7 Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 21 Oct 2024 17:37:42 +0200 Subject: [PATCH 18/36] chore: pass extra parameters to sdk --- bouncer/package.json | 2 +- bouncer/pnpm-lock.yaml | 204 +------------------------------- bouncer/shared/contract_swap.ts | 13 +- bouncer/shared/new_swap.ts | 4 +- bouncer/shared/perform_swap.ts | 2 +- bouncer/shared/swapping.ts | 3 +- bouncer/shared/utils.ts | 12 +- 7 files changed, 21 insertions(+), 219 deletions(-) diff --git a/bouncer/package.json b/bouncer/package.json index d41a0d3f9c..2300998922 100644 --- a/bouncer/package.json +++ b/bouncer/package.json @@ -6,7 +6,7 @@ "prettier:write": "prettier --write ." }, "dependencies": { - "@chainflip/cli": "1.6.3", + "@chainflip/cli": "~/work/chainflip/sdk/chainflip-sdk-monorepo/packages/cli", "@chainflip/utils": "^0.4.0", "@coral-xyz/anchor": "^0.30.1", "@iarna/toml": "^2.2.5", diff --git a/bouncer/pnpm-lock.yaml b/bouncer/pnpm-lock.yaml index 1b3b56eaa3..6e0f9a6741 100644 --- a/bouncer/pnpm-lock.yaml +++ b/bouncer/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@chainflip/cli': - specifier: 1.6.3 - version: 1.6.3(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10) + specifier: ~/work/chainflip/sdk/chainflip-sdk-monorepo/packages/cli + version: link:../../../sdk/chainflip-sdk-monorepo/packages/cli '@chainflip/utils': specifier: ^0.4.0 version: 0.4.0 @@ -142,28 +142,6 @@ packages: resolution: {integrity: sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==} engines: {node: '>=6.9.0'} - '@chainflip/bitcoin@1.1.1': - resolution: {integrity: sha512-Jr6X/0QTSFYpTp23ZPhyioL6wL9x3Xpj6OGjadQKZyhobRN4BZkhLogv20HDYTJcRzVphzrTJArbEaNie04XVA==} - - '@chainflip/cli@1.6.3': - resolution: {integrity: sha512-isbPdFbO0tmQ7+7OjWSyzKtuog7FOgvkeb7fIini88LHsTjTXf8UvoKGYncOgwvLVQIY+J7NDnSQQmKdBg7PUw==} - hasBin: true - peerDependencies: - axios: ^1.x - ethers: ^6.13.2 - - '@chainflip/extrinsics@1.6.1': - resolution: {integrity: sha512-sm3v2QguNW4/RiIZYHd+VRSxup2q4cVBY0VjbQJw6xYqhNCzZlt+Hl38Kni+TCHQu3hP/WgIF72yvvSs7/PBdg==} - - '@chainflip/rpc@1.6.7': - resolution: {integrity: sha512-OIE2cqzDy9Oq9sHuxJKOtbjP438QwMFdc6tuWdAmjjPcHGATI0Ft/lIKeCutD/8uH/CumOzaOoBaT2pI6G78Gg==} - - '@chainflip/solana@1.0.2': - resolution: {integrity: sha512-8M+z0yjVCZBMpdCTGuBRt/Ns9NBJCNFvnSOjDu/kyaBRvxdUvECJOIseL0ENLBd0J/YmO9TcrZ30M0po3a96BA==} - - '@chainflip/utils@0.3.0': - resolution: {integrity: sha512-csW8E3lRcSG1udN/kgsOhjZ7bfRrSbgv8Hdh/pzjM+VjQ6Hh46/LuiZHeQR0rQMimfG+lu2Afxk4jeRXRGFWTg==} - '@chainflip/utils@0.4.0': resolution: {integrity: sha512-OuMFlgbIbyJ1Kt39zytfGh4HZ5dVY25/a3qb0c1K137+QmhdOuF+R7QSkFPqYAfDG4KhGRqo0rgUtEpaEEcSKA==} @@ -422,9 +400,6 @@ packages: '@iarna/toml@2.2.5': resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==} - '@ioredis/commands@1.2.0': - resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} - '@noble/curves@1.2.0': resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} @@ -985,9 +960,6 @@ packages: base-x@4.0.0: resolution: {integrity: sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==} - base-x@5.0.0: - resolution: {integrity: sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ==} - base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -1011,10 +983,6 @@ packages: resolution: {integrity: sha512-mdFV5+/v0XyNYXjBS6CQPLo9ekCx4gtKZFnJm5PMto7Fs9hTTDpkkzOB7/FtluRI6JbUUAu+snTYfJRgHLZbZQ==} engines: {node: '>=8.0.0'} - bip174@3.0.0-rc.1: - resolution: {integrity: sha512-+8P3BpSairVNF2Nee6Ksdc1etIjWjBOi/MH0MwKtq9YaYp+S2Hk2uvup0e8hCT4IKlS58nXJyyQVmW92zPoD4Q==} - engines: {node: '>=18.0.0'} - bitcoin-core@4.2.0: resolution: {integrity: sha512-QFmer//rZhyuYm0mBOVAmMhIG/EFmXDahC3a1LvNTwM8/KszxUGEAjvAT4tzm1FaDj4c7pQWMG/vOWtoKjeR3Q==} engines: {node: '>=7'} @@ -1023,10 +991,6 @@ packages: resolution: {integrity: sha512-Fk8+Vc+e2rMoDU5gXkW9tD+313rhkm5h6N9HfZxXvYU9LedttVvmXKTgd9k5rsQJjkSfsv6XRM8uhJv94SrvcA==} engines: {node: '>=8.0.0'} - bitcoinjs-lib@7.0.0-rc.0: - resolution: {integrity: sha512-7CQgOIbREemKR/NT2uc3uO/fkEy+6CM0sLxboVVY6bv6DbZmPt3gg5Y/hhWgQFeZu5lfTbtVAv32MIxf7lMh4g==} - engines: {node: '>=18.0.0'} - blakejs@1.2.1: resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} @@ -1071,18 +1035,12 @@ packages: bs58@5.0.0: resolution: {integrity: sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==} - bs58@6.0.0: - resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==} - bs58check@2.1.2: resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==} bs58check@3.0.1: resolution: {integrity: sha512-hjuuJvoWEybo7Hn/0xOrczQKKEKD63WguEjlhLExYs2wUBcebDC1jDNK17eEAD2lYfw82d5ASC1d7K3SWszjaQ==} - bs58check@4.0.0: - resolution: {integrity: sha512-FsGDOnFg9aVI9erdriULkd/JjEWONV/lQE5aYziB5PoBsXRind56lh8doIZIc9X4HoxT5x4bLjMWN1/NB8Zp5g==} - buffer-layout@1.2.2: resolution: {integrity: sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==} engines: {node: '>=4.5'} @@ -1174,10 +1132,6 @@ packages: clone-response@1.0.3: resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} - cluster-key-slot@1.1.2: - resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} - engines: {node: '>=0.10.0'} - color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -1343,10 +1297,6 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} - denque@2.1.0: - resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} - engines: {node: '>=0.10'} - depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -1910,10 +1860,6 @@ packages: resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} - ioredis@5.4.1: - resolution: {integrity: sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==} - engines: {node: '>=12.22.0'} - ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -2097,12 +2043,6 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - lodash.defaults@4.2.0: - resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} - - lodash.isarguments@3.1.0: - resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} - lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -2497,14 +2437,6 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} - redis-errors@1.2.0: - resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} - engines: {node: '>=4'} - - redis-parser@3.0.0: - resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} - engines: {node: '>=4'} - regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} @@ -2674,9 +2606,6 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - standard-as-callback@2.1.0: - resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} - standard-error@1.1.0: resolution: {integrity: sha512-4v7qzU7oLJfMI5EltUSHCaaOd65J6S4BqKRWgzMi4EYaE5fvNabPxmAPGdxpGXqrcWjhDGI/H09CIdEuUOUeXg==} @@ -2858,14 +2787,6 @@ packages: resolution: {integrity: sha512-vrrNZJiusLWoFWBqz5Y5KMCgP9W9hnjZHzZiZRT8oNAkq3d5Z5Oe76jAvVVSRh4U8GGR90N2X1dWtrhvx6L8UQ==} engines: {node: '>=14.0.0'} - uint8array-tools@0.0.8: - resolution: {integrity: sha512-xS6+s8e0Xbx++5/0L+yyexukU7pz//Yg6IHg3BKhXotg1JcYtgxVcUctQ0HxLByiJzpAkNFawz1Nz5Xadzo82g==} - engines: {node: '>=14.0.0'} - - uint8array-tools@0.0.9: - resolution: {integrity: sha512-9vqDWmoSXOoi+K14zNaf6LBV51Q8MayF0/IiQs3GlygIKUYtog603e6virExkjjFosfJUBI4LhbQK1iq8IG11A==} - engines: {node: '>=14.0.0'} - ultron@1.1.1: resolution: {integrity: sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==} @@ -2919,23 +2840,12 @@ packages: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true - valibot@0.38.0: - resolution: {integrity: sha512-RCJa0fetnzp+h+KN9BdgYOgtsMAG9bfoJ9JSjIhFHobKWVWyzM3jjaeNTdpFK9tQtf3q1sguXeERJ/LcmdFE7w==} - peerDependencies: - typescript: '>=5' - peerDependenciesMeta: - typescript: - optional: true - varint@5.0.2: resolution: {integrity: sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==} varuint-bitcoin@1.1.2: resolution: {integrity: sha512-4EVb+w4rx+YfVM32HQX42AbbT7/1f5zwAYhIujKXKk8NQK+JfRVl3pqT3hjNn/L+RstigmGGKVwHA/P0wgITZw==} - varuint-bitcoin@2.0.0: - resolution: {integrity: sha512-6QZbU/rHO2ZQYpWFDALCDSRsXbAs1VOEmXAxtbtjLtKuMJ/FQ8YbhfxlaiKv5nklci0M6lZtlZyxo9Q+qNnyog==} - vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -3162,44 +3072,6 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 - '@chainflip/bitcoin@1.1.1(typescript@5.5.3)': - dependencies: - '@chainflip/utils': 0.4.0 - bitcoinjs-lib: 7.0.0-rc.0(typescript@5.5.3) - transitivePeerDependencies: - - typescript - - '@chainflip/cli@1.6.3(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10)': - dependencies: - '@chainflip/bitcoin': 1.1.1(typescript@5.5.3) - '@chainflip/extrinsics': 1.6.1 - '@chainflip/rpc': 1.6.7 - '@chainflip/solana': 1.0.2 - '@chainflip/utils': 0.4.0 - axios: 1.7.2 - ethers: 6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) - ioredis: 5.4.1 - ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) - yargs: 17.7.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - typescript - - utf-8-validate - - '@chainflip/extrinsics@1.6.1': {} - - '@chainflip/rpc@1.6.7': - dependencies: - '@chainflip/utils': 0.3.0 - zod: 3.23.8 - - '@chainflip/solana@1.0.2': - dependencies: - '@chainflip/utils': 0.4.0 - - '@chainflip/utils@0.3.0': {} - '@chainflip/utils@0.4.0': {} '@coral-xyz/anchor-errors@0.30.1': {} @@ -3479,8 +3351,6 @@ snapshots: '@iarna/toml@2.2.5': {} - '@ioredis/commands@1.2.0': {} - '@noble/curves@1.2.0': dependencies: '@noble/hashes': 1.3.2 @@ -4322,8 +4192,6 @@ snapshots: base-x@4.0.0: {} - base-x@5.0.0: {} - base64-js@1.5.1: {} bcrypt-pbkdf@1.0.2: @@ -4344,11 +4212,6 @@ snapshots: bip174@2.1.1: {} - bip174@3.0.0-rc.1: - dependencies: - uint8array-tools: 0.0.9 - varuint-bitcoin: 2.0.0 - bitcoin-core@4.2.0: dependencies: '@uphold/request-logger': 2.0.0(request@2.88.2) @@ -4370,18 +4233,6 @@ snapshots: typeforce: 1.18.0 varuint-bitcoin: 1.1.2 - bitcoinjs-lib@7.0.0-rc.0(typescript@5.5.3): - dependencies: - '@noble/hashes': 1.4.0 - bech32: 2.0.0 - bip174: 3.0.0-rc.1 - bs58check: 4.0.0 - uint8array-tools: 0.0.9 - valibot: 0.38.0(typescript@5.5.3) - varuint-bitcoin: 2.0.0 - transitivePeerDependencies: - - typescript - blakejs@1.2.1: {} bluebird@3.7.2: {} @@ -4447,10 +4298,6 @@ snapshots: dependencies: base-x: 4.0.0 - bs58@6.0.0: - dependencies: - base-x: 5.0.0 - bs58check@2.1.2: dependencies: bs58: 4.0.1 @@ -4462,11 +4309,6 @@ snapshots: '@noble/hashes': 1.4.0 bs58: 5.0.0 - bs58check@4.0.0: - dependencies: - '@noble/hashes': 1.4.0 - bs58: 6.0.0 - buffer-layout@1.2.2: {} buffer-to-arraybuffer@0.0.5: {} @@ -4562,8 +4404,6 @@ snapshots: dependencies: mimic-response: 1.0.1 - cluster-key-slot@1.1.2: {} - color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -4724,8 +4564,6 @@ snapshots: delayed-stream@1.0.0: {} - denque@2.1.0: {} - depd@2.0.0: {} destroy@1.2.0: {} @@ -5559,20 +5397,6 @@ snapshots: hasown: 2.0.2 side-channel: 1.0.6 - ioredis@5.4.1: - dependencies: - '@ioredis/commands': 1.2.0 - cluster-key-slot: 1.1.2 - debug: 4.3.5 - denque: 2.1.0 - lodash.defaults: 4.2.0 - lodash.isarguments: 3.1.0 - redis-errors: 1.2.0 - redis-parser: 3.0.0 - standard-as-callback: 2.1.0 - transitivePeerDependencies: - - supports-color - ipaddr.js@1.9.1: {} is-arguments@1.1.1: @@ -5751,10 +5575,6 @@ snapshots: dependencies: p-locate: 5.0.0 - lodash.defaults@4.2.0: {} - - lodash.isarguments@3.1.0: {} - lodash.merge@4.6.2: {} lodash@4.17.21: {} @@ -6108,12 +5928,6 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 - redis-errors@1.2.0: {} - - redis-parser@3.0.0: - dependencies: - redis-errors: 1.2.0 - regenerator-runtime@0.14.1: {} regexp.prototype.flags@1.5.2: @@ -6353,8 +6167,6 @@ snapshots: safer-buffer: 2.1.2 tweetnacl: 0.14.5 - standard-as-callback@2.1.0: {} - standard-error@1.1.0: {} statuses@2.0.1: {} @@ -6563,10 +6375,6 @@ snapshots: uint8array-tools@0.0.7: {} - uint8array-tools@0.0.8: {} - - uint8array-tools@0.0.9: {} - ultron@1.1.1: {} unbox-primitive@1.0.2: @@ -6612,20 +6420,12 @@ snapshots: uuid@9.0.1: {} - valibot@0.38.0(typescript@5.5.3): - optionalDependencies: - typescript: 5.5.3 - varint@5.0.2: {} varuint-bitcoin@1.1.2: dependencies: safe-buffer: 5.2.1 - varuint-bitcoin@2.0.0: - dependencies: - uint8array-tools: 0.0.8 - vary@1.1.2: {} verror@1.10.0: diff --git a/bouncer/shared/contract_swap.ts b/bouncer/shared/contract_swap.ts index 16a5e1c223..cb5c23e7f9 100644 --- a/bouncer/shared/contract_swap.ts +++ b/bouncer/shared/contract_swap.ts @@ -110,7 +110,7 @@ export async function executeContractSwap( const cfParameters = encodeCfParameters( sourceAsset, - messageMetadata?.cfParameters, + messageMetadata?.ccmAdditionalData, boostFeeBps, fillOrKillParams, dcaParams, @@ -126,15 +126,16 @@ export async function executeContractSwap( destAddress, srcAsset: stateChainAssetFromAsset(sourceAsset), srcChain, - // TODO: This will need some refactoring either putting the cfParameters outside the - // ccmParams and the user should encode it as done here or, probably better, we just - // add the SwapParameters support (Fok/Dca/Boost) as separate parameters, rename - // cfParameters to ccmAdditionalData and do the encoding within the SDK. ccmParams: messageMetadata && { gasBudget: messageMetadata.gasBudget.toString(), message: messageMetadata.message, - cfParameters, + ccmAdditionalData: messageMetadata.ccmAdditionalData }, + // TODO: Temporal until SDK has the encoding + cfParameters, + boostFeeBps, + fillOrKillParams, + dcaParams, } as ExecuteSwapParams, networkOptions, txOptions, diff --git a/bouncer/shared/new_swap.ts b/bouncer/shared/new_swap.ts index 69453842c2..53c455e631 100644 --- a/bouncer/shared/new_swap.ts +++ b/bouncer/shared/new_swap.ts @@ -23,6 +23,8 @@ export async function newSwap( destAsset === 'Dot' ? decodeDotAddressForContract(destAddress) : destAddress; const brokerUrl = process.env.BROKER_ENDPOINT || 'http://127.0.0.1:10997'; + console.log("request channel ccmAdditionalData", messageMetadata?.ccmAdditionalData) + // If the dry_run of the extrinsic fails on the broker-api then it won't retry. So we retry here to // avoid flakiness on CI. let retryCount = 0; @@ -38,7 +40,7 @@ export async function newSwap( ccmParams: messageMetadata && { message: messageMetadata.message as `0x${string}`, gasBudget: messageMetadata.gasBudget.toString(), - cfParameters: messageMetadata.cfParameters as `0x${string}`, + ccmAdditionalData: messageMetadata.ccmAdditionalData as `0x${string}`, }, commissionBps: brokerCommissionBps, maxBoostFeeBps: boostFeeBps, diff --git a/bouncer/shared/perform_swap.ts b/bouncer/shared/perform_swap.ts index 45814b70f2..465b84805e 100644 --- a/bouncer/shared/perform_swap.ts +++ b/bouncer/shared/perform_swap.ts @@ -70,7 +70,7 @@ export async function requestNewSwap( ? event.data.channelMetadata !== null && event.data.channelMetadata.message === messageMetadata.message && event.data.channelMetadata.gasBudget.replace(/,/g, '') === messageMetadata.gasBudget && - event.data.channelMetadata.cfParameters === messageMetadata.cfParameters + event.data.channelMetadata.ccmAdditionalData === messageMetadata.ccmAdditionalData : event.data.channelMetadata === null; return destAddressMatches && destAssetMatches && sourceAssetMatches && ccmMetadataMatches; diff --git a/bouncer/shared/swapping.ts b/bouncer/shared/swapping.ts index 73a3dd9850..c32db7aed1 100644 --- a/bouncer/shared/swapping.ts +++ b/bouncer/shared/swapping.ts @@ -178,8 +178,7 @@ export function newCcmMetadata( return { message, gasBudget, - // TODO: To rename to ccmAdditionalData - cfParameters: ccmAdditionalData, + ccmAdditionalData, }; } diff --git a/bouncer/shared/utils.ts b/bouncer/shared/utils.ts index fd295e5551..3de26afebe 100644 --- a/bouncer/shared/utils.ts +++ b/bouncer/shared/utils.ts @@ -718,10 +718,10 @@ export async function observeSolanaCcmEvent( sourceAddress: string | null, messageMetadata: CcmDepositMetadata, ): Promise { - function decodeExpectedCfParameters(cfParametersHex: string) { + function decodeExpectedCcmAdditionalData(ccmAdditionalDataHex: string) { // Convert the hexadecimal string back to a byte array - const cfParameters = new Uint8Array( - cfParametersHex + const ccmAdditionalData = new Uint8Array( + ccmAdditionalDataHex .slice(2) .match(/.{1,2}/g) ?.map((byte) => parseInt(byte, 16)) ?? [], @@ -731,7 +731,7 @@ export async function observeSolanaCcmEvent( const remainingAccountSize = publicKeySize + 1; // Extra byte for the encoded length - const remainingAccountsBytes = cfParameters.slice(remainingAccountSize + 1, -publicKeySize); + const remainingAccountsBytes = ccmAdditionalData.slice(remainingAccountSize + 1, -publicKeySize); const remainingAccounts = []; const remainingIsWritable = []; @@ -746,7 +746,7 @@ export async function observeSolanaCcmEvent( } // fallback account - const fallbackAccount = cfParameters.slice(-publicKeySize); + const fallbackAccount = ccmAdditionalData.slice(-publicKeySize); return { remainingAccounts, remainingIsWritable, fallbackAccount }; } @@ -775,7 +775,7 @@ export async function observeSolanaCcmEvent( const { remainingAccounts: expectedRemainingAccounts, remainingIsWritable: expectedRemainingIsWritable, - } = decodeExpectedCfParameters(messageMetadata.cfParameters!); + } = decodeExpectedCcmAdditionalData(messageMetadata.ccmAdditionalData!); if ( expectedRemainingIsWritable.length !== event.data.remaining_is_writable.length || From f9e67ab694ef7a0c6203d4bdcb66a09544aacdf7 Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 22 Oct 2024 10:06:31 +0200 Subject: [PATCH 19/36] chore: fix issues --- bouncer/shared/contract_swap.ts | 45 +------------------ bouncer/shared/new_swap.ts | 2 - bouncer/tests/DCA_test.ts | 44 ++++++++---------- bouncer/tests/fill_or_kill.ts | 19 +++++--- ...st_swap_deposit_address_with_affiliates.ts | 6 +-- 5 files changed, 34 insertions(+), 82 deletions(-) diff --git a/bouncer/shared/contract_swap.ts b/bouncer/shared/contract_swap.ts index cb5c23e7f9..feb36d34b5 100644 --- a/bouncer/shared/contract_swap.ts +++ b/bouncer/shared/contract_swap.ts @@ -8,7 +8,6 @@ import { Chain, } from '@chainflip/cli'; import { u32, Struct, Option, u16, u256, Bytes as TsBytes, Enum } from 'scale-ts'; -import { u8aToHex, hexToU8a } from '@polkadot/util'; import { HDNodeWallet, Wallet } from 'ethers'; import { observeBalanceIncrease, @@ -19,7 +18,6 @@ import { chainFromAsset, assetDecimals, stateChainAssetFromAsset, - shortChainFromAsset, createEvmWalletAndFund, } from './utils'; import { getBalance } from './get_balance'; @@ -51,37 +49,6 @@ export const vaultSwapCfParametersCodec = Struct({ ), }); -export function encodeCfParameters( - sourceAsset: Asset, - ccmAdditionalData?: string | undefined, - boostFeeBps?: number, - fillOrKillParams?: FillOrKillParamsX128, - dcaParams?: DcaParams, -): string | undefined { - return ccmAdditionalData || fillOrKillParams || dcaParams || boostFeeBps - ? u8aToHex( - vaultSwapCfParametersCodec.enc({ - ccmAdditionalData: ccmAdditionalData ? hexToU8a(ccmAdditionalData) : undefined, - vaultSwapParameters: - fillOrKillParams || dcaParams || boostFeeBps - ? { - refundParams: fillOrKillParams && { - retryDurationBlocks: fillOrKillParams.retryDurationBlocks, - refundAddress: { - tag: shortChainFromAsset(sourceAsset), - value: hexToU8a(fillOrKillParams.refundAddress), - }, - minPriceX128: BigInt(fillOrKillParams.minPriceX128), - }, - dcaParams, - boostFee: boostFeeBps, - } - : undefined, - }), - ) - : undefined; -} - export async function executeContractSwap( sourceAsset: Asset, destAsset: Asset, @@ -108,14 +75,6 @@ export async function executeContractSwap( gasLimit: srcChain === Chains.Arbitrum ? 10000000n : 200000n, } as const; - const cfParameters = encodeCfParameters( - sourceAsset, - messageMetadata?.ccmAdditionalData, - boostFeeBps, - fillOrKillParams, - dcaParams, - ); - const receipt = await executeSwap( { destChain, @@ -129,10 +88,8 @@ export async function executeContractSwap( ccmParams: messageMetadata && { gasBudget: messageMetadata.gasBudget.toString(), message: messageMetadata.message, - ccmAdditionalData: messageMetadata.ccmAdditionalData + ccmAdditionalData: messageMetadata.ccmAdditionalData, }, - // TODO: Temporal until SDK has the encoding - cfParameters, boostFeeBps, fillOrKillParams, dcaParams, diff --git a/bouncer/shared/new_swap.ts b/bouncer/shared/new_swap.ts index 53c455e631..0919ddd0a4 100644 --- a/bouncer/shared/new_swap.ts +++ b/bouncer/shared/new_swap.ts @@ -23,8 +23,6 @@ export async function newSwap( destAsset === 'Dot' ? decodeDotAddressForContract(destAddress) : destAddress; const brokerUrl = process.env.BROKER_ENDPOINT || 'http://127.0.0.1:10997'; - console.log("request channel ccmAdditionalData", messageMetadata?.ccmAdditionalData) - // If the dry_run of the extrinsic fails on the broker-api then it won't retry. So we retry here to // avoid flakiness on CI. let retryCount = 0; diff --git a/bouncer/tests/DCA_test.ts b/bouncer/tests/DCA_test.ts index 2102f47671..bb1aa77b64 100644 --- a/bouncer/tests/DCA_test.ts +++ b/bouncer/tests/DCA_test.ts @@ -2,9 +2,7 @@ import { InternalAsset as Asset, InternalAssets as Assets } from '@chainflip/cli import { randomBytes } from 'crypto'; import assert from 'assert'; import { - chainFromAsset, createEvmWalletAndFund, - getContractAddress, newAddress, observeBalanceIncrease, observeSwapRequested, @@ -16,7 +14,6 @@ import { getBalance } from '../shared/get_balance'; import { ExecutableTest } from '../shared/executable_test'; import { requestNewSwap } from '../shared/perform_swap'; import { DcaParams, FillOrKillParamsX128 } from '../shared/new_swap'; -import { newCcmMetadata } from '../shared/swapping'; import { executeContractSwap } from '../shared/contract_swap'; /* eslint-disable @typescript-eslint/no-use-before-define */ @@ -45,10 +42,7 @@ async function testDCASwap( const destAsset = inputAsset === Assets.Usdc ? Assets.Flip : Assets.Usdc; - // TODO: Temporary while we are forced to have CCM when passing VaultSwapParameters - const destAddress = !swapviaContract - ? await newAddress(destAsset, randomBytes(32).toString('hex')) - : getContractAddress(chainFromAsset(destAsset), 'CFTESTER'); + const destAddress = await newAddress(destAsset, randomBytes(32).toString('hex')); const destBalanceBefore = await getBalance(inputAsset, destAddress); testDCASwaps.debugLog(`DCA destination address: ${destAddress}`); @@ -88,23 +82,25 @@ async function testDCASwap( destAsset, destAddress, wallet, - // Creating CCM metadata because we need a CCM metadata with the current SDK to be able - // to pass the ccmAdditionalData even if we dont' need it. Then if the gasBudget is - // very high the swap might fail so we force a lower gasBudget. - // TODO: Remove the entire CCM metadata. - newCcmMetadata(inputAsset, destAsset, undefined, 100), + // newCcmMetadata(inputAsset, destAsset, undefined, 100), + undefined, amount.toString(), undefined, + // TODO: Something is wrong when passing fillOrKillParams but no CCM Metadata. + // Problem is when ccmAdditionalData is undefined. fillOrKillParams, + // undefined, dcaParams, ); + testDCASwaps.log(`Contract swap executed, tx hash: ${contractSwapParams.hash}`); + // Look after Swap Requested of data.origin.Vault.tx_hash swapRequestedHandle = observeSwapRequested( inputAsset, destAsset, contractSwapParams.hash, - SwapRequestType.Ccm, + SwapRequestType.Regular, ); } @@ -127,22 +123,18 @@ async function testDCASwap( // Check that there were the correct number of SwapExecuted events, one for each chunk. assert.strictEqual( observeSwapExecutedEvents.length, - // TODO: Temporary because of gas swap - !swapviaContract ? numberOfChunks : numberOfChunks + 1, + numberOfChunks, 'Unexpected number of SwapExecuted events', ); - // TODO: Temporary because of gas swap - if (!swapviaContract) { - // Check the chunk interval of all chunks - for (let i = 1; i < numberOfChunks; i++) { - const interval = observeSwapExecutedEvents[i].block - observeSwapExecutedEvents[i - 1].block; - assert.strictEqual( - interval, - CHUNK_INTERVAL, - `Unexpected chunk interval between chunk ${i - 1} & ${i}`, - ); - } + // Check the chunk interval of all chunks + for (let i = 1; i < numberOfChunks; i++) { + const interval = observeSwapExecutedEvents[i].block - observeSwapExecutedEvents[i - 1].block; + assert.strictEqual( + interval, + CHUNK_INTERVAL, + `Unexpected chunk interval between chunk ${i - 1} & ${i}`, + ); } testDCASwaps.log(`Chunk interval of ${CHUNK_INTERVAL} verified for all ${numberOfChunks} chunks`); diff --git a/bouncer/tests/fill_or_kill.ts b/bouncer/tests/fill_or_kill.ts index 7a3b73a151..e377badd1b 100644 --- a/bouncer/tests/fill_or_kill.ts +++ b/bouncer/tests/fill_or_kill.ts @@ -13,7 +13,7 @@ import { requestNewSwap } from '../shared/perform_swap'; import { send } from '../shared/send'; import { getBalance } from '../shared/get_balance'; import { observeEvent } from '../shared/utils/substrate'; -import { FillOrKillParamsX128 } from '../shared/new_swap'; +import { CcmDepositMetadata, FillOrKillParamsX128 } from '../shared/new_swap'; import { ExecutableTest } from '../shared/executable_test'; import { performSwapViaContract } from '../shared/contract_swap'; import { newCcmMetadata } from '../shared/swapping'; @@ -27,6 +27,7 @@ async function testMinPriceRefund(inputAsset: Asset, amount: number, swapviaCont const refundAddress = await newAddress(inputAsset, randomBytes(32).toString('hex')); const destAddress = await newAddress(destAsset, randomBytes(32).toString('hex')); testFillOrKill.debugLog(`Swap destination address: ${destAddress}`); + testFillOrKill.debugLog(`Refund address: ${refundAddress}`); const refundBalanceBefore = await getBalance(inputAsset, refundAddress); @@ -84,22 +85,26 @@ async function testMinPriceRefund(inputAsset: Asset, amount: number, swapviaCont testFillOrKill.log( `Swapping via contract from ${inputAsset} to ${destAsset} with unrealistic min price`, ); + + // Randomly use CCM to test different encodings + let ccmMetadata: CcmDepositMetadata | undefined; + if (Math.random() < 0.5) { + ccmMetadata = newCcmMetadata(inputAsset, destAsset, undefined, 100); + ccmMetadata.ccmAdditionalData = + Math.random() < 0.5 ? ccmMetadata.ccmAdditionalData : undefined; + } + swapHandle = performSwapViaContract( inputAsset, destAsset, destAddress, undefined, - // Creating CCM metadata because we need a CCM metadata with the current SDK to be able - // to pass the ccmAdditionalData even if we dont' need it. Then if the gasBudget is - // very high the swap might fail so we force a lower gasBudget. - // TODO: Remove the entire CCM metadata. - newCcmMetadata(inputAsset, destAsset, undefined, 100), + ccmMetadata, undefined, true, amount.toString(), undefined, refundParameters, - undefined, ); } diff --git a/bouncer/tests/request_swap_deposit_address_with_affiliates.ts b/bouncer/tests/request_swap_deposit_address_with_affiliates.ts index 794468dacc..d90a905803 100644 --- a/bouncer/tests/request_swap_deposit_address_with_affiliates.ts +++ b/bouncer/tests/request_swap_deposit_address_with_affiliates.ts @@ -40,7 +40,7 @@ const eventSchema = z destinationAsset: z.string(), brokerCommissionRate: numberSchema, channelMetadata: z - .object({ message: z.string(), gasBudget: bigintSchema, cfParameters: z.string() }) + .object({ message: z.string(), gasBudget: bigintSchema, ccmAdditionalData: z.string() }) .nullable(), boostFee: numberSchema, affiliateFees: z.array(z.object({ account: z.string(), bps: numberSchema })), @@ -141,7 +141,7 @@ const requestSwapDepositAddress = async ( if (params.ccmParams) { assert.strictEqual(event.channelMetadata?.message, params.ccmParams.message); assert.strictEqual(event.channelMetadata.gasBudget, BigInt(params.ccmParams.gasBudget)); - assert.strictEqual(event.channelMetadata.cfParameters, params.ccmParams.cfParameters); + assert.strictEqual(event.channelMetadata.ccmAdditionalData, params.ccmParams.ccmAdditionalData); } }; @@ -215,7 +215,7 @@ const withCcm: NewSwapRequest = { ccmParams: { message: '0xcafebabe', gasBudget: '1000000', - cfParameters: '0xdeadbeef', + ccmAdditionalData: '0xdeadbeef', }, }; From de1bf998508ff934eb68aa70aece6db9c11c8198 Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 22 Oct 2024 10:06:45 +0200 Subject: [PATCH 20/36] chore: engine renaming --- engine/src/witness/common/cf_parameters.rs | 16 ++++++++-------- engine/src/witness/evm/vault.rs | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/engine/src/witness/common/cf_parameters.rs b/engine/src/witness/common/cf_parameters.rs index 5e42693ee5..99391f97a8 100644 --- a/engine/src/witness/common/cf_parameters.rs +++ b/engine/src/witness/common/cf_parameters.rs @@ -13,7 +13,7 @@ pub const MAX_CF_PARAM_LENGTH: u32 = pub type CfParameters = BoundedVec>; #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] -pub struct VaultSwapCfParameters { +pub struct VaultCfParameters { pub ccm_additional_data: Option, pub vault_swap_parameters: Option, } @@ -26,8 +26,8 @@ pub struct VaultSwapParameters { } pub trait CfParametersDecode { - fn decode_vault_swap_parameters(self) -> Result; - fn decode_vault_swap_cf_parameters(self) -> Result<(CcmAdditionalData, VaultSwapParameters)>; + fn decode_into_swap_parameters(self) -> Result; + fn decode_into_ccm_swap_parameters(self) -> Result<(CcmAdditionalData, VaultSwapParameters)>; } // CfParameters is swap data encoded in Vault Swaps that is to be decoded into the adequate @@ -35,7 +35,7 @@ pub trait CfParametersDecode { // chains and Solana. BTC has it's own format for VaultSwapParameters and does not // support initiating CCM swaps via vault swaps. impl CfParametersDecode for CfParameters { - fn decode_vault_swap_parameters(self) -> Result { + fn decode_into_swap_parameters(self) -> Result { if self.is_empty() { Ok(VaultSwapParameters { refund_params: None, dca_params: None, boost_fee: None }) } else { @@ -45,7 +45,7 @@ impl CfParametersDecode for CfParameters { } } - fn decode_vault_swap_cf_parameters(self) -> Result<(CcmAdditionalData, VaultSwapParameters)> { + fn decode_into_ccm_swap_parameters(self) -> Result<(CcmAdditionalData, VaultSwapParameters)> { if self.is_empty() { // Return the empty vector since the CCM additional data is required Ok(( @@ -53,9 +53,9 @@ impl CfParametersDecode for CfParameters { VaultSwapParameters { refund_params: None, dca_params: None, boost_fee: None }, )) } else { - let vault_swap_cf_parameters: VaultSwapCfParameters = - VaultSwapCfParameters::decode(&mut &self[..]) - .map_err(|_| anyhow!("Failed to decode to `VaultSwapCfParameters`"))?; + let vault_swap_cf_parameters: VaultCfParameters = + VaultCfParameters::decode(&mut &self[..]) + .map_err(|_| anyhow!("Failed to decode to `VaultCfParameters`"))?; Ok(( // Default to empty CcmAdditionalData vector if not present diff --git a/engine/src/witness/evm/vault.rs b/engine/src/witness/evm/vault.rs index a1dfb9127b..dadb69d9bc 100644 --- a/engine/src/witness/evm/vault.rs +++ b/engine/src/witness/evm/vault.rs @@ -70,7 +70,7 @@ where .to_vec() .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; - let vault_swap_parameters = cf_parameters_vec.decode_vault_swap_parameters()?; + let vault_swap_parameters = cf_parameters_vec.decode_into_swap_parameters()?; Some(CallBuilder::contract_swap_request( native_asset, @@ -97,7 +97,7 @@ where .to_vec() .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; - let vault_swap_parameters = cf_parameters_vec.decode_vault_swap_parameters()?; + let vault_swap_parameters = cf_parameters_vec.decode_into_swap_parameters()?; Some(CallBuilder::contract_swap_request( *(supported_assets @@ -128,7 +128,7 @@ where .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; let (ccm_additional_data, vault_swap_parameters) = - cf_parameters_vec.decode_vault_swap_cf_parameters()?; + cf_parameters_vec.decode_into_ccm_swap_parameters()?; Some(CallBuilder::contract_swap_request( native_asset, @@ -173,7 +173,7 @@ where .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; let (ccm_additional_data, vault_swap_parameters) = - cf_parameters_vec.decode_vault_swap_cf_parameters()?; + cf_parameters_vec.decode_into_ccm_swap_parameters()?; Some(CallBuilder::contract_swap_request( *(supported_assets From 5eba5c7bc5afbe795cca3c58b5bbe2787e46582d Mon Sep 17 00:00:00 2001 From: albert Date: Wed, 23 Oct 2024 11:23:38 +0200 Subject: [PATCH 21/36] chore: update SDK with new encoding logic --- bouncer/package.json | 2 +- bouncer/pnpm-lock.yaml | 204 +++++++++++++++++++++++++++++++++++++- bouncer/tests/DCA_test.ts | 4 - 3 files changed, 203 insertions(+), 7 deletions(-) diff --git a/bouncer/package.json b/bouncer/package.json index 2300998922..7254aae2c2 100644 --- a/bouncer/package.json +++ b/bouncer/package.json @@ -6,7 +6,7 @@ "prettier:write": "prettier --write ." }, "dependencies": { - "@chainflip/cli": "~/work/chainflip/sdk/chainflip-sdk-monorepo/packages/cli", + "@chainflip/cli": "1.8.0-cf-parameters-rename.0", "@chainflip/utils": "^0.4.0", "@coral-xyz/anchor": "^0.30.1", "@iarna/toml": "^2.2.5", diff --git a/bouncer/pnpm-lock.yaml b/bouncer/pnpm-lock.yaml index 6e0f9a6741..d0bab95fbf 100644 --- a/bouncer/pnpm-lock.yaml +++ b/bouncer/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@chainflip/cli': - specifier: ~/work/chainflip/sdk/chainflip-sdk-monorepo/packages/cli - version: link:../../../sdk/chainflip-sdk-monorepo/packages/cli + specifier: 1.8.0-cf-parameters-rename.0 + version: 1.8.0-cf-parameters-rename.0(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10) '@chainflip/utils': specifier: ^0.4.0 version: 0.4.0 @@ -142,6 +142,28 @@ packages: resolution: {integrity: sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==} engines: {node: '>=6.9.0'} + '@chainflip/bitcoin@1.1.1': + resolution: {integrity: sha512-Jr6X/0QTSFYpTp23ZPhyioL6wL9x3Xpj6OGjadQKZyhobRN4BZkhLogv20HDYTJcRzVphzrTJArbEaNie04XVA==} + + '@chainflip/cli@1.8.0-cf-parameters-rename.0': + resolution: {integrity: sha512-aNGUAPfWCQLx3i4UC25F15/kP4Hczd5dFzZVXgwp20nMjoUsSy8cK2DW7JnVTF3DBHJd3Fw3ZQMjjk3PdWZXDA==} + hasBin: true + peerDependencies: + axios: ^1.x + ethers: ^6.13.2 + + '@chainflip/extrinsics@1.6.1': + resolution: {integrity: sha512-sm3v2QguNW4/RiIZYHd+VRSxup2q4cVBY0VjbQJw6xYqhNCzZlt+Hl38Kni+TCHQu3hP/WgIF72yvvSs7/PBdg==} + + '@chainflip/rpc@1.6.9': + resolution: {integrity: sha512-FtaoZBey4kIFhWQY5mMMAGXIgzSpZCX0DTnXQqPEn9q5qvt6FoQLDQk9k2IYKOTiIP+XsLy9w/WPPiH7+3BpnQ==} + + '@chainflip/solana@1.0.2': + resolution: {integrity: sha512-8M+z0yjVCZBMpdCTGuBRt/Ns9NBJCNFvnSOjDu/kyaBRvxdUvECJOIseL0ENLBd0J/YmO9TcrZ30M0po3a96BA==} + + '@chainflip/utils@0.3.0': + resolution: {integrity: sha512-csW8E3lRcSG1udN/kgsOhjZ7bfRrSbgv8Hdh/pzjM+VjQ6Hh46/LuiZHeQR0rQMimfG+lu2Afxk4jeRXRGFWTg==} + '@chainflip/utils@0.4.0': resolution: {integrity: sha512-OuMFlgbIbyJ1Kt39zytfGh4HZ5dVY25/a3qb0c1K137+QmhdOuF+R7QSkFPqYAfDG4KhGRqo0rgUtEpaEEcSKA==} @@ -400,6 +422,9 @@ packages: '@iarna/toml@2.2.5': resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==} + '@ioredis/commands@1.2.0': + resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} + '@noble/curves@1.2.0': resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} @@ -960,6 +985,9 @@ packages: base-x@4.0.0: resolution: {integrity: sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==} + base-x@5.0.0: + resolution: {integrity: sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ==} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -983,6 +1011,10 @@ packages: resolution: {integrity: sha512-mdFV5+/v0XyNYXjBS6CQPLo9ekCx4gtKZFnJm5PMto7Fs9hTTDpkkzOB7/FtluRI6JbUUAu+snTYfJRgHLZbZQ==} engines: {node: '>=8.0.0'} + bip174@3.0.0-rc.1: + resolution: {integrity: sha512-+8P3BpSairVNF2Nee6Ksdc1etIjWjBOi/MH0MwKtq9YaYp+S2Hk2uvup0e8hCT4IKlS58nXJyyQVmW92zPoD4Q==} + engines: {node: '>=18.0.0'} + bitcoin-core@4.2.0: resolution: {integrity: sha512-QFmer//rZhyuYm0mBOVAmMhIG/EFmXDahC3a1LvNTwM8/KszxUGEAjvAT4tzm1FaDj4c7pQWMG/vOWtoKjeR3Q==} engines: {node: '>=7'} @@ -991,6 +1023,10 @@ packages: resolution: {integrity: sha512-Fk8+Vc+e2rMoDU5gXkW9tD+313rhkm5h6N9HfZxXvYU9LedttVvmXKTgd9k5rsQJjkSfsv6XRM8uhJv94SrvcA==} engines: {node: '>=8.0.0'} + bitcoinjs-lib@7.0.0-rc.0: + resolution: {integrity: sha512-7CQgOIbREemKR/NT2uc3uO/fkEy+6CM0sLxboVVY6bv6DbZmPt3gg5Y/hhWgQFeZu5lfTbtVAv32MIxf7lMh4g==} + engines: {node: '>=18.0.0'} + blakejs@1.2.1: resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} @@ -1035,12 +1071,18 @@ packages: bs58@5.0.0: resolution: {integrity: sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==} + bs58@6.0.0: + resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==} + bs58check@2.1.2: resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==} bs58check@3.0.1: resolution: {integrity: sha512-hjuuJvoWEybo7Hn/0xOrczQKKEKD63WguEjlhLExYs2wUBcebDC1jDNK17eEAD2lYfw82d5ASC1d7K3SWszjaQ==} + bs58check@4.0.0: + resolution: {integrity: sha512-FsGDOnFg9aVI9erdriULkd/JjEWONV/lQE5aYziB5PoBsXRind56lh8doIZIc9X4HoxT5x4bLjMWN1/NB8Zp5g==} + buffer-layout@1.2.2: resolution: {integrity: sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==} engines: {node: '>=4.5'} @@ -1132,6 +1174,10 @@ packages: clone-response@1.0.3: resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} + cluster-key-slot@1.1.2: + resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} + engines: {node: '>=0.10.0'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -1297,6 +1343,10 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -1860,6 +1910,10 @@ packages: resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} + ioredis@5.4.1: + resolution: {integrity: sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==} + engines: {node: '>=12.22.0'} + ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -2043,6 +2097,12 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + + lodash.isarguments@3.1.0: + resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -2437,6 +2497,14 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} + redis-errors@1.2.0: + resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} + engines: {node: '>=4'} + + redis-parser@3.0.0: + resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} + engines: {node: '>=4'} + regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} @@ -2606,6 +2674,9 @@ packages: engines: {node: '>=0.10.0'} hasBin: true + standard-as-callback@2.1.0: + resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + standard-error@1.1.0: resolution: {integrity: sha512-4v7qzU7oLJfMI5EltUSHCaaOd65J6S4BqKRWgzMi4EYaE5fvNabPxmAPGdxpGXqrcWjhDGI/H09CIdEuUOUeXg==} @@ -2787,6 +2858,14 @@ packages: resolution: {integrity: sha512-vrrNZJiusLWoFWBqz5Y5KMCgP9W9hnjZHzZiZRT8oNAkq3d5Z5Oe76jAvVVSRh4U8GGR90N2X1dWtrhvx6L8UQ==} engines: {node: '>=14.0.0'} + uint8array-tools@0.0.8: + resolution: {integrity: sha512-xS6+s8e0Xbx++5/0L+yyexukU7pz//Yg6IHg3BKhXotg1JcYtgxVcUctQ0HxLByiJzpAkNFawz1Nz5Xadzo82g==} + engines: {node: '>=14.0.0'} + + uint8array-tools@0.0.9: + resolution: {integrity: sha512-9vqDWmoSXOoi+K14zNaf6LBV51Q8MayF0/IiQs3GlygIKUYtog603e6virExkjjFosfJUBI4LhbQK1iq8IG11A==} + engines: {node: '>=14.0.0'} + ultron@1.1.1: resolution: {integrity: sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==} @@ -2840,12 +2919,23 @@ packages: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true + valibot@0.38.0: + resolution: {integrity: sha512-RCJa0fetnzp+h+KN9BdgYOgtsMAG9bfoJ9JSjIhFHobKWVWyzM3jjaeNTdpFK9tQtf3q1sguXeERJ/LcmdFE7w==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true + varint@5.0.2: resolution: {integrity: sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==} varuint-bitcoin@1.1.2: resolution: {integrity: sha512-4EVb+w4rx+YfVM32HQX42AbbT7/1f5zwAYhIujKXKk8NQK+JfRVl3pqT3hjNn/L+RstigmGGKVwHA/P0wgITZw==} + varuint-bitcoin@2.0.0: + resolution: {integrity: sha512-6QZbU/rHO2ZQYpWFDALCDSRsXbAs1VOEmXAxtbtjLtKuMJ/FQ8YbhfxlaiKv5nklci0M6lZtlZyxo9Q+qNnyog==} + vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -3072,6 +3162,44 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 + '@chainflip/bitcoin@1.1.1(typescript@5.5.3)': + dependencies: + '@chainflip/utils': 0.4.0 + bitcoinjs-lib: 7.0.0-rc.0(typescript@5.5.3) + transitivePeerDependencies: + - typescript + + '@chainflip/cli@1.8.0-cf-parameters-rename.0(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10)': + dependencies: + '@chainflip/bitcoin': 1.1.1(typescript@5.5.3) + '@chainflip/extrinsics': 1.6.1 + '@chainflip/rpc': 1.6.9 + '@chainflip/solana': 1.0.2 + '@chainflip/utils': 0.4.0 + axios: 1.7.2 + ethers: 6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) + ioredis: 5.4.1 + ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + yargs: 17.7.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - typescript + - utf-8-validate + + '@chainflip/extrinsics@1.6.1': {} + + '@chainflip/rpc@1.6.9': + dependencies: + '@chainflip/utils': 0.3.0 + zod: 3.23.8 + + '@chainflip/solana@1.0.2': + dependencies: + '@chainflip/utils': 0.4.0 + + '@chainflip/utils@0.3.0': {} + '@chainflip/utils@0.4.0': {} '@coral-xyz/anchor-errors@0.30.1': {} @@ -3351,6 +3479,8 @@ snapshots: '@iarna/toml@2.2.5': {} + '@ioredis/commands@1.2.0': {} + '@noble/curves@1.2.0': dependencies: '@noble/hashes': 1.3.2 @@ -4192,6 +4322,8 @@ snapshots: base-x@4.0.0: {} + base-x@5.0.0: {} + base64-js@1.5.1: {} bcrypt-pbkdf@1.0.2: @@ -4212,6 +4344,11 @@ snapshots: bip174@2.1.1: {} + bip174@3.0.0-rc.1: + dependencies: + uint8array-tools: 0.0.9 + varuint-bitcoin: 2.0.0 + bitcoin-core@4.2.0: dependencies: '@uphold/request-logger': 2.0.0(request@2.88.2) @@ -4233,6 +4370,18 @@ snapshots: typeforce: 1.18.0 varuint-bitcoin: 1.1.2 + bitcoinjs-lib@7.0.0-rc.0(typescript@5.5.3): + dependencies: + '@noble/hashes': 1.4.0 + bech32: 2.0.0 + bip174: 3.0.0-rc.1 + bs58check: 4.0.0 + uint8array-tools: 0.0.9 + valibot: 0.38.0(typescript@5.5.3) + varuint-bitcoin: 2.0.0 + transitivePeerDependencies: + - typescript + blakejs@1.2.1: {} bluebird@3.7.2: {} @@ -4298,6 +4447,10 @@ snapshots: dependencies: base-x: 4.0.0 + bs58@6.0.0: + dependencies: + base-x: 5.0.0 + bs58check@2.1.2: dependencies: bs58: 4.0.1 @@ -4309,6 +4462,11 @@ snapshots: '@noble/hashes': 1.4.0 bs58: 5.0.0 + bs58check@4.0.0: + dependencies: + '@noble/hashes': 1.4.0 + bs58: 6.0.0 + buffer-layout@1.2.2: {} buffer-to-arraybuffer@0.0.5: {} @@ -4404,6 +4562,8 @@ snapshots: dependencies: mimic-response: 1.0.1 + cluster-key-slot@1.1.2: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -4564,6 +4724,8 @@ snapshots: delayed-stream@1.0.0: {} + denque@2.1.0: {} + depd@2.0.0: {} destroy@1.2.0: {} @@ -5397,6 +5559,20 @@ snapshots: hasown: 2.0.2 side-channel: 1.0.6 + ioredis@5.4.1: + dependencies: + '@ioredis/commands': 1.2.0 + cluster-key-slot: 1.1.2 + debug: 4.3.5 + denque: 2.1.0 + lodash.defaults: 4.2.0 + lodash.isarguments: 3.1.0 + redis-errors: 1.2.0 + redis-parser: 3.0.0 + standard-as-callback: 2.1.0 + transitivePeerDependencies: + - supports-color + ipaddr.js@1.9.1: {} is-arguments@1.1.1: @@ -5575,6 +5751,10 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash.defaults@4.2.0: {} + + lodash.isarguments@3.1.0: {} + lodash.merge@4.6.2: {} lodash@4.17.21: {} @@ -5928,6 +6108,12 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 + redis-errors@1.2.0: {} + + redis-parser@3.0.0: + dependencies: + redis-errors: 1.2.0 + regenerator-runtime@0.14.1: {} regexp.prototype.flags@1.5.2: @@ -6167,6 +6353,8 @@ snapshots: safer-buffer: 2.1.2 tweetnacl: 0.14.5 + standard-as-callback@2.1.0: {} + standard-error@1.1.0: {} statuses@2.0.1: {} @@ -6375,6 +6563,10 @@ snapshots: uint8array-tools@0.0.7: {} + uint8array-tools@0.0.8: {} + + uint8array-tools@0.0.9: {} + ultron@1.1.1: {} unbox-primitive@1.0.2: @@ -6420,12 +6612,20 @@ snapshots: uuid@9.0.1: {} + valibot@0.38.0(typescript@5.5.3): + optionalDependencies: + typescript: 5.5.3 + varint@5.0.2: {} varuint-bitcoin@1.1.2: dependencies: safe-buffer: 5.2.1 + varuint-bitcoin@2.0.0: + dependencies: + uint8array-tools: 0.0.8 + vary@1.1.2: {} verror@1.10.0: diff --git a/bouncer/tests/DCA_test.ts b/bouncer/tests/DCA_test.ts index bb1aa77b64..92e93f53c9 100644 --- a/bouncer/tests/DCA_test.ts +++ b/bouncer/tests/DCA_test.ts @@ -82,14 +82,10 @@ async function testDCASwap( destAsset, destAddress, wallet, - // newCcmMetadata(inputAsset, destAsset, undefined, 100), undefined, amount.toString(), undefined, - // TODO: Something is wrong when passing fillOrKillParams but no CCM Metadata. - // Problem is when ccmAdditionalData is undefined. fillOrKillParams, - // undefined, dcaParams, ); From b14cb63515359d8c1920d63e0c9768067e11ec87 Mon Sep 17 00:00:00 2001 From: albert Date: Wed, 23 Oct 2024 11:29:19 +0200 Subject: [PATCH 22/36] chore: remove unnecessary bouncer ts-scale --- bouncer/package.json | 1 - bouncer/pnpm-lock.yaml | 6 ++---- bouncer/shared/contract_swap.ts | 26 ++------------------------ 3 files changed, 4 insertions(+), 29 deletions(-) diff --git a/bouncer/package.json b/bouncer/package.json index 7254aae2c2..940ea55d68 100644 --- a/bouncer/package.json +++ b/bouncer/package.json @@ -30,7 +30,6 @@ "md5": "^2.3.0", "minimist": "^1.2.8", "rxjs": "^7.8.1", - "scale-ts": "1.6.0", "tiny-secp256k1": "^2.2.1", "toml": "^3.0.0", "web3": "^1.9.0", diff --git a/bouncer/pnpm-lock.yaml b/bouncer/pnpm-lock.yaml index d0bab95fbf..d998892c4f 100644 --- a/bouncer/pnpm-lock.yaml +++ b/bouncer/pnpm-lock.yaml @@ -80,9 +80,6 @@ importers: rxjs: specifier: ^7.8.1 version: 7.8.1 - scale-ts: - specifier: 1.6.0 - version: 1.6.0 tiny-secp256k1: specifier: ^2.2.1 version: 2.2.3 @@ -6227,7 +6224,8 @@ snapshots: safer-buffer@2.1.2: {} - scale-ts@1.6.0: {} + scale-ts@1.6.0: + optional: true scrypt-js@3.0.1: {} diff --git a/bouncer/shared/contract_swap.ts b/bouncer/shared/contract_swap.ts index feb36d34b5..fc2757643a 100644 --- a/bouncer/shared/contract_swap.ts +++ b/bouncer/shared/contract_swap.ts @@ -7,7 +7,6 @@ import { Chains, Chain, } from '@chainflip/cli'; -import { u32, Struct, Option, u16, u256, Bytes as TsBytes, Enum } from 'scale-ts'; import { HDNodeWallet, Wallet } from 'ethers'; import { observeBalanceIncrease, @@ -26,29 +25,6 @@ import { SwapContext, SwapStatus } from './swap_context'; const erc20Assets: Asset[] = ['Flip', 'Usdc', 'Usdt', 'ArbUsdc']; -export const vaultSwapCfParametersCodec = Struct({ - ccmAdditionalData: Option(TsBytes()), - vaultSwapParameters: Option( - Struct({ - refundParams: Option( - Struct({ - retryDurationBlocks: u32, - refundAddress: Enum({ - Eth: TsBytes(20), - Dot: TsBytes(32), - Btc: TsBytes(), - Arb: TsBytes(20), - Sol: TsBytes(32), - }), - minPriceX128: u256, - }), - ), - dcaParams: Option(Struct({ numberOfChunks: u32, chunkIntervalBlocks: u32 })), - boostFee: Option(u16), - }), - ), -}); - export async function executeContractSwap( sourceAsset: Asset, destAsset: Asset, @@ -90,6 +66,8 @@ export async function executeContractSwap( message: messageMetadata.message, ccmAdditionalData: messageMetadata.ccmAdditionalData, }, + // The SDK will encode these parameters and the ccmAdditionalData + // into the `cfParameters` field for the vault swap. boostFeeBps, fillOrKillParams, dcaParams, From c06e294594114aedc2abec7584492b8af3ece971 Mon Sep 17 00:00:00 2001 From: albert Date: Wed, 23 Oct 2024 11:32:39 +0200 Subject: [PATCH 23/36] chore: lint --- bouncer/shared/utils.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bouncer/shared/utils.ts b/bouncer/shared/utils.ts index 3de26afebe..a93fb92253 100644 --- a/bouncer/shared/utils.ts +++ b/bouncer/shared/utils.ts @@ -731,7 +731,10 @@ export async function observeSolanaCcmEvent( const remainingAccountSize = publicKeySize + 1; // Extra byte for the encoded length - const remainingAccountsBytes = ccmAdditionalData.slice(remainingAccountSize + 1, -publicKeySize); + const remainingAccountsBytes = ccmAdditionalData.slice( + remainingAccountSize + 1, + -publicKeySize, + ); const remainingAccounts = []; const remainingIsWritable = []; From c621a7def79a92fb742aa53c93d643f359d00452 Mon Sep 17 00:00:00 2001 From: albert Date: Wed, 23 Oct 2024 12:52:00 +0200 Subject: [PATCH 24/36] chore: update to right name --- bouncer/shared/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bouncer/shared/utils.ts b/bouncer/shared/utils.ts index 3832ad8d52..8d9fb6e9fa 100644 --- a/bouncer/shared/utils.ts +++ b/bouncer/shared/utils.ts @@ -54,7 +54,7 @@ const isSDKChain = (chain: Chain): chain is SDKChain => chain in chainConstants; export const solanaNumberOfNonces = 10; -export const solCfParamsCodec = Struct({ +export const solCcmAdditionalDataCodec = Struct({ cf_receiver: Struct({ pubkey: TsBytes(32), is_writable: bool, @@ -751,7 +751,7 @@ export async function observeSolanaCcmEvent( // The message is being used as the main discriminator if (matchEventName && matchSourceChain && matchMessage) { - const { remaining_accounts: expectedRemainingAccounts } = solCfParamsCodec.dec( + const { remaining_accounts: expectedRemainingAccounts } = solCcmAdditionalDataCodec.dec( messageMetadata.ccmAdditionalData!, ); From 23814152a147d120c765c51e409e0cf54d984f6c Mon Sep 17 00:00:00 2001 From: albert Date: Wed, 23 Oct 2024 13:28:07 +0200 Subject: [PATCH 25/36] chore: fix missing rename --- bouncer/shared/swapping.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bouncer/shared/swapping.ts b/bouncer/shared/swapping.ts index 79ec61eec2..04f5e54f2a 100644 --- a/bouncer/shared/swapping.ts +++ b/bouncer/shared/swapping.ts @@ -12,7 +12,7 @@ import { defaultAssetAmounts, ccmSupportedChains, assetDecimals, - solCfParamsCodec, + solCcmAdditionalDataCodec, } from '../shared/utils'; import { BtcAddressType } from '../shared/new_btc_address'; import { CcmDepositMetadata } from '../shared/new_swap'; @@ -93,7 +93,7 @@ export function newSolanaCcmAdditionalData(maxAccounts: number) { fallback_address: fallbackAddress, }; - return u8aToHex(solCfParamsCodec.enc(cfParameters)); + return u8aToHex(solCcmAdditionalDataCodec.enc(cfParameters)); } // Solana CCM-related parameters. These are values in the protocol. From cfe63fdc6fb2e894f750fe014cf9188d44f0ea57 Mon Sep 17 00:00:00 2001 From: albert Date: Wed, 23 Oct 2024 16:54:31 +0200 Subject: [PATCH 26/36] chore: add beneficiares and make FoK mandatory --- bouncer/package.json | 2 +- bouncer/pnpm-lock.yaml | 10 ++--- bouncer/shared/contract_swap.ts | 12 +++++- engine/src/witness/common/cf_parameters.rs | 45 ++++++--------------- engine/src/witness/evm/vault.rs | 46 +++++++++++++++------- 5 files changed, 62 insertions(+), 53 deletions(-) diff --git a/bouncer/package.json b/bouncer/package.json index 7254aae2c2..ce82c3ae15 100644 --- a/bouncer/package.json +++ b/bouncer/package.json @@ -6,7 +6,7 @@ "prettier:write": "prettier --write ." }, "dependencies": { - "@chainflip/cli": "1.8.0-cf-parameters-rename.0", + "@chainflip/cli": "1.8.0-cf-parameters-rename.1", "@chainflip/utils": "^0.4.0", "@coral-xyz/anchor": "^0.30.1", "@iarna/toml": "^2.2.5", diff --git a/bouncer/pnpm-lock.yaml b/bouncer/pnpm-lock.yaml index d0bab95fbf..c258dcc0bd 100644 --- a/bouncer/pnpm-lock.yaml +++ b/bouncer/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@chainflip/cli': - specifier: 1.8.0-cf-parameters-rename.0 - version: 1.8.0-cf-parameters-rename.0(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10) + specifier: 1.8.0-cf-parameters-rename.1 + version: 1.8.0-cf-parameters-rename.1(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10) '@chainflip/utils': specifier: ^0.4.0 version: 0.4.0 @@ -145,8 +145,8 @@ packages: '@chainflip/bitcoin@1.1.1': resolution: {integrity: sha512-Jr6X/0QTSFYpTp23ZPhyioL6wL9x3Xpj6OGjadQKZyhobRN4BZkhLogv20HDYTJcRzVphzrTJArbEaNie04XVA==} - '@chainflip/cli@1.8.0-cf-parameters-rename.0': - resolution: {integrity: sha512-aNGUAPfWCQLx3i4UC25F15/kP4Hczd5dFzZVXgwp20nMjoUsSy8cK2DW7JnVTF3DBHJd3Fw3ZQMjjk3PdWZXDA==} + '@chainflip/cli@1.8.0-cf-parameters-rename.1': + resolution: {integrity: sha512-Hfnb3p822RFEj+Pz/pPqfgTLqDurGnQHh4E/B1RbOcuTuPwKaNzxr5vdvVgXQWPOhO14/Pdmn8ORamSx7LyNMA==} hasBin: true peerDependencies: axios: ^1.x @@ -3169,7 +3169,7 @@ snapshots: transitivePeerDependencies: - typescript - '@chainflip/cli@1.8.0-cf-parameters-rename.0(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10)': + '@chainflip/cli@1.8.0-cf-parameters-rename.1(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10)': dependencies: '@chainflip/bitcoin': 1.1.1(typescript@5.5.3) '@chainflip/extrinsics': 1.6.1 diff --git a/bouncer/shared/contract_swap.ts b/bouncer/shared/contract_swap.ts index fc2757643a..19aef8ea4a 100644 --- a/bouncer/shared/contract_swap.ts +++ b/bouncer/shared/contract_swap.ts @@ -8,6 +8,7 @@ import { Chain, } from '@chainflip/cli'; import { HDNodeWallet, Wallet } from 'ethers'; +import { randomBytes } from 'crypto'; import { observeBalanceIncrease, getContractAddress, @@ -18,6 +19,7 @@ import { assetDecimals, stateChainAssetFromAsset, createEvmWalletAndFund, + newAddress, } from './utils'; import { getBalance } from './get_balance'; import { CcmDepositMetadata, DcaParams, FillOrKillParamsX128 } from '../shared/new_swap'; @@ -40,6 +42,13 @@ export async function executeContractSwap( const destChain = chainFromAsset(destAsset); const amountToSwap = amount ?? defaultAssetAmounts(sourceAsset); + const refundAddress = await newAddress(sourceAsset, randomBytes(32).toString('hex')); + const fokParams = fillOrKillParams ?? { + retryDurationBlocks: 0, + refundAddress, + minPriceX128: "0", + }; + const networkOptions = { signer: wallet, network: 'localnet', @@ -69,8 +78,9 @@ export async function executeContractSwap( // The SDK will encode these parameters and the ccmAdditionalData // into the `cfParameters` field for the vault swap. boostFeeBps, - fillOrKillParams, + fillOrKillParams: fokParams, dcaParams, + beneficiaries: undefined } as ExecuteSwapParams, networkOptions, txOptions, diff --git a/engine/src/witness/common/cf_parameters.rs b/engine/src/witness/common/cf_parameters.rs index 99391f97a8..4b11ec44d9 100644 --- a/engine/src/witness/common/cf_parameters.rs +++ b/engine/src/witness/common/cf_parameters.rs @@ -15,19 +15,22 @@ pub type CfParameters = BoundedVec>; #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] pub struct VaultCfParameters { pub ccm_additional_data: Option, - pub vault_swap_parameters: Option, + pub vault_swap_parameters: VaultSwapParameters, } #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] pub struct VaultSwapParameters { - pub refund_params: Option, + pub refund_params: ChannelRefundParameters, pub dca_params: Option, pub boost_fee: Option, + // TODO: Should we make broker mandatory? Should we have a separate field? + pub broker_fees: Option>>, + // pub broker_fees: Option>, } pub trait CfParametersDecode { fn decode_into_swap_parameters(self) -> Result; - fn decode_into_ccm_swap_parameters(self) -> Result<(CcmAdditionalData, VaultSwapParameters)>; + fn decode_into_ccm_swap_parameters(self) -> Result; } // CfParameters is swap data encoded in Vault Swaps that is to be decoded into the adequate @@ -36,36 +39,14 @@ pub trait CfParametersDecode { // support initiating CCM swaps via vault swaps. impl CfParametersDecode for CfParameters { fn decode_into_swap_parameters(self) -> Result { - if self.is_empty() { - Ok(VaultSwapParameters { refund_params: None, dca_params: None, boost_fee: None }) - } else { - let parameters: VaultSwapParameters = VaultSwapParameters::decode(&mut &self[..]) - .map_err(|_| anyhow!("Failed to decode to `VaultSwapParameters`"))?; - Ok(parameters) - } + let parameters: VaultSwapParameters = VaultSwapParameters::decode(&mut &self[..]) + .map_err(|_| anyhow!("Failed to decode to `VaultSwapParameters`"))?; + Ok(parameters) } - fn decode_into_ccm_swap_parameters(self) -> Result<(CcmAdditionalData, VaultSwapParameters)> { - if self.is_empty() { - // Return the empty vector since the CCM additional data is required - Ok(( - CcmAdditionalData::default(), - VaultSwapParameters { refund_params: None, dca_params: None, boost_fee: None }, - )) - } else { - let vault_swap_cf_parameters: VaultCfParameters = - VaultCfParameters::decode(&mut &self[..]) - .map_err(|_| anyhow!("Failed to decode to `VaultCfParameters`"))?; - - Ok(( - // Default to empty CcmAdditionalData vector if not present - vault_swap_cf_parameters.ccm_additional_data.unwrap_or_default(), - vault_swap_cf_parameters.vault_swap_parameters.unwrap_or(VaultSwapParameters { - refund_params: None, - dca_params: None, - boost_fee: None, - }), - )) - } + fn decode_into_ccm_swap_parameters(self) -> Result { + let vault_swap_cf_parameters: VaultCfParameters = VaultCfParameters::decode(&mut &self[..]) + .map_err(|_| anyhow!("Failed to decode to `VaultCfParameters`"))?; + Ok(vault_swap_cf_parameters) } } diff --git a/engine/src/witness/evm/vault.rs b/engine/src/witness/evm/vault.rs index dadb69d9bc..8efce7625d 100644 --- a/engine/src/witness/evm/vault.rs +++ b/engine/src/witness/evm/vault.rs @@ -70,6 +70,9 @@ where .to_vec() .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; + + // TODO: We can consider defaulting values if decoding fails for backwards + // compatibility. Or we can default in the decoding functions if it's an empty array. let vault_swap_parameters = cf_parameters_vec.decode_into_swap_parameters()?; Some(CallBuilder::contract_swap_request( @@ -79,9 +82,11 @@ where try_into_encoded_address(try_into_primitive(dst_chain)?, dst_address.to_vec())?, None, event.tx_hash.into(), - vault_swap_parameters.refund_params, + Some(vault_swap_parameters.refund_params), vault_swap_parameters.dca_params, vault_swap_parameters.boost_fee, + // TODO: Add broker_fees. Probably pass None for now as it'll need decoding id -> + // account_id )) }, VaultEvents::SwapTokenFilter(SwapTokenFilter { @@ -97,6 +102,9 @@ where .to_vec() .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; + + // TODO: We can consider defaulting values if decoding fails for backwards + // compatibility. Or we can default in the decoding functions if it's an empty array. let vault_swap_parameters = cf_parameters_vec.decode_into_swap_parameters()?; Some(CallBuilder::contract_swap_request( @@ -108,9 +116,11 @@ where try_into_encoded_address(try_into_primitive(dst_chain)?, dst_address.to_vec())?, None, event.tx_hash.into(), - vault_swap_parameters.refund_params, + Some(vault_swap_parameters.refund_params), vault_swap_parameters.dca_params, vault_swap_parameters.boost_fee, + // TODO: Add broker_fees. Probably pass None for now as it'll need decoding id -> + // account_id )) }, VaultEvents::XcallNativeFilter(XcallNativeFilter { @@ -127,8 +137,10 @@ where .to_vec() .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; - let (ccm_additional_data, vault_swap_parameters) = - cf_parameters_vec.decode_into_ccm_swap_parameters()?; + + // TODO: We can consider defaulting values if decoding fails for backwards + // compatibility. Or we can default in the decoding functions if it's an empty array. + let parameters = cf_parameters_vec.decode_into_ccm_swap_parameters()?; Some(CallBuilder::contract_swap_request( native_asset, @@ -148,13 +160,15 @@ where .try_into() .map_err(|_| anyhow!("Failed to deposit CCM: `message` too long."))?, gas_budget: try_into_primitive(gas_amount)?, - ccm_additional_data, + ccm_additional_data: parameters.ccm_additional_data.unwrap_or_default(), }, }), event.tx_hash.into(), - vault_swap_parameters.refund_params, - vault_swap_parameters.dca_params, - vault_swap_parameters.boost_fee, + Some(parameters.vault_swap_parameters.refund_params), + parameters.vault_swap_parameters.dca_params, + parameters.vault_swap_parameters.boost_fee, + // TODO: Add broker_fees. Probably pass None for now as it'll need decoding id -> + // account_id )) }, VaultEvents::XcallTokenFilter(XcallTokenFilter { @@ -172,8 +186,10 @@ where .to_vec() .try_into() .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; - let (ccm_additional_data, vault_swap_parameters) = - cf_parameters_vec.decode_into_ccm_swap_parameters()?; + + // TODO: We can consider defaulting values if decoding fails for backwards + // compatibility. Or we can default in the decoding functions if it's an empty array. + let parameters = cf_parameters_vec.decode_into_ccm_swap_parameters()?; Some(CallBuilder::contract_swap_request( *(supported_assets @@ -195,13 +211,15 @@ where .try_into() .map_err(|_| anyhow!("Failed to deposit CCM. Message too long."))?, gas_budget: try_into_primitive(gas_amount)?, - ccm_additional_data, + ccm_additional_data: parameters.ccm_additional_data.unwrap_or_default(), }, }), event.tx_hash.into(), - vault_swap_parameters.refund_params, - vault_swap_parameters.dca_params, - vault_swap_parameters.boost_fee, + Some(parameters.vault_swap_parameters.refund_params), + parameters.vault_swap_parameters.dca_params, + parameters.vault_swap_parameters.boost_fee, + // TODO: Add broker_fees. Probably pass None for now as it'll need decoding id -> + // account_id )) }, VaultEvents::TransferNativeFailedFilter(TransferNativeFailedFilter { From 399846f06b989bb4d8522892c92bb1cac842c538 Mon Sep 17 00:00:00 2001 From: albert Date: Wed, 23 Oct 2024 16:56:20 +0200 Subject: [PATCH 27/36] chore: lint --- bouncer/shared/contract_swap.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bouncer/shared/contract_swap.ts b/bouncer/shared/contract_swap.ts index 19aef8ea4a..01ab72b8f2 100644 --- a/bouncer/shared/contract_swap.ts +++ b/bouncer/shared/contract_swap.ts @@ -46,7 +46,7 @@ export async function executeContractSwap( const fokParams = fillOrKillParams ?? { retryDurationBlocks: 0, refundAddress, - minPriceX128: "0", + minPriceX128: '0', }; const networkOptions = { @@ -80,7 +80,7 @@ export async function executeContractSwap( boostFeeBps, fillOrKillParams: fokParams, dcaParams, - beneficiaries: undefined + beneficiaries: undefined, } as ExecuteSwapParams, networkOptions, txOptions, From d77a0da6e93b4277010e0fcce234d53334debe82 Mon Sep 17 00:00:00 2001 From: albert Date: Wed, 23 Oct 2024 17:54:23 +0200 Subject: [PATCH 28/36] chore: update broker_fees and cli --- bouncer/package.json | 2 +- bouncer/pnpm-lock.yaml | 10 +++++----- engine/src/witness/common/cf_parameters.rs | 6 ++++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/bouncer/package.json b/bouncer/package.json index ce82c3ae15..5d40d53447 100644 --- a/bouncer/package.json +++ b/bouncer/package.json @@ -6,7 +6,7 @@ "prettier:write": "prettier --write ." }, "dependencies": { - "@chainflip/cli": "1.8.0-cf-parameters-rename.1", + "@chainflip/cli": "1.8.0-cf-parameters-rename.2", "@chainflip/utils": "^0.4.0", "@coral-xyz/anchor": "^0.30.1", "@iarna/toml": "^2.2.5", diff --git a/bouncer/pnpm-lock.yaml b/bouncer/pnpm-lock.yaml index c258dcc0bd..dabc487c19 100644 --- a/bouncer/pnpm-lock.yaml +++ b/bouncer/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@chainflip/cli': - specifier: 1.8.0-cf-parameters-rename.1 - version: 1.8.0-cf-parameters-rename.1(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10) + specifier: 1.8.0-cf-parameters-rename.2 + version: 1.8.0-cf-parameters-rename.2(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10) '@chainflip/utils': specifier: ^0.4.0 version: 0.4.0 @@ -145,8 +145,8 @@ packages: '@chainflip/bitcoin@1.1.1': resolution: {integrity: sha512-Jr6X/0QTSFYpTp23ZPhyioL6wL9x3Xpj6OGjadQKZyhobRN4BZkhLogv20HDYTJcRzVphzrTJArbEaNie04XVA==} - '@chainflip/cli@1.8.0-cf-parameters-rename.1': - resolution: {integrity: sha512-Hfnb3p822RFEj+Pz/pPqfgTLqDurGnQHh4E/B1RbOcuTuPwKaNzxr5vdvVgXQWPOhO14/Pdmn8ORamSx7LyNMA==} + '@chainflip/cli@1.8.0-cf-parameters-rename.2': + resolution: {integrity: sha512-N7Cg9UlN6VbVPsGwQ+/J8V8qC2e6AU40e131syzOOb9J/hfA2Z/bSP4ukpzkpVpSTxjc4nEv5xKIz6WdvvqcFw==} hasBin: true peerDependencies: axios: ^1.x @@ -3169,7 +3169,7 @@ snapshots: transitivePeerDependencies: - typescript - '@chainflip/cli@1.8.0-cf-parameters-rename.1(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10)': + '@chainflip/cli@1.8.0-cf-parameters-rename.2(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10)': dependencies: '@chainflip/bitcoin': 1.1.1(typescript@5.5.3) '@chainflip/extrinsics': 1.6.1 diff --git a/engine/src/witness/common/cf_parameters.rs b/engine/src/witness/common/cf_parameters.rs index 4b11ec44d9..2c81989154 100644 --- a/engine/src/witness/common/cf_parameters.rs +++ b/engine/src/witness/common/cf_parameters.rs @@ -23,8 +23,10 @@ pub struct VaultSwapParameters { pub refund_params: ChannelRefundParameters, pub dca_params: Option, pub boost_fee: Option, - // TODO: Should we make broker mandatory? Should we have a separate field? - pub broker_fees: Option>>, + // TODO: Should we make broker mandatory? Should we have a separate fields or + // we just pass the array to the SC and it will handle it? + pub broker_fees: + Option>>, // pub broker_fees: Option>, } From ea61dce8f352312283f0e7e71e2cc462e633b36a Mon Sep 17 00:00:00 2001 From: albert Date: Thu, 24 Oct 2024 08:44:04 +0200 Subject: [PATCH 29/36] chore: update with hardcoded cfParameters --- bouncer/tests/evm_deposits.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bouncer/tests/evm_deposits.ts b/bouncer/tests/evm_deposits.ts index 73638b5f7a..02a293e5d1 100644 --- a/bouncer/tests/evm_deposits.ts +++ b/bouncer/tests/evm_deposits.ts @@ -97,7 +97,8 @@ async function testTxMultipleContractSwaps(sourceAsset: Asset, destAsset: Asset) assetContractId(destAsset), getContractAddress(chainFromAsset(sourceAsset), sourceAsset), amount, - '0x', + // Encoded EVM refund address and no other swap parameters. + '0x0000000000000e879c89cad7076b347bde13c99cf2c33e7299b60000000000000000000000000000000000000000000000000000000000000000000000', numSwaps, ) .encodeABI(); From 2282405c28a4f6997981d52e5378a1793c0a84e2 Mon Sep 17 00:00:00 2001 From: albert Date: Thu, 24 Oct 2024 09:35:10 +0200 Subject: [PATCH 30/36] chore: bump sdk --- bouncer/package.json | 2 +- bouncer/pnpm-lock.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bouncer/package.json b/bouncer/package.json index 5d40d53447..09d2cde2c5 100644 --- a/bouncer/package.json +++ b/bouncer/package.json @@ -6,7 +6,7 @@ "prettier:write": "prettier --write ." }, "dependencies": { - "@chainflip/cli": "1.8.0-cf-parameters-rename.2", + "@chainflip/cli": "1.8.0-cf-parameters-rename.3", "@chainflip/utils": "^0.4.0", "@coral-xyz/anchor": "^0.30.1", "@iarna/toml": "^2.2.5", diff --git a/bouncer/pnpm-lock.yaml b/bouncer/pnpm-lock.yaml index dabc487c19..4421c80a14 100644 --- a/bouncer/pnpm-lock.yaml +++ b/bouncer/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@chainflip/cli': - specifier: 1.8.0-cf-parameters-rename.2 - version: 1.8.0-cf-parameters-rename.2(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10) + specifier: 1.8.0-cf-parameters-rename.3 + version: 1.8.0-cf-parameters-rename.3(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10) '@chainflip/utils': specifier: ^0.4.0 version: 0.4.0 @@ -145,8 +145,8 @@ packages: '@chainflip/bitcoin@1.1.1': resolution: {integrity: sha512-Jr6X/0QTSFYpTp23ZPhyioL6wL9x3Xpj6OGjadQKZyhobRN4BZkhLogv20HDYTJcRzVphzrTJArbEaNie04XVA==} - '@chainflip/cli@1.8.0-cf-parameters-rename.2': - resolution: {integrity: sha512-N7Cg9UlN6VbVPsGwQ+/J8V8qC2e6AU40e131syzOOb9J/hfA2Z/bSP4ukpzkpVpSTxjc4nEv5xKIz6WdvvqcFw==} + '@chainflip/cli@1.8.0-cf-parameters-rename.3': + resolution: {integrity: sha512-1+i11YjTg7/9yGUWysLc/PQE4hgKcAL6WHTIL/V2LunxFZxp27vowaxDixDMaBZIvL3AUBcs5oAV4kjWmPtJKw==} hasBin: true peerDependencies: axios: ^1.x @@ -3169,7 +3169,7 @@ snapshots: transitivePeerDependencies: - typescript - '@chainflip/cli@1.8.0-cf-parameters-rename.2(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10)': + '@chainflip/cli@1.8.0-cf-parameters-rename.3(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10)': dependencies: '@chainflip/bitcoin': 1.1.1(typescript@5.5.3) '@chainflip/extrinsics': 1.6.1 From de719c5cc1769c7412fef237d436ed623673a406 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 24 Oct 2024 16:59:00 +0200 Subject: [PATCH 31/36] fix: simplify cf params decoding --- engine/src/witness/common/cf_parameters.rs | 62 ++++++++++------------ engine/src/witness/evm/vault.rs | 57 ++++++-------------- state-chain/primitives/src/lib.rs | 4 +- 3 files changed, 48 insertions(+), 75 deletions(-) diff --git a/engine/src/witness/common/cf_parameters.rs b/engine/src/witness/common/cf_parameters.rs index 2c81989154..1419d2cb7f 100644 --- a/engine/src/witness/common/cf_parameters.rs +++ b/engine/src/witness/common/cf_parameters.rs @@ -1,23 +1,21 @@ +use cf_chains::{CcmAdditionalData, ChannelRefundParameters}; +use cf_primitives::{BasisPoints, Beneficiaries, DcaParameters}; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_core::ConstU32; - -use anyhow::{anyhow, Result}; -use cf_chains::{CcmAdditionalData, ChannelRefundParameters, MAX_CCM_ADDITIONAL_DATA_LENGTH}; -use cf_primitives::{BasisPoints, DcaParameters}; -use frame_support::sp_runtime::BoundedVec; - -pub const MAX_VAULT_SWAP_PARAMETERS_LENGTH: u32 = 1_000; -pub const MAX_CF_PARAM_LENGTH: u32 = - MAX_CCM_ADDITIONAL_DATA_LENGTH + MAX_VAULT_SWAP_PARAMETERS_LENGTH; -pub type CfParameters = BoundedVec>; #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] -pub struct VaultCfParameters { - pub ccm_additional_data: Option, +pub struct CfParameters { + /// CCMs may require additional data (for example CCMs to Solana require adding a list of + /// addresses). + pub ccm_additional_data: CcmData, pub vault_swap_parameters: VaultSwapParameters, } +pub type CcmCfParameters = CfParameters; + +// TODO: Define this / implement it on the SC. +type ShortId = u8; + #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] pub struct VaultSwapParameters { pub refund_params: ChannelRefundParameters, @@ -25,30 +23,26 @@ pub struct VaultSwapParameters { pub boost_fee: Option, // TODO: Should we make broker mandatory? Should we have a separate fields or // we just pass the array to the SC and it will handle it? - pub broker_fees: - Option>>, - // pub broker_fees: Option>, + pub broker_fees: Beneficiaries, } -pub trait CfParametersDecode { - fn decode_into_swap_parameters(self) -> Result; - fn decode_into_ccm_swap_parameters(self) -> Result; -} +#[cfg(test)] +mod tests { + use super::*; + use cf_chains::MAX_CCM_ADDITIONAL_DATA_LENGTH; -// CfParameters is swap data encoded in Vault Swaps that is to be decoded into the adequate -// parameters to pass to the State Chain along with the contract swap. This applies to EVM -// chains and Solana. BTC has it's own format for VaultSwapParameters and does not -// support initiating CCM swaps via vault swaps. -impl CfParametersDecode for CfParameters { - fn decode_into_swap_parameters(self) -> Result { - let parameters: VaultSwapParameters = VaultSwapParameters::decode(&mut &self[..]) - .map_err(|_| anyhow!("Failed to decode to `VaultSwapParameters`"))?; - Ok(parameters) - } + const MAX_VAULT_SWAP_PARAMETERS_LENGTH: u32 = 1_000; + const MAX_CF_PARAM_LENGTH: u32 = + MAX_CCM_ADDITIONAL_DATA_LENGTH + MAX_VAULT_SWAP_PARAMETERS_LENGTH; - fn decode_into_ccm_swap_parameters(self) -> Result { - let vault_swap_cf_parameters: VaultCfParameters = VaultCfParameters::decode(&mut &self[..]) - .map_err(|_| anyhow!("Failed to decode to `VaultCfParameters`"))?; - Ok(vault_swap_cf_parameters) + #[test] + fn test_cf_parameters_max_length() { + assert!( + MAX_VAULT_SWAP_PARAMETERS_LENGTH as usize >= VaultSwapParameters::max_encoded_len() + ); + assert!(MAX_CF_PARAM_LENGTH as usize >= CfParameters::<()>::max_encoded_len()); + assert!( + MAX_VAULT_SWAP_PARAMETERS_LENGTH as usize >= VaultSwapParameters::max_encoded_len() + ); } } diff --git a/engine/src/witness/evm/vault.rs b/engine/src/witness/evm/vault.rs index 8efce7625d..01ff9bb99f 100644 --- a/engine/src/witness/evm/vault.rs +++ b/engine/src/witness/evm/vault.rs @@ -1,3 +1,4 @@ +use codec::Decode; use ethers::types::Bloom; use sp_core::H256; use std::collections::HashMap; @@ -66,14 +67,8 @@ where sender: _, cf_parameters, }) => { - let cf_parameters_vec: CfParameters = cf_parameters - .to_vec() - .try_into() - .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; - - // TODO: We can consider defaulting values if decoding fails for backwards - // compatibility. Or we can default in the decoding functions if it's an empty array. - let vault_swap_parameters = cf_parameters_vec.decode_into_swap_parameters()?; + let CfParameters { ccm_additional_data: (), vault_swap_parameters } = + CfParameters::decode(&mut &cf_parameters[..])?; Some(CallBuilder::contract_swap_request( native_asset, @@ -98,14 +93,8 @@ where sender: _, cf_parameters, }) => { - let cf_parameters_vec: CfParameters = cf_parameters - .to_vec() - .try_into() - .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; - - // TODO: We can consider defaulting values if decoding fails for backwards - // compatibility. Or we can default in the decoding functions if it's an empty array. - let vault_swap_parameters = cf_parameters_vec.decode_into_swap_parameters()?; + let CfParameters { ccm_additional_data: (), vault_swap_parameters } = + CfParameters::decode(&mut &cf_parameters[..])?; Some(CallBuilder::contract_swap_request( *(supported_assets @@ -133,14 +122,8 @@ where gas_amount, cf_parameters, }) => { - let cf_parameters_vec: CfParameters = cf_parameters - .to_vec() - .try_into() - .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; - - // TODO: We can consider defaulting values if decoding fails for backwards - // compatibility. Or we can default in the decoding functions if it's an empty array. - let parameters = cf_parameters_vec.decode_into_ccm_swap_parameters()?; + let CfParameters { ccm_additional_data, vault_swap_parameters } = + CcmCfParameters::decode(&mut &cf_parameters[..])?; Some(CallBuilder::contract_swap_request( native_asset, @@ -160,13 +143,13 @@ where .try_into() .map_err(|_| anyhow!("Failed to deposit CCM: `message` too long."))?, gas_budget: try_into_primitive(gas_amount)?, - ccm_additional_data: parameters.ccm_additional_data.unwrap_or_default(), + ccm_additional_data, }, }), event.tx_hash.into(), - Some(parameters.vault_swap_parameters.refund_params), - parameters.vault_swap_parameters.dca_params, - parameters.vault_swap_parameters.boost_fee, + Some(vault_swap_parameters.refund_params), + vault_swap_parameters.dca_params, + vault_swap_parameters.boost_fee, // TODO: Add broker_fees. Probably pass None for now as it'll need decoding id -> // account_id )) @@ -182,14 +165,8 @@ where gas_amount, cf_parameters, }) => { - let cf_parameters_vec: CfParameters = cf_parameters - .to_vec() - .try_into() - .map_err(|_| anyhow!("Failed to decode `cf_parameters` too long."))?; - - // TODO: We can consider defaulting values if decoding fails for backwards - // compatibility. Or we can default in the decoding functions if it's an empty array. - let parameters = cf_parameters_vec.decode_into_ccm_swap_parameters()?; + let CfParameters { ccm_additional_data, vault_swap_parameters } = + CcmCfParameters::decode(&mut &cf_parameters[..])?; Some(CallBuilder::contract_swap_request( *(supported_assets @@ -211,13 +188,13 @@ where .try_into() .map_err(|_| anyhow!("Failed to deposit CCM. Message too long."))?, gas_budget: try_into_primitive(gas_amount)?, - ccm_additional_data: parameters.ccm_additional_data.unwrap_or_default(), + ccm_additional_data, }, }), event.tx_hash.into(), - Some(parameters.vault_swap_parameters.refund_params), - parameters.vault_swap_parameters.dca_params, - parameters.vault_swap_parameters.boost_fee, + Some(vault_swap_parameters.refund_params), + vault_swap_parameters.dca_params, + vault_swap_parameters.boost_fee, // TODO: Add broker_fees. Probably pass None for now as it'll need decoding id -> // account_id )) diff --git a/state-chain/primitives/src/lib.rs b/state-chain/primitives/src/lib.rs index 6efde071d2..b5c584df1a 100644 --- a/state-chain/primitives/src/lib.rs +++ b/state-chain/primitives/src/lib.rs @@ -399,7 +399,9 @@ pub type Affiliates = BoundedVec, ConstU32>; pub type Beneficiaries = BoundedVec, ConstU32<{ MAX_AFFILIATES + 1 }>>; -#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, TypeInfo, Serialize, Deserialize)] +#[derive( + Clone, Debug, PartialEq, Eq, MaxEncodedLen, Encode, Decode, TypeInfo, Serialize, Deserialize, +)] pub struct Beneficiary { pub account: Id, pub bps: BasisPoints, From e3b831483f65d9fa7d18bef70e819f4dad95c5b9 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 24 Oct 2024 17:40:58 +0200 Subject: [PATCH 32/36] chore: downgrade error -> warning --- engine/src/witness/evm/vault.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/engine/src/witness/evm/vault.rs b/engine/src/witness/evm/vault.rs index 01ff9bb99f..357f1d48b8 100644 --- a/engine/src/witness/evm/vault.rs +++ b/engine/src/witness/evm/vault.rs @@ -1,10 +1,9 @@ +use crate::evm::retry_rpc::EvmRetryRpcApi; use codec::Decode; use ethers::types::Bloom; use sp_core::H256; use std::collections::HashMap; -use crate::evm::retry_rpc::EvmRetryRpcApi; - use super::{ super::common::{ cf_parameters::*, @@ -307,7 +306,7 @@ impl ChunkedByVaultBuilder { process_call(call, epoch.index).await; }, Err(message) => { - tracing::error!("Ignoring vault contract event: {message}"); + tracing::warn!("Ignoring vault contract event: {message}"); }, } } From 785ab48e6903938f1b379212eb9406dd8d6e371f Mon Sep 17 00:00:00 2001 From: albert Date: Fri, 25 Oct 2024 09:16:30 +0200 Subject: [PATCH 33/36] chore: bump sdk with new broker_fees type --- bouncer/package.json | 2 +- bouncer/pnpm-lock.yaml | 10 +++++----- engine/src/witness/common/cf_parameters.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bouncer/package.json b/bouncer/package.json index 09d2cde2c5..c925e20da6 100644 --- a/bouncer/package.json +++ b/bouncer/package.json @@ -6,7 +6,7 @@ "prettier:write": "prettier --write ." }, "dependencies": { - "@chainflip/cli": "1.8.0-cf-parameters-rename.3", + "@chainflip/cli": "1.8.0-cf-parameters-rename.4", "@chainflip/utils": "^0.4.0", "@coral-xyz/anchor": "^0.30.1", "@iarna/toml": "^2.2.5", diff --git a/bouncer/pnpm-lock.yaml b/bouncer/pnpm-lock.yaml index 4421c80a14..bf39821772 100644 --- a/bouncer/pnpm-lock.yaml +++ b/bouncer/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@chainflip/cli': - specifier: 1.8.0-cf-parameters-rename.3 - version: 1.8.0-cf-parameters-rename.3(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10) + specifier: 1.8.0-cf-parameters-rename.4 + version: 1.8.0-cf-parameters-rename.4(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10) '@chainflip/utils': specifier: ^0.4.0 version: 0.4.0 @@ -145,8 +145,8 @@ packages: '@chainflip/bitcoin@1.1.1': resolution: {integrity: sha512-Jr6X/0QTSFYpTp23ZPhyioL6wL9x3Xpj6OGjadQKZyhobRN4BZkhLogv20HDYTJcRzVphzrTJArbEaNie04XVA==} - '@chainflip/cli@1.8.0-cf-parameters-rename.3': - resolution: {integrity: sha512-1+i11YjTg7/9yGUWysLc/PQE4hgKcAL6WHTIL/V2LunxFZxp27vowaxDixDMaBZIvL3AUBcs5oAV4kjWmPtJKw==} + '@chainflip/cli@1.8.0-cf-parameters-rename.4': + resolution: {integrity: sha512-yFGI+i5zf4Iet1bu8zeyDChX8+OTTJsmh9g+UtvlmP2/WSB5whlPOuIKpupSbMTO7RhcKUGcuUASWs9Nit+0fw==} hasBin: true peerDependencies: axios: ^1.x @@ -3169,7 +3169,7 @@ snapshots: transitivePeerDependencies: - typescript - '@chainflip/cli@1.8.0-cf-parameters-rename.3(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10)': + '@chainflip/cli@1.8.0-cf-parameters-rename.4(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10)': dependencies: '@chainflip/bitcoin': 1.1.1(typescript@5.5.3) '@chainflip/extrinsics': 1.6.1 diff --git a/engine/src/witness/common/cf_parameters.rs b/engine/src/witness/common/cf_parameters.rs index 07027a870b..e84d88812f 100644 --- a/engine/src/witness/common/cf_parameters.rs +++ b/engine/src/witness/common/cf_parameters.rs @@ -13,7 +13,7 @@ pub struct CfParameters { pub type CcmCfParameters = CfParameters; -// TODO: Define this / implement it on the SC. +// TODO: Define this / implement it on the SC - PRO-1743. pub type ShortId = u8; #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)] From 2033df7a9c589f23649870177759eb4aaaaa5966 Mon Sep 17 00:00:00 2001 From: albert Date: Fri, 25 Oct 2024 12:39:26 +0200 Subject: [PATCH 34/36] chore: fix failing test --- bouncer/shared/contract_swap.ts | 30 +++++++++++----------- bouncer/shared/swap_context.ts | 11 +-------- bouncer/shared/utils.ts | 4 +-- bouncer/tests/DCA_test.ts | 10 +++----- bouncer/tests/fill_or_kill.ts | 44 ++++++++++++++++++--------------- 5 files changed, 46 insertions(+), 53 deletions(-) diff --git a/bouncer/shared/contract_swap.ts b/bouncer/shared/contract_swap.ts index 01ab72b8f2..37cc2be019 100644 --- a/bouncer/shared/contract_swap.ts +++ b/bouncer/shared/contract_swap.ts @@ -31,12 +31,12 @@ export async function executeContractSwap( sourceAsset: Asset, destAsset: Asset, destAddress: string, - wallet: HDNodeWallet, messageMetadata?: CcmDepositMetadata, amount?: string, boostFeeBps?: number, fillOrKillParams?: FillOrKillParamsX128, dcaParams?: DcaParams, + wallet?: HDNodeWallet, ): ReturnType { const srcChain = chainFromAsset(sourceAsset); const destChain = chainFromAsset(destAsset); @@ -49,8 +49,20 @@ export async function executeContractSwap( minPriceX128: '0', }; + const evmWallet = wallet ?? (await createEvmWalletAndFund(sourceAsset)); + + if (erc20Assets.includes(sourceAsset)) { + // Doing effectively infinite approvals to make sure it doesn't fail. + // eslint-disable-next-line @typescript-eslint/no-use-before-define + await approveTokenVault( + sourceAsset, + (BigInt(amountToFineAmount(amountToSwap, assetDecimals(sourceAsset))) * 100n).toString(), + evmWallet, + ); + } + const networkOptions = { - signer: wallet, + signer: evmWallet, network: 'localnet', vaultContractAddress: getContractAddress(srcChain, 'VAULT'), srcTokenContractAddress: getContractAddress(srcChain, sourceAsset), @@ -117,19 +129,9 @@ export async function performSwapViaContract( if (mnemonic === '') { throw new Error('Failed to create random mnemonic'); } - const wallet = await createEvmWalletAndFund(sourceAsset); try { - if (erc20Assets.includes(sourceAsset)) { - // Doing effectively infinite approvals to make sure it doesn't fail. - // eslint-disable-next-line @typescript-eslint/no-use-before-define - await approveTokenVault( - sourceAsset, - (BigInt(amountToFineAmount(amountToSwap, assetDecimals(sourceAsset))) * 100n).toString(), - wallet, - ); - } - swapContext?.updateStatus(swapTag, SwapStatus.ContractApproved); + const wallet = await createEvmWalletAndFund(sourceAsset); const oldBalance = await getBalance(destAsset, destAddress); if (log) { @@ -146,12 +148,12 @@ export async function performSwapViaContract( sourceAsset, destAsset, destAddress, - wallet, messageMetadata, amountToSwap, boostFeeBps, fillOrKillParams, dcaParams, + wallet, ); swapContext?.updateStatus(swapTag, SwapStatus.ContractExecuted); diff --git a/bouncer/shared/swap_context.ts b/bouncer/shared/swap_context.ts index 6c9ff44286..2d2a6bc681 100644 --- a/bouncer/shared/swap_context.ts +++ b/bouncer/shared/swap_context.ts @@ -3,8 +3,6 @@ import assert from 'assert'; export enum SwapStatus { Initiated, Funded, - // Contract swap specific statuses - ContractApproved, ContractExecuted, SwapScheduled, Success, @@ -37,16 +35,9 @@ export class SwapContext { ); break; } - case SwapStatus.ContractApproved: { - assert( - currentStatus === SwapStatus.Initiated, - `Unexpected status transition for ${tag}. Transitioning from ${currentStatus} to ${status}`, - ); - break; - } case SwapStatus.ContractExecuted: { assert( - currentStatus === SwapStatus.ContractApproved, + currentStatus === SwapStatus.Initiated, `Unexpected status transition for ${tag}. Transitioning from ${currentStatus} to ${status}`, ); break; diff --git a/bouncer/shared/utils.ts b/bouncer/shared/utils.ts index 8d9fb6e9fa..073626d3af 100644 --- a/bouncer/shared/utils.ts +++ b/bouncer/shared/utils.ts @@ -1166,7 +1166,7 @@ export async function createEvmWalletAndFund(asset: Asset): Promise Number(event.data.swapRequestId.replaceAll(',', '')) === swapRequestId, - historicalCheckBlocks: 10, - }).event; } else { testFillOrKill.log( `Swapping via contract from ${inputAsset} to ${destAsset} with unrealistic min price`, @@ -94,31 +85,44 @@ async function testMinPriceRefund(inputAsset: Asset, amount: number, swapviaCont Math.random() < 0.5 ? ccmMetadata.ccmAdditionalData : undefined; } - swapHandle = performSwapViaContract( + const receipt = await executeContractSwap( inputAsset, destAsset, destAddress, undefined, - ccmMetadata, - undefined, - true, amount.toString(), undefined, refundParameters, ); + + swapRequestedHandle = observeSwapRequested( + inputAsset, + destAsset, + receipt.hash, + SwapRequestType.Regular, + ); } + const swapRequestedEvent = await swapRequestedHandle; + const swapRequestId = Number(swapRequestedEvent.data.swapRequestId.replaceAll(',', '')); + testFillOrKill.log(`${inputAsset} swap requested, swapRequestId: ${swapRequestId}`); + + const observeSwapExecuted = observeEvent(`swapping:SwapExecuted`, { + test: (event) => Number(event.data.swapRequestId.replaceAll(',', '')) === swapRequestId, + historicalCheckBlocks: 10, + }).event; + // Wait for the swap to execute or get refunded const executeOrRefund = await Promise.race([ - swapHandle, + observeSwapExecuted, observeBalanceIncrease(inputAsset, refundAddress, refundBalanceBefore), ]); if (typeof executeOrRefund !== 'number') { - throw new Error(`${inputAsset} swap was executed instead of failing and being refunded`); + throw new Error( + `${inputAsset} swap ${swapRequestId} was executed instead of failing and being refunded`, + ); } - - testFillOrKill.log(`FoK ${inputAsset} ${swapviaContract ? 'via contract' : ''} swap refunded`); } async function main() { From 99310e5ffcc8d1d16992a467d36747bec2698bc0 Mon Sep 17 00:00:00 2001 From: albert Date: Fri, 25 Oct 2024 14:28:08 +0200 Subject: [PATCH 35/36] chore: bump sdk --- bouncer/package.json | 2 +- bouncer/pnpm-lock.yaml | 10 +++++----- bouncer/shared/contract_swap.ts | 9 ++------- bouncer/shared/swapping.ts | 2 +- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/bouncer/package.json b/bouncer/package.json index c925e20da6..0a0ff85f2b 100644 --- a/bouncer/package.json +++ b/bouncer/package.json @@ -6,7 +6,7 @@ "prettier:write": "prettier --write ." }, "dependencies": { - "@chainflip/cli": "1.8.0-cf-parameters-rename.4", + "@chainflip/cli": "1.8.0-cf-parameters-rename.5", "@chainflip/utils": "^0.4.0", "@coral-xyz/anchor": "^0.30.1", "@iarna/toml": "^2.2.5", diff --git a/bouncer/pnpm-lock.yaml b/bouncer/pnpm-lock.yaml index bf39821772..1cdd1b8811 100644 --- a/bouncer/pnpm-lock.yaml +++ b/bouncer/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@chainflip/cli': - specifier: 1.8.0-cf-parameters-rename.4 - version: 1.8.0-cf-parameters-rename.4(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10) + specifier: 1.8.0-cf-parameters-rename.5 + version: 1.8.0-cf-parameters-rename.5(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10) '@chainflip/utils': specifier: ^0.4.0 version: 0.4.0 @@ -145,8 +145,8 @@ packages: '@chainflip/bitcoin@1.1.1': resolution: {integrity: sha512-Jr6X/0QTSFYpTp23ZPhyioL6wL9x3Xpj6OGjadQKZyhobRN4BZkhLogv20HDYTJcRzVphzrTJArbEaNie04XVA==} - '@chainflip/cli@1.8.0-cf-parameters-rename.4': - resolution: {integrity: sha512-yFGI+i5zf4Iet1bu8zeyDChX8+OTTJsmh9g+UtvlmP2/WSB5whlPOuIKpupSbMTO7RhcKUGcuUASWs9Nit+0fw==} + '@chainflip/cli@1.8.0-cf-parameters-rename.5': + resolution: {integrity: sha512-+/1U/8IMuLZcRMCekq76heU0gptGvWho7joJ/I3Gbd/4SNI/K1pLp5wtATtE+bcELZ1QrtvAt+bK8yM9WNrCYg==} hasBin: true peerDependencies: axios: ^1.x @@ -3169,7 +3169,7 @@ snapshots: transitivePeerDependencies: - typescript - '@chainflip/cli@1.8.0-cf-parameters-rename.4(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10)': + '@chainflip/cli@1.8.0-cf-parameters-rename.5(axios@1.7.2)(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typescript@5.5.3)(utf-8-validate@5.0.10)': dependencies: '@chainflip/bitcoin': 1.1.1(typescript@5.5.3) '@chainflip/extrinsics': 1.6.1 diff --git a/bouncer/shared/contract_swap.ts b/bouncer/shared/contract_swap.ts index 37cc2be019..f2719a0aa8 100644 --- a/bouncer/shared/contract_swap.ts +++ b/bouncer/shared/contract_swap.ts @@ -123,14 +123,9 @@ export async function performSwapViaContract( const tag = swapTag ?? ''; const amountToSwap = amount ?? defaultAssetAmounts(sourceAsset); - // Generate a new wallet for each contract swap to prevent nonce issues when running in parallel - // with other swaps via deposit channels. - const mnemonic = Wallet.createRandom().mnemonic?.phrase ?? ''; - if (mnemonic === '') { - throw new Error('Failed to create random mnemonic'); - } - try { + // Generate a new wallet for each contract swap to prevent nonce issues when running in parallel + // with other swaps via deposit channels. const wallet = await createEvmWalletAndFund(sourceAsset); const oldBalance = await getBalance(destAsset, destAddress); diff --git a/bouncer/shared/swapping.ts b/bouncer/shared/swapping.ts index 04f5e54f2a..0bde37e88d 100644 --- a/bouncer/shared/swapping.ts +++ b/bouncer/shared/swapping.ts @@ -250,7 +250,7 @@ export async function testSwapViaContract( destAsset, addressType, messageMetadata, - (tagSuffix ?? '') + ' Contract', + (tagSuffix ?? '') + 'Contract', log, swapContext, ); From 2d070ea99e007dd3141a60721be2ed00b3738ef2 Mon Sep 17 00:00:00 2001 From: albert Date: Fri, 25 Oct 2024 14:30:56 +0200 Subject: [PATCH 36/36] chore: lint --- bouncer/shared/contract_swap.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bouncer/shared/contract_swap.ts b/bouncer/shared/contract_swap.ts index f2719a0aa8..d3a0d80eb4 100644 --- a/bouncer/shared/contract_swap.ts +++ b/bouncer/shared/contract_swap.ts @@ -7,7 +7,7 @@ import { Chains, Chain, } from '@chainflip/cli'; -import { HDNodeWallet, Wallet } from 'ethers'; +import { HDNodeWallet } from 'ethers'; import { randomBytes } from 'crypto'; import { observeBalanceIncrease,