-
Notifications
You must be signed in to change notification settings - Fork 0
Description
[SC-3] Deployment Scripts, Base Sepolia Deploy & Rust Backend EIP712 Integration
Labels: smart-contract, integration, priority:high, week-4
Assignee: Yash
Context
Per the Source of Truth (Sections 10, 11, and Week 3-4 milestone), the FishnetWallet needs deployment scripts for Base Sepolia and an end-to-end integration test proving that permits signed by the Rust backend are accepted by the on-chain contract. The Rust backend already has EIP712 signing logic (crates/server/src/signer.rs) — this issue ensures the two sides match exactly.
1. Foundry Deployment Script
File: contracts/script/Deploy.s.sol
- Deploy script using Foundry
forge script:contract DeployFishnetWallet is Script { function run() external { vm.startBroadcast(); FishnetWallet wallet = new FishnetWallet(owner, initialSigner); vm.stopBroadcast(); console.log("FishnetWallet deployed at:", address(wallet)); } } - Accept constructor args via environment variables:
OWNER_ADDRESS,SIGNER_ADDRESS - Output deployed contract address to console and to a JSON file (
deployments/base-sepolia.json) - Verification script — auto-verify on Basescan after deploy:
forge verify-contract <address> FishnetWallet --chain base-sepolia
2. Deploy to Base Sepolia
- Deploy FishnetWallet to Base Sepolia testnet (Chain ID: 84532)
- Fund wallet with testnet ETH for testing
- Verify contract source on BaseScan Sepolia explorer
- Record deployed address in
contracts/deployments/base-sepolia.json:{ "network": "base-sepolia", "chainId": 84532, "fishnetWallet": "0x...", "owner": "0x...", "signer": "0x...", "deployedAt": "2026-..." } - Document deployment steps in
contracts/README.md
3. EIP712 Compatibility Verification (Rust ↔ Solidity)
The Rust backend (crates/server/src/signer.rs) already generates EIP712 permit signatures. Ensure the two sides are perfectly aligned:
- PERMIT_TYPEHASH must match exactly:
- Rust: verify the typehash string in
signer.rsmatches the Solidity constant - Both must produce the same
keccak256hash
- Rust: verify the typehash string in
- EIP712 Domain must match exactly:
name = "Fishnet"(both sides)version = "1"(both sides)chainId— Rust uses the chain from permit request, Solidity usesblock.chainidverifyingContract— Rust must use the deployed wallet address, Solidity usesaddress(this)
- Struct encoding must match:
- Field order in
abi.encode()must match between Rust and Solidity - Type sizes must match (
uint64for chainId,uint48for expiry, etc.)
- Field order in
- Signature format:
- Rust produces
(v, r, s)or 65-byte packed signature - Solidity
ecrecoverexpects the correct unpacking
- Rust produces
4. End-to-End Integration Test
The Week 4 milestone test: "gateway signs permit, wallet executes swap"
- Test flow:
- Rust backend generates a secp256k1 signing key (or uses existing signer)
- Deploy FishnetWallet on Base Sepolia with that key's address as
fishnetSigner - Construct an onchain intent (e.g., call a test contract's function)
- Rust signs the intent as an EIP712
FishnetPermit - Submit the signed permit + calldata to the FishnetWallet contract
- Contract verifies signature and executes the call
- Verify the target contract's state changed
- Automated script:
scripts/integration-test.shor Rust integration test that:- Spins up a local Anvil fork of Base Sepolia
- Deploys contract
- Uses Rust signer to produce permit
- Submits transaction
- Asserts success
- Document the integration test in
contracts/README.md
5. Nonce Management Sync
- Rust nonce counter (
nonce_countertable in SQLite) must stay in sync with contract state - On Rust side: increment nonce after each signed permit
- On contract side:
usedNonces[nonce] = trueafter each execution - Recovery mechanism: if a permit is signed but never submitted (agent fails), the nonce is "wasted" — this is acceptable, nonces don't need to be sequential
- Startup sync: on Fishnet start, optionally query contract for last known nonce to detect gaps
6. Multi-Chain Preparation
Per Source of Truth: chain_ids = [8453, 42161] (Base + Arbitrum)
- Deployment config supports multiple chains
-
deployments/directory structure:contracts/deployments/ ├── base-sepolia.json (testnet) ├── base-mainnet.json (future) └── arbitrum-sepolia.json (future) - Rust config reads deployed address per chain from config or deployment files
- EIP712 domain separator is chain-specific (different
chainIdandverifyingContract)
Acceptance Criteria
- FishnetWallet deployed and verified on Base Sepolia
- Rust-signed EIP712 permits are accepted by the on-chain contract (proven by integration test)
- Typehash, domain separator, and struct encoding match exactly between Rust and Solidity
- Nonce management prevents replays and handles gaps gracefully
- Deployment is documented and reproducible
- Integration test is automated and can run in CI