eth_twc_sdk/
lib.rs

1//! # eth-twc-sdk
2//!
3//! **TransferWithCommitment(TWC)** 向け Ethereum クライアント SDK(EIP-712・コントラクト呼び出し・レシート検証)。
4//!
5//! ## Usage
6//!
7//! 1. **TWC アドレス** — 通常ビルドでは [`config`] のソース([`transfer_with_commitment_address`] が返すコンパイル時定数)をデプロイ先に合わせる。`integration-test` 時のみ環境変数 `ETH_TWC_CONTRACT_ADDRESS` を参照します。
8//! 2. **プロバイダ** — Alloy の [`Provider`](alloy::providers::Provider)(例: `ProviderBuilder::new().connect_http(url)`)を用意します。
9//! 3. **送金** — EIP-712 委任なら [`sign`] で署名バンドルを作り [`send_transaction::signature_transfer`] で送信。`msg.sender` 送金なら [`send_transaction::self_transfer`] を直接呼びます。
10//! 4. **検証** — マイニング後のトランザクションハッシュと [`VerifyArgs`] で [`verify`] を呼び、レシート上の `TransferWithCommitmentSent` を照合します。
11//!
12//! `msg.sender` で送金して検証する例(接続チェーンの [`config::transfer_with_commitment_address`] に TWC がデプロイ済みであること)。
13//!
14//! ```ignore
15//! use alloy::primitives::{address, utils::parse_ether, B256};
16//! use alloy::providers::ProviderBuilder;
17//! use eth_twc_sdk::{
18//!     send_transaction::self_transfer,
19//!     types::SelfSingleTransferArgs,
20//!     verify,
21//!     VerifyArgs,
22//! };
23//!
24//! #[tokio::main]
25//! async fn main() -> Result<(), eth_twc_sdk::SdkError> {
26//!     let provider = ProviderBuilder::new().connect_http("http://127.0.0.1:8545".parse().unwrap());
27//!     let from = address!("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266");
28//!     let token = address!("0x5FbDB2315678afecb367f032d93F642f64180aa3");
29//!     let to = address!("0x70997970C51812dc3A010C7d01b50e0d17dc79C8");
30//!     let value = parse_ether("1").unwrap();
31//!     let commitment = B256::ZERO;
32//!
33//!     let args = SelfSingleTransferArgs {
34//!         token,
35//!         to,
36//!         value,
37//!         commitment,
38//!     };
39//!     let tx_hash = self_transfer::transfer(&provider, from, args).await?;
40//!
41//!     verify::verify(
42//!         &provider,
43//!         tx_hash,
44//!         &VerifyArgs {
45//!             from,
46//!             token,
47//!             to,
48//!             value,
49//!             commitment,
50//!         },
51//!     )
52//!     .await?;
53//!     Ok(())
54//! }
55//! ```
56//!
57//! EIP-712 署名を executor が送信し、同じく検証する例(読み取り用 Provider・署名者・executor 用ウォレット付き Provider)。
58//!
59//! ```ignore
60//! use alloy::network::EthereumWallet;
61//! use alloy::primitives::{address, utils::parse_ether, B256};
62//! use alloy::providers::ProviderBuilder;
63//! use alloy::signers::local::PrivateKeySigner;
64//! use eth_twc_sdk::{
65//!     send_transaction::signature_transfer,
66//!     sign,
67//!     types::SingleTransferArgs,
68//!     verify,
69//!     VerifyArgs,
70//! };
71//!
72//! #[tokio::main]
73//! async fn main() -> Result<(), eth_twc_sdk::SdkError> {
74//!     let read_provider =
75//!         ProviderBuilder::new().connect_http("http://127.0.0.1:8545".parse().unwrap());
76//!
77//!     let sender: PrivateKeySigner =
78//!         "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
79//!             .parse()
80//!             .unwrap();
81//!     let executor: PrivateKeySigner =
82//!         "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"
83//!             .parse()
84//!             .unwrap();
85//!
86//!     let token = address!("0x5FbDB2315678afecb367f032d93F642f64180aa3");
87//!     let to = address!("0x70997970C51812dc3A010C7d01b50e0d17dc79C8");
88//!     let value = parse_ether("1").unwrap();
89//!     let commitment = B256::ZERO;
90//!
91//!     let signed = sign::single_transfer(
92//!         &read_provider,
93//!         &sender,
94//!         SingleTransferArgs {
95//!             from: sender.address(),
96//!             to,
97//!             token,
98//!             executor: executor.address(),
99//!             value,
100//!             commitment,
101//!             valid_after: None,
102//!             valid_before: None,
103//!         },
104//!     )
105//!     .await?;
106//!
107//!     let executor_provider = ProviderBuilder::new()
108//!         .wallet(EthereumWallet::new(executor.clone()))
109//!         .connect_http("http://127.0.0.1:8545".parse().unwrap());
110//!     let tx_hash =
111//!         signature_transfer::single_transfer(&executor_provider, executor.address(), signed).await?;
112//!
113//!     verify::verify(
114//!         &read_provider,
115//!         tx_hash,
116//!         &VerifyArgs {
117//!             from: sender.address(),
118//!             token,
119//!             to,
120//!             value,
121//!             commitment,
122//!         },
123//!     )
124//!     .await?;
125//!     Ok(())
126//! }
127//! ```
128//!
129//! ## Commitment(`B256`)の導出 — 利用者向け注意
130//!
131//! 本クレートは **`commitment` を生成するヘルパを提供しない**。理由は、(1) 外部とランダム nonce を共有するスキームなど、アプリ層のスキーマとの**相互運用性**を SDK で固定しないため、(2) ハッシュ関数の選択を SDK に押し付けず、**ハッシュに関する単一障害点**にならないためである。
132//!
133//! オフチェーンで `commitment` を導出するときは、利用者の責任で **暗号学的にランダムな `r`** と、用途に適した**安全なハッシュ関数 `H`** を選び、少なくとも **`commitment = H(message || r)`** の形(`message` はアプリのスキーマに従うバイト列)を満たすことを推奨する。`H` の具体(例: Keccak-256)や `message` のエンコードは、アプリと合意者間で定義する。
134//!
135//! ## 構成
136//!
137//! | モジュール | 役割 |
138//! |------------|------|
139//! | [`config`] | 決定論 TWC アドレス・EIP-712 / CREATE2 salt 定数 |
140//! | [`sign`] | EIP-712 署名([`Provider`](alloy::providers::Provider) + [`Signer`](alloy::signers::Signer)) |
141//! | [`verify`] | トランザクションレシート上のイベント検証 |
142//! | [`send_transaction::self_transfer`] | `msg.sender` による `transfer` |
143//! | [`send_transaction::signature_transfer`] | 署名付き `transferWithAuthorization` / `cancelAuthorization` |
144//! | [`types`] | 引数・署名済みバンドル・明細型 |
145//! | [`utils`] | チェーン/domain 整合の検証ヘルパ |
146//! | [`events`] | ログデコード用イベント型 |
147//!
148//! オンチェーン呼び出し・型生成は **alloy** に依存します。
149//!
150//! ## クイックリンク
151//!
152//! - エラー型: [`SdkError`](署名 API は [`SdkError::FromSignerMismatch`] / [`SdkError::AuthorizerSignerMismatch`] で `from` / `authorizer` と署名キーの不一致を検出)
153//! - 検証用イベント引数: [`VerifyArgs`]
154//!
155//! ## ドキュメントの生成
156//!
157//! ```text
158//! cargo doc --no-deps
159//! ```
160//!
161//! 非公開モジュール(`contract` など)を含める場合は `--document-private-items` を付けます。
162
163pub mod config;
164
165pub use config::transfer_with_commitment_address;
166pub mod error;
167pub mod sign;
168pub mod types;
169pub mod utils;
170pub mod verify;
171
172/// レシート解析用の `sol!` イベント定義。
173pub mod events;
174
175/// トランザクション送信(自己送金・署名付き)。
176pub mod send_transaction;
177
178/// Ethereum アドレス([`alloy::primitives::Address`] の再エクスポート)。
179pub use alloy::primitives::Address;
180/// EIP-712 ドメイン([`alloy::sol_types::Eip712Domain`] の再エクスポート)。
181pub use alloy::sol_types::Eip712Domain;
182/// SDK 全体で用いるエラー型。
183pub use error::SdkError;
184pub use types::signed_data::{
185    SignedBatchTransferWithCommit, SignedCancelAuthorization, SignedTransferWithCommit,
186    SignedUniCommitTransfers,
187};
188/// [`verify`] に渡すオフチェーン検証引数。
189pub use verify::VerifyArgs;
190/// `sol!` が生成する `TransferWithCommitmentSent` イベント型([`SolEvent::decode_log`](alloy::sol_types::SolEvent::decode_log) の `.data` と同型)。
191pub use events::TransferWithCommitmentSent;
192pub use utils::{
193    assert_provider_supported_chain, assert_signed_domain_matches_client_and_config,
194    assert_signed_domain_matches_provider_and_config,
195};
196
197mod contract;