From 0c546836db770b4281b90d15b08d868b4ec6c696 Mon Sep 17 00:00:00 2001 From: Alexandre Date: Tue, 17 Jun 2025 15:34:30 +0200 Subject: [PATCH 1/8] docs: add fetch and verify proof example script --- examples/sdk/fetchAndVerifyProofOfRead.ts | 174 ++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 examples/sdk/fetchAndVerifyProofOfRead.ts diff --git a/examples/sdk/fetchAndVerifyProofOfRead.ts b/examples/sdk/fetchAndVerifyProofOfRead.ts new file mode 100644 index 000000000..a828638c5 --- /dev/null +++ b/examples/sdk/fetchAndVerifyProofOfRead.ts @@ -0,0 +1,174 @@ +/** + * t1 Protocol - Proof of Read Verification Example Script + * + * This script demonstrates how to fetch and verify cross-chain read proofs using the t1 Protocol. + * It retrieves Merkle proofs for cross-chain read operations from t1's API and verifies them on-chain via t1 XChainReader contract. + * + * Before running this script, ensure you have: + * 1. Node.js and npm installed + * 2. Installed dependencies (ethers.js) + * 3. A valid Ethereum address that has performed cross-chain reads through t1 Protocol + * + * Usage: node fetchAndVerifyProofOfRead + * - requester_address: The Ethereum address that initiated cross-chain reads + * - direction: Either "ARB_TO_BASE" or "BASE_TO_ARB" for the cross-chain direction + * + * Example: node fetchAndVerifyProofOfRead 0x1234567890123456789012345678901234567890 ARB_TO_BASE + */ + +import { ethers } from 'ethers'; + +enum Direction { + ARB_TO_BASE = 'L1_TO_L2', + BASE_TO_ARB = 'L2_TO_L1', +} + +interface ClaimInfo { + from: string; + to: string; + value: string; + nonce: string; + message: string; + x_chain_read_result: string; + request_id: string; + handle_read_result_with_proof_calldata: string; + proof: { + batch_index: string; + merkle_proof: string; + }; +} + +interface Result { + source_tx_hash: string; + message_type: number; + block_number: number; + message_hash: string; + tx_sender: string; + direction: Direction; + claim_info: ClaimInfo; +} + +interface ReadProofsResponse { + results: Result[]; + page: number; + page_size: number; + total: number; +} + +interface VerifiedProofReturn { + requestId: string; + result: string; +} + +const XCHAINREADER_ABI = [ + 'function verifyProofOfRead(bytes encodedProofOfRead) external view returns (bytes32, bytes)', +]; +const API_BASE_URL = 'https://api.v05.t1protocol.com/api'; +const ARB_RPC_URL = 'https://arbitrum-sepolia-rpc.publicnode.com'; +const BASE_RPC_URL = 'https://base-sepolia-rpc.publicnode.com'; +const ARB_XCHAINREADER_ADDRESS = '0x42d389A9007e446b92C0ce7bd8F42Ea10292881B'; +const BASE_XCHAINREADER_ADDRESS = '0x3821b214B4c9D053fa744dc2B355E2039696dFb7'; + +async function getMerkleProofs( + address: string, + direction: Direction, + page: number = 1, + pageSize: number = 100, +): Promise { + const url = `${API_BASE_URL}/read-proofs?address=${address}&direction=${direction}&page=${page}&page_size=${pageSize}`; + + console.log(`Fetching Merkle proofs from: ${url}`); + + const response = await fetch(url); + + if (!response.ok) { + throw new Error( + `Failed to fetch proofs: ${response.status} ${response.statusText}`, + ); + } + + const { data } = await response.json(); + return data; +} + +async function verifyProofOfRead( + direction: Direction, + proofCalldata: string, +): Promise { + const provider = new ethers.JsonRpcProvider( + direction === Direction.ARB_TO_BASE ? ARB_RPC_URL : BASE_RPC_URL, + ); + const contract = new ethers.Contract( + direction === Direction.ARB_TO_BASE + ? ARB_XCHAINREADER_ADDRESS + : BASE_XCHAINREADER_ADDRESS, + XCHAINREADER_ABI, + provider, + ); + + try { + const response = await contract.verifyProofOfRead(proofCalldata); + return { requestId: response[0], result: response[1] }; + } catch (error) { + console.error('Error verifying proof:', error); + return undefined; + } +} + +async function main() { + const address = process.argv[2]; + const direction = process.argv[3]; + + if ( + !address || + (direction !== 'ARB_TO_BASE' && direction !== 'BASE_TO_ARB') + ) { + console.error( + 'Usage: npm run dev ', + ); + process.exit(1); + } + + const parsedDirection = + direction === 'ARB_TO_BASE' ? Direction.ARB_TO_BASE : Direction.BASE_TO_ARB; + + try { + console.log(`Getting Merkle proofs for address: ${address}`); + + const response = await getMerkleProofs(address, parsedDirection); + + if (response.results.length === 0) { + console.log('No proofs found for this address.'); + return; + } + + console.log(`Found ${response.results.length} proof(s)`); + + for (let i = 0; i < response.results.length; i++) { + const item = response.results[i]; + + console.log(`\nVerifying proof ${i + 1}/${response.results.length}:`); + console.log(`- Request ID: ${item.claim_info.request_id}`); + console.log(`- Source TX Hash: ${item.source_tx_hash}`); + console.log(`- Batch Index: ${item.claim_info.proof.batch_index}`); + + const res = await verifyProofOfRead( + parsedDirection, + item.claim_info.handle_read_result_with_proof_calldata, + ); + + if (!res) { + console.log('Proof verification FAILED'); + } else { + console.log('Proof verification SUCCESSFUL'); + } + } + + console.log('\nProof verifications completed'); + } catch (error) { + console.error('Error:', error); + process.exit(1); + } +} + +main().catch(console.error); From 5e8a31167df502dd6f25554dc3a78179c1ffc399 Mon Sep 17 00:00:00 2001 From: Alexandre Date: Thu, 19 Jun 2025 16:11:20 +0200 Subject: [PATCH 2/8] docs: document solver integration --- docs/7683/solver-integration.md | 155 ++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 docs/7683/solver-integration.md diff --git a/docs/7683/solver-integration.md b/docs/7683/solver-integration.md new file mode 100644 index 000000000..7c320aeec --- /dev/null +++ b/docs/7683/solver-integration.md @@ -0,0 +1,155 @@ +# t1 intents protocol: solver integration + +Our intent protocol implements the ERC 7683 specification. + +The workflow is the same for intents opening, filling and settlement. + + +There is only a difference in the process for settlement of solvers on origin chain. + +Solvers need to require a so called Proof of Read, and then use a merkle proof to get repaid. + +## Workflow + +Here is the full workflow from intent open to settlement (t1 specific steps with 🔴) : + +1 - Intent is opened on source chain settler contract (whether on chain by user or gasslessly by solver) + +2 - Solver listen for open event on source chain settler contract and fill on destination chain settler contract + +🔴 3 - Solver call a verify function on source chain settler contract + +🔴 4 - Solver listen for new Proof of Read commitment event on source chain XChainReader contract + +🔴 5 - Solver call t1 offchain API to get the merkle proof data + +🔴 6 - Solver call settlement function on source chain settler contract and get repaid + +## Implementation + +Here is how you integrate from step 3. + +### 3 - Solver call a verify function on source chain settler contract + +Location: source chain + +Contract: T1ERC7683 (see deployment file for address and ABI) + +Timing: should be called once intent is filled on destination chain + +```solidity + /// @param destinationDomain The chain id of the destination chain + /// @param gasLimit The gas limit for the read operation + /// @param orderId The ID of the order to verify fillment + /// @return requestId The ID of the read request + function verifySettlement( + uint32 destinationDomain, + uint256 gasLimit, + bytes32 orderId + ) + payable + returns (bytes32 requestId); +``` + +### 4 - Solver listen for new Proof of Read commitment event on source chain XChainReader contract + +Location: source chain + +Contract: T1XChainReader (see deployment file for address and ABI) + +Timing: should be listened to once `verifySettlement` has been called + +```solidity + /// @param batchIndex The index where the Proof of Read batch has been committed + event ProofOfReadRootCommitted(uint256 batchIndex); +``` + +### 5 - Solver call t1 offchain API to get the merkle proof data + +Location: offchain + +Timing: once a new `ProofOfReadRootCommitted` event has been emitted + +Base URL: `https://api.v05.t1protocol.com` + +Endpoint: `/api/read-proofs` + +Method: `GET` + +**Query Parameters:** +| Parameter | Type | Optional | Description | Value suggested | +|-----------|------|----------|-------------|---------| +| `address` | string | No | Address that called `verifySettlement` | - | +| `direction` | string | Yes | Direction of the read: `"L1_TO_L2"` \| `"L2_TO_L1"` | - | +| `page` | number | Yes | Page number to fetch | `1` | +| `page_size` | number | Yes | Items per page | `100` | + +**Example Request:** +```bash +curl "https://api.v05.t1protocol.com/api/read-proofs?address=0x123...&direction=L1_TO_L2&page=1&page_size=100" +``` + +The HTTP call will return the following structure as a response : + +```typescript +interface ReadProofsResponse { + results: Result[]; + page: number; + page_size: number; + total: number; +} + +interface Result { + source_tx_hash: string; + message_type: number; + block_number: number; + message_hash: string; + tx_sender: string; + direction: Direction; + claim_info: ClaimInfo; +} + +enum Direction { + L1_TO_L2 = 'L1_TO_L2', + L2_TO_L1 = 'L2_TO_L1', +} + +interface ClaimInfo { + from: string; + to: string; + value: string; + nonce: string; + message: string; + x_chain_read_result: string; + request_id: string; + handle_read_result_with_proof_calldata: string; + proof: { + batch_index: string; + merkle_proof: string; + }; +} + +``` + +Solver will then iterate on the `results` array and find the one that matches its request. + +Solver can check values like `source_tx_hash` or `tx_sender` for that. + +Solver will then get the value in `claim_info.handle_read_result_with_proof_calldata` from the matching result for next step. + +See more: https://docs.t1protocol.com/api/xChainRead/overview + +### 6 - Solver call settlement function on source chain settler contract and get repaid + +Location: source chain + +Contract: T1ERC7683 (see deployment file for address and ABI) + +Timing: should be called once new `ProofOfReadRootCommitted` event has been emitted and merkle proof has been fetched from API + +```solidity + /// @param encodedProofOfRead The encoded proof of read which is formatted as following: + /// abi.encode(uint256 batchIndex, bytes32 requestId, uint256 position, bytes result, bytes proof) + /// This is the value returned in previous step as `handle_read_result_with_proof_calldata` + function handleReadResultWithProof(bytes encodedProofOfRead); +``` From 149c0da1193957741eec9dc575dd2c973d81ad87 Mon Sep 17 00:00:00 2001 From: Alexandre Wolff <55669233+aharvet@users.noreply.github.com> Date: Wed, 25 Jun 2025 14:17:59 +0200 Subject: [PATCH 3/8] Update docs/7683/solver-integration.md Co-authored-by: Krzysztof Spisak-Spisacki Signed-off-by: Alexandre Wolff <55669233+aharvet@users.noreply.github.com> --- docs/7683/solver-integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/7683/solver-integration.md b/docs/7683/solver-integration.md index 7c320aeec..ed4ab1e1d 100644 --- a/docs/7683/solver-integration.md +++ b/docs/7683/solver-integration.md @@ -15,7 +15,7 @@ Here is the full workflow from intent open to settlement (t1 specific steps with 1 - Intent is opened on source chain settler contract (whether on chain by user or gasslessly by solver) -2 - Solver listen for open event on source chain settler contract and fill on destination chain settler contract +2 - Solver listens for open event on source chain settler contract and fill on destination chain settler contract 🔴 3 - Solver call a verify function on source chain settler contract From 5a5ad0eccae59c4facef15bee603fa3c2a55795e Mon Sep 17 00:00:00 2001 From: Alexandre Wolff <55669233+aharvet@users.noreply.github.com> Date: Wed, 25 Jun 2025 14:18:57 +0200 Subject: [PATCH 4/8] Update docs/7683/solver-integration.md Co-authored-by: Krzysztof Spisak-Spisacki Signed-off-by: Alexandre Wolff <55669233+aharvet@users.noreply.github.com> --- docs/7683/solver-integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/7683/solver-integration.md b/docs/7683/solver-integration.md index ed4ab1e1d..0e87fa8d1 100644 --- a/docs/7683/solver-integration.md +++ b/docs/7683/solver-integration.md @@ -17,7 +17,7 @@ Here is the full workflow from intent open to settlement (t1 specific steps with 2 - Solver listens for open event on source chain settler contract and fill on destination chain settler contract -🔴 3 - Solver call a verify function on source chain settler contract +🔴 3 - Solver calls a verify function on source chain settler contract 🔴 4 - Solver listen for new Proof of Read commitment event on source chain XChainReader contract From 72bf531cfd22a653cd823fbe80a0beb978c64baa Mon Sep 17 00:00:00 2001 From: Alexandre Wolff <55669233+aharvet@users.noreply.github.com> Date: Wed, 25 Jun 2025 14:22:16 +0200 Subject: [PATCH 5/8] Update solver-integration.md Signed-off-by: Alexandre Wolff <55669233+aharvet@users.noreply.github.com> --- docs/7683/solver-integration.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/7683/solver-integration.md b/docs/7683/solver-integration.md index 0e87fa8d1..e6f0243cb 100644 --- a/docs/7683/solver-integration.md +++ b/docs/7683/solver-integration.md @@ -11,9 +11,11 @@ Solvers need to require a so called Proof of Read, and then use a merkle proof t ## Workflow -Here is the full workflow from intent open to settlement (t1 specific steps with 🔴) : +Here is the full workflow from intent open to settlement (t1 specific steps with 🔴). -1 - Intent is opened on source chain settler contract (whether on chain by user or gasslessly by solver) +The settler contract implementation is `T1ERC7683.sol`. + +1 - Intent is opened on source chain settler contract whether on chain by user or gasslessly by solver 2 - Solver listens for open event on source chain settler contract and fill on destination chain settler contract From 69fab554cfab6f8544656c6f121572109ca05b45 Mon Sep 17 00:00:00 2001 From: Alexandre Wolff <55669233+aharvet@users.noreply.github.com> Date: Wed, 25 Jun 2025 14:22:37 +0200 Subject: [PATCH 6/8] Update docs/7683/solver-integration.md Co-authored-by: Krzysztof Spisak-Spisacki Signed-off-by: Alexandre Wolff <55669233+aharvet@users.noreply.github.com> --- docs/7683/solver-integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/7683/solver-integration.md b/docs/7683/solver-integration.md index e6f0243cb..64b8f55a4 100644 --- a/docs/7683/solver-integration.md +++ b/docs/7683/solver-integration.md @@ -21,7 +21,7 @@ The settler contract implementation is `T1ERC7683.sol`. 🔴 3 - Solver calls a verify function on source chain settler contract -🔴 4 - Solver listen for new Proof of Read commitment event on source chain XChainReader contract +🔴 4 - Solver listens for new Proof of Read commitment event on source chain XChainReader contract 🔴 5 - Solver call t1 offchain API to get the merkle proof data From 17a1c0e37c694baf75011281b8f6728075692775 Mon Sep 17 00:00:00 2001 From: Alexandre Wolff <55669233+aharvet@users.noreply.github.com> Date: Wed, 25 Jun 2025 14:22:45 +0200 Subject: [PATCH 7/8] Update docs/7683/solver-integration.md Co-authored-by: Krzysztof Spisak-Spisacki Signed-off-by: Alexandre Wolff <55669233+aharvet@users.noreply.github.com> --- docs/7683/solver-integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/7683/solver-integration.md b/docs/7683/solver-integration.md index 64b8f55a4..36da30023 100644 --- a/docs/7683/solver-integration.md +++ b/docs/7683/solver-integration.md @@ -23,7 +23,7 @@ The settler contract implementation is `T1ERC7683.sol`. 🔴 4 - Solver listens for new Proof of Read commitment event on source chain XChainReader contract -🔴 5 - Solver call t1 offchain API to get the merkle proof data +🔴 5 - Solver calls t1 offchain API to get the merkle proof data 🔴 6 - Solver call settlement function on source chain settler contract and get repaid From ab35794326eb96968a3c29383467d6695674b0b8 Mon Sep 17 00:00:00 2001 From: Alexandre Wolff <55669233+aharvet@users.noreply.github.com> Date: Wed, 25 Jun 2025 14:22:59 +0200 Subject: [PATCH 8/8] Update docs/7683/solver-integration.md Co-authored-by: Krzysztof Spisak-Spisacki Signed-off-by: Alexandre Wolff <55669233+aharvet@users.noreply.github.com> --- docs/7683/solver-integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/7683/solver-integration.md b/docs/7683/solver-integration.md index 36da30023..eb62e446f 100644 --- a/docs/7683/solver-integration.md +++ b/docs/7683/solver-integration.md @@ -25,7 +25,7 @@ The settler contract implementation is `T1ERC7683.sol`. 🔴 5 - Solver calls t1 offchain API to get the merkle proof data -🔴 6 - Solver call settlement function on source chain settler contract and get repaid +🔴 6 - Solver calls settlement function on source chain settler contract and get repaid ## Implementation