Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ crypto-shared = { git = "https://github.com/near-one/mpc", package = "crypto-sha
near-mpc-contract-interface = "0.0.1"
openssl-sys = { version = "*", features = ["vendored"] }
light-client = { path = "bridge-sdk/light-client" }
zcash_primitives = { git = "https://github.com/Near-One/librustzcash", rev = "63fdfdbecec3523dd3ca8eea247af83e4718a032", default-features = false, features = ["circuits", "test-dependencies", "transparent-inputs"] }
zcash_primitives = { git = "https://github.com/Near-One/librustzcash", rev = "63fdfdbecec3523dd3ca8eea247af83e4718a032", default-features = false, features = ["circuits", "test-dependencies", "transparent-inputs", "non-standard-fees"] }
zcash_transparent = { git = "https://github.com/Near-One/librustzcash", rev = "63fdfdbecec3523dd3ca8eea247af83e4718a032", features = ["transparent-inputs"] }
zcash_protocol = { git = "https://github.com/Near-One/librustzcash", rev = "63fdfdbecec3523dd3ca8eea247af83e4718a032" }
pczt = { git = "https://github.com/Near-One/librustzcash", rev = "63fdfdbecec3523dd3ca8eea247af83e4718a032", features = ["std", "signer", "io-finalizer", "prover", "signer", "tx-extractor", "spend-finalizer", "zcp-builder"] }
Expand Down
134 changes: 118 additions & 16 deletions bridge-cli/src/omni_connector_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,9 @@ struct ManualDepositInput {
///
/// - When `manual` is `Some`, builds `BtcDepositArgs` from the supplied
/// recipient/fee/msg/refund and resolves `vout` either from the explicit
/// value or by matching it against the derived deposit address.
/// value or by matching it against the derived deposit address (fetched
/// from the UTXO connector contract when `from_contract` is set, from the
/// bridge indexer otherwise).
/// - When `manual` is `None`, asks the bridge indexer (via
/// `resolve_deposit_from_tx`) which output is a tracked deposit address;
/// the recovered `DepositMsg` is wrapped as `BtcDepositArgs::DepositMsg`.
Expand All @@ -217,6 +219,7 @@ async fn resolve_btc_deposit(
btc_tx_hash: &str,
vout: Option<usize>,
manual: Option<ManualDepositInput>,
from_contract: bool,
) -> (BtcDepositArgs, usize, Option<PrefetchedTxData>) {
match manual {
Some(ManualDepositInput {
Expand Down Expand Up @@ -250,7 +253,13 @@ async fn resolve_btc_deposit(
Some(v) => (v, None),
None => {
let (v, p) = connector
.resolve_deposit_vout(chain, network, btc_tx_hash, &deposit_args)
.resolve_deposit_vout(
chain,
network,
btc_tx_hash,
&deposit_args,
from_contract,
)
.await
.unwrap();
(v, Some(p))
Expand Down Expand Up @@ -805,15 +814,11 @@ pub enum OmniConnectorSubCommand {
#[command(flatten)]
config_cli: CliConfig,
},
#[clap(about = "Request a refund for a never-finalized BTC deposit (Bitcoin only)")]
#[clap(about = "Request a refund for a never-finalized UTXO-chain deposit (Bitcoin/Zcash)")]
BtcRequestRefund {
#[clap(
short,
long,
help = "Chain the deposit was made on. Only Bitcoin is currently supported; the flag exists for forward compatibility."
)]
#[clap(short, long, help = "Chain the deposit was made on (Bitcoin/Zcash)")]
chain: UTXOChainArg,
#[clap(short, long, help = "Bitcoin deposit tx hash")]
#[clap(short, long, help = "Bitcoin/Zcash deposit tx hash")]
btc_tx_hash: String,
#[clap(
short,
Expand Down Expand Up @@ -852,16 +857,61 @@ pub enum OmniConnectorSubCommand {
no_deposit_refund_address: bool,
#[clap(long, help = "Optional custom gas fee in satoshi (DAO/Operator only)")]
gas_fee: Option<u128>,
#[clap(
long,
help = "Derive the deposit address via the UTXO connector contract view method (true, default) or the bridge indexer service (false). Only used with --recipient-id; auto-discovery always asks the indexer.",
default_value_t = true,
action = clap::ArgAction::Set
)]
from_contract: bool,
#[command(flatten)]
config_cli: CliConfig,
},
#[clap(about = "Verify the refund BTC transaction is confirmed (Bitcoin only)")]
#[clap(about = "Verify the refund transaction is confirmed on the UTXO chain (Bitcoin/Zcash)")]
BtcVerifyRefundFinalize {
#[clap(short, long, help = "Refund Bitcoin tx hash")]
#[clap(
short,
long,
help = "Chain the refund was made on (Bitcoin/Zcash)",
default_value = "btc"
)]
chain: UTXOChainArg,
#[clap(short, long, help = "Refund Bitcoin/Zcash tx hash")]
btc_tx_hash: String,
#[command(flatten)]
config_cli: CliConfig,
},
#[clap(
about = "Execute a previously requested refund, sending the deposit back to the refund address (Bitcoin/Zcash)"
)]
BtcExecuteRefund {
#[clap(short, long, help = "Chain the deposit was made on (Bitcoin/Zcash)")]
chain: UTXOChainArg,
#[clap(
long,
help = "Refund request key in the form `<tx_id>@<vout>`. Mutually exclusive with --btc-tx-hash/--vout."
)]
utxo_storage_key: Option<String>,
#[clap(
short,
long,
help = "Deposit tx hash; combined with --vout to form the refund request key. Ignored if --utxo-storage-key is given."
)]
btc_tx_hash: Option<String>,
#[clap(
short,
long,
help = "Index of the deposit output; combined with --btc-tx-hash to form the refund request key."
)]
vout: Option<usize>,
#[clap(
long,
help = "Transparent refund: send the deposit back to a transparent address with no Orchard bundle. For Zcash this overrides the default of auto-generating a shielded Orchard bundle; on Bitcoin refunds are always transparent."
)]
transparent: bool,
#[command(flatten)]
config_cli: CliConfig,
},
#[clap(about = "Finalize Transfer from Near on Bitcoin")]
BtcFinTransfer {
#[clap(short, long, help = "Chain for the UTXO rebalancing (Bitcoin/Zcash)")]
Expand Down Expand Up @@ -1730,6 +1780,7 @@ pub async fn match_subcommand(cmd: OmniConnectorSubCommand, network: Network) {
&btc_tx_hash,
vout,
manual,
false,
)
.await;

Expand Down Expand Up @@ -1807,13 +1858,10 @@ pub async fn match_subcommand(cmd: OmniConnectorSubCommand, network: Network) {
msg,
no_deposit_refund_address,
gas_fee,
from_contract,
config_cli,
} => {
let chain_kind: ChainKind = chain.into();
if chain_kind != ChainKind::Btc {
panic!("btc-request-refund currently supports only --chain btc; got {chain:?}");
}

let connector = omni_connector(network, config_cli);

let manual = match recipient_id {
Expand Down Expand Up @@ -1845,6 +1893,7 @@ pub async fn match_subcommand(cmd: OmniConnectorSubCommand, network: Network) {
&btc_tx_hash,
vout,
manual,
from_contract,
)
.await;

Expand All @@ -1867,6 +1916,7 @@ pub async fn match_subcommand(cmd: OmniConnectorSubCommand, network: Network) {
// transaction is printed as an unsigned payload instead of broadcast.
connector
.btc_request_refund(
chain_kind,
btc_tx_hash,
resolved_vout,
btc_deposit_args,
Expand All @@ -1879,11 +1929,63 @@ pub async fn match_subcommand(cmd: OmniConnectorSubCommand, network: Network) {
.unwrap();
}
OmniConnectorSubCommand::BtcVerifyRefundFinalize {
chain,
btc_tx_hash,
config_cli,
} => {
omni_connector(network, config_cli)
.btc_verify_refund_finalize(btc_tx_hash, TransactionOptions::default())
.btc_verify_refund_finalize(
chain.into(),
btc_tx_hash,
TransactionOptions::default(),
)
.await
.unwrap();
}
OmniConnectorSubCommand::BtcExecuteRefund {
chain,
utxo_storage_key,
btc_tx_hash,
vout,
transparent,
config_cli,
} => {
let chain_kind: ChainKind = chain.into();
let utxo_storage_key = match utxo_storage_key {
Some(key) => key,
None => {
let tx_id = btc_tx_hash.expect(
"Provide either --utxo-storage-key or both --btc-tx-hash and --vout",
);
let vout = vout.expect(
"Provide either --utxo-storage-key or both --btc-tx-hash and --vout",
);
format!("{tx_id}@{vout}")
}
};

let connector = omni_connector(network, config_cli);

// Zcash defaults to a shielded refund (auto-generated Orchard bundle);
// `--transparent` and Bitcoin refunds carry no bundle.
let chain_specific_data = if transparent || chain_kind != ChainKind::Zcash {
None
} else {
Some(
connector
.build_refund_chain_specific_data(&utxo_storage_key)
.await
.unwrap(),
)
};

connector
.btc_execute_refund(
chain_kind,
utxo_storage_key,
chain_specific_data,
TransactionOptions::default(),
)
.await
.unwrap();
}
Expand Down
Loading
Loading