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
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions