Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b4218a9
feat: added ci to update contracts
frolvanya Aug 18, 2025
7261945
chore: removed ssh agent
frolvanya Aug 18, 2025
af66cd9
provide max gas fee
olga24912 Aug 28, 2025
4dfb588
Bump version
karim-en Sep 2, 2025
d86c662
Merge pull request #3 from Near-One/max_gas_fee
karim-en Sep 2, 2025
9e9aa55
Merge pull request #1 from Near-One/feat/release-ci
karim-en Sep 2, 2025
da0c1d6
Fix release repo (#7)
karim-en Sep 17, 2025
fc60281
Add Zcash support (#2)
olga24912 Sep 19, 2025
a0a9e61
feat: implement safe deposit (#5)
karim-en Oct 9, 2025
88a7a33
Fix config migration (#12)
karim-en Oct 16, 2025
8c62c7d
fix sequence for rbf (#15)
olga24912 Oct 23, 2025
9381244
chore: added ci (#14)
frolvanya Oct 23, 2025
843af34
Improve `utxo_id` injection (#18)
karim-en Nov 19, 2025
624c46c
fix: `utxo_id` injection in nested json (#19)
frolvanya Nov 20, 2025
22510c0
Create and check proposals for update nBTC (#10)
olga24912 Nov 21, 2025
e06f92f
Activate NU6.1 on mainnet (#21)
karim-en Nov 26, 2025
533e461
feat: shielded TX support (#6)
karim-en Jan 12, 2026
bb1e2a5
Added CLAUDE.md and AGENTS.md (#25)
olga24912 Feb 16, 2026
3b00d85
feat: added trusted relayer (#26)
frolvanya Mar 26, 2026
042955e
chore: updated `omni-utils` (#27)
frolvanya Mar 27, 2026
abd0ed6
feat: unlimited pending sign txs whitelist (#31)
olga24912 Apr 17, 2026
b6a4725
feat: unlimited pending sign txs whitelist (#31)
olga24912 Apr 17, 2026
bc68214
Support BTC refund flow (#28)
olga24912 Apr 17, 2026
2afe466
fix: config migration (#34)
karim-en Apr 20, 2026
7e62867
feat: Add paged view for refund requests (#36)
olga24912 Apr 22, 2026
b4e2bf8
feat: removed lock time verification (#35)
frolvanya Apr 22, 2026
edab79a
Check gas fee < amount in refund (#37)
olga24912 Apr 22, 2026
26997f9
update refund timelock (#39)
olga24912 Apr 23, 2026
4a66906
fix safe mint (#38)
olga24912 Apr 23, 2026
9672b39
fix: test
karim-en Apr 23, 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
40 changes: 40 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: CI

on:
push:
branches:
- omni-main
pull_request:

permissions:
checks: write

jobs:
rust-checks:
runs-on: warp-ubuntu-latest-x64-4x
steps:
- uses: actions/checkout@v5

- name: Install system dependencies
run: sudo apt-get update && sudo apt-get install -y libudev-dev

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy

- name: Setup Rust cache
uses: Swatinem/rust-cache@v2
with:
cache-provider: warpbuild

- 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: Run tests
run: make test

43 changes: 43 additions & 0 deletions .github/workflows/update-contracts.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
on:
push:
tags:
- 'btc-bridge-v[0-9]+.[0-9]+.[0-9]+*'

workflow_dispatch:

name: Update Contracts
jobs:
update-contracts:
runs-on: ubuntu-latest
name: Update Contracts
permissions:
contents: write
steps:
- name: Clone the repository
uses: actions/checkout@v3

- 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 NEAR contracts
run: |
make release
timeout-minutes: 60

- name: Archive built WASM files
env:
RAW_TAG: ${{ github.ref_name }}
run: |
SAFE_TAG="${RAW_TAG//./-}"
ZIP_NAME="${SAFE_TAG}.zip"
mkdir -p artifacts
find ./res -name "*.wasm" -exec cp {} artifacts/ \;
zip -j "$ZIP_NAME" artifacts/*
shell: bash

- name: Create Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
files: "*.zip"
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CLAUDE.md
149 changes: 149 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# NEAR BTC/Zcash Bridge

Bridge between Bitcoin/Zcash and NEAR Protocol. Users deposit BTC/ZEC to receive nBTC/nZEC (NEP-141 token) and withdraw nBTC/nZEC to receive BTC/ZEC back.

**Trust Model:**
- **BTC → NEAR (deposit):** Trustless verification via BTC Light Client (Merkle proof validation)
- **NEAR → BTC (withdraw):** Requires trust in NEAR validator set for Chain Signatures (MPC)

---

## Build / Test / Lint

```bash
# Build for development (non-reproducible)
make build-local-bitcoin # Bitcoin bridge
make build-local-zcash # Zcash bridge

# Run tests
make test

# Format and clippy
cargo fmt --all # Format all code
make clippy-bitcoin # Clippy for Bitcoin
make clippy-zcash # Clippy for Zcash
```

---

## Key Architecture

**Contracts:** `contracts/nbtc/` (NEP-141 token), `contracts/satoshi-bridge/` (main bridge), `contracts/mock-*` (testing)

**External Dependencies:** BTC Light Client (Merkle proof verification), Chain Signatures (MPC signing)

### Bridge Flows

**Deposit (BTC → nBTC)**
```
1. User sends BTC to deposit address (derived from DepositMsg hash)
2. Relayer: bridge.verify_deposit(tx_proof)
3. Bridge verifies with Light Client → calls nbtc.mint(user, amount)
4. UTXO added to bridge's available set
```

**Withdraw (nBTC → BTC)**
```
1. User: nbtc.ft_transfer(bridge, amount, WithdrawMsg)
→ Tokens TRANSFERRED to bridge (not burned yet!)
2. nBTC: bridge.ft_on_transfer(user, amount, msg) → Bridge returns 0 (keeps tokens)
3. Bridge creates BTC tx, Chain Signatures signs
4. Tx broadcast to Bitcoin network
5. Relayer: bridge.verify_withdraw(tx_proof)
6. Bridge verifies → calls nbtc.burn(user, amount, relayer, fee)
→ Burns from bridge balance (tokens already there!)
```

---

## Security Invariants

### Token Flow (NEP-141)
- **Withdraw tokens already transferred:** By the time `burn()` is called, tokens are in bridge balance via `ft_transfer`
- **burn_account_id is for events only:** Actual burn happens from bridge balance, not from burn_account_id
- **ft_on_transfer return value:** `0` = keep all tokens, `amount` = refund amount
- Only burn after BTC tx is verified on-chain

### Arithmetic Safety
- **overflow-checks = true:** All overflow panics in release mode (fail-safe)
- Use `checked_mul()`, `checked_add()` for explicit error handling
- Prefer panic over silent

### State Management
- Mutate state (mark UTXO used, update balances) BEFORE cross-contract calls
- Create and emit events AFTER all state mutations complete
- **Cross-contract calls are NOT atomic:** Each callback is a separate transaction - must manually rollback state in callback if external call fails

### Zcash-Specific
- **Mutual exclusion:** `actual_received_amounts.len() == 1` ensures EITHER transparent OR Orchard output, never both
- **OVK required:** All Orchard bundles must provide valid Outgoing Viewing Key for decryption
- **Address restrictions:** Transparent addresses CANNOT accept Orchard bundles (panics)
- **Bridge transparency:** Full transaction tracking required, privacy is NOT a design goal
- **Branch IDs hardcoded:** Network upgrades require contract redeployment anyway

---

## Critical Patterns

**NEAR decorators:** `#[private]` for callbacks, `#[access_control_any(roles(...))]` for admin functions, `#[pause(except(roles(...)))]` for pausable functions, `assert_one_yocto()` to prevent batching

**Security checks:** Always use `require!(condition, "message")` for validation, `checked_*` arithmetic for money operations, emit events AFTER state changes

---

## Safe Functions (Omni Bridge Integration)

The bridge provides "safe" versions of deposit/mint functions primarily used by Omni Bridge:

### verify_deposit vs safe_verify_deposit

**verify_deposit (standard):**
- Normal deposit flow with fees
- Charges deposit bridge fee
- Pays for user's token storage
- Requires `safe_deposit: None` in DepositMsg
- Does NOT revert on mint failures (uses lost & found)

**safe_verify_deposit (integration):**
- Primarily used by Omni Bridge
- NO fees charged
- User must attach NEAR for storage (via `#[payable]`)
- **Reverts entire transaction if mint fails** (no lost & found)
- Requires `safe_deposit: Some(SafeDepositMsg)` in DepositMsg
- **post_actions must be None** (not supported in safe mode)
- Safer for integrations - atomic success/failure

### mint vs safe_mint (nbtc contract)

**mint (standard):**
- Mints tokens unconditionally
- If account not registered → panics or creates account

**safe_mint (integration):**
- Checks if account is registered first
- If NOT registered → returns `U128(0)` instead of panicking
- Used by safe_verify_deposit to detect failures

---

## Design Decisions (Non-Issues)

These patterns are intentional. Do not flag or "fix" them:

- **DAO powers are by design:** Governance functions with DAO role are necessary, not a vulnerability
- **Expiry height gap:** Buffer for transaction processing delays (Zcash)
- **No validation for self-serialized data:** Format guaranteed by construction - only validate external inputs
- **Public API vs private callbacks:** If parameter cannot be passed through public API, no vulnerability exists

---

## Git Workflow

**Main branch:** `omni-main` (use for PRs)

**Before committing:** Run `cargo test`, `cargo fmt`, `cargo clippy`. **Only commit if user explicitly requests.**

---

*Version: 2.1*
*Last Updated: 2026-02-16*
Loading
Loading