Skip to content

[SC-3] Deployment Scripts, Base Sepolia Deploy & Rust ↔ Solidity Integration #33

@iamyxsh

Description

@iamyxsh

[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.rs matches the Solidity constant
    • Both must produce the same keccak256 hash
  • EIP712 Domain must match exactly:
    • name = "Fishnet" (both sides)
    • version = "1" (both sides)
    • chainId — Rust uses the chain from permit request, Solidity uses block.chainid
    • verifyingContract — Rust must use the deployed wallet address, Solidity uses address(this)
  • Struct encoding must match:
    • Field order in abi.encode() must match between Rust and Solidity
    • Type sizes must match (uint64 for chainId, uint48 for expiry, etc.)
  • Signature format:
    • Rust produces (v, r, s) or 65-byte packed signature
    • Solidity ecrecover expects the correct unpacking

4. End-to-End Integration Test

The Week 4 milestone test: "gateway signs permit, wallet executes swap"

  • Test flow:
    1. Rust backend generates a secp256k1 signing key (or uses existing signer)
    2. Deploy FishnetWallet on Base Sepolia with that key's address as fishnetSigner
    3. Construct an onchain intent (e.g., call a test contract's function)
    4. Rust signs the intent as an EIP712 FishnetPermit
    5. Submit the signed permit + calldata to the FishnetWallet contract
    6. Contract verifies signature and executes the call
    7. Verify the target contract's state changed
  • Automated script: scripts/integration-test.sh or 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_counter table in SQLite) must stay in sync with contract state
  • On Rust side: increment nonce after each signed permit
  • On contract side: usedNonces[nonce] = true after 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 chainId and verifyingContract)

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

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions