Skip to content

Commit

Permalink
Merge branch 'main' into feat/better-chain-traits
Browse files Browse the repository at this point in the history
  • Loading branch information
dandanlen committed Aug 31, 2023
2 parents 6ba6b71 + c44279b commit c7622a9
Show file tree
Hide file tree
Showing 52 changed files with 1,349 additions and 300 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

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

92 changes: 71 additions & 21 deletions api/bin/chainflip-cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![feature(absolute_path)]
use anyhow::{Context, Result};
use anyhow::{bail, Context, Result};
use clap::Parser;
use futures::FutureExt;
use serde::Serialize;
Expand All @@ -10,8 +10,8 @@ use crate::settings::{
LiquidityProviderSubcommands,
};
use api::{
lp::LpApi, primitives::RedemptionAmount, AccountId32, BrokerApi, GovernanceApi, KeyPair,
OperatorApi, StateChainApi, SwapDepositAddress,
lp::LpApi, primitives::RedemptionAmount, queries::QueryApi, AccountId32, BrokerApi,
GovernanceApi, KeyPair, OperatorApi, SignedExtrinsicApi, StateChainApi, SwapDepositAddress,
};
use cf_chains::eth::Address as EthereumAddress;
use chainflip_api as api;
Expand Down Expand Up @@ -91,7 +91,13 @@ async fn run_cli() -> Result<()> {
println!("Emergency Withdrawal Address registered. Tx hash: {tx_hash}");
},
Redeem { amount, eth_address, executor } => {
request_redemption(api.operator_api(), amount, &eth_address, executor).await?;
request_redemption(api, amount, eth_address, executor).await?;
},
BindRedeemAddress { eth_address } => {
bind_redeem_address(api.operator_api(), &eth_address).await?;
},
GetBoundRedeemAddress {} => {
get_bound_redeem_address(api.query_api()).await?;
},
RegisterAccountRole { role } => {
println!(
Expand Down Expand Up @@ -129,36 +135,51 @@ async fn run_cli() -> Result<()> {
}

async fn request_redemption(
api: Arc<impl OperatorApi + Sync>,
api: StateChainApi,
amount: Option<f64>,
eth_address: &str,
supplied_address: Option<String>,
executor: Option<cf_chains::eth::Address>,
) -> Result<()> {
// Sanitise data
let eth_address = EthereumAddress::from_slice(
clean_hex_address::<[u8; 20]>(eth_address)
.context("Invalid ETH address supplied")?
.as_slice(),
);
let supplied_address = if let Some(address) = supplied_address {
Some(EthereumAddress::from(
clean_hex_address::<[u8; 20]>(&address).context("Invalid ETH address supplied")?,
))
} else {
None
};

let account_id = api.state_chain_client.account_id();
let bound_address =
api.query_api().get_bound_redeem_address(None, Some(account_id.clone())).await?;

let redeem_address = match (supplied_address, bound_address) {
(Some(supplied_address), Some(bound_address)) =>
if supplied_address != bound_address {
bail!("Supplied ETH address `{supplied_address:?}` does not match bound address for this account `{bound_address:?}`.");
} else {
bound_address
},
(Some(supplied_address), None) => supplied_address,
(None, Some(bound_address)) => {
println!("Using bound redeem address.");
bound_address
},
(None, None) =>
bail!("No redeem address supplied and no bound redeem address found for your account {account_id}."),
};

let amount = match amount {
Some(amount_float) => {
let atomic_amount = (amount_float * 10_f64.powi(18)) as u128;

println!(
"Submitting redemption with amount `{}` FLIP (`{}` Flipperinos) to ETH address `0x{}`.",
amount_float,
atomic_amount,
hex::encode(eth_address)
"Submitting redemption with amount `{amount_float}` FLIP (`{atomic_amount}` Flipperinos) to ETH address `{redeem_address:?}`."
);

RedemptionAmount::Exact(atomic_amount)
},
None => {
println!(
"Submitting redemption with MAX amount to ETH address `0x{}`.",
hex::encode(eth_address)
);
println!("Submitting redemption with MAX amount to ETH address `{redeem_address:?}`.");

RedemptionAmount::Max
},
Expand All @@ -168,7 +189,7 @@ async fn request_redemption(
return Ok(())
}

let tx_hash = api.request_redemption(amount, eth_address, executor).await?;
let tx_hash = api.operator_api().request_redemption(amount, redeem_address, executor).await?;

println!(
"Your redemption request has transaction hash: `{tx_hash:#x}`. View your redemption's progress on the funding app."
Expand All @@ -177,6 +198,35 @@ async fn request_redemption(
Ok(())
}

async fn bind_redeem_address(api: Arc<impl OperatorApi + Sync>, eth_address: &str) -> Result<()> {
let eth_address = EthereumAddress::from(
clean_hex_address::<[u8; 20]>(eth_address).context("Invalid ETH address supplied")?,
);

println!(
"Binding your account to a redemption address is irreversible. You will only ever be able to redeem to this address: {eth_address:?}.",
);
if !confirm_submit() {
return Ok(())
}

let tx_hash = api.bind_redeem_address(eth_address).await?;

println!("Account bound to address {eth_address}, transaction hash: `{tx_hash:#x}`.");

Ok(())
}

async fn get_bound_redeem_address(api: QueryApi) -> Result<()> {
if let Some(bound_address) = api.get_bound_redeem_address(None, None).await? {
println!("Your account is bound to redeem address: {bound_address:?}");
} else {
println!("Your account is not bound to any redeem address.");
}

Ok(())
}

fn confirm_submit() -> bool {
use std::{io, io::*};

Expand Down
13 changes: 11 additions & 2 deletions api/bin/chainflip-cli/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,22 @@ pub enum CliCommand {
long = "exact"
)]
amount: Option<f64>,
#[clap(help = "The Ethereum address you wish to redeem your FLIP to")]
eth_address: String,
#[clap(
help = "The Ethereum address you wish to redeem your FLIP to. If not specified, the redeem address bound to your account will be used"
)]
eth_address: Option<String>,
#[clap(
help = "Optional executor. If specified, only this address will be able to execute the redemption."
)]
executor: Option<cf_chains::eth::Address>,
},
#[clap(about = "Restricts your account to only be able to redeem to the specified address")]
BindRedeemAddress {
#[clap(help = "The Ethereum address you wish to bind your account to")]
eth_address: String,
},
#[clap(about = "Shows the redeem address your account is bound to")]
GetBoundRedeemAddress,
#[clap(
about = "Submit an extrinsic to request generation of a redemption certificate (redeeming all available FLIP)"
)]
Expand Down
10 changes: 10 additions & 0 deletions api/lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,16 @@ pub trait OperatorApi: SignedExtrinsicApi + RotateSessionKeysApi + AuctionPhaseA
Ok(tx_hash)
}

async fn bind_redeem_address(&self, address: EthereumAddress) -> Result<H256> {
let (tx_hash, ..) = self
.submit_signed_extrinsic(pallet_cf_funding::Call::bind_redeem_address { address })
.await
.until_finalized()
.await?;

Ok(tx_hash)
}

async fn register_account_role(&self, role: AccountRole) -> Result<H256> {
let call = match role {
AccountRole::Validator =>
Expand Down
18 changes: 18 additions & 0 deletions api/lib/src/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,24 @@ impl QueryApi {
})
.collect())
}

pub async fn get_bound_redeem_address(
&self,
block_hash: Option<state_chain_runtime::Hash>,
account_id: Option<state_chain_runtime::AccountId>,
) -> Result<Option<EthereumAddress>, anyhow::Error> {
let block_hash =
block_hash.unwrap_or_else(|| self.state_chain_client.latest_finalized_hash());
let account_id = account_id.unwrap_or_else(|| self.state_chain_client.account_id());

Ok(self
.state_chain_client
.storage_map_entry::<pallet_cf_funding::BoundAddress<state_chain_runtime::Runtime>>(
block_hash,
&account_id,
)
.await?)
}
}

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down
2 changes: 2 additions & 0 deletions bouncer/commands/explorer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#!/usr/bin/env -S pnpm tsx

// Set the node you want to query by setting the `CF_NODE_ENDPOINT` environment variable.
// e.g. CF_NODE_ENDPOINT=wss://perseverance.chainflip.xyz
// Call with a range of blocks to query, like:
// ./explorer.js 1234 1300
// Alternatively, the first argument can be the string "live" to query the latest blocks.
Expand Down
9 changes: 8 additions & 1 deletion bouncer/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,12 @@ set -e
./tests/all_concurrent_tests.ts
./tests/gaslimit_ccm.ts
./tests/rotates_through_btc_swap.ts
./tests/swap_after_temp_disconnecting_chains.ts

if [[ $LOCALNET == false ]]; then
echo "🤫 Skipping tests that require localnet"
else
echo "🚀 Running tests that require localnet"
./tests/swap_after_temp_disconnecting_chains.ts
fi

./tests/multiple_members_governance.ts
16 changes: 14 additions & 2 deletions bouncer/shared/contract_swap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,27 @@ export async function performSwapViaContract(
const receipt = await executeContractSwap(sourceAsset, destAsset, destAddress, messageMetadata);
await observeEvent('swapping:SwapScheduled', api, (event) => {
if ('Vault' in event.data.origin) {
return event.data.origin.Vault.txHash === receipt.transactionHash;
const sourceAssetMatches = sourceAsset === (event.data.sourceAsset.toUpperCase() as Asset);
const destAssetMatches = destAsset === (event.data.destinationAsset.toUpperCase() as Asset);
const txHashMatches = event.data.origin.Vault.txHash === receipt.transactionHash;
return sourceAssetMatches && destAssetMatches && txHashMatches;
}
// Otherwise it was a swap scheduled by requesting a deposit address
return false;
});
console.log(`${tag} Successfully observed event: swapping: SwapScheduled`);

const ccmEventEmitted = messageMetadata
? observeCcmReceived(sourceAsset, destAsset, destAddress, messageMetadata)
? observeCcmReceived(
sourceAsset,
destAsset,
destAddress,
messageMetadata,
Wallet.fromMnemonic(
process.env.ETH_USDC_WHALE_MNEMONIC ??
'test test test test test test test test test test test junk',
).address.toLowerCase(),
)
: Promise.resolve();

const [newBalance] = await Promise.all([
Expand Down
1 change: 1 addition & 0 deletions bouncer/shared/gaslimit_ccm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ async function testGasLimitSwap(
destAsset,
destAddress,
messageMetadata,
undefined,
() => stopObservingCcmReceived,
).then((event) => {
if (event)
Expand Down
9 changes: 5 additions & 4 deletions bouncer/shared/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ export async function observeBalanceIncrease(
address: string,
oldBalance: string,
): Promise<number> {
for (let i = 0; i < 120; i++) {
for (let i = 0; i < 1200; i++) {
const newBalance = Number(await getBalance(dstCcy as Asset, address));
if (newBalance > Number(oldBalance)) {
return newBalance;
Expand Down Expand Up @@ -323,7 +323,7 @@ export async function observeEVMEvent(
contractAbi: any,
address: string,
eventName: string,
eventParametersExpected: string[],
eventParametersExpected: (string | null)[],
stopObserveEvent?: () => boolean,
initialBlockNumber?: number,
): Promise<EVMEvent | undefined> {
Expand All @@ -338,7 +338,7 @@ export async function observeEVMEvent(
// Get the parameter names of the event
const parameterNames = eventAbi.inputs.map((input) => input.name);

for (let i = 0; i < 120; i++) {
for (let i = 0; i < 1200; i++) {
if (stopObserve()) return undefined;
const currentBlockNumber = await web3.eth.getBlockNumber();
if (currentBlockNumber >= initBlockNumber) {
Expand Down Expand Up @@ -379,6 +379,7 @@ export async function observeCcmReceived(
destAsset: Asset,
address: string,
messageMetadata: CcmDepositMetadata,
sourceAddress?: string,
stopObserveEvent?: () => boolean,
): Promise<EVMEvent | undefined> {
return observeEVMEvent(
Expand All @@ -387,7 +388,7 @@ export async function observeCcmReceived(
'ReceivedxSwapAndCall',
[
chainContractIds[assetChains[sourceAsset]].toString(),
'*',
sourceAddress ?? null,
messageMetadata.message,
getEthContractAddress(destAsset.toString()),
'*',
Expand Down
24 changes: 24 additions & 0 deletions ci/docker/prod/chainflip-btc-deposit-tracker.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FROM debian:bullseye
ARG BUILD_DATETIME
ARG VCS_REF

LABEL org.opencontainers.image.authors="dev@chainflip.io"
LABEL org.opencontainers.image.vendor="Chainflip Labs GmbH"
LABEL org.opencontainers.image.title="chainflip/chainflip-btc-deposit-tracker"
LABEL org.opencontainers.image.source="https://github.com/chainflip-io/chainflip-backend/blob/${VCS_REF}/ci/docker/chainflip-binaries/prod/chainflip-btc-deposit-tracker.Dockerfile"
LABEL org.opencontainers.image.revision="${VCS_REF}"
LABEL org.opencontainers.image.created="${BUILD_DATETIME}"
LABEL org.opencontainers.image.environment="production"
LABEL org.opencontainers.image.documentation="https://github.com/chainflip-io/chainflip-backend"

RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates && \
rm -rf /var/lib/apt/lists/*

COPY chainflip-btc-deposit-tracker /usr/local/bin/chainflip-btc-deposit-tracker

WORKDIR /etc/chainflip

RUN chmod +x /usr/local/bin/chainflip-btc-deposit-tracker

CMD ["/usr/local/bin/chainflip-btc-deposit-tracker"]
22 changes: 22 additions & 0 deletions ci/docker/prod/chainflip-engine-databases.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
FROM debian:bullseye
ARG BUILD_DATETIME
ARG VCS_REF

LABEL org.opencontainers.image.authors="dev@chainflip.io"
LABEL org.opencontainers.image.vendor="Chainflip Labs GmbH"
LABEL org.opencontainers.image.title="chainflip/chainflip-engine"
LABEL org.opencontainers.image.source="https://github.com/chainflip-io/chainflip-backend/blob/${VCS_REF}/ci/docker/chainflip-binaries/prod/chainflip-engine-databases.Dockerfile"
LABEL org.opencontainers.image.revision="${VCS_REF}"
LABEL org.opencontainers.image.created="${BUILD_DATETIME}"
LABEL org.opencontainers.image.environment="production"
LABEL org.opencontainers.image.documentation="https://github.com/chainflip-io/chainflip-backend"

WORKDIR /databases/3-node
COPY ./localnet/init/keyshare/3-node/bashful.db bashful.db
COPY ./localnet/init/keyshare/3-node/doc.db doc.db
COPY ./localnet/init/keyshare/3-node/dopey.db dopey.db

WORKDIR /databases/1-node
COPY ./localnet/init/keyshare/1-node/bashful.db bashful.db

WORKDIR /databases/
1 change: 1 addition & 0 deletions engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ futures-util = "0.3.14"
hex = "0.4.3"
httparse = "1.4.1"
itertools = "0.11"
prometheus = { version = "0.13.0", default-features = false }

# Same version of jsonrpsee as the substrate version our StateChain is on.
jsonrpsee = { version = "0.16.2", features = ["full"] }
Expand Down
4 changes: 4 additions & 0 deletions engine/config/CI/config/Settings.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ private_key_file = "eth_private_key_file"
[health_check]
hostname = "0.0.0.0"
port = 5555

[prometheus]
hostname = "0.0.0.0"
port = 5566
Loading

0 comments on commit c7622a9

Please sign in to comment.