From ef9e3a7e854369a945c48833cd95aef1987343c5 Mon Sep 17 00:00:00 2001 From: Jamie Ford Date: Tue, 12 Nov 2024 15:29:55 +1100 Subject: [PATCH] feat: btc vault swap bouncer test can open private channel --- api/bin/chainflip-broker-api/src/main.rs | 20 ++++++++-- api/lib/src/lib.rs | 50 ++++++++++++++++++++++++ bouncer/tests/all_concurrent_tests.ts | 2 + bouncer/tests/btc_vault_swap.ts | 21 +++++++++- engine/src/witness/btc/deposits.rs | 11 +++++- state-chain/runtime/src/lib.rs | 3 +- 6 files changed, 99 insertions(+), 8 deletions(-) diff --git a/api/bin/chainflip-broker-api/src/main.rs b/api/bin/chainflip-broker-api/src/main.rs index 3b70c4c5298..c393b0d057a 100644 --- a/api/bin/chainflip-broker-api/src/main.rs +++ b/api/bin/chainflip-broker-api/src/main.rs @@ -14,9 +14,9 @@ use chainflip_api::{ DcaParameters, }, settings::StateChain, - AccountId32, AddressString, BlockUpdate, BrokerApi, ChainApi, DepositMonitorApi, OperatorApi, - RefundParameters, SignedExtrinsicApi, StateChainApi, SwapDepositAddress, TransactionInId, - WithdrawFeesDetail, + AccountId32, AddressString, BlockUpdate, BrokerApi, ChainApi, ChannelId, DepositMonitorApi, + OperatorApi, RefundParameters, SignedExtrinsicApi, StateChainApi, SwapDepositAddress, + TransactionInId, WithdrawFeesDetail, }; use clap::Parser; use custom_rpc::CustomApiClient; @@ -128,6 +128,12 @@ pub trait Rpc { #[subscription(name = "subscribe_tainted_transaction_events", item = BlockUpdate)] async fn subscribe_tainted_transaction_events(&self) -> SubscriptionResult; + + #[method(name = "open_private_btc_channel", aliases = ["broker_openPrivateBtcChannel"])] + async fn open_private_btc_channel(&self) -> RpcResult; + + #[method(name = "close_private_btc_channel", aliases = ["broker_closePrivateBtcChannel"])] + async fn close_private_btc_channel(&self) -> RpcResult; } pub struct RpcServerImpl { @@ -298,6 +304,14 @@ impl RpcServer for RpcServerImpl { }); Ok(()) } + + async fn open_private_btc_channel(&self) -> RpcResult { + Ok(self.api.broker_api().open_private_btc_channel().await?) + } + + async fn close_private_btc_channel(&self) -> RpcResult { + Ok(self.api.broker_api().close_private_btc_channel().await?) + } } #[derive(Parser, Debug, Clone, Default)] diff --git a/api/lib/src/lib.rs b/api/lib/src/lib.rs index 20e2e1e0a13..fa10f9e343a 100644 --- a/api/lib/src/lib.rs +++ b/api/lib/src/lib.rs @@ -474,6 +474,56 @@ pub trait BrokerApi: SignedExtrinsicApi + StorageApi + Sized + Send + Sync + 'st self.simple_submission_with_dry_run(pallet_cf_swapping::Call::deregister_as_broker {}) .await } + + async fn open_private_btc_channel(&self) -> Result { + let (_, events, ..) = self + .submit_signed_extrinsic(RuntimeCall::from( + pallet_cf_swapping::Call::open_private_btc_channel {}, + )) + .await + .until_in_block() + .await?; + + if let Some(state_chain_runtime::RuntimeEvent::Swapping( + pallet_cf_swapping::Event::PrivateBrokerChannelOpened { channel_id, .. }, + )) = events.iter().find(|event| { + matches!( + event, + state_chain_runtime::RuntimeEvent::Swapping( + pallet_cf_swapping::Event::PrivateBrokerChannelOpened { .. } + ) + ) + }) { + Ok(*channel_id) + } else { + bail!("No PrivateBrokerChannelOpened event was found"); + } + } + + async fn close_private_btc_channel(&self) -> Result { + let (_, events, ..) = self + .submit_signed_extrinsic(RuntimeCall::from( + pallet_cf_swapping::Call::close_private_btc_channel {}, + )) + .await + .until_in_block() + .await?; + + if let Some(state_chain_runtime::RuntimeEvent::Swapping( + pallet_cf_swapping::Event::PrivateBrokerChannelClosed { channel_id, .. }, + )) = events.iter().find(|event| { + matches!( + event, + state_chain_runtime::RuntimeEvent::Swapping( + pallet_cf_swapping::Event::PrivateBrokerChannelClosed { .. } + ) + ) + }) { + Ok(*channel_id) + } else { + bail!("No PrivateBrokerChannelClosed event was found"); + } + } } #[async_trait] diff --git a/bouncer/tests/all_concurrent_tests.ts b/bouncer/tests/all_concurrent_tests.ts index 28b3628b325..d5b26a92b52 100755 --- a/bouncer/tests/all_concurrent_tests.ts +++ b/bouncer/tests/all_concurrent_tests.ts @@ -15,6 +15,7 @@ import { testAllSwaps } from './all_swaps'; import { depositChannelCreation } from './request_swap_deposit_address_with_affiliates'; import { testDCASwaps } from './DCA_test'; import { testBrokerLevelScreening } from './broker_level_screening'; +import { testBtcVaultSwap } from './btc_vault_swap'; async function runAllConcurrentTests() { // Specify the number of nodes via providing an argument to this script. @@ -46,6 +47,7 @@ async function runAllConcurrentTests() { testDCASwaps.run(), testCancelOrdersBatch.run(), depositChannelCreation.run(), + testBtcVaultSwap.run(), ]; // Tests that only work if there is more than one node diff --git a/bouncer/tests/btc_vault_swap.ts b/bouncer/tests/btc_vault_swap.ts index dd491288b7f..f0c9d12ad84 100644 --- a/bouncer/tests/btc_vault_swap.ts +++ b/bouncer/tests/btc_vault_swap.ts @@ -12,6 +12,7 @@ import { } from '../shared/utils'; import { getChainflipApi, observeEvent } from '../shared/utils/substrate'; import { getBalance } from '../shared/get_balance'; +import { jsonRpc } from '../shared/json_rpc'; /* eslint-disable @typescript-eslint/no-use-before-define */ export const testBtcVaultSwap = new ExecutableTest('Btc-Vault-Swap', main, 100); @@ -51,6 +52,7 @@ async function buildAndSendBtcVaultSwap( assert.strictEqual(vaultSwapDetails.chain, 'Bitcoin'); testBtcVaultSwap.debugLog('nulldata_utxo:', vaultSwapDetails.nulldata_utxo); + testBtcVaultSwap.debugLog('deposit_address:', vaultSwapDetails.deposit_address); // The `createRawTransaction` function will add the op codes, so we have to remove them here. const nullDataWithoutOpCodes = vaultSwapDetails.nulldata_utxo.replace('0x', '').substring(4); @@ -112,8 +114,25 @@ async function testVaultSwap(depositAmountBtc: number, brokerUri: string, destin testBtcVaultSwap.log(`Balance increased, Vault Swap Complete`); } +async function openPrivateBtcChannel(brokerUri: string) { + // TODO: Use chainflip SDK instead so we can support any broker uri + assert.strictEqual(brokerUri, '//BROKER_1', 'Support for other brokers is not implemented'); + + // TODO: use chainflip SDK to check if the channel is already open + try { + await jsonRpc('broker_open_private_btc_channel', [], 'http://127.0.0.1:10997'); + testBtcVaultSwap.log('Private Btc channel opened'); + } catch (error) { + // We expect this to fail if the channel already exists from a previous run + testBtcVaultSwap.debugLog('Failed to open private Btc channel', error); + } +} + async function main() { const btcDepositAmount = 0.1; + const brokerUri = '//BROKER_1'; + + await openPrivateBtcChannel(brokerUri); - await testVaultSwap(btcDepositAmount, '//BROKER_1', 'Flip'); + await testVaultSwap(btcDepositAmount, brokerUri, 'Flip'); } diff --git a/engine/src/witness/btc/deposits.rs b/engine/src/witness/btc/deposits.rs index a4acf5ac339..ffe5af334ee 100644 --- a/engine/src/witness/btc/deposits.rs +++ b/engine/src/witness/btc/deposits.rs @@ -65,7 +65,7 @@ impl ChunkedByVaultBuilder { let key: &AggKey = &epoch.info.0; - // Take all current private broker chanenls and use them to build a list of all + // Take all current private broker channels and use them to build a list of all // deposit addresses that we should check for vault swaps. Note that we // monitor previous epoch key (if exists) in addition to the current one, which // means we get up to two deposit addresses per broker. A special case is the @@ -74,7 +74,14 @@ impl ChunkedByVaultBuilder { [(None, CHANGE_ADDRESS_SALT)] .into_iter() .chain(private_channels.clone().into_iter().map( - |(broker_id, channel_id)| (Some(broker_id), channel_id as u32), + |(broker_id, channel_id)| { + ( + Some(broker_id), + channel_id + .try_into() + .expect("Channel id should be within u32 bounds"), + ) + }, )) .map(move |(maybe_broker_id, channel_id)| { (maybe_broker_id, DepositAddress::new(key, channel_id)) diff --git a/state-chain/runtime/src/lib.rs b/state-chain/runtime/src/lib.rs index b2ef836e1b2..4b9857d261f 100644 --- a/state-chain/runtime/src/lib.rs +++ b/state-chain/runtime/src/lib.rs @@ -2127,8 +2127,7 @@ impl_runtime_apis! { Ok(()) } }) - .map_err(|()| pallet_cf_swapping::Error::::InvalidDestinationAddress)?; - + .map_err(|_| pallet_cf_swapping::Error::::InvalidDestinationAddress)?; // Encode swap match ForeignChain::from(source_asset) {