Skip to content
Draft
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
367 changes: 346 additions & 21 deletions Cargo.lock

Large diffs are not rendered by default.

10 changes: 8 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ members = [
"bridge-sdk/bridge-clients/utxo-bridge-client",
"bridge-sdk/bridge-clients/starknet-bridge-client",
"bridge-sdk/bridge-clients/aptos-bridge-client",
"bridge-sdk/bridge-clients/sui-bridge-client",
"bridge-sdk/bridge-clients/hypercore-bridge-client",
"bridge-sdk/crypto-utils",
"bridge-sdk/utxo-utils",
Expand Down Expand Up @@ -57,7 +58,7 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
base64 = "0.22"
near-token = "0.3"
near-contract-standards = "5.5"
omni-types = { git = "https://github.com/near-one/omni-bridge", package = "omni-types", rev = "f499d46c2d58869e4cbb5d19cff703ff7d2731d6" }
omni-types = { git = "https://github.com/near-one/omni-bridge", package = "omni-types", rev = "67b37e6c0277c42b5bc3ab76e202bec1ac4b4845" }
starknet = "0.17.0"
serde_with = { version = "3.12.0", features = ["schemars_0_8"] }
solana-sdk = "4.0.1"
Expand All @@ -82,9 +83,14 @@ spl-token = "9.0.0"
spl-token-2022-interface = "3.1.1"
spl-associated-token-account-interface = "2.0.0"
crypto-shared = { git = "https://github.com/near-one/mpc", package = "crypto-shared", rev = "463172481597ee09b12020b72c61d6b01da7b167" }
near-mpc-contract-interface = { git = "https://github.com/near/mpc", package = "near-mpc-contract-interface", rev = "dcc9e042cad6784d33cfa736afb61b876a14ded0" }
near-mpc-contract-interface = { git = "https://github.com/near/mpc", package = "near-mpc-contract-interface", rev = "9295cf29ee2761e44e00c67538859a1ef648285a" }
bcs = "0.1"
ed25519-dalek = "2"
sui-sdk-types = { version = "=0.3.2", features = ["serde", "hash"] }
sui-crypto = { version = "=0.3.1", features = ["ed25519", "bech32"] }
sui-transaction-builder = "=0.3.2"
sui-rpc = "=0.3.2"
tonic = "0.14"
openssl-sys = { version = "*", features = ["vendored"] }
light-client = { path = "bridge-sdk/light-client" }
zcash_primitives = { git = "https://github.com/Near-One/librustzcash", rev = "3dbb28e2254b309e3097a7995aa6dcf5a6d459c1", default-features = false, features = ["circuits", "test-dependencies", "transparent-inputs"] }
Expand Down
3 changes: 2 additions & 1 deletion bridge-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bridge-cli"
version = "0.3.66"
version = "0.3.67"
edition = "2021"
repository = "https://github.com/Near-One/bridge-sdk-rs"
rust-version = "1.88.0"
Expand Down Expand Up @@ -28,6 +28,7 @@ wormhole-bridge-client = { path = "../bridge-sdk/bridge-clients/wormhole-bridge-
utxo-bridge-client = { path = "../bridge-sdk/bridge-clients/utxo-bridge-client" }
starknet-bridge-client = { path = "../bridge-sdk/bridge-clients/starknet-bridge-client" }
aptos-bridge-client = { path = "../bridge-sdk/bridge-clients/aptos-bridge-client" }
sui-bridge-client = { path = "../bridge-sdk/bridge-clients/sui-bridge-client" }
hypercore-bridge-client = { path = "../bridge-sdk/bridge-clients/hypercore-bridge-client" }
utxo-utils = { path = "../bridge-sdk/utxo-utils" }
near-sdk.workspace = true
Expand Down
19 changes: 19 additions & 0 deletions bridge-cli/src/defaults.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ pub const APTOS_RPC_MAINNET: &str = "https://fullnode.mainnet.aptoslabs.com/v1";
pub const APTOS_BRIDGE_TOKEN_FACTORY_ADDRESS_MAINNET: &str =
"0xe4ec15f237e5a8c7daa7a34ece28e2bd2c079360763f181bf65862ec148b914a";

pub const SUI_RPC_MAINNET: &str = "https://fullnode.mainnet.sui.io";
// No mainnet deployment yet; placeholders until the Sui bridge ships on mainnet.
pub const SUI_BRIDGE_ADDRESS_MAINNET: &str =
"0x0000000000000000000000000000000000000000000000000000000000000000";
pub const SUI_STATE_OBJECT_ID_MAINNET: &str =
"0x0000000000000000000000000000000000000000000000000000000000000000";

pub const FOGO_RPC_MAINNET: &str = "https://mainnet.fogo.io";
pub const FOGO_BRIDGE_ADDRESS_MAINNET: &str = "dahPEoZGXfyV58JqqH85okdHmpN8U2q8owgPUXSCPxe";
pub const FOGO_WORMHOLE_ADDRESS_MAINNET: &str = "worm2mrQkG1B1KTz37erMfWN8anHkSK24nzca7UD8BB";
Expand Down Expand Up @@ -151,6 +158,12 @@ pub const APTOS_RPC_TESTNET: &str = "https://fullnode.testnet.aptoslabs.com/v1";
pub const APTOS_BRIDGE_TOKEN_FACTORY_ADDRESS_TESTNET: &str =
"0x904a7d620944eec42d5d46cf4fe12463f713c8a705d581c10a010672228f967c";

pub const SUI_RPC_TESTNET: &str = "https://fullnode.testnet.sui.io";
pub const SUI_BRIDGE_ADDRESS_TESTNET: &str =
"0x587d69879cb01f62a88526a7448424c37cf767387473c1e610bd007dc95fa6ba";
pub const SUI_STATE_OBJECT_ID_TESTNET: &str =
"0xcbe9d3824224eaa23e2ef70667fff857ddd0929b7c0e42935d509347505fe858";

pub const FOGO_RPC_TESTNET: &str = "https://testnet.fogo.io";
// pub const FOGO_BRIDGE_ADDRESS_TESTNET: &str = "";
pub const FOGO_WORMHOLE_ADDRESS_TESTNET: &str = "BhnQyKoQQgpuRTRo6D8Emz93PvXCYfVgHhnrR4T3qhw4";
Expand Down Expand Up @@ -228,6 +241,12 @@ pub const APTOS_RPC_DEVNET: &str = "https://fullnode.testnet.aptoslabs.com/v1";
pub const APTOS_BRIDGE_TOKEN_FACTORY_ADDRESS_DEVNET: &str =
"0x0000000000000000000000000000000000000000000000000000000000000000";

pub const SUI_RPC_DEVNET: &str = "https://fullnode.testnet.sui.io";
pub const SUI_BRIDGE_ADDRESS_DEVNET: &str =
"0x587d69879cb01f62a88526a7448424c37cf767387473c1e610bd007dc95fa6ba";
pub const SUI_STATE_OBJECT_ID_DEVNET: &str =
"0xcbe9d3824224eaa23e2ef70667fff857ddd0929b7c0e42935d509347505fe858";

pub const FOGO_RPC_DEVNET: &str = "https://testnet.fogo.io";
// pub const FOGO_BRIDGE_ADDRESS_DEVNET: &str = "";
pub const FOGO_WORMHOLE_ADDRESS_DEVNET: &str = FOGO_WORMHOLE_ADDRESS_TESTNET;
Expand Down
29 changes: 29 additions & 0 deletions bridge-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,15 @@ struct CliConfig {
#[arg(long)]
aptos_bridge_address: Option<String>,

#[arg(long)]
sui_rpc: Option<String>,
#[arg(long)]
sui_private_key: Option<String>,
#[arg(long)]
sui_bridge_address: Option<String>,
#[arg(long)]
sui_state_object_id: Option<String>,

#[arg(long)]
config: Option<String>,
}
Expand Down Expand Up @@ -311,6 +320,10 @@ impl CliConfig {
aptos_private_key: self.aptos_private_key.or(other.aptos_private_key),
aptos_account_address: self.aptos_account_address.or(other.aptos_account_address),
aptos_bridge_address: self.aptos_bridge_address.or(other.aptos_bridge_address),
sui_rpc: self.sui_rpc.or(other.sui_rpc),
sui_private_key: self.sui_private_key.or(other.sui_private_key),
sui_bridge_address: self.sui_bridge_address.or(other.sui_bridge_address),
sui_state_object_id: self.sui_state_object_id.or(other.sui_state_object_id),

config: self.config.or(other.config),
}
Expand Down Expand Up @@ -414,6 +427,10 @@ fn env_config() -> CliConfig {
aptos_private_key: env::var("APTOS_PRIVATE_KEY").ok(),
aptos_account_address: env::var("APTOS_ACCOUNT_ADDRESS").ok(),
aptos_bridge_address: env::var("APTOS_BRIDGE_ADDRESS").ok(),
sui_rpc: env::var("SUI_RPC").ok(),
sui_private_key: env::var("SUI_PRIVATE_KEY").ok(),
sui_bridge_address: env::var("SUI_BRIDGE_ADDRESS").ok(),
sui_state_object_id: env::var("SUI_STATE_OBJECT_ID").ok(),

config: None,
}
Expand Down Expand Up @@ -534,6 +551,10 @@ fn default_config(network: Network) -> CliConfig {
aptos_bridge_address: Some(
defaults::APTOS_BRIDGE_TOKEN_FACTORY_ADDRESS_MAINNET.to_owned(),
),
sui_rpc: Some(defaults::SUI_RPC_MAINNET.to_owned()),
sui_private_key: None,
sui_bridge_address: Some(defaults::SUI_BRIDGE_ADDRESS_MAINNET.to_owned()),
sui_state_object_id: Some(defaults::SUI_STATE_OBJECT_ID_MAINNET.to_owned()),

config: None,
},
Expand Down Expand Up @@ -650,6 +671,10 @@ fn default_config(network: Network) -> CliConfig {
aptos_bridge_address: Some(
defaults::APTOS_BRIDGE_TOKEN_FACTORY_ADDRESS_TESTNET.to_owned(),
),
sui_rpc: Some(defaults::SUI_RPC_TESTNET.to_owned()),
sui_private_key: None,
sui_bridge_address: Some(defaults::SUI_BRIDGE_ADDRESS_TESTNET.to_owned()),
sui_state_object_id: Some(defaults::SUI_STATE_OBJECT_ID_TESTNET.to_owned()),

config: None,
},
Expand Down Expand Up @@ -766,6 +791,10 @@ fn default_config(network: Network) -> CliConfig {
aptos_bridge_address: Some(
defaults::APTOS_BRIDGE_TOKEN_FACTORY_ADDRESS_DEVNET.to_owned(),
),
sui_rpc: Some(defaults::SUI_RPC_DEVNET.to_owned()),
sui_private_key: None,
sui_bridge_address: Some(defaults::SUI_BRIDGE_ADDRESS_DEVNET.to_owned()),
sui_state_object_id: Some(defaults::SUI_STATE_OBJECT_ID_DEVNET.to_owned()),

config: None,
},
Expand Down
120 changes: 116 additions & 4 deletions bridge-cli/src/omni_connector_command.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use clap::Subcommand;
use core::panic;
use near_mpc_contract_interface::types::{AptosFinality, EvmFinality, StarknetFinality};
use near_mpc_contract_interface::types::{
AptosFinality, EvmFinality, StarknetFinality, SuiFinality,
};
use std::collections::HashMap;
use std::{path::Path, str::FromStr};

Expand All @@ -24,6 +26,7 @@ use solana_bridge_client::{SolanaBridgeClientBuilder, SvmSigner};
use solana_rpc_client::nonblocking::rpc_client::RpcClient;
use solana_sdk::{signature::Keypair, signature::Signer as SolanaSigner, signer::EncodableKey};
use starknet_bridge_client::StarknetBridgeClientBuilder;
use sui_bridge_client::SuiBridgeClientBuilder;
use utxo_bridge_client::{
types::{Bitcoin, PrefetchedTxData, Zcash},
AuthOptions, UTXOBridgeClient,
Expand Down Expand Up @@ -619,6 +622,46 @@ pub enum OmniConnectorSubCommand {
config_cli: CliConfig,
},

#[clap(about = "Initialize a transfer on Sui")]
SuiInitTransfer {
#[clap(short, long, help = "Coin type on Sui (e.g. 0x2::sui::SUI)")]
token: String,
#[clap(short, long, help = "Amount to transfer")]
amount: u128,
#[clap(short, long, help = "Recipient address on the destination chain")]
recipient: OmniAddress,
#[clap(short, long, help = "Fee to charge for the transfer")]
fee: Option<u128>,
#[clap(short, long, help = "Native fee (in SUI) to charge for the transfer")]
native_fee: Option<u128>,
#[clap(short, long, help = "Additional message")]
message: Option<String>,
#[command(flatten)]
config_cli: CliConfig,
},
#[clap(about = "Finalize a transfer on Sui")]
SuiFinTransfer {
#[clap(
short,
long,
help = "Transaction hash of the sign_transfer call on NEAR"
)]
tx_hash: String,
#[clap(long, help = "Sender ID of the sign_transfer call on NEAR")]
sender_id: Option<AccountId>,
#[command(flatten)]
config_cli: CliConfig,
},
#[clap(
about = "Log token metadata on Sui (Sui tokens are types, so this takes the coin type instead of the LogMetadata token address)"
)]
SuiLogMetadata {
#[clap(short, long, help = "Coin type on Sui (e.g. 0x2::sui::SUI)")]
token: String,
#[command(flatten)]
config_cli: CliConfig,
},

