Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
118 commits
Select commit Hold shift + click to select a range
8b7e96e
provide metadata for nBTC
olga24912 Jul 3, 2025
5bffba6
fix satoshi bridge cargo toml
olga24912 Jul 3, 2025
21d3776
address -> script_pubkey
olga24912 Jul 8, 2025
a1db442
btc-p2wpkh -> utxo_chain
olga24912 Jul 8, 2025
b887eeb
remove btc_network
olga24912 Jul 8, 2025
7002936
draft zcash tx impl
olga24912 Jul 15, 2025
68883e2
fix consenses decode
olga24912 Jul 16, 2025
0f484cd
zcash_primitives
olga24912 Jul 16, 2025
5ebffa2
fix cargo toml
olga24912 Jul 16, 2025
2883749
test for script
olga24912 Jul 16, 2025
1f8932c
fix get output
olga24912 Jul 16, 2025
673da64
change signhash
olga24912 Jul 17, 2025
0307c59
Refactor transaction type
karim-en Jul 17, 2025
31a2e7f
Bump zcash_primitives version
karim-en Jul 17, 2025
6be07c5
Convert btc tx into zcash tx
karim-en Jul 18, 2025
0e96dd0
Set `final_script_sig`
karim-en Jul 18, 2025
527e439
Fix sighash
karim-en Jul 18, 2025
c78f4cf
fix
karim-en Jul 18, 2025
ff8d87a
fix sequence
olga24912 Jul 20, 2025
6a2f5e7
zcash build
olga24912 Jul 20, 2025
db2dc1d
add zcash features
olga24912 Jul 20, 2025
bdd78e5
AddressInner -> Address
olga24912 Jul 20, 2025
b6a54b2
new line
olga24912 Jul 20, 2025
c3cc9d9
test parse address
olga24912 Jul 20, 2025
15fa72b
test from pubkey
olga24912 Jul 21, 2025
dbbd678
improve tests
olga24912 Jul 21, 2025
e72188e
fix warnings
olga24912 Jul 21, 2025
d1f47ff
check zcash fee
olga24912 Jul 22, 2025
b467c49
safe expiry height
olga24912 Jul 23, 2025
15e0bd1
fix expiry_height
olga24912 Jul 23, 2025
31633fd
add rbf
olga24912 Jul 24, 2025
2f7cca2
fix sequence
olga24912 Jul 24, 2025
986564b
extract expire_height for cancel_withdraw
olga24912 Jul 24, 2025
ec69040
fix cancel active utxo managment
olga24912 Jul 24, 2025
1b124ca
fix active utxo managment
olga24912 Jul 24, 2025
cb67c3d
utxo_mamagment extract block height
olga24912 Jul 25, 2025
725f5bc
gap into config
olga24912 Jul 25, 2025
8380486
Replace last_block_header with last_block_height
karim-en Jul 30, 2025
dc4136d
construct output for zcash
olga24912 Aug 6, 2025
8caa61c
add simple try from address
olga24912 Aug 6, 2025
d471465
parse unified address
olga24912 Aug 6, 2025
dcf242c
script pubkey
olga24912 Aug 6, 2025
28bb108
fmt for unified address
olga24912 Aug 6, 2025
b1871d8
fix find receiver in list
olga24912 Aug 7, 2025
bda96c5
fix warnings
olga24912 Aug 8, 2025
b7531b0
safe psbt wraper
olga24912 Aug 8, 2025
36dcef4
deserialize
olga24912 Aug 8, 2025
c351bdf
move het hash to sign
olga24912 Aug 8, 2025
08cca99
extract tx byte
olga24912 Aug 8, 2025
86d3d76
save signature
olga24912 Aug 8, 2025
7d8601c
incapsulate psbt
olga24912 Aug 8, 2025
f5a2b2d
separate transaction
olga24912 Aug 11, 2025
b2d1eeb
separate expiry hight
olga24912 Aug 11, 2025
e6424da
separate psbt creation
olga24912 Aug 11, 2025
03b98ba
separate chain specific functions
olga24912 Aug 11, 2025
23c6dcd
separate zcash functions
olga24912 Aug 11, 2025
a292d73
separate zcash
olga24912 Aug 11, 2025
35f0f3c
fix btc
olga24912 Aug 11, 2025
54515e4
fix warnings
olga24912 Aug 11, 2025
1fffdc4
optimize get min fee
olga24912 Aug 12, 2025
4374342
remove psbt for zcash
olga24912 Aug 12, 2025
2a7c2dd
remove unsed function
olga24912 Aug 12, 2025
a69a203
add get_input_num and get_output_num
olga24912 Aug 12, 2025
91accdf
fix satoshi bridge
olga24912 Aug 12, 2025
d643f47
fix new
olga24912 Aug 12, 2025
f3638d0
make psbt field private
olga24912 Aug 13, 2025
a7fed6d
reduce copy past
olga24912 Aug 13, 2025
d629183
reduce copypast
olga24912 Aug 13, 2025
9429bb4
fix test contract config for zcash
olga24912 Aug 13, 2025
7ad9489
don't panic
olga24912 Aug 13, 2025
e93e376
fmt
olga24912 Aug 13, 2025
57762bd
reduce include
olga24912 Aug 13, 2025
4344a0e
updaye zcash_protocol
olga24912 Aug 13, 2025
0c7595f
fix chain id
olga24912 Aug 13, 2025
0182643
remove default
olga24912 Aug 13, 2025
68c072c
add version
olga24912 Aug 14, 2025
3482f1a
fix bitcoin connector
olga24912 Aug 14, 2025
8087bbb
remove bytes_to_btc_transaction
olga24912 Aug 18, 2025
5ec8b1d
don't use fully-qualified name
olga24912 Aug 18, 2025
d3bfdb1
fix bitcoin tests
olga24912 Aug 20, 2025
f1250b7
fix check block heigth for branch id
olga24912 Aug 20, 2025
f4ca9b9
save block height
olga24912 Aug 21, 2025
ca251c7
fix
olga24912 Aug 21, 2025
cbe475b
fix make
olga24912 Aug 21, 2025
4a3d3e5
fix valid confiramtions range
olga24912 Aug 21, 2025
f3103dd
Bump version
karim-en Aug 21, 2025
641d411
fix: use `U128` type for amount in `ft_on_transfer_callback`
frolvanya Aug 22, 2025
7e9057a
provide max gas fee
olga24912 Aug 28, 2025
3100dfa
Merge branch 'omni-main' into zcash_support
olga24912 Sep 5, 2025
e778abc
Add orchard support
karim-en Sep 12, 2025
2c4dc0a
Add comments
karim-en Sep 15, 2025
852f39f
Add comment
karim-en Sep 15, 2025
c8114f5
fix outputs checks
olga24912 Sep 29, 2025
945f087
Calculate sighash with `orchard_bundle`
karim-en Nov 19, 2025
43475c5
Implement Orchard Bundle Validation for Zcash Withdrawals (#20)
r-near Jan 6, 2026
3612052
Avoid extra clone of Orchard bundle
karim-en Jan 6, 2026
0be10b6
Replace panic with panic_str
karim-en Jan 7, 2026
95cd8ef
Bump version
karim-en Jan 7, 2026
0e88488
Fix clippy
karim-en Jan 7, 2026
2a7d703
Fix build variant
karim-en Jan 7, 2026
2960fb9
Fix orchard tests
karim-en Jan 7, 2026
c4341aa
Run lint and tests to CI
karim-en Jan 7, 2026
b347aef
Merge branch 'omni-main' into orchard_tx
karim-en Jan 7, 2026
2f0a2b8
Revert default
karim-en Jan 7, 2026
4db11cf
Remove added ci
karim-en Jan 7, 2026
ac14727
Remove unused fmt
karim-en Jan 7, 2026
089cc58
Fix tests
karim-en Jan 7, 2026
c9ec7e4
Fix orchard test
karim-en Jan 7, 2026
39f3c17
Fix orchard test
karim-en Jan 7, 2026
561e38e
Add missed `safe_deposit`
karim-en Jan 7, 2026
a80df03
add different wasm path
olga24912 Jan 8, 2026
cf0a130
fix orchard tests
olga24912 Jan 8, 2026
56f7687
fix test_base
olga24912 Jan 8, 2026
70dd014
fix check predecessor account id
olga24912 Jan 9, 2026
a07ebe1
fix test
olga24912 Jan 9, 2026
c43a72c
fix check outputs number
olga24912 Jan 12, 2026
629a189
unwrap -> expect
olga24912 Jan 12, 2026
dd4487c
extract expiry height check
olga24912 Jan 12, 2026
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
14 changes: 4 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,13 @@ jobs:
with:
cache-provider: warpbuild

- name: Check formatting
run: cargo fmt --all -- --check

- name: Run Clippy
run: cargo clippy --lib --bins --examples -- -D warnings -D clippy::pedantic -D clippy::as_conversions -A clippy::must_use_candidate -A clippy::needless_pass_by_value -A clippy::missing_panics_doc -A clippy::missing_errors_doc -A clippy::match_same_arms -A clippy::unused_self -A clippy::too_many_lines
- name: Run lint
run: make lint

- name: Install cargo-near
run: |
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/near/cargo-near/releases/latest/download/cargo-near-installer.sh | sh

- name: Build contracts
run: make build
timeout-minutes: 60

- name: Run tests
run: cargo test --all -- --nocapture
run: make test

6 changes: 5 additions & 1 deletion Cargo.lock

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

63 changes: 40 additions & 23 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,21 +1,48 @@
.PHONY: zcash-bridge
MAKEFILE_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
#INT_OPTIONS = -D warnings -D clippy::pedantic -A clippy::must_use_candidate -A clippy::used_underscore_binding -A clippy::needless_range_loop //TODO: enable it later
BRIDGE_MANIFEST := $(MAKEFILE_DIR)/contracts/satoshi-bridge/Cargo.toml

RFLAGS="-C link-arg=-s"

build: lint satoshi-bridge zcash-bridge nbtc mock-chain-signatures mock-btc-light-client mock-dapp
FEATURES = bitcoin zcash

lint:
release: $(addprefix build-,$(FEATURES))
$(call build_release_wasm,nbtc,nbtc)

build-local: $(addprefix build-local-,$(FEATURES)) nbtc mock-chain-signatures mock-btc-light-client mock-dapp

lint: $(addprefix clippy-,$(FEATURES)) $(addprefix fmt-,$(FEATURES))
@cargo fmt --all
@cargo clippy --fix --allow-dirty --allow-staged
@cargo clippy -- $(LINT_OPTIONS)

satoshi-bridge: contracts/satoshi-bridge
$(call local_build_wasm,satoshi-bridge,satoshi_bridge)
test: build-local $(addprefix test-,$(FEATURES))

zcash-bridge: contracts/satoshi-bridge
$(call local_build_zcash_wasm)
$(foreach feature,$(FEATURES), \
$(eval build-$(feature): ; \
cargo near build reproducible-wasm --variant "$(feature)" --manifest-path $(BRIDGE_MANIFEST) && \
mkdir -p res && mv ./target/near/satoshi_bridge/satoshi_bridge.wasm ./res/$(feature)_bridge_release.wasm \
) \
)

$(foreach feature,$(FEATURES), \
$(eval build-local-$(feature): ; \
cargo near build non-reproducible-wasm --features "$(feature)" --manifest-path $(BRIDGE_MANIFEST) --no-abi && \
mkdir -p res && mv ./target/near/satoshi_bridge/satoshi_bridge.wasm ./res/$(feature)_bridge.wasm \
) \
)

$(foreach feature,$(FEATURES), \
$(eval clippy-$(feature): ; cargo clippy --no-default-features --features "$(feature)" --manifest-path $(BRIDGE_MANIFEST) -- $(LINT_OPTIONS)) \
)

$(foreach feature,$(FEATURES), \
$(eval fmt-$(feature): ; cargo fmt --all --check --manifest-path $(BRIDGE_MANIFEST)) \
)

$(foreach feature,$(FEATURES), \
$(eval test-$(feature): ; cargo test --no-default-features --features "$(feature)" --manifest-path $(BRIDGE_MANIFEST)) \
)

nbtc: contracts/nbtc
$(call local_build_wasm,nbtc,nbtc)

mock-dapp: contracts/mock-dapp
$(call local_build_wasm,mock-dapp,mock_dapp)
Expand All @@ -26,19 +53,9 @@ mock-chain-signatures: contracts/mock-chain-signatures
mock-btc-light-client: contracts/mock-btc-light-client
$(call local_build_wasm,mock-btc-light-client,mock_btc_light_client)

count:
@tokei ./contracts/satoshi-bridge/src/ --files --exclude unit
@tokei ./contracts/nbtc/src/ --files

release:
$(call build_release_wasm,satoshi-bridge,satoshi_bridge)
$(call build_release_wasm,nbtc,nbtc)
$(call build_release_zcash_wasm)

clean:
cargo clean
rm -rf res/

nbtc: contracts/nbtc
$(call local_build_wasm,nbtc,nbtc)

define local_build_wasm
$(eval PACKAGE_NAME := $(1))
$(eval WASM_NAME := $(2))
Expand Down
5 changes: 5 additions & 0 deletions contracts/mock-btc-light-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,9 @@ impl Contract {
pub fn verify_transaction_inclusion(&self, #[serializer(borsh)] args: ProofArgs) -> bool {
true
}

pub fn get_last_block_height(&self) -> u32 {
// Return a reasonable mock block height for Zcash testnet
1000
}
}
25 changes: 12 additions & 13 deletions contracts/satoshi-bridge/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "satoshi-bridge"
version = "0.7.3"
version = "0.7.4"
edition.workspace = true
publish.workspace = true
repository.workspace = true
Expand All @@ -21,18 +21,11 @@ container_build_command = [
"--no-abi",
]

[package.metadata.near.reproducible_build.variant.bitcoin]
container_build_command = ["cargo", "near", "build", "non-reproducible-wasm", "--locked", "--no-abi", "--no-default-features", "--features", "bitcoin"]

[package.metadata.near.reproducible_build.variant.zcash]
container_build_command = [
"cargo",
"near",
"build",
"non-reproducible-wasm",
"--locked",
"--no-abi",
"--no-default-features",
"--features",
"zcash"
]
container_build_command = ["cargo", "near", "build", "non-reproducible-wasm", "--locked", "--no-abi", "--no-default-features", "--features", "zcash"]

[dependencies]
near-sdk.workspace = true
Expand All @@ -45,6 +38,8 @@ ed25519-dalek = "2.1.0"
crypto-shared = { git = "https://github.com/near/mpc_old", rev = "0afee9004a1b1c3386940e60c28cff7cf1b5978c" }
zcash_primitives = { version = "0.24.0", default-features = false, features = ["circuits", "transparent-inputs"], optional = true }
zcash_transparent = { version = "0.4.0", features = ["transparent-inputs"], optional = true }
orchard = { version = "0.11.0", default-features = false, optional = true }
sapling-crypto = { version = "0.5.0", default-features = false, optional = true }
zcash_protocol = { version = "0.6.1" }
core2 = { version = "0.3", optional = true }
zcash_address = { version = "0.9.0" }
Expand All @@ -55,7 +50,11 @@ getrandom = { version = "0.2.12", features = ["custom"] }
[dev-dependencies]
near-workspaces = { version = "0.20", features = ["unstable"] }
tokio = { version = "1.12.0", features = ["full"] }
rand = "0.8"
hex = "0.4"
bs58 = "0.5"

[features]
default = []
zcash = ["zcash_primitives", "zcash_transparent", "core2"]
zcash = ["zcash_primitives", "zcash_transparent", "orchard", "core2", "sapling-crypto"]
bitcoin = []
13 changes: 9 additions & 4 deletions contracts/satoshi-bridge/src/account.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{near, u128_dec_format, AccountId, Contract};
use near_sdk::env;
use std::collections::HashSet;

#[near(serializers = [borsh, json])]
Expand Down Expand Up @@ -85,16 +86,20 @@ impl Contract {
self.data()
.accounts
.get(account_id)
.map(Into::into)
.expect("ACCOUNT NOT REGISTERED")
.map(|o| o.into())
.unwrap_or_else(|| {
env::panic_str(&format!("ERR_ACCOUNT_NOT_REGISTERED: {}", account_id))
})
}

pub fn internal_unwrap_mut_account(&mut self, account_id: &AccountId) -> &mut Account {
self.data_mut()
.accounts
.get_mut(account_id)
.map(Into::into)
.expect("ACCOUNT NOT REGISTERED")
.map(|o| o.into())
.unwrap_or_else(|| {
env::panic_str(&format!("ERR_ACCOUNT_NOT_REGISTERED: {}", account_id))
})
}

pub fn internal_unwrap_or_create_mut_account(
Expand Down
31 changes: 20 additions & 11 deletions contracts/satoshi-bridge/src/api/bridge.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
use crate::{
assert_one_yocto, env, generate_utxo_storage_key, get_deposit_path, nano_to_sec, near,
psbt_wrapper::PsbtWrapper, require, AccessControllable, AccountId, BTCPendingInfo, Contract,
ContractExt, DepositMsg, Event, LockTime, OriginalState, OutPoint, Pausable, PendingInfoStage,
PendingInfoState, PendingUTXOInfo, Promise, Role, TxOut, WrappedTransaction, UTXO,
};
use crate::psbt_wrapper::PsbtWrapper;
use crate::*;
use near_plugins::{access_control_any, pause};

#[near]
Expand Down Expand Up @@ -204,7 +200,12 @@ impl Contract {
/// * `original_btc_pending_verify_id` - Pending verify ID of the original transaction.
/// * `output` - Modified output.
#[pause(except(roles(Role::DAO)))]
pub fn withdraw_rbf(&mut self, original_btc_pending_verify_id: String, output: Vec<TxOut>) {
pub fn withdraw_rbf(
&mut self,
original_btc_pending_verify_id: String,
output: Vec<TxOut>,
chain_specific_data: Option<ChainSpecificData>,
) {
let account_id = env::predecessor_account_id();
require!(
self.internal_unwrap_account(&account_id)
Expand All @@ -213,7 +214,12 @@ impl Contract {
"Previous btc tx has not been signed"
);

self.withdraw_rbf_chain_specific(account_id, original_btc_pending_verify_id, output);
self.withdraw_rbf_chain_specific(
account_id,
original_btc_pending_verify_id,
output,
chain_specific_data,
);
}

/// If the user's Withdraw is not verified within a certain time, the protocol can actively cancel the Withdraw through RBF, with the gas fee borne by the user.
Expand Down Expand Up @@ -242,6 +248,7 @@ impl Contract {
user_account_id,
original_btc_pending_verify_id,
output,
None,
);
}

Expand Down Expand Up @@ -327,6 +334,7 @@ impl Contract {
account_id,
original_btc_pending_verify_id,
output,
None,
);
}

Expand Down Expand Up @@ -359,6 +367,7 @@ impl Contract {
user_account_id,
original_btc_pending_verify_id,
output,
None,
);
}

Expand Down Expand Up @@ -416,17 +425,17 @@ impl Contract {
pub fn create_active_utxo_management_pending_info(
&mut self,
account_id: AccountId,
psbt: &mut PsbtWrapper,
mut psbt: PsbtWrapper,
) {
let account = self.internal_unwrap_account(&account_id);
require!(
account.btc_pending_sign_id.is_none(),
"Previous btc tx has not been signed"
);

let (utxo_storage_keys, vutxos) = self.generate_vutxos(psbt);
let (utxo_storage_keys, vutxos) = self.generate_vutxos(&mut psbt);
let (actual_received_amount, gas_fee) =
self.check_active_management_psbt_valid(psbt, &vutxos);
self.check_active_management_psbt_valid(&psbt, &vutxos);
require!(
gas_fee <= self.data().cur_available_protocol_fee,
"Insufficient protocol_fee"
Expand Down
22 changes: 9 additions & 13 deletions contracts/satoshi-bridge/src/api/token_receiver.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
use crate::{
env, nano_to_sec, near, psbt_wrapper::PsbtWrapper, require, serde_json, AccessControllable,
AccountId, BTCPendingInfo, Contract, ContractExt, Event, Gas, OriginalState, OutPoint,
Pausable, PendingInfoStage, PendingInfoState, PromiseOrValue, Role, TxOut, U128,
};

use crate::{psbt_wrapper::PsbtWrapper, *};
use near_contract_standards::fungible_token::receiver::FungibleTokenReceiver;
use near_plugins::pause;

Expand All @@ -12,11 +7,13 @@ pub const GAS_FOR_FT_ON_TRANSFER_CALL_BACK: Gas = Gas::from_tgas(100);
#[near(serializers = [json])]
pub enum TokenReceiverMessage {
DepositProtocolFee,
// Here is the withdraw message structure that will be sent from user or dApp to the btc/zcash connector
Withdraw {
target_btc_address: String,
input: Vec<OutPoint>,
output: Vec<TxOut>,
max_gas_fee: Option<U128>,
chain_specific_data: Option<ChainSpecificData>,
},
}

Expand Down Expand Up @@ -56,13 +53,15 @@ impl FungibleTokenReceiver for Contract {
input,
output,
max_gas_fee,
chain_specific_data,
} => self.ft_on_transfer_withdraw_chain_specific(
sender_id,
amount,
target_btc_address,
input,
output,
max_gas_fee,
chain_specific_data,
),
}
}
Expand All @@ -74,27 +73,24 @@ impl Contract {
sender_id: AccountId,
amount: u128,
target_btc_address: String,
psbt: &mut PsbtWrapper,
mut psbt: PsbtWrapper,
max_gas_fee: Option<U128>,
) {
let (utxo_storage_keys, vutxos) = self.generate_vutxos(psbt);
let (utxo_storage_keys, vutxos) = self.generate_vutxos(&mut psbt);
require!(
self.internal_unwrap_or_create_mut_account(&sender_id)
.btc_pending_sign_id
.is_none(),
"Previous btc tx has not been signed"
);
let target_address_script_pubkey = self
.internal_config()
.string_to_script_pubkey(&target_btc_address);

let withdraw_change_address_script_pubkey =
self.internal_config().get_change_script_pubkey();
let withdraw_fee = self.internal_config().withdraw_bridge_fee.get_fee(amount);
let (actual_received_amount, gas_fee) = self.check_withdraw_psbt_valid(
&target_address_script_pubkey,
target_btc_address.clone(),
&withdraw_change_address_script_pubkey,
psbt,
&psbt,
&vutxos,
amount,
withdraw_fee,
Expand Down
Loading