paralock_evm/lib.rs
1//! # paralock-evm
2//!
3//! The EVM layer of [Paralock](https://paralock.xyz) — trustless swaps between shielded ZEC and stablecoins on EVM
4//! chains (Tempo, Base, Ethereum, Arbitrum, Robinhood Chain, HyperEVM). It is the Rust counterpart of the TypeScript
5//! package `@paralock/evm`, built on [alloy](https://alloy.rs):
6//!
7//! - [`EvmHtlcClient`] for `ParalockHTLC` (htlc mode) and [`AdaptorEscrowClient`] for `ParalockAdaptorEscrow`
8//! (adaptor mode): exact approvals, lock, claim, refund, lock lookups with block and transaction, outcomes
9//! (empty / active / claimed with the preimage or signature / refunded), EVM time and balances;
10//! - the protocol math they rely on ([`hashlock_of`], [`HtlcSwap::commitment`], [`AdaptorSwap::id`],
11//! [`claim_digest`], [`ClaimSignature`] normalization), identical to the contracts and to `spec/vectors/evm.json`;
12//! - [`EvmConnection`]: chain-id verification before anything is sent, simulation with typed revert decoding
13//! ([`EvmError::TransactionReverted`], [`RevertReason`]), gas and fee estimation with a fee cap, process-wide nonce
14//! management, receipt waits with per-call timeouts ([`EvmConnection::send_and_confirm_with`]), fee bumps that
15//! replace a stuck transaction ([`EvmConnection::bump`]), status lookups ([`EvmConnection::transaction_status`]),
16//! and bounded retries with backoff on transport errors and 429/5xx. Every error raised after a transaction was
17//! signed carries its hash ([`EvmError::tx_hash`]);
18//! - escrow address checks against the embedded bytecode ([`EvmConnection::verify_escrow_code`]);
19//! - Tempo transactions that pay gas in a TIP-20 fee token, through Tempo's official `tempo-alloy` (feature `tempo`,
20//! on by default; opt out with `default-features = false` if you don't need fee tokens; see [`tempo`]);
21//! - [`KNOWN_NETWORKS`] (verified public networks and stablecoins) and [`TESTNET_DEPLOYMENTS`] (Paralock's public
22//! testnet contracts), and [`deploy_paralock_contracts`] for local chains.
23//!
24//! The clients need a Tokio runtime. Amounts are token base units ([`alloy::primitives::U256`]; every supported
25//! stablecoin has 6 decimals) and expiries are Unix **seconds** of EVM block time.
26//!
27//! ```no_run
28//! use paralock_evm::{EvmConfig, EvmConnection, EvmHtlcClient, HtlcSwap, ScanConfig, testnet_deployment};
29//! use alloy::primitives::{B256, U256};
30//!
31//! # async fn run() -> Result<(), paralock_evm::EvmError> {
32//! let deployment = testnet_deployment(84532).expect("Base Sepolia");
33//! let config = EvmConfig::new("https://sepolia.base.org", 84532).with_private_key("0x…")?;
34//! let conn = EvmConnection::connect(config).await?; // verifies the chain id
35//! let htlc = EvmHtlcClient::new(conn.clone(), deployment.htlc, ScanConfig::from_block(deployment.start_block));
36//!
37//! let preimage = B256::random();
38//! let swap = HtlcSwap {
39//! hashlock: paralock_evm::hashlock_of(&preimage),
40//! token: deployment.quote_token_address().expect("USDC"),
41//! sender: conn.address().expect("signer"),
42//! recipient: "0x36e33698492d087ee35db0830ba305faf075d087".parse().expect("address"),
43//! amount: U256::from(25_000_000u64), // 25 USDC
44//! expiry: htlc.now().await? + 3_600,
45//! };
46//! htlc.approve_and_lock(&swap).await?;
47//! println!("{:?}", htlc.outcome(swap.hashlock).await?);
48//! # Ok(()) }
49//! ```
50//!
51//! The code is experimental and not audited.
52#![forbid(unsafe_code)]
53#![cfg_attr(docsrs, feature(doc_cfg))]
54
55mod adaptor;
56pub mod artifacts;
57pub mod bindings;
58mod config;
59mod connection;
60mod deploy;
61mod error;
62mod escrow;
63mod htlc;
64mod locks;
65pub mod networks;
66#[cfg(test)]
67mod proptests;
68mod swap;
69pub mod tempo;
70mod transport;
71
72pub use adaptor::{AdaptorEscrowClient, AdaptorLock, AdaptorLockReceipt};
73pub use artifacts::{ContractArtifact, ParalockContract};
74pub use config::{EvmConfig, EvmSigner};
75pub use connection::{BlockInfo, EvmConnection, SentTx, TxRequest, TxResult, TxStatus, fetch_chain_id};
76pub use deploy::{
77 DeployOptions, DeployResult, LOCAL_MINT_AMOUNT, PreviousDeployment, Reused, deploy_paralock_contracts,
78 local_ousd_salt,
79};
80pub use error::{EvmError, RevertReason, RevertSource, SignatureError};
81pub use escrow::{LockReceipt, ScanConfig};
82pub use htlc::{EvmHtlcClient, HtlcState};
83pub use networks::{
84 EvmChainName, KNOWN_NETWORKS, KnownNetwork, ParalockDeployment, TESTNET_DEPLOYMENTS, TestnetDeployment,
85 known_network, known_networks, testnet_deployment,
86};
87pub use swap::{
88 AdaptorOutcome, AdaptorSwap, CLAIM_TYPEHASH, ClaimSignature, EscrowStatus, HTLC_EMPTY_STATE, HTLC_SETTLED_STATE,
89 HtlcOutcome, HtlcSwap, LockInfo, Outcome, SECP256K1_N, SECP256K1_N_HALF, adaptor_swap_id, address_of_public_key,
90 claim_digest, commitment_of, hashlock_of, random_salt,
91};
92pub use tempo::{
93 ANVIL_TEMPO_CHAIN_ID, TEMPO_CHAIN_IDS, TEMPO_TOKENS, TempoTokens, is_tempo_chain_id, is_tip20_address,
94};
95
96/// Re-export of the alloy version this crate is built on.
97pub use alloy;
98
99/// Compiles the README's examples as doctests.
100#[doc = include_str!("../README.md")]
101#[cfg(doctest)]
102pub struct ReadmeDoctests;