#[clap(about = "Initialize an SVM OmniBridge program (Solana or Fogo)")]
SvmInitialize {
#[clap(long, help = "SVM chain (sol or fogo)")]
Expand Down Expand Up @@ -1056,6 +1099,9 @@ fn ensure_dry_run_supported(cmd: &OmniConnectorSubCommand, network: Network) {
| Cmd::EvmFinTransfer { config_cli, .. }
| Cmd::AptosInitTransfer { config_cli, .. }
| Cmd::AptosFinTransfer { config_cli, .. }
| Cmd::SuiInitTransfer { config_cli, .. }
| Cmd::SuiFinTransfer { config_cli, .. }
| Cmd::SuiLogMetadata { config_cli, .. }
| Cmd::StarknetInitTransfer { config_cli, .. }
| Cmd::StarknetFinTransfer { config_cli, .. }
// `initialize` needs the program keypair as a real signer; no dry-run.
Expand Down Expand Up @@ -1189,7 +1235,7 @@ pub async fn match_subcommand(cmd: OmniConnectorSubCommand, network: Network) {
.await
.unwrap();
}
ChainKind::Abs | ChainKind::Strk | ChainKind::Aptos => {
ChainKind::Abs | ChainKind::Strk | ChainKind::Aptos | ChainKind::Sui => {
omni_connector(network, config_cli)
.deploy_token(DeployTokenArgs::NearDeployTokenWithMpcProof {
chain_kind: source_chain,
Expand Down Expand Up @@ -1264,6 +1310,15 @@ pub async fn match_subcommand(cmd: OmniConnectorSubCommand, network: Network) {
.await
.unwrap();
}
ChainKind::Sui => {
omni_connector(network, config_cli)
.deploy_token(DeployTokenArgs::SuiDeployTokenWithTxHash {
near_tx_hash: CryptoHash::from_str(&tx_hash).expect("Invalid tx_hash"),
sender_id: None,
})
.await
.unwrap();
}
ChainKind::Zcash | ChainKind::Btc => {
panic!("DeployToken is not supported for UTXO chains");
}
Expand Down Expand Up @@ -1462,7 +1517,7 @@ pub async fn match_subcommand(cmd: OmniConnectorSubCommand, network: Network) {
.await
.unwrap();
}
ChainKind::Abs | ChainKind::Strk | ChainKind::Aptos => {
ChainKind::Abs | ChainKind::Strk | ChainKind::Aptos | ChainKind::Sui => {
connector
.fin_transfer(FinTransferArgs::NearFinTransferWithMpcProof {
chain_kind: chain,
Expand Down Expand Up @@ -1683,6 +1738,53 @@ pub async fn match_subcommand(cmd: OmniConnectorSubCommand, network: Network) {
.await
.unwrap();
}
OmniConnectorSubCommand::SuiInitTransfer {
token,
amount,
recipient,
fee,
native_fee,
message,
config_cli,
} => {
let (fee, native_fee) = match (fee, native_fee) {
(Some(f), Some(nf)) => (f, nf),
(Some(f), None) => (f, 0),
(None, Some(nf)) => (0, nf),
_ => (0, 0),
};

omni_connector(network, config_cli)
.init_transfer(InitTransferArgs::SuiInitTransfer {
token,
amount,
recipient: recipient.to_string(),
fee,
native_fee,
message: message.unwrap_or_default(),
})
.await
.unwrap();
}
OmniConnectorSubCommand::SuiFinTransfer {
tx_hash,
sender_id,
config_cli,
} => {
omni_connector(network, config_cli)
.fin_transfer(FinTransferArgs::SuiFinTransferWithTxHash {
near_tx_hash: CryptoHash::from_str(&tx_hash).expect("Invalid tx_hash"),
sender_id,
})
.await
.unwrap();
}
OmniConnectorSubCommand::SuiLogMetadata { token, config_cli } => {
omni_connector(network, config_cli)
.sui_log_metadata(token)
.await
.unwrap();
}

OmniConnectorSubCommand::SvmInitialize {
chain,
Expand Down Expand Up @@ -1838,7 +1940,7 @@ pub async fn match_subcommand(cmd: OmniConnectorSubCommand, network: Network) {
.await
.unwrap();
}
ChainKind::Abs | ChainKind::Strk | ChainKind::Aptos => {
ChainKind::Abs | ChainKind::Strk | ChainKind::Aptos | ChainKind::Sui => {
omni_connector(network, config_cli)
.bind_token(BindTokenArgs::BindTokenWithMpcProofTx {
chain_kind: chain,
Expand Down Expand Up @@ -2474,6 +2576,15 @@ fn omni_connector(network: Network, cli_config: CliConfig) -> OmniConnector {
.build()
.unwrap();

let sui_bridge_client = SuiBridgeClientBuilder::default()
.endpoint(combined_config.sui_rpc)
.private_key(combined_config.sui_private_key)
.bridge_address(combined_config.sui_bridge_address)
.state_object_id(combined_config.sui_state_object_id)
.mpc_finality(Some(SuiFinality::Checkpointed))
.build()
.unwrap();

OmniConnectorBuilder::default()
.network(Some(network.into()))
.near_bridge_client(Some(near_bridge_client))
Expand All @@ -2489,6 +2600,7 @@ fn omni_connector(network: Network, cli_config: CliConfig) -> OmniConnector {
.fogo_bridge_client(Some(fogo_bridge_client))
.starknet_bridge_client(Some(starknet_bridge_client))
.aptos_bridge_client(Some(aptos_bridge_client))
.sui_bridge_client(Some(sui_bridge_client))
.wormhole_bridge_client(Some(wormhole_bridge_client))
.btc_bridge_client(Some(btc_bridge_client))
.zcash_bridge_client(Some(zcash_bridge_client))
Expand Down
2 changes: 1 addition & 1 deletion bridge-sdk/bridge-clients/evm-bridge-client/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "evm-bridge-client"
version = "0.3.7"
version = "0.3.8"
edition = "2021"
rust-version = "1.96.0"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,8 @@ impl EvmBridgeClient {
| ChainKind::Btc
| ChainKind::Zcash
| ChainKind::Strk
| ChainKind::Aptos => Err(EvmBridgeClientError::InvalidArgument(format!(
| ChainKind::Aptos
| ChainKind::Sui => Err(EvmBridgeClientError::InvalidArgument(format!(
"Expected evm chain but got {chain_kind:?}"
))),
}
Expand Down Expand Up @@ -729,7 +730,8 @@ impl EvmBridgeClient {
| OmniAddress::Btc(_)
| OmniAddress::Zcash(_)
| OmniAddress::Strk(_)
| OmniAddress::Aptos(_) => Err(EvmBridgeClientError::InvalidArgument(format!(
| OmniAddress::Aptos(_)
| OmniAddress::Sui(_) => Err(EvmBridgeClientError::InvalidArgument(format!(
"Unsupported address type in SignTransferEvent: {address:?}",
))),
}
Expand Down
Loading
Loading