diff --git a/.github/workflows/frontend-prod.yaml b/.github/workflows/frontend-prod.yaml index 3792dee0..bee10d5c 100644 --- a/.github/workflows/frontend-prod.yaml +++ b/.github/workflows/frontend-prod.yaml @@ -46,6 +46,7 @@ jobs: --build-arg NEXT_PUBLIC_API_URL=${{ vars.NEXT_PUBLIC_API_URL }} \ --build-arg NEXT_PUBLIC_NETWORK=${{ vars.NEXT_PUBLIC_NETWORK }} \ --build-arg NEXT_PUBLIC_FEATURE_X402_DEPOSIT=${{ vars.NEXT_PUBLIC_FEATURE_X402_DEPOSIT }} \ + --build-arg NEXT_PUBLIC_ENABLE_MOBILE_BLOCK=${{ vars.NEXT_PUBLIC_ENABLE_MOBILE_BLOCK }} \ -f docker/frontend.Dockerfile \ -t ${GCP_LOCATION}-docker.pkg.dev/${GCP_PROJECT_ID}/${GCP_REPOSITORY}/${GCP_IMAGE}:${SHORT_SHA} \ . diff --git a/.github/workflows/frontend-staging.yaml b/.github/workflows/frontend-staging.yaml index 36d13409..1aae2b6a 100644 --- a/.github/workflows/frontend-staging.yaml +++ b/.github/workflows/frontend-staging.yaml @@ -46,6 +46,7 @@ jobs: --build-arg NEXT_PUBLIC_API_URL=${{ vars.NEXT_PUBLIC_API_URL }} \ --build-arg NEXT_PUBLIC_NETWORK=${{ vars.NEXT_PUBLIC_NETWORK }} \ --build-arg NEXT_PUBLIC_FEATURE_X402_DEPOSIT=${{ vars.NEXT_PUBLIC_FEATURE_X402_DEPOSIT }} \ + --build-arg NEXT_PUBLIC_ENABLE_MOBILE_BLOCK=${{ vars.NEXT_PUBLIC_ENABLE_MOBILE_BLOCK }} \ -f docker/frontend.Dockerfile \ -t ${GCP_LOCATION}-docker.pkg.dev/${GCP_PROJECT_ID}/${GCP_REPOSITORY}/${GCP_IMAGE}:${SHORT_SHA} \ . diff --git a/docker/frontend.Dockerfile b/docker/frontend.Dockerfile index bb76a5fb..878865f3 100644 --- a/docker/frontend.Dockerfile +++ b/docker/frontend.Dockerfile @@ -57,11 +57,13 @@ COPY packages/nextjs ./packages/nextjs ARG NEXT_PUBLIC_API_URL ARG NEXT_PUBLIC_NETWORK ARG NEXT_PUBLIC_FEATURE_X402_DEPOSIT +ARG NEXT_PUBLIC_ENABLE_MOBILE_BLOCK ARG STANDALONE=true ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL ENV NEXT_PUBLIC_NETWORK=$NEXT_PUBLIC_NETWORK ENV NEXT_PUBLIC_FEATURE_X402_DEPOSIT=$NEXT_PUBLIC_FEATURE_X402_DEPOSIT +ENV NEXT_PUBLIC_ENABLE_MOBILE_BLOCK=$NEXT_PUBLIC_ENABLE_MOBILE_BLOCK ENV STANDALONE=$STANDALONE # Build shared and frontend packages diff --git a/docs/README.md b/docs/README.md index 488e61eb..fc8c366a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -34,6 +34,7 @@ PolyPay uses **zero-knowledge proofs** and **multi-chain deployment** (Horizen a * **Horizen** (mainnet & testnet) * **Base** (mainnet & Sepolia) +* **Arbitrum Sepolia** (testnet only; account contract is a Rust/WASM port via [Arbitrum Stylus](arbitrum-stylus.md)) ### Roadmap diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 8587ed28..262ef24a 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -8,6 +8,7 @@ - [Zero-Knowledge Implementation](zero-knowledge-implementation.md) - [ZK Authentication](zk-authentication.md) - [zkVerify, Horizen & Base Integration](zkverify-horizen-integration.md) +- [Arbitrum Stylus Support (testnet)](arbitrum-stylus.md) - [Gasless USDC Deposits (x402)](x402-deposits.md) - [PolyPay for AI Agents](llms-txt-for-agents.md) - [Architecture](architecture.md) diff --git a/docs/arbitrum-stylus.md b/docs/arbitrum-stylus.md new file mode 100644 index 00000000..9cd298fd --- /dev/null +++ b/docs/arbitrum-stylus.md @@ -0,0 +1,132 @@ +# Arbitrum Stylus Support + +## Overview + +PolyPay supports **Arbitrum Sepolia** (chain ID 421614) as a destination chain +for multisig accounts, in addition to Horizen and Base. Most flows (create +account, deposit / send ETH and USDC, propose / approve / execute transfers +and batch transfers) work the same as on the other chains; **add / remove +signer and update-threshold are currently broken on Arbitrum only** — see the +[caveat below](#add--remove-signer-is-currently-broken). + +The only structural difference vs. Horizen / Base is that the account contract +is a Rust/WASM port of `MetaMultiSigWallet` deployed via +[Arbitrum Stylus](https://arbitrum.io/stylus) instead of Solidity, fronted by +a per-account EIP-1167 proxy. + +Arbitrum is **testnet only** in PolyPay: zkVerify has a verifier on Arbitrum +Sepolia but not Arbitrum One mainnet, so production use is not possible yet. + +## For end users — just pick it in the UI + +There is **no setup**. Pick "Arbitrum Sepolia" in the network chooser when +creating an account; everything else works the same as Horizen / Base: + +| Step | What happens | +|------|--------------| +| Create account | Backend relayer calls the on-chain factory, which clones a tiny EIP-1167 proxy in front of the shared Stylus implementation and initializes it with your commitment(s). | +| Send / receive ETH or USDC | Plain wallet transfers to the proxy address. ETH and Circle USDC (`0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d`) are the supported tokens. Gasless x402 deposit is **not** supported on Arbitrum (Base only). | +| Propose / approve | Same ZK-proof flow as the other chains; the proof targets zkVerify aggregation domain **4** (Arbitrum Sepolia). | +| Execute | Relayer calls `execute(...)` on the proxy once the aggregation receipt is published. | + +Fund the account from any wallet (MetaMask, Rabby, …) by sending Arbitrum +Sepolia ETH to the proxy address shown in the account detail page. + +### One thing to be aware of: aggregation cadence + +zkVerify publishes aggregation receipts to Arbitrum Sepolia **at most every 6 +hours** ([kurier docs][zkv-cadence]). So a freshly-submitted transaction can +sit in "pending aggregation" for hours before `execute()` becomes possible. For +fast end-to-end demos, prefer Horizen Testnet (≈2 min cadence). + +[zkv-cadence]: https://testnet.kurier.xyz/docs/FAQ#5-how-long-does-it-take-for-an-aggregation-to-finalize + +### Add / remove signer is currently broken + +Executing **`add_signer`** (and likely `remove_signer` / `update_threshold`) on +an Arbitrum account reverts on-chain with `WalletError("Tx failed")`. All other +wallet management actions are working: + +| Action | Arbitrum Sepolia | +|--------|------------------| +| Create account | ✅ | +| Receive / send ETH, USDC | ✅ | +| Transfer via `execute()` | ✅ | +| Batch transfer via `execute()` | ✅ | +| Add / remove signer, update threshold | ❌ (open issue) | + +Use Horizen or Base for accounts that need to change their signer set. See +`packages/stylus/NOTES.md` for the technical write-up and current debugging +leads. + +### MetaMask "transaction may fail" warning when sending ETH + +MetaMask's Blockaid security checker does not understand Stylus WASM +bytecode and may refuse to broadcast plain ETH transfers to a Stylus-backed +account, even though the on-chain call succeeds. Workaround: disable +"Transaction security alerts" in MetaMask settings, or use Rabby / `cast send`. + +## How it works under the hood + +The Stylus impl is ~31 KB compressed, above the EVM 24 KB code-size limit, so +`cargo-stylus` fragments it across two contracts on-chain. That makes the +single-bytecode `StylusDeployer.deploy(bytecode, ...)` path unusable for +per-account creation. Instead the architecture splits into three pieces per +chain: + +``` + Stylus impl (deployed once, ~31 KB WASM) + - holds the contract logic + - its own storage is unused + ▲ + │ delegatecall on every call + │ + Per-account proxy (~52 bytes EVM bytecode) + - one per PolyPay account + - holds the live storage (signers, nonces, nullifiers) + ▲ + │ created by + │ + Factory (deployed once) + - createWallet(...) clones a new proxy + calls init() on it + - factory's `implementation` address is immutable +``` + +Each proxy is a thin custom variant of EIP-1167: + +- `calldatasize == 0` → `STOP` (accept plain ETH transfers; required because + the fragmented Stylus loader reverts on empty calldata, which would + otherwise break `addr.transfer(...)` deposits). +- Otherwise → delegatecall to the impl, same as standard EIP-1167. + +`execute()` in the impl detects when `to == address(this)` (i.e., a self-call +to `add_signer` / `remove_signer` / `update_threshold` / `batch_transfer*`) +and dispatches to internal Rust helpers directly instead of going through an +EVM `CALL`. This workaround is what makes `batch_transfer` succeed on +Arbitrum despite the suspected Stylus delegatecall + CALL `msg.sender` bug; +`add_signer` still fails through the same path and the root cause is open +(see `packages/stylus/NOTES.md`). + +### On-chain addresses (Arbitrum Sepolia, chain 421614) + +| Component | Address | +|-----------|---------| +| PoseidonT3 (deterministic) | `0x3333333C0A88F9BE4fd23ed0536F9B6c427e3B93` | +| zkVerify aggregation (proxy) | `0xd007494945580eEb25522c8e0b2fa798B3F0FDE2` | +| Circle USDC | `0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d` | +| Stylus impl | `0x0395b99f3a45bd08d018d3d3060a0e2bf8dc8978` | +| Stylus factory | `0x8F5f249210fFc91a2b1D86828764562f97C9eEdd` | + +The impl + factory addresses live in `packages/shared/src/contracts/contracts-config.ts` +(`stylusImplAddress` / `stylusFactoryAddress`); bump them there after a +re-deploy. + +## For developers who need to redeploy + +If you change `packages/stylus/src/lib.rs` you must redeploy both the impl +(via cargo-stylus) and the factory (it captures the impl address as an +immutable). Then bump the addresses in `contracts-config.ts`. + +See `packages/stylus/README.md` for the full step-by-step build + deploy +guide. No env vars are required on the backend; the factory address is +sourced from `@polypay/shared`. diff --git a/docs/developer-documentation/README.md b/docs/developer-documentation/README.md index ddd9581d..e9cd51a2 100644 --- a/docs/developer-documentation/README.md +++ b/docs/developer-documentation/README.md @@ -29,6 +29,7 @@ This section covers: | Horizen | Testnet | 2651420 | [horizen-testnet.explorer.caldera.xyz](https://horizen-testnet.explorer.caldera.xyz/) | | Base | Mainnet | 8453 | [basescan.org](https://basescan.org/) | | Base | Sepolia | 84532 | [sepolia.basescan.org](https://sepolia.basescan.org/) | +| Arbitrum | Sepolia (testnet only, Stylus WASM contract) | 421614 | [sepolia.arbiscan.io](https://sepolia.arbiscan.io/) | ## Quick Links diff --git a/docs/how-to-use-polipay-app.md b/docs/how-to-use-polipay-app.md index 4645e551..497d3e87 100644 --- a/docs/how-to-use-polipay-app.md +++ b/docs/how-to-use-polipay-app.md @@ -2,9 +2,9 @@ ## Polypay App (Beta v0.1) -Polypay app beta v0.1 is an initial release of the Polypay platform. It is a web application that allows you to create and manage a multisig account on **Horizen** or **Base** with a focus on privacy. Current version includes the following features: +Polypay app beta v0.1 is an initial release of the Polypay platform. It is a web application that allows you to create and manage a multisig account on **Horizen**, **Base**, or **Arbitrum Sepolia** (testnet) with a focus on privacy. Current version includes the following features: -- Choose between Horizen and Base networks +- Choose between Horizen, Base, and Arbitrum Sepolia networks - Create and manage a multisig account - Hide signers(multisig account owners) identities with ZK proofs - Execute payroll payments: Transfer funds to multiple recipients @@ -24,7 +24,7 @@ Polypay app beta v0.1 is an initial release of the Polypay platform. It is a web 1. **Connect Wallet**: Connect your wallet 2. **Generate Identity**: Sign a message to create your secret -3. **Choose Network**: Select Horizen or Base +3. **Choose Network**: Select Horizen, Base, or Arbitrum Sepolia (see [Arbitrum Stylus Support](arbitrum-stylus.md) for current limitations on Arbitrum) 4. **Create/Join Account**: Deploy new multisig or join existing one 4. **Propose Transaction**: Create transfer and generate ZK proof 5. **Sign**: Other signers approve with their ZK proofs diff --git a/docs/llms-txt-for-agents.md b/docs/llms-txt-for-agents.md index 20e8c9e1..5c9db3ed 100644 --- a/docs/llms-txt-for-agents.md +++ b/docs/llms-txt-for-agents.md @@ -29,7 +29,7 @@ A complete playbook covering the five most common agent flows: | # | Flow | What the agent can do | |---|---|---| | 1 | **Login** | Generate a ZK auth proof and obtain a JWT | -| 2 | **Create multisig account** | Deploy a new PolyPay multisig on Horizen or Base | +| 2 | **Create multisig account** | Deploy a new PolyPay multisig on Horizen, Base, or Arbitrum Sepolia (testnet, see [Arbitrum Stylus Support](arbitrum-stylus.md) for limitations) | | 3 | **Single transfer** | Propose, vote, and execute a private payroll payment | | 4 | **Batch transfer** | Propose and execute multi-recipient payroll in one transaction | | 5 | **Gasless USDC deposit (x402)** | Fund any PolyPay multisig with USDC on Base without holding ETH | diff --git a/docs/zkverify-horizen-integration.md b/docs/zkverify-horizen-integration.md index c452a1e2..11b7df6b 100644 --- a/docs/zkverify-horizen-integration.md +++ b/docs/zkverify-horizen-integration.md @@ -8,7 +8,7 @@ PolyPay uses multiple blockchain layers for privacy-preserving multisig operatio - **[Horizen](https://www.horizen.io/)**: EVM-compatible L3 blockchain where multisig accounts (`MetaMultiSigWallet` contracts) are deployed and transactions are executed - **[Base](https://base.org/)**: EVM-compatible L2 blockchain, also supported as a destination chain for account deployment and transaction execution -> **"Destination Chain"** refers to the EVM chain where the multisig account is deployed — either **Horizen** (L3, chain ID 26514) or **Base** (L2, chain ID 8453). The user selects the destination chain when creating an account, and all subsequent operations for that account happen on the same chain. +> **"Destination Chain"** refers to the EVM chain where the multisig account is deployed — **Horizen** (L3, chain ID 26514), **Base** (L2, chain ID 8453), or **Arbitrum Sepolia** (L2 testnet, chain ID 421614). The user selects the destination chain when creating an account, and all subsequent operations for that account happen on the same chain. Arbitrum support uses a Rust/WASM port of the account contract via [Arbitrum Stylus](arbitrum-stylus.md) — see that page for current scope and limitations. ## Blockchain Classification diff --git a/packages/backend/src/common/constants/campaign.ts b/packages/backend/src/common/constants/campaign.ts index 6a89bdb4..880da981 100644 --- a/packages/backend/src/common/constants/campaign.ts +++ b/packages/backend/src/common/constants/campaign.ts @@ -15,7 +15,8 @@ export const QUEST_POINTS_ACCOUNT_FIRST_TX = 100; export const QUEST_POINTS_SUCCESSFUL_TX = 50; // Supported chain IDs -export const SUPPORTED_CHAIN_IDS = [2651420, 84532, 26514, 8453]; +// 421614 = Arbitrum Sepolia (testnet only; account contract is the Stylus port). +export const SUPPORTED_CHAIN_IDS = [2651420, 84532, 26514, 8453, 421614]; // External APIs export const COINGECKO_API_URL = diff --git a/packages/backend/src/common/constants/proof.ts b/packages/backend/src/common/constants/proof.ts index 7ec8d80e..24f66ac2 100644 --- a/packages/backend/src/common/constants/proof.ts +++ b/packages/backend/src/common/constants/proof.ts @@ -1,6 +1,7 @@ export const DOMAIN_ID_BY_CHAIN_ID = { 2651420: 175, // Horizen testnet 84532: 2, // Base Sepolia + 421614: 4, // Arbitrum Sepolia (zkVerify testnet domain) 26514: 3, // Horizen mainnet 8453: 2, // Base mainnet } as const; diff --git a/packages/backend/src/config/config.keys.ts b/packages/backend/src/config/config.keys.ts index 66c18c6e..5061431a 100644 --- a/packages/backend/src/config/config.keys.ts +++ b/packages/backend/src/config/config.keys.ts @@ -20,7 +20,6 @@ export const CONFIG_KEYS = { RELAYER_ZK_VERIFY_API_KEY: 'relayer.zkVerifyApiKey', RELAYER_WALLET_KEY: 'relayer.walletKey', REWARD_WALLET_KEY: 'relayer.rewardWalletKey', - // Telegram TELEGRAM_BOT_TOKEN: 'telegram.botToken', TELEGRAM_CHAT_ID: 'telegram.chatId', diff --git a/packages/backend/src/relayer-wallet/relayer-wallet.service.ts b/packages/backend/src/relayer-wallet/relayer-wallet.service.ts index ebc7a363..5f18274b 100644 --- a/packages/backend/src/relayer-wallet/relayer-wallet.service.ts +++ b/packages/backend/src/relayer-wallet/relayer-wallet.service.ts @@ -10,6 +10,9 @@ import { ZERO_ADDRESS, getChainById, getContractConfigByChainId, + isStylusChain, + getStylusFactoryAddress, + METAMULTISIG_STYLUS_FACTORY_ABI, } from '@polypay/shared'; import { METAMULTISIG_ABI, METAMULTISIG_BYTECODE } from '@polypay/shared'; import { ConfigService } from '@nestjs/config'; @@ -95,6 +98,11 @@ export class RelayerService { threshold: number, chainId: number, ): Promise<{ address: string; txHash: string }> { + // Stylus chains (Arbitrum) deploy the Rust/WASM port via StylusDeployer. + if (isStylusChain(chainId)) { + return this.deployStylusAccount(commitments, threshold, chainId); + } + const { chain, walletClient, publicClient, contractConfig } = this.getChainClient(chainId); @@ -134,6 +142,63 @@ export class RelayerService { }; } + /** + * Deploy a per-account MetaMultiSigWallet on an Arbitrum Stylus chain via an + * EIP-1167 minimal proxy in front of the shared Stylus impl. + * + * Why the proxy: the Stylus impl is ~29 KB compressed (over the 24 KB EVM + * code-size limit) so cargo-stylus fragments it on-chain, which makes + * single-bytecode StylusDeployer deploys unusable for per-account creation. + * The factory clones a tiny EVM proxy whose fallback delegatecalls into the + * impl, then atomically calls `init(...)` on the clone in the same tx so we + * never expose a half-initialized wallet. + */ + private async deployStylusAccount( + commitments: string[], + threshold: number, + chainId: number, + ): Promise<{ address: string; txHash: string }> { + const { chain, walletClient, publicClient, contractConfig } = + this.getChainClient(chainId); + + const factoryAddress = getStylusFactoryAddress(chainId); + + const commitmentsBigInt = commitments.map((c) => BigInt(c)); + + // Simulate first to capture the proxy address returned by `createWallet`. + const { result: deployedAddress, request } = + await publicClient.simulateContract({ + address: factoryAddress, + abi: METAMULTISIG_STYLUS_FACTORY_ABI, + functionName: 'createWallet', + args: [ + contractConfig.zkVerifyAddress, + contractConfig.vkHash as `0x${string}`, + contractConfig.poseidonT3Address as `0x${string}`, + BigInt(chain.id), + commitmentsBigInt, + BigInt(threshold), + ], + account: this.account, + chain, + }); + + const txHash = await walletClient.writeContract(request); + this.logger.log( + `Stylus factory createWallet tx sent on chain ${chainId}: ${txHash}`, + ); + + const receipt = await waitForReceiptWithRetry(publicClient, txHash); + if (receipt.status === 'reverted') { + throw new Error(`Stylus deployment reverted. TxHash: ${txHash}`); + } + + const address = deployedAddress as string; + this.logger.log(`Stylus wallet (proxy) deployed at: ${address}`); + + return { address, txHash }; + } + /** * Execute transaction on MetaMultiSigWallet */ diff --git a/packages/backend/src/transaction/transaction-executor.service.ts b/packages/backend/src/transaction/transaction-executor.service.ts index 70a6187d..788d4902 100644 --- a/packages/backend/src/transaction/transaction-executor.service.ts +++ b/packages/backend/src/transaction/transaction-executor.service.ts @@ -292,7 +292,12 @@ export class TransactionExecutorService { const signers: SignerData[] = JSON.parse(transaction.signerData); const account = await tx.account.findUnique({ - where: { address: transaction.accountAddress }, + where: { + address_chainId: { + address: transaction.accountAddress, + chainId: transaction.chainId, + }, + }, }); if (!account) return; @@ -345,7 +350,12 @@ export class TransactionExecutorService { const signers: SignerData[] = JSON.parse(transaction.signerData); const account = await tx.account.findUnique({ - where: { address: transaction.accountAddress }, + where: { + address_chainId: { + address: transaction.accountAddress, + chainId: transaction.chainId, + }, + }, }); if (!account) return; diff --git a/packages/hardhat/contracts/MetaMultiSigWalletStylusFactory.sol b/packages/hardhat/contracts/MetaMultiSigWalletStylusFactory.sol new file mode 100644 index 00000000..0cbd1ff1 --- /dev/null +++ b/packages/hardhat/contracts/MetaMultiSigWalletStylusFactory.sol @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +// EIP-1167 minimal-proxy factory for the Stylus MetaMultiSigWallet. +// +// The Stylus port of MetaMultiSigWallet is ~29 KB compressed on Arbitrum, which +// exceeds the 24 KB EVM code-size limit. cargo-stylus deploys it as a +// fragmented contract, which means the canonical StylusDeployer's single- +// bytecode `deploy(bytecode, initData, ...)` path cannot represent it. Instead +// we deploy the Stylus contract ONCE as an implementation, then for each user +// account we deploy a tiny EIP-1167 proxy (~45 bytes of EVM bytecode, well +// under the limit) that delegatecalls into the impl. The proxy holds its own +// storage, so each account has independent signers/nonces/nullifiers while +// sharing one piece of WASM logic. +// +// Stylus/EVM interop note: when an EVM contract DELEGATECALLs a Stylus +// program, the Arbitrum runtime routes the call into the WASM VM with the +// caller's storage context — confirmed compatible with EIP-1167 proxies (see +// the Stylus Saturdays "Writing proxies in Arbitrum Stylus" issue). +contract MetaMultiSigWalletStylusFactory { + // Stylus impl whose code every proxy will delegatecall into. Immutable so + // the factory commits to a single, audited impl version per deployment. + address public immutable implementation; + + event WalletCreated(address indexed wallet, uint256[] commitments, uint256 signaturesRequired); + + constructor(address _implementation) { + require(_implementation != address(0), "Invalid implementation"); + implementation = _implementation; + } + + // Atomically clone the impl and call init() on the new proxy. Reverts if + // init reverts so we never return a half-initialized wallet address. + function createWallet( + address zkvContract, + bytes32 vkHash, + address poseidonT3, + uint256 chainId, + uint256[] calldata initialCommitments, + uint256 signaturesRequired + ) external returns (address wallet) { + wallet = _cloneEIP1167(implementation); + + (bool ok, bytes memory ret) = wallet.call( + abi.encodeWithSignature( + "init(address,bytes32,address,uint256,uint256[],uint256)", + zkvContract, + vkHash, + poseidonT3, + chainId, + initialCommitments, + signaturesRequired + ) + ); + if (!ok) { + // Bubble up the original revert data so the relayer sees the real + // reason (e.g. WalletError(reason)) rather than a generic "init + // failed". + assembly { + revert(add(ret, 0x20), mload(ret)) + } + } + + emit WalletCreated(wallet, initialCommitments, signaturesRequired); + } + + // Minimal proxy deployment via CREATE. EIP-1167 with a 5-byte prefix that + // accepts plain ETH transfers locally instead of delegatecalling on empty + // calldata. Required because the Stylus impl is fragmented by cargo-stylus; + // the loader fragment dispatches on a 4-byte selector and reverts on empty + // calldata, which would otherwise make plain `addr.transfer(...)` deposits + // (and `receive()` routing) revert at gas estimation. + // + // Runtime layout (52 bytes): + // 00: 36 15 60 32 57 if calldatasize == 0 → JUMPI to 0x32 + // 05..30: standard EIP-1167 body (PUSH1 jumpdest 0x2b shifted to 0x30) + // 31: f3 (RETURN inside EIP-1167 body) + // 32: 5b 00 JUMPDEST + STOP — empty-calldata branch + function _cloneEIP1167(address target) private returns (address instance) { + bytes20 targetBytes = bytes20(target); + assembly { + let ptr := mload(0x40) + // bytes [0..24]: creation prefix (10) + empty-calldata check (5) + + // EIP-1167 prelude up to PUSH20 (10); last 7 bytes of the word are + // zero padding that the next mstore overwrites with the address. + mstore(ptr, 0x3d603480600a3d3981f33615603257363d3d373d3d3d363d7300000000000000) + // bytes [25..44]: 20-byte impl address (bytes20 left-aligned). + mstore(add(ptr, 25), targetBytes) + // bytes [45..61]: EIP-1167 suffix with internal JUMPDEST shifted + // from 0x2b to 0x30, followed by the empty-calldata JUMPDEST + STOP. + mstore(add(ptr, 45), 0x5af43d82803e903d91603057fd5bf35b00000000000000000000000000000000) + instance := create(0, ptr, 62) + } + require(instance != address(0), "Clone failed"); + } +} diff --git a/packages/hardhat/deploy/01_deploy_poseidon_t3.ts b/packages/hardhat/deploy/01_deploy_poseidon_t3.ts new file mode 100644 index 00000000..fd259906 --- /dev/null +++ b/packages/hardhat/deploy/01_deploy_poseidon_t3.ts @@ -0,0 +1,43 @@ +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { DeployFunction } from "hardhat-deploy/types"; +import { PoseidonT3, proxy } from "poseidon-solidity"; + +/** + * Deploys the PoseidonT3 hashing library to its deterministic address + * (0x3333333C0A88F9BE4fd23ed0536F9B6c427e3B93) via the CREATE2 proxy. + * + * The Stylus MetaMultiSigWallet on Arbitrum STATICCALLs this contract by address, + * so it must exist on the target chain. Idempotent: skips anything already deployed. + * + * Run only this (without deploying the Solidity multisig): + * yarn deploy --tags PoseidonT3 --network arbitrumSepolia + */ +const deployPoseidonT3: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { + const [signer] = await hre.ethers.getSigners(); + const provider = hre.ethers.provider; + + // 1. Deploy the deterministic CREATE2 proxy if it's not already on this chain. + if ((await provider.getCode(proxy.address)) === "0x") { + console.log("Deploying CREATE2 proxy..."); + const fundTx = await signer.sendTransaction({ to: proxy.from, value: proxy.gas }); + await fundTx.wait(); + await provider.broadcastTransaction(proxy.tx); + console.log(`Proxy deployed to: ${proxy.address}`); + } else { + console.log(`Proxy already at: ${proxy.address}`); + } + + // 2. Deploy PoseidonT3 via the proxy (CREATE2 -> deterministic address). + if ((await provider.getCode(PoseidonT3.address)) === "0x") { + console.log("Deploying PoseidonT3..."); + const tx = await signer.sendTransaction({ to: proxy.address, data: PoseidonT3.data }); + await tx.wait(); + console.log(`PoseidonT3 deployed to: ${PoseidonT3.address}`); + } else { + console.log(`PoseidonT3 already at: ${PoseidonT3.address}`); + } +}; + +export default deployPoseidonT3; + +deployPoseidonT3.tags = ["PoseidonT3"]; diff --git a/packages/hardhat/deploy/02_deploy_stylus_factory.ts b/packages/hardhat/deploy/02_deploy_stylus_factory.ts new file mode 100644 index 00000000..ca2792c8 --- /dev/null +++ b/packages/hardhat/deploy/02_deploy_stylus_factory.ts @@ -0,0 +1,41 @@ +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { DeployFunction } from "hardhat-deploy/types"; + +/** + * Deploys MetaMultiSigWalletStylusFactory on the target chain. + * + * The Stylus implementation is deployed separately via `cargo stylus deploy` + * (see packages/stylus/README.md). Pass its address through the + * STYLUS_IMPL_ADDRESS env var, e.g.: + * + * STYLUS_IMPL_ADDRESS=0x... yarn deploy --tags StylusFactory --network arbitrumSepolia + * + * Idempotent via hardhat-deploy's `deterministicDeployment` flag-free default + * (re-runs return the existing deployment). + */ +const deployStylusFactory: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { + const { deployer } = await hre.getNamedAccounts(); + const { deploy } = hre.deployments; + + const implAddress = process.env.STYLUS_IMPL_ADDRESS; + if (!implAddress) { + throw new Error( + "STYLUS_IMPL_ADDRESS is not set. Deploy the Stylus contract first with `cargo stylus deploy` " + + "in packages/stylus and pass its address via STYLUS_IMPL_ADDRESS.", + ); + } + + const result = await deploy("MetaMultiSigWalletStylusFactory", { + from: deployer, + args: [implAddress], + log: true, + autoMine: true, + }); + + console.log(`MetaMultiSigWalletStylusFactory at: ${result.address}`); + console.log(`Implementation: ${implAddress}`); +}; + +export default deployStylusFactory; + +deployStylusFactory.tags = ["StylusFactory"]; diff --git a/packages/hardhat/deployments/arbitrumSepolia/MetaMultiSigWalletStylusFactory.json b/packages/hardhat/deployments/arbitrumSepolia/MetaMultiSigWalletStylusFactory.json new file mode 100644 index 00000000..6949f942 --- /dev/null +++ b/packages/hardhat/deployments/arbitrumSepolia/MetaMultiSigWalletStylusFactory.json @@ -0,0 +1,136 @@ +{ + "address": "0x8F5f249210fFc91a2b1D86828764562f97C9eEdd", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "wallet", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "commitments", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "signaturesRequired", + "type": "uint256" + } + ], + "name": "WalletCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "zkvContract", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "vkHash", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "poseidonT3", + "type": "address" + }, + { + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "initialCommitments", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "signaturesRequired", + "type": "uint256" + } + ], + "name": "createWallet", + "outputs": [ + { + "internalType": "address", + "name": "wallet", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "implementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x9ccdab68514e272a4d0bfb2fba952b53f55f50bec3dc65e537770af0d748fe11", + "receipt": { + "to": null, + "from": "0xd95E85e86D3Be5C86846435b8F0C3a476C5a9e42", + "contractAddress": "0x8F5f249210fFc91a2b1D86828764562f97C9eEdd", + "transactionIndex": 2, + "gasUsed": "364038", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xee73f963ea89007e7fa13e7e3c2d9635688f97d3146aea932536aa75d6864c76", + "transactionHash": "0x9ccdab68514e272a4d0bfb2fba952b53f55f50bec3dc65e537770af0d748fe11", + "logs": [], + "blockNumber": 273307930, + "cumulativeGasUsed": "393146", + "status": 1, + "byzantium": true + }, + "args": [ + "0x0395b99f3a45bd08d018d3d3060a0e2bf8dc8978" + ], + "numDeployments": 3, + "solcInputHash": "85dffce1f60a7637c1cae920f9b4a60d", + "metadata": "{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_implementation\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"wallet\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"commitments\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"signaturesRequired\",\"type\":\"uint256\"}],\"name\":\"WalletCreated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"zkvContract\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"vkHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"poseidonT3\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"initialCommitments\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"signaturesRequired\",\"type\":\"uint256\"}],\"name\":\"createWallet\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"wallet\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/MetaMultiSigWalletStylusFactory.sol\":\"MetaMultiSigWalletStylusFactory\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/MetaMultiSigWalletStylusFactory.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.20;\\n\\n// EIP-1167 minimal-proxy factory for the Stylus MetaMultiSigWallet.\\n//\\n// The Stylus port of MetaMultiSigWallet is ~29 KB compressed on Arbitrum, which\\n// exceeds the 24 KB EVM code-size limit. cargo-stylus deploys it as a\\n// fragmented contract, which means the canonical StylusDeployer's single-\\n// bytecode `deploy(bytecode, initData, ...)` path cannot represent it. Instead\\n// we deploy the Stylus contract ONCE as an implementation, then for each user\\n// account we deploy a tiny EIP-1167 proxy (~45 bytes of EVM bytecode, well\\n// under the limit) that delegatecalls into the impl. The proxy holds its own\\n// storage, so each account has independent signers/nonces/nullifiers while\\n// sharing one piece of WASM logic.\\n//\\n// Stylus/EVM interop note: when an EVM contract DELEGATECALLs a Stylus\\n// program, the Arbitrum runtime routes the call into the WASM VM with the\\n// caller's storage context \\u2014 confirmed compatible with EIP-1167 proxies (see\\n// the Stylus Saturdays \\\"Writing proxies in Arbitrum Stylus\\\" issue).\\ncontract MetaMultiSigWalletStylusFactory {\\n // Stylus impl whose code every proxy will delegatecall into. Immutable so\\n // the factory commits to a single, audited impl version per deployment.\\n address public immutable implementation;\\n\\n event WalletCreated(address indexed wallet, uint256[] commitments, uint256 signaturesRequired);\\n\\n constructor(address _implementation) {\\n require(_implementation != address(0), \\\"Invalid implementation\\\");\\n implementation = _implementation;\\n }\\n\\n // Atomically clone the impl and call init() on the new proxy. Reverts if\\n // init reverts so we never return a half-initialized wallet address.\\n function createWallet(\\n address zkvContract,\\n bytes32 vkHash,\\n address poseidonT3,\\n uint256 chainId,\\n uint256[] calldata initialCommitments,\\n uint256 signaturesRequired\\n ) external returns (address wallet) {\\n wallet = _cloneEIP1167(implementation);\\n\\n (bool ok, bytes memory ret) = wallet.call(\\n abi.encodeWithSignature(\\n \\\"init(address,bytes32,address,uint256,uint256[],uint256)\\\",\\n zkvContract,\\n vkHash,\\n poseidonT3,\\n chainId,\\n initialCommitments,\\n signaturesRequired\\n )\\n );\\n if (!ok) {\\n // Bubble up the original revert data so the relayer sees the real\\n // reason (e.g. WalletError(reason)) rather than a generic \\\"init\\n // failed\\\".\\n assembly {\\n revert(add(ret, 0x20), mload(ret))\\n }\\n }\\n\\n emit WalletCreated(wallet, initialCommitments, signaturesRequired);\\n }\\n\\n // Minimal proxy deployment via CREATE. EIP-1167 with a 5-byte prefix that\\n // accepts plain ETH transfers locally instead of delegatecalling on empty\\n // calldata. Required because the Stylus impl is fragmented by cargo-stylus;\\n // the loader fragment dispatches on a 4-byte selector and reverts on empty\\n // calldata, which would otherwise make plain `addr.transfer(...)` deposits\\n // (and `receive()` routing) revert at gas estimation.\\n //\\n // Runtime layout (52 bytes):\\n // 00: 36 15 60 32 57 if calldatasize == 0 \\u2192 JUMPI to 0x32\\n // 05..30: standard EIP-1167 body (PUSH1 jumpdest 0x2b shifted to 0x30)\\n // 31: f3 (RETURN inside EIP-1167 body)\\n // 32: 5b 00 JUMPDEST + STOP \\u2014 empty-calldata branch\\n function _cloneEIP1167(address target) private returns (address instance) {\\n bytes20 targetBytes = bytes20(target);\\n assembly {\\n let ptr := mload(0x40)\\n // bytes [0..24]: creation prefix (10) + empty-calldata check (5) +\\n // EIP-1167 prelude up to PUSH20 (10); last 7 bytes of the word are\\n // zero padding that the next mstore overwrites with the address.\\n mstore(ptr, 0x3d603480600a3d3981f33615603257363d3d373d3d3d363d7300000000000000)\\n // bytes [25..44]: 20-byte impl address (bytes20 left-aligned).\\n mstore(add(ptr, 25), targetBytes)\\n // bytes [45..61]: EIP-1167 suffix with internal JUMPDEST shifted\\n // from 0x2b to 0x30, followed by the empty-calldata JUMPDEST + STOP.\\n mstore(add(ptr, 45), 0x5af43d82803e903d91603057fd5bf35b00000000000000000000000000000000)\\n instance := create(0, ptr, 62)\\n }\\n require(instance != address(0), \\\"Clone failed\\\");\\n }\\n}\\n\",\"keccak256\":\"0xf43f56c35db36443fa23ac096dd33183d688696a388cca617cb730f88eee7ff7\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x60a060405234801561001057600080fd5b5060405161052838038061052883398101604081905261002f9161009a565b6001600160a01b0381166100895760405162461bcd60e51b815260206004820152601660248201527f496e76616c696420696d706c656d656e746174696f6e00000000000000000000604482015260640160405180910390fd5b6001600160a01b03166080526100ca565b6000602082840312156100ac57600080fd5b81516001600160a01b03811681146100c357600080fd5b9392505050565b60805161043e6100ea60003960008181604001526093015261043e6000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80635c60da1b1461003b578063e8fbf4d91461007e575b600080fd5b6100627f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b61006261008c366004610280565b60006100b77f00000000000000000000000000000000000000000000000000000000000000006101be565b9050600080826001600160a01b03168a8a8a8a8a8a8a6040516024016100e39796959493929190610366565b60408051601f198184030181529181526020820180516001600160e01b0316630f5ebddd60e31b1790525161011891906103b5565b6000604051808303816000865af19150503d8060008114610155576040519150601f19603f3d011682016040523d82523d6000602084013e61015a565b606091505b50915091508161016c57805160208201fd5b826001600160a01b03167f42ee8ab389d0f668ad3d714d22ab7a5112414d6c43f79a8167b849019b6cf4e28787876040516101a9939291906103e4565b60405180910390a25050979650505050505050565b6000808260601b90506040517f3d603480600a3d3981f33615603257363d3d373d3d3d363d730000000000000081528160198201526f5af43d82803e903d91603057fd5bf35b60801b602d820152603e816000f09250506001600160a01b03821661025e5760405162461bcd60e51b815260206004820152600c60248201526b10db1bdb994819985a5b195960a21b604482015260640160405180910390fd5b50919050565b80356001600160a01b038116811461027b57600080fd5b919050565b600080600080600080600060c0888a03121561029b57600080fd5b6102a488610264565b9650602088013595506102b960408901610264565b945060608801359350608088013567ffffffffffffffff808211156102dd57600080fd5b818a0191508a601f8301126102f157600080fd5b81358181111561030057600080fd5b8b60208260051b850101111561031557600080fd5b60208301955080945050505060a0880135905092959891949750929550565b81835260006001600160fb1b0383111561034d57600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b03888116825260208201889052861660408201526060810185905260c0608082018190526000906103a19083018587610334565b90508260a083015298975050505050505050565b6000825160005b818110156103d657602081860181015185830152016103bc565b506000920191825250919050565b6040815260006103f8604083018587610334565b905082602083015294935050505056fea264697066735822122080130a10d20e7d222c75e9fe23fbe4b0623fd7ad2364634949902cea3b2c619c64736f6c63430008140033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c80635c60da1b1461003b578063e8fbf4d91461007e575b600080fd5b6100627f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b61006261008c366004610280565b60006100b77f00000000000000000000000000000000000000000000000000000000000000006101be565b9050600080826001600160a01b03168a8a8a8a8a8a8a6040516024016100e39796959493929190610366565b60408051601f198184030181529181526020820180516001600160e01b0316630f5ebddd60e31b1790525161011891906103b5565b6000604051808303816000865af19150503d8060008114610155576040519150601f19603f3d011682016040523d82523d6000602084013e61015a565b606091505b50915091508161016c57805160208201fd5b826001600160a01b03167f42ee8ab389d0f668ad3d714d22ab7a5112414d6c43f79a8167b849019b6cf4e28787876040516101a9939291906103e4565b60405180910390a25050979650505050505050565b6000808260601b90506040517f3d603480600a3d3981f33615603257363d3d373d3d3d363d730000000000000081528160198201526f5af43d82803e903d91603057fd5bf35b60801b602d820152603e816000f09250506001600160a01b03821661025e5760405162461bcd60e51b815260206004820152600c60248201526b10db1bdb994819985a5b195960a21b604482015260640160405180910390fd5b50919050565b80356001600160a01b038116811461027b57600080fd5b919050565b600080600080600080600060c0888a03121561029b57600080fd5b6102a488610264565b9650602088013595506102b960408901610264565b945060608801359350608088013567ffffffffffffffff808211156102dd57600080fd5b818a0191508a601f8301126102f157600080fd5b81358181111561030057600080fd5b8b60208260051b850101111561031557600080fd5b60208301955080945050505060a0880135905092959891949750929550565b81835260006001600160fb1b0383111561034d57600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b03888116825260208201889052861660408201526060810185905260c0608082018190526000906103a19083018587610334565b90508260a083015298975050505050505050565b6000825160005b818110156103d657602081860181015185830152016103bc565b506000920191825250919050565b6040815260006103f8604083018587610334565b905082602083015294935050505056fea264697066735822122080130a10d20e7d222c75e9fe23fbe4b0623fd7ad2364634949902cea3b2c619c64736f6c63430008140033", + "devdoc": { + "kind": "dev", + "methods": {}, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} \ No newline at end of file diff --git a/packages/hardhat/deployments/arbitrumSepolia/solcInputs/2eec667ebfd1c722d37f9f99805e3852.json b/packages/hardhat/deployments/arbitrumSepolia/solcInputs/2eec667ebfd1c722d37f9f99805e3852.json new file mode 100644 index 00000000..ac01049f --- /dev/null +++ b/packages/hardhat/deployments/arbitrumSepolia/solcInputs/2eec667ebfd1c722d37f9f99805e3852.json @@ -0,0 +1,36 @@ +{ + "language": "Solidity", + "sources": { + "contracts/MetaMultiSigWalletStylusFactory.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\n// EIP-1167 minimal-proxy factory for the Stylus MetaMultiSigWallet.\n//\n// The Stylus port of MetaMultiSigWallet is ~29 KB compressed on Arbitrum, which\n// exceeds the 24 KB EVM code-size limit. cargo-stylus deploys it as a\n// fragmented contract, which means the canonical StylusDeployer's single-\n// bytecode `deploy(bytecode, initData, ...)` path cannot represent it. Instead\n// we deploy the Stylus contract ONCE as an implementation, then for each user\n// account we deploy a tiny EIP-1167 proxy (~45 bytes of EVM bytecode, well\n// under the limit) that delegatecalls into the impl. The proxy holds its own\n// storage, so each account has independent signers/nonces/nullifiers while\n// sharing one piece of WASM logic.\n//\n// Stylus/EVM interop note: when an EVM contract DELEGATECALLs a Stylus\n// program, the Arbitrum runtime routes the call into the WASM VM with the\n// caller's storage context — confirmed compatible with EIP-1167 proxies (see\n// the Stylus Saturdays \"Writing proxies in Arbitrum Stylus\" issue).\ncontract MetaMultiSigWalletStylusFactory {\n // Stylus impl whose code every proxy will delegatecall into. Immutable so\n // the factory commits to a single, audited impl version per deployment.\n address public immutable implementation;\n\n event WalletCreated(address indexed wallet, uint256[] commitments, uint256 signaturesRequired);\n\n constructor(address _implementation) {\n require(_implementation != address(0), \"Invalid implementation\");\n implementation = _implementation;\n }\n\n // Atomically clone the impl and call init() on the new proxy. Reverts if\n // init reverts so we never return a half-initialized wallet address.\n function createWallet(\n address zkvContract,\n bytes32 vkHash,\n address poseidonT3,\n uint256 chainId,\n uint256[] calldata initialCommitments,\n uint256 signaturesRequired\n ) external returns (address wallet) {\n wallet = _cloneEIP1167(implementation);\n\n (bool ok, bytes memory ret) = wallet.call(\n abi.encodeWithSignature(\n \"init(address,bytes32,address,uint256,uint256[],uint256)\",\n zkvContract,\n vkHash,\n poseidonT3,\n chainId,\n initialCommitments,\n signaturesRequired\n )\n );\n if (!ok) {\n // Bubble up the original revert data so the relayer sees the real\n // reason (e.g. WalletError(reason)) rather than a generic \"init\n // failed\".\n assembly {\n revert(add(ret, 0x20), mload(ret))\n }\n }\n\n emit WalletCreated(wallet, initialCommitments, signaturesRequired);\n }\n\n // Standard EIP-1167 minimal proxy deployment via CREATE. Inline-assembly\n // copy of the canonical 45-byte runtime that DELEGATECALLs `target`.\n function _cloneEIP1167(address target) private returns (address instance) {\n bytes20 targetBytes = bytes20(target);\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), targetBytes)\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\n instance := create(0, ptr, 0x37)\n }\n require(instance != address(0), \"Clone failed\");\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "evmVersion": "paris", + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/packages/hardhat/deployments/arbitrumSepolia/solcInputs/85dffce1f60a7637c1cae920f9b4a60d.json b/packages/hardhat/deployments/arbitrumSepolia/solcInputs/85dffce1f60a7637c1cae920f9b4a60d.json new file mode 100644 index 00000000..b03623e1 --- /dev/null +++ b/packages/hardhat/deployments/arbitrumSepolia/solcInputs/85dffce1f60a7637c1cae920f9b4a60d.json @@ -0,0 +1,36 @@ +{ + "language": "Solidity", + "sources": { + "contracts/MetaMultiSigWalletStylusFactory.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\n// EIP-1167 minimal-proxy factory for the Stylus MetaMultiSigWallet.\n//\n// The Stylus port of MetaMultiSigWallet is ~29 KB compressed on Arbitrum, which\n// exceeds the 24 KB EVM code-size limit. cargo-stylus deploys it as a\n// fragmented contract, which means the canonical StylusDeployer's single-\n// bytecode `deploy(bytecode, initData, ...)` path cannot represent it. Instead\n// we deploy the Stylus contract ONCE as an implementation, then for each user\n// account we deploy a tiny EIP-1167 proxy (~45 bytes of EVM bytecode, well\n// under the limit) that delegatecalls into the impl. The proxy holds its own\n// storage, so each account has independent signers/nonces/nullifiers while\n// sharing one piece of WASM logic.\n//\n// Stylus/EVM interop note: when an EVM contract DELEGATECALLs a Stylus\n// program, the Arbitrum runtime routes the call into the WASM VM with the\n// caller's storage context — confirmed compatible with EIP-1167 proxies (see\n// the Stylus Saturdays \"Writing proxies in Arbitrum Stylus\" issue).\ncontract MetaMultiSigWalletStylusFactory {\n // Stylus impl whose code every proxy will delegatecall into. Immutable so\n // the factory commits to a single, audited impl version per deployment.\n address public immutable implementation;\n\n event WalletCreated(address indexed wallet, uint256[] commitments, uint256 signaturesRequired);\n\n constructor(address _implementation) {\n require(_implementation != address(0), \"Invalid implementation\");\n implementation = _implementation;\n }\n\n // Atomically clone the impl and call init() on the new proxy. Reverts if\n // init reverts so we never return a half-initialized wallet address.\n function createWallet(\n address zkvContract,\n bytes32 vkHash,\n address poseidonT3,\n uint256 chainId,\n uint256[] calldata initialCommitments,\n uint256 signaturesRequired\n ) external returns (address wallet) {\n wallet = _cloneEIP1167(implementation);\n\n (bool ok, bytes memory ret) = wallet.call(\n abi.encodeWithSignature(\n \"init(address,bytes32,address,uint256,uint256[],uint256)\",\n zkvContract,\n vkHash,\n poseidonT3,\n chainId,\n initialCommitments,\n signaturesRequired\n )\n );\n if (!ok) {\n // Bubble up the original revert data so the relayer sees the real\n // reason (e.g. WalletError(reason)) rather than a generic \"init\n // failed\".\n assembly {\n revert(add(ret, 0x20), mload(ret))\n }\n }\n\n emit WalletCreated(wallet, initialCommitments, signaturesRequired);\n }\n\n // Minimal proxy deployment via CREATE. EIP-1167 with a 5-byte prefix that\n // accepts plain ETH transfers locally instead of delegatecalling on empty\n // calldata. Required because the Stylus impl is fragmented by cargo-stylus;\n // the loader fragment dispatches on a 4-byte selector and reverts on empty\n // calldata, which would otherwise make plain `addr.transfer(...)` deposits\n // (and `receive()` routing) revert at gas estimation.\n //\n // Runtime layout (52 bytes):\n // 00: 36 15 60 32 57 if calldatasize == 0 → JUMPI to 0x32\n // 05..30: standard EIP-1167 body (PUSH1 jumpdest 0x2b shifted to 0x30)\n // 31: f3 (RETURN inside EIP-1167 body)\n // 32: 5b 00 JUMPDEST + STOP — empty-calldata branch\n function _cloneEIP1167(address target) private returns (address instance) {\n bytes20 targetBytes = bytes20(target);\n assembly {\n let ptr := mload(0x40)\n // bytes [0..24]: creation prefix (10) + empty-calldata check (5) +\n // EIP-1167 prelude up to PUSH20 (10); last 7 bytes of the word are\n // zero padding that the next mstore overwrites with the address.\n mstore(ptr, 0x3d603480600a3d3981f33615603257363d3d373d3d3d363d7300000000000000)\n // bytes [25..44]: 20-byte impl address (bytes20 left-aligned).\n mstore(add(ptr, 25), targetBytes)\n // bytes [45..61]: EIP-1167 suffix with internal JUMPDEST shifted\n // from 0x2b to 0x30, followed by the empty-calldata JUMPDEST + STOP.\n mstore(add(ptr, 45), 0x5af43d82803e903d91603057fd5bf35b00000000000000000000000000000000)\n instance := create(0, ptr, 62)\n }\n require(instance != address(0), \"Clone failed\");\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "evmVersion": "paris", + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/packages/hardhat/hardhat.config.ts b/packages/hardhat/hardhat.config.ts index c37fc85d..11e1f236 100644 --- a/packages/hardhat/hardhat.config.ts +++ b/packages/hardhat/hardhat.config.ts @@ -66,7 +66,8 @@ const config: HardhatUserConfig = { accounts: [deployerPrivateKey], }, arbitrumSepolia: { - url: `https://arb-sepolia.g.alchemy.com/v2/${providerApiKey}`, + // Default Alchemy key is IP-whitelisted; use the public RPC unless overridden. + url: process.env.ARBITRUM_SEPOLIA_RPC || "https://sepolia-rollup.arbitrum.io/rpc", accounts: [deployerPrivateKey], }, optimism: { diff --git a/packages/nextjs/.env.example b/packages/nextjs/.env.example index 8e1d93db..d235b781 100644 --- a/packages/nextjs/.env.example +++ b/packages/nextjs/.env.example @@ -3,3 +3,7 @@ NEXT_PUBLIC_NETWORK="testnet" # x402 gasless USDC deposit (optional) NEXT_PUBLIC_FEATURE_X402_DEPOSIT=false + +# Block mobile devices (redirect to /mobile). Default off: mobile users see the +# zoomed-out desktop layout. Set to "true" to re-enable mobile blocking. +NEXT_PUBLIC_ENABLE_MOBILE_BLOCK=false diff --git a/packages/nextjs/app/layout.tsx b/packages/nextjs/app/layout.tsx index 7344d837..9a0c43f9 100644 --- a/packages/nextjs/app/layout.tsx +++ b/packages/nextjs/app/layout.tsx @@ -25,6 +25,14 @@ export const metadata = getMetadata({ description: "A secure and user-friendly wallet for your digital assets", }); +// When mobile blocking is off (default), force a desktop-width viewport so +// mobile browsers render the full desktop layout (zoomed out) instead of +// breaking. When blocking is on, fall back to device-width so the /mobile +// screen renders correctly. Temporary while mobile is unsupported. +export const viewport = { + width: process.env.NEXT_PUBLIC_ENABLE_MOBILE_BLOCK === "true" ? "device-width" : 1440, +}; + const ScaffoldEthApp = ({ children }: { children: React.ReactNode }) => { return ( diff --git a/packages/nextjs/components/NewAccount/ChooseNetwork.tsx b/packages/nextjs/components/NewAccount/ChooseNetwork.tsx index 5fe075bd..e8d27bbc 100644 --- a/packages/nextjs/components/NewAccount/ChooseNetwork.tsx +++ b/packages/nextjs/components/NewAccount/ChooseNetwork.tsx @@ -16,6 +16,8 @@ interface ChooseNetworkProps { const HORIZEN_MAINNET = 26514; const BASE_MAINNET = 8453; +// Arbitrum is testnet-only (zkVerify has no Arbitrum One mainnet verifier yet). +const ARBITRUM_SEPOLIA = 421614; const ChooseNetwork: React.FC = ({ className, @@ -27,12 +29,16 @@ const ChooseNetwork: React.FC = ({ }) => { const defaultChainId = getDefaultChainId(); + const isTestnet = defaultChainId === 2651420; + const networks = [ { chainId: HORIZEN_MAINNET, fallbackChainId: 2651420 }, { chainId: BASE_MAINNET, fallbackChainId: 84532 }, + // Arbitrum has no mainnet entry; only surfaced on testnet. + ...(isTestnet ? [{ chainId: ARBITRUM_SEPOLIA, fallbackChainId: ARBITRUM_SEPOLIA }] : []), ].map(n => { // If we are on testnet env, use testnet ids instead - const chainId = defaultChainId === 2651420 ? n.fallbackChainId : n.chainId; + const chainId = isTestnet ? n.fallbackChainId : n.chainId; return { chainId, meta: getNetworkMeta(chainId) }; }); diff --git a/packages/nextjs/components/Sidebar/NetworkChooserSidebar.tsx b/packages/nextjs/components/Sidebar/NetworkChooserSidebar.tsx index 1eb881b6..e8e964b5 100644 --- a/packages/nextjs/components/Sidebar/NetworkChooserSidebar.tsx +++ b/packages/nextjs/components/Sidebar/NetworkChooserSidebar.tsx @@ -13,7 +13,8 @@ interface NetworkChooserSidebarProps { } const NETWORKS_MAINNET = [26514, 8453]; -const NETWORKS_TESTNET = [2651420, 84532]; +// Arbitrum Sepolia (421614) is testnet-only — no Arbitrum One mainnet entry. +const NETWORKS_TESTNET = [2651420, 84532, 421614]; export default function NetworkChooserSidebar({ isOpen, accounts, onSelectNetwork }: NetworkChooserSidebarProps) { const { selectedNetworkChainId } = useSidebarStore(); diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index fc5d8122..011c166c 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -5,6 +5,108 @@ import { GenericContractsDeclaration } from "~~/utils/scaffold-eth/contract"; const deployedContracts = { + 421614: { + MetaMultiSigWalletStylusFactory: { + address: "0x8F5f249210fFc91a2b1D86828764562f97C9eEdd", + abi: [ + { + inputs: [ + { + internalType: "address", + name: "_implementation", + type: "address", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "wallet", + type: "address", + }, + { + indexed: false, + internalType: "uint256[]", + name: "commitments", + type: "uint256[]", + }, + { + indexed: false, + internalType: "uint256", + name: "signaturesRequired", + type: "uint256", + }, + ], + name: "WalletCreated", + type: "event", + }, + { + inputs: [ + { + internalType: "address", + name: "zkvContract", + type: "address", + }, + { + internalType: "bytes32", + name: "vkHash", + type: "bytes32", + }, + { + internalType: "address", + name: "poseidonT3", + type: "address", + }, + { + internalType: "uint256", + name: "chainId", + type: "uint256", + }, + { + internalType: "uint256[]", + name: "initialCommitments", + type: "uint256[]", + }, + { + internalType: "uint256", + name: "signaturesRequired", + type: "uint256", + }, + ], + name: "createWallet", + outputs: [ + { + internalType: "address", + name: "wallet", + type: "address", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "implementation", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + ], + inheritedFunctions: {}, + deployedOnBlock: 273307930, + }, + }, 2651420: { MetaMultiSigWallet: { address: "0xE146bA86fef4056566D7EE9dBB9fFaCf8A994AC2", diff --git a/packages/nextjs/hooks/app/useMobileDetection.ts b/packages/nextjs/hooks/app/useMobileDetection.ts index c37faccf..3a782c22 100644 --- a/packages/nextjs/hooks/app/useMobileDetection.ts +++ b/packages/nextjs/hooks/app/useMobileDetection.ts @@ -10,6 +10,13 @@ export function useMobileDetection() { const router = useAppRouter(); useEffect(() => { + // Mobile blocking is opt-in via env flag; disabled by default so mobile + // users see the (zoomed-out) desktop layout instead of the /mobile screen. + if (process.env.NEXT_PUBLIC_ENABLE_MOBILE_BLOCK !== "true") { + setIsLoading(false); + return; + } + const checkMobile = () => { const isMobileDevice = window.innerWidth <= 780; diff --git a/packages/nextjs/public/token/arbitrum.svg b/packages/nextjs/public/token/arbitrum.svg new file mode 100644 index 00000000..df5b5701 --- /dev/null +++ b/packages/nextjs/public/token/arbitrum.svg @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/nextjs/scaffold.config.ts b/packages/nextjs/scaffold.config.ts index 143f16f0..708c6467 100644 --- a/packages/nextjs/scaffold.config.ts +++ b/packages/nextjs/scaffold.config.ts @@ -68,10 +68,11 @@ const scaffoldConfig = { // The networks on which your DApp is live // targetNetworks: [chains.sepolia], // targetNetworks: [chains.hardhat], + // Arbitrum is testnet-only: zkVerify has a verifier on Arbitrum Sepolia but not Arbitrum One. targetNetworks: process.env.NEXT_PUBLIC_NETWORK === NetworkValue.mainnet ? [horizenMainnet, chains.base] - : [horizenTestnet, chains.baseSepolia], + : [horizenTestnet, chains.baseSepolia, chains.arbitrumSepolia], // The interval at which your front-end polls the RPC servers for new data (it has no effect if you only target the local network (default is 4000)) pollingInterval: RPC_POLLING_INTERVAL, // This is ours Alchemy's default API key. diff --git a/packages/nextjs/utils/network.ts b/packages/nextjs/utils/network.ts index f00b6b79..fcf02721 100644 --- a/packages/nextjs/utils/network.ts +++ b/packages/nextjs/utils/network.ts @@ -29,6 +29,12 @@ const NETWORK_META_BY_CHAIN_ID: Record = { icon: "/token/base.svg", badge: "/token/base.svg", }, + // Arbitrum (testnet only). Add /token/arbitrum.svg asset for the icon/badge. + 421614: { + name: "Arbitrum Sepolia", + icon: "/token/arbitrum.svg", + badge: "/token/arbitrum.svg", + }, }; export const getDefaultChainId = (): number => { diff --git a/packages/shared/src/chains/arbitrumSepolia.ts b/packages/shared/src/chains/arbitrumSepolia.ts new file mode 100644 index 00000000..b4a01f1e --- /dev/null +++ b/packages/shared/src/chains/arbitrumSepolia.ts @@ -0,0 +1,6 @@ +import { arbitrumSepolia } from "viem/chains"; + +// Re-export viem's Arbitrum Sepolia chain definition for consistency with other chains module. +// Arbitrum is testnet-only in PolyPay: zkVerify has a verifier on Arbitrum Sepolia (421614) +// but not on Arbitrum One mainnet yet. +export { arbitrumSepolia }; diff --git a/packages/shared/src/chains/index.ts b/packages/shared/src/chains/index.ts index 3b5de4f1..782453c5 100644 --- a/packages/shared/src/chains/index.ts +++ b/packages/shared/src/chains/index.ts @@ -2,8 +2,15 @@ import { horizenTestnet } from "./horizenTestnet"; import { horizenMainnet } from "./horizenMainnet"; import { baseSepolia } from "./baseSepolia"; import { baseMainnet } from "./baseMainnet"; +import { arbitrumSepolia } from "./arbitrumSepolia"; -export { horizenTestnet, horizenMainnet, baseSepolia, baseMainnet }; +export { + horizenTestnet, + horizenMainnet, + baseSepolia, + baseMainnet, + arbitrumSepolia, +}; export type NetworkType = "testnet" | "mainnet"; export const NetworkValue = { @@ -29,6 +36,8 @@ export const getChainById = (chainId: number) => { return baseSepolia; case baseMainnet.id: return baseMainnet; + case arbitrumSepolia.id: + return arbitrumSepolia; default: throw new Error(`Unsupported chainId: ${chainId}`); } diff --git a/packages/shared/src/constants/token.ts b/packages/shared/src/constants/token.ts index 645ba263..39e72d5b 100644 --- a/packages/shared/src/constants/token.ts +++ b/packages/shared/src/constants/token.ts @@ -20,12 +20,15 @@ const HORIZEN_MAINNET = 26514; const HORIZEN_TESTNET = 2651420; const BASE_MAINNET = 8453; const BASE_SEPOLIA = 84532; +// Arbitrum is testnet-only in PolyPay (zkVerify has no Arbitrum One verifier). +const ARBITRUM_SEPOLIA = 421614; const ALL_CHAIN_IDS = [ HORIZEN_MAINNET, HORIZEN_TESTNET, BASE_MAINNET, BASE_SEPOLIA, + ARBITRUM_SEPOLIA, ]; export const NATIVE_ETH: Token = { @@ -75,6 +78,8 @@ export const USDC_TOKEN: Token = { [HORIZEN_MAINNET]: "0xDF7108f8B10F9b9eC1aba01CCa057268cbf86B6c", [BASE_MAINNET]: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", [BASE_SEPOLIA]: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + // Circle official USDC on Arbitrum Sepolia (source: developers.circle.com). + [ARBITRUM_SEPOLIA]: "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", }, symbol: "USDC", name: "USD Coin", diff --git a/packages/shared/src/contracts/MetaMultiSigWalletStylus.ts b/packages/shared/src/contracts/MetaMultiSigWalletStylus.ts new file mode 100644 index 00000000..d290c823 --- /dev/null +++ b/packages/shared/src/contracts/MetaMultiSigWalletStylus.ts @@ -0,0 +1,78 @@ +// Arbitrum Stylus deployment helpers for the Rust port of MetaMultiSigWallet. +// +// The Stylus contract exports the SAME Solidity ABI as the EVM contract for its +// runtime methods (execute, getTransactionHash, ...), so the relayer/frontend +// reuse `METAMULTISIG_ABI` for reads/writes against deployed wallet addresses. +// +// Deployment is the only thing that differs from the EVM path: +// - The Stylus impl is ~29 KB compressed (above the 24 KB EVM code-size cap), +// so cargo-stylus fragments it on-chain. That makes the single-bytecode +// `StylusDeployer.deploy(bytecode, ...)` path unusable for per-account +// deploys from the relayer. +// - We deploy the Stylus impl ONCE (via `cargo stylus deploy`), then route +// all per-account creation through `MetaMultiSigWalletStylusFactory`, which +// clones an EIP-1167 minimal proxy in front of the impl and calls +// `init(...)` atomically. Each proxy gets its own storage, so signers / +// nonces / nullifiers stay isolated per wallet. +// - The Stylus contract exposes both a `constructor` (used once by +// cargo-stylus when deploying the impl) and an `init` function with the +// same args. The latter is what the factory calls on the freshly-cloned +// proxy through delegatecall. + +// Chains whose account contract is the Stylus port instead of the EVM .sol one. +export const STYLUS_CHAIN_IDS: readonly number[] = [ + 421614, // Arbitrum Sepolia +]; + +export const isStylusChain = (chainId: number): boolean => + STYLUS_CHAIN_IDS.includes(chainId); + +// Minimal factory ABI: createWallet(...) returns the proxy address and emits +// WalletCreated. `init` is included so callers can build calldata for the +// proxy if they ever need to skip the factory (testing/manual). +export const METAMULTISIG_STYLUS_FACTORY_ABI = [ + { + type: "function", + name: "createWallet", + stateMutability: "nonpayable", + inputs: [ + { name: "zkvContract", type: "address" }, + { name: "vkHash", type: "bytes32" }, + { name: "poseidonT3", type: "address" }, + { name: "chainId", type: "uint256" }, + { name: "initialCommitments", type: "uint256[]" }, + { name: "signaturesRequired", type: "uint256" }, + ], + outputs: [{ name: "wallet", type: "address" }], + }, + { + type: "function", + name: "implementation", + stateMutability: "view", + inputs: [], + outputs: [{ name: "", type: "address" }], + }, + { + type: "event", + name: "WalletCreated", + inputs: [ + { name: "wallet", type: "address", indexed: true }, + { name: "commitments", type: "uint256[]", indexed: false }, + { name: "signaturesRequired", type: "uint256", indexed: false }, + ], + }, + { + type: "function", + name: "init", + stateMutability: "nonpayable", + inputs: [ + { name: "zkvContract", type: "address" }, + { name: "vkHash", type: "bytes32" }, + { name: "poseidonT3", type: "address" }, + { name: "chainId", type: "uint256" }, + { name: "initialCommitments", type: "uint256[]" }, + { name: "signaturesRequired", type: "uint256" }, + ], + outputs: [], + }, +] as const; diff --git a/packages/shared/src/contracts/contracts-config.ts b/packages/shared/src/contracts/contracts-config.ts index 8213ab1a..b9a5cde3 100644 --- a/packages/shared/src/contracts/contracts-config.ts +++ b/packages/shared/src/contracts/contracts-config.ts @@ -27,6 +27,25 @@ export const CONTRACT_CONFIG_BY_CHAIN_ID = { "0xb3c5381523a496996868370791ec7ae490be7e2c996296fb67708daed8a6ea38", poseidonT3Address: "0x3333333C0A88F9BE4fd23ed0536F9B6c427e3B93", }, + 421614: { + // Arbitrum Sepolia (testnet only — zkVerify has no Arbitrum One mainnet verifier yet). + // On this chain the account contract is the Stylus (Rust/WASM) port of + // MetaMultiSigWallet, deployed once as `stylusImplAddress` and fronted by + // EIP-1167 minimal proxies created per-account through `stylusFactoryAddress`. + // The Stylus impl STATICCALLs the PoseidonT3 + zkVerify contracts below. + zkVerifyAddress: "0xd007494945580eEb25522c8e0b2fa798B3F0FDE2", + vkHash: + "0xb3c5381523a496996868370791ec7ae490be7e2c996296fb67708daed8a6ea38", + // PoseidonT3 must be deployed on Arbitrum Sepolia. Use the deterministic + // address if redeployed via the same CREATE2 factory; otherwise update this. + poseidonT3Address: "0x3333333C0A88F9BE4fd23ed0536F9B6c427e3B93", + // Stylus MetaMultiSigWallet impl (deployed via `cargo stylus deploy`). + // Update after redeploying with the `init()` entry added in this branch. + stylusImplAddress: "0x0395b99f3a45bd08d018d3d3060a0e2bf8dc8978", + // EIP-1167 factory that clones the impl and calls init() per account. + // Update after running `yarn deploy --tags StylusFactory --network arbitrumSepolia`. + stylusFactoryAddress: "0x8F5f249210fFc91a2b1D86828764562f97C9eEdd", + }, } as const; export const getContractConfigByChainId = (chainId: number) => { @@ -39,3 +58,19 @@ export const getContractConfigByChainId = (chainId: number) => { } return config; }; + +// Returns the Stylus factory address for a chain whose account contract is the +// Stylus port. Throws if the chain is not Stylus-backed or the factory has not +// been wired yet (zero address sentinel). +export const getStylusFactoryAddress = (chainId: number): `0x${string}` => { + const config = getContractConfigByChainId(chainId) as { + stylusFactoryAddress?: string; + }; + const addr = config.stylusFactoryAddress; + if (!addr || addr === "0x0000000000000000000000000000000000000000") { + throw new Error( + `stylusFactoryAddress is not configured for chainId ${chainId}`, + ); + } + return addr as `0x${string}`; +}; diff --git a/packages/shared/src/contracts/index.ts b/packages/shared/src/contracts/index.ts index 1d4aceb4..8628a929 100644 --- a/packages/shared/src/contracts/index.ts +++ b/packages/shared/src/contracts/index.ts @@ -1,2 +1,3 @@ export * from "./MetaMultiSigWallet"; +export * from "./MetaMultiSigWalletStylus"; export * from "./contracts-config"; diff --git a/packages/stylus/.gitignore b/packages/stylus/.gitignore new file mode 100644 index 00000000..85183ca8 --- /dev/null +++ b/packages/stylus/.gitignore @@ -0,0 +1,3 @@ +/target +*.wasm +# Cargo.lock is committed on purpose: Stylus reproducible builds hash it. diff --git a/packages/stylus/Cargo.lock b/packages/stylus/Cargo.lock new file mode 100644 index 00000000..68c67236 --- /dev/null +++ b/packages/stylus/Cargo.lock @@ -0,0 +1,4752 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "alloy-chains" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84e0378e959aa6a885897522080a990e80eb317f1e9a222a604492ea50e13096" +dependencies = [ + "alloy-primitives", + "num_enum", + "strum", +] + +[[package]] +name = "alloy-consensus" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f16daaf7e1f95f62c6c3bf8a3fc3d78b08ae9777810c0bb5e94966c7cd57ef0" +dependencies = [ + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "alloy-trie", + "alloy-tx-macros", + "auto_impl", + "borsh", + "c-kzg", + "derive_more", + "either", + "k256", + "once_cell", + "rand 0.8.6", + "secp256k1 0.30.0", + "serde", + "serde_json", + "serde_with", + "thiserror", +] + +[[package]] +name = "alloy-consensus-any" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "118998d9015332ab1b4720ae1f1e3009491966a0349938a1f43ff45a8a4c6299" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-eip2124" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "741bdd7499908b3aa0b159bba11e71c8cddd009a2c2eb7a06e825f1ec87900a5" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "crc", + "serde", + "thiserror", +] + +[[package]] +name = "alloy-eip2930" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9441120fa82df73e8959ae0e4ab8ade03de2aaae61be313fbf5746277847ce25" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "borsh", + "serde", +] + +[[package]] +name = "alloy-eip7702" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2919c5a56a1007492da313e7a3b6d45ef5edc5d33416fdec63c0d7a2702a0d20" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "borsh", + "serde", + "thiserror", +] + +[[package]] +name = "alloy-eip7928" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b827a6d7784fe3eb3489d40699407a4cdcce74271421a01bdffe60cf573bb16" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "borsh", + "once_cell", + "serde", + "thiserror", +] + +[[package]] +name = "alloy-eips" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ef28c9fdad22d4eec52d894f5f2673a0895f1e5ef196734568e68c0f6caca8" +dependencies = [ + "alloy-eip2124", + "alloy-eip2930", + "alloy-eip7702", + "alloy-eip7928", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "auto_impl", + "borsh", + "c-kzg", + "derive_more", + "either", + "serde", + "serde_with", + "sha2", +] + +[[package]] +name = "alloy-json-abi" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c36c9d7f9021601b04bfef14a4b64849f6d73116a4e91e071d7fbfe10247901" +dependencies = [ + "alloy-primitives", + "alloy-sol-type-parser", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-json-rpc" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "422d110f1c40f1f8d0e5562b0b649c35f345fccb7093d9f02729943dcd1eef71" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "http", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "alloy-network" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7197a66d94c4de1591cdc16a9bcea5f8cccd0da81b865b49aef97b1b4016e0fa" +dependencies = [ + "alloy-consensus", + "alloy-consensus-any", + "alloy-eips", + "alloy-json-rpc", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rpc-types-any", + "alloy-rpc-types-eth", + "alloy-serde", + "alloy-signer", + "alloy-sol-types", + "async-trait", + "auto_impl", + "derive_more", + "futures-utils-wasm", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "alloy-network-primitives" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb82711d59a43fdfd79727c99f270b974c784ec4eb5728a0d0d22f26716c87ef" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-primitives" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4885c1409b6936c4898e646ef58baf6ec54edaf6d8179f79df805a7b85b7cf3e" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "foldhash 0.2.0", + "hashbrown 0.17.1", + "indexmap 2.11.1", + "itoa", + "k256", + "keccak-asm", + "paste", + "proptest", + "rand 0.9.4", + "rapidhash", + "ruint", + "rustc-hash", + "secp256k1 0.31.1", + "serde", + "sha3 0.11.0", + "tiny-keccak", +] + +[[package]] +name = "alloy-provider" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf6b18b929ef1d078b834c3631e9c925177f3b23ddc6fa08a722d13047205876" +dependencies = [ + "alloy-chains", + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-network", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rpc-client", + "alloy-rpc-types-eth", + "alloy-signer", + "alloy-sol-types", + "alloy-transport", + "alloy-transport-http", + "async-stream", + "async-trait", + "auto_impl", + "dashmap", + "either", + "futures", + "futures-utils-wasm", + "lru", + "parking_lot", + "pin-project", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "url", + "wasmtimer", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc90b1e703d3c03f4ff7f48e82dd0bc1c8211ab7d079cd836a06fcfeb06651cb" +dependencies = [ + "alloy-rlp-derive", + "arrayvec", + "bytes", +] + +[[package]] +name = "alloy-rlp-derive" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36834a5c0a2fa56e171bf256c34d70fca07d0c0031583edea1c4946b7889c9e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "alloy-rpc-client" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fcc9604042ca80bd37aa5e232ea1cd851f337e31e2babbbb345bc0b1c30de3" +dependencies = [ + "alloy-json-rpc", + "alloy-primitives", + "alloy-transport", + "alloy-transport-http", + "futures", + "pin-project", + "reqwest", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower", + "tracing", + "url", + "wasmtimer", +] + +[[package]] +name = "alloy-rpc-types-any" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3823026d1ed239a40f12364fac50726c8daf1b6ab8077a97212c5123910429ed" +dependencies = [ + "alloy-consensus-any", + "alloy-rpc-types-eth", + "alloy-serde", +] + +[[package]] +name = "alloy-rpc-types-eth" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59c095f92c4e1ff4981d89e9aa02d5f98c762a1980ab66bec49c44be11349da2" +dependencies = [ + "alloy-consensus", + "alloy-consensus-any", + "alloy-eips", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "alloy-sol-types", + "itertools 0.14.0", + "serde", + "serde_json", + "serde_with", + "thiserror", +] + +[[package]] +name = "alloy-serde" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ece63b89294b8614ab3f483560c08d016930f842bf36da56bf0b764a15c11e" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-signer" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f447aefab0f1c0649f71edc33f590992d4e122bc35fb9cdbbf67d4421ace85" +dependencies = [ + "alloy-primitives", + "async-trait", + "auto_impl", + "either", + "elliptic-curve", + "k256", + "thiserror", +] + +[[package]] +name = "alloy-sol-macro" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "840128ed2b2971d6d4668a553fe403a82683d3acc646c73e75887e7157408033" +dependencies = [ + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63ec265e5d65d725175f6ca7711c970824c90ef9c0d1f1973711d4150ee612dd" +dependencies = [ + "alloy-sol-macro-input", + "const-hex", + "heck", + "indexmap 2.11.1", + "proc-macro-error2", + "proc-macro2", + "quote", + "sha3 0.11.0", + "syn 2.0.117", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-macro-input" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89bf01077f18650876cfa682eb1f949967b5cde03f1a51c955c469d2c9b4aa67" +dependencies = [ + "const-hex", + "dunce", + "heck", + "macro-string", + "proc-macro2", + "quote", + "syn 2.0.117", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-type-parser" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "857b470ecdd2ed38beaf82ad1a38c516a8ff75266750f38b9eeed001d575241b" +dependencies = [ + "serde", + "winnow 1.0.3", +] + +[[package]] +name = "alloy-sol-types" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384cf252de0db2dec52821eac037a7f57e2aa33fe5b900ce6fe39973402341f1" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-macro", + "serde", +] + +[[package]] +name = "alloy-transport" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8098f965442a9feb620965ba4b4be5e2b320f4ec5a3fff6bfa9e1ff7ef42bed1" +dependencies = [ + "alloy-json-rpc", + "auto_impl", + "base64", + "derive_more", + "futures", + "futures-utils-wasm", + "parking_lot", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "tracing", + "url", + "wasmtimer", +] + +[[package]] +name = "alloy-transport-http" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8597d36d546e1dab822345ad563243ec3920e199322cb554ce56c8ef1a1e2e7" +dependencies = [ + "alloy-json-rpc", + "alloy-transport", + "itertools 0.14.0", + "reqwest", + "serde_json", + "tower", + "tracing", + "url", +] + +[[package]] +name = "alloy-trie" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f14b5d9b2c2173980202c6ff470d96e7c5e202c65a9f67884ad565226df7fbb" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "derive_more", + "nybbles", + "serde", + "smallvec", + "thiserror", + "tracing", +] + +[[package]] +name = "alloy-tx-macros" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69722eddcdf1ce096c3ab66cf8116999363f734eb36fe94a148f4f71c85da84" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.4.1", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand 0.8.6", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.6", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "auto_impl" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "aws-lc-rs" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitcoin-io" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953" + +[[package]] +name = "bitcoin_hashes" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" +dependencies = [ + "bitcoin-io", + "hex-conservative", +] + +[[package]] +name = "bitflags" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "blst" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcdb4c7013139a150f9fc55d123186dbfaba0d912817466282c73ac49e71fb45" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + +[[package]] +name = "borsh" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +dependencies = [ + "borsh-derive", + "bytes", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfcfdc083699101d5a7965e49925975f2f55060f94f9a05e7187be95d530ca59" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "branches" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e426eb5cc1900033930ec955317b302e68f19f326cc7bb0c8a86865a826cdf0c" +dependencies = [ + "rustc_version 0.4.1", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +dependencies = [ + "serde", +] + +[[package]] +name = "c-kzg" +version = "2.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6648ed1e4ea8e8a1a4a2c78e1cda29a3fd500bc622899c340d8525ea9a76b24a" +dependencies = [ + "blst", + "cc", + "glob", + "hex", + "libc", + "once_cell", + "serde", +] + +[[package]] +name = "cc" +version = "1.2.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "num-traits", + "serde", + "windows-link", +] + +[[package]] +name = "clap" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "const-hex" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dccd746bf9b1038c0507b7cec21eb2b11222db96a2902c96e8c185d6d20fb9c4" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "serde", + "strsim", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dashmap" +version = "6.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", + "serde_core", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case 0.10.0", + "proc-macro2", + "quote", + "rustc_version 0.4.1", + "syn 2.0.117", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common 0.1.6", + "subtle", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.0", + "crypto-common 0.2.2", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "serdect", + "signature", + "spki", +] + +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" +dependencies = [ + "serde", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "serdect", + "subtle", + "zeroize", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "fastrlp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand 0.8.6", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "futures-utils-wasm" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" + +[[package]] +name = "generic-array" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 5.3.0", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "foldhash 0.2.0", + "serde", + "serde_core", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-conservative" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda06d18ac606267c40c04e41b9947729bf8b9efe74bd4e82b61a5f26a510b9f" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hybrid-array" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" +dependencies = [ + "typenum", +] + +[[package]] +name = "hyper" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921" +dependencies = [ + "equivalent", + "hashbrown 0.15.5", + "serde", +] + +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys", + "log", + "simd_cesu8", + "thiserror", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version 0.4.1", + "simd_cesu8", + "syn 2.0.117", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.117", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08" +dependencies = [ + "cfg-if", + "futures-util", + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "serdect", + "sha2", +] + +[[package]] +name = "keccak" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" +dependencies = [ + "cpufeatures 0.2.17", +] + +[[package]] +name = "keccak" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e24a010dd405bd7ed803e5253182815b41bf2e6a80cc3bfc066658e03a198aa" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", +] + +[[package]] +name = "keccak-asm" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1766b89733097006f3a1388a02849865d6bc98c89273cb622e29fdd209922183" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + +[[package]] +name = "keccak-const" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d8d8ce877200136358e0bbff3a77965875db3af755a11e1fa6b1b3e2df13ea" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "lru" +version = "0.16.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f66e8d5d03f609abc3a39e6f08e4164ebf1447a732906d39eb9b99b7919ef39" +dependencies = [ + "hashbrown 0.16.1", +] + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "macro-string" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a9dbbfc75d2688ed057456ce8a3ee3f48d12eec09229f560f3643b9f275653" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "mini-alloc" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b620761d4c29ede39bb1351c4360dba54d3b414d9fb460d37cba4c98b37a0b9d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "mio" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "nybbles" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa11e84403164a9f12982ab728f3c67c6fd4ab5b5f0254ffc217bdbd3b28ab0" +dependencies = [ + "alloy-rlp", + "cfg-if", + "proptest", + "ruint", + "serde", + "smallvec", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pest" +version = "2.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "pin-project" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "polypay-multisig-stylus" +version = "0.1.0" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "stylus-sdk", +] + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.117", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags", + "num-traits", + "rand 0.9.4", + "rand_chacha 0.9.0", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +dependencies = [ + "aws-lc-rs", + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.4", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.60.2", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", + "serde", +] + +[[package]] +name = "rand" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", + "serde", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", + "serde", +] + +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "rapidhash" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e48930979c155e2f33aa36ab3119b5ee81332beb6482199a8ecd6029b80b59" +dependencies = [ + "rustversion", +] + +[[package]] +name = "rclite" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6716a637a8a17bce72da6b6ddab8548619cc748658c41ab6ee5c4a3c1001385" +dependencies = [ + "branches", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "reqwest" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62e0021ea2c22aed41653bc7e1419abb2c97e038ff2c33d0e1309e49a97deec0" +dependencies = [ + "base64", + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", + "serde", + "serde_json", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "ruint" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecb38f82477f20c5c3d62ef52d7c4e536e38ea9b73fb570a20c5cae0e14bcf6" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp 0.3.1", + "fastrlp 0.4.0", + "num-bigint", + "num-integer", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand 0.8.6", + "rand 0.9.4", + "rlp", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver 1.0.28", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" +dependencies = [ + "aws-lc-rs", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.103.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "rusty-fork" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "serdect", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" +dependencies = [ + "bitcoin_hashes", + "rand 0.8.6", + "secp256k1-sys 0.10.1", + "serde", +] + +[[package]] +name = "secp256k1" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3c81b43dc2d8877c216a3fccf76677ee1ebccd429566d3e67447290d0c42b2" +dependencies = [ + "bitcoin_hashes", + "rand 0.9.4", + "secp256k1-sys 0.11.0", +] + +[[package]] +name = "secp256k1-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +dependencies = [ + "cc", +] + +[[package]] +name = "secp256k1-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb913707158fadaf0d8702c2db0e857de66eb003ccfdda5924b5f5ac98efb38" +dependencies = [ + "cc", +] + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "semver-parser" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_with" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e72c1c2cb7b223fafb600a619537a871c2818583d619401b785e7c0b746ccde2" +dependencies = [ + "base64", + "bs58", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.11.1", + "schemars 0.9.0", + "schemars 1.2.1", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b90c488738ecb4fb0262f41f43bc40efc5868d9fb744319ddf5f5317f417bfac" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serdect" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" +dependencies = [ + "base16ct", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874" +dependencies = [ + "digest 0.10.7", + "keccak 0.1.6", +] + +[[package]] +name = "sha3" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1" +dependencies = [ + "digest 0.11.3", + "keccak 0.2.0", +] + +[[package]] +name = "sha3-asm" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f3f15d4e239ebe08413eed880e0f9b5af4b40ee0472543320efa91d488e96a7" +dependencies = [ + "cc", + "cfg-if", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "simd_cesu8" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +dependencies = [ + "rustc_version 0.4.1", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "stylus-core" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69490f4425dba8b15f04077a05323d2b798fbfac6db6e198e4ae758f2e4332b" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "cfg-if", + "dyn-clone", + "lazy_static", + "regex", +] + +[[package]] +name = "stylus-proc" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef6c66876a6b42a30656137f3f5116ca3a46b772ec6afd913fed6d0e73e111e" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "cfg-if", + "convert_case 0.6.0", + "lazy_static", + "proc-macro-error", + "proc-macro2", + "quote", + "regex", + "sha3 0.10.9", + "stylus-core", + "syn 2.0.117", + "syn-solidity", + "trybuild", +] + +[[package]] +name = "stylus-sdk" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5814fb3d3a8d602203abe708b3aeb4319e8d7f6f9f7b66981ab8af579dab052" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "branches", + "cfg-if", + "clap", + "derivative", + "hex", + "keccak 0.1.6", + "keccak-const", + "mini-alloc", + "rclite", + "ruint", + "stylus-core", + "stylus-proc", + "stylus-test", +] + +[[package]] +name = "stylus-test" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb3933c091cbaa2b4c7fcc65cbe8b583f5a46985f944984d9e2b622bb82eb746" +dependencies = [ + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "stylus-core", + "tokio", + "url", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn-solidity" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec005042c7d952febc1a3ef5b0f6674e9054aa836877a31c90b20e25b3d31744" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "target-triple" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "591ef38edfb78ca4771ee32cf494cb8771944bee237a9b91fc9c1424ac4b777b" + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.2", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" +dependencies = [ + "indexmap 2.11.1", + "serde", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow 0.7.15", +] + +[[package]] +name = "toml_datetime" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7211ff1b8f0d3adae1663b7da9ffe396eabe1ca25f0b0bee42b0da29a9ddce93" +dependencies = [ + "indexmap 2.11.1", + "toml_datetime", + "toml_parser", + "winnow 0.7.15", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow 1.0.3", +] + +[[package]] +name = "toml_writer" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "url", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "trybuild" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f614c21bd3a61bad9501d75cbb7686f00386c806d7f456778432c25cf86948a" +dependencies = [ + "glob", + "serde", + "serde_derive", + "serde_json", + "target-triple", + "termcolor", + "toml", +] + +[[package]] +name = "typenum" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wait-timeout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +dependencies = [ + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.3+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen 0.57.1", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96492d0d3ffba25305a7dc88720d250b1401d7edca02cc3bcd50633b424673b8" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.117", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap 2.11.1", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap 2.11.1", + "semver 1.0.28", +] + +[[package]] +name = "wasmtimer" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c598d6b99ea013e35844697fc4670d08339d5cda15588f193c6beedd12f644b" +dependencies = [ + "futures", + "js-sys", + "parking_lot", + "pin-utils", + "slab", + "wasm-bindgen", +] + +[[package]] +name = "web-sys" +version = "0.3.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap 2.11.1", + "prettyplease", + "syn 2.0.117", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap 2.11.1", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.11.1", + "log", + "semver 1.0.28", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yoke" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/packages/stylus/Cargo.toml b/packages/stylus/Cargo.toml new file mode 100644 index 00000000..74bda076 --- /dev/null +++ b/packages/stylus/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "polypay-multisig-stylus" +version = "0.1.0" +edition = "2021" +license = "MIT" +description = "PolyPay MetaMultiSigWallet ported to Arbitrum Stylus (Rust/WASM)" + +[dependencies] +# Match cargo-stylus 0.10.x so `#[constructor]` is detected and deployed. +stylus-sdk = "0.10.7" +# The `sol!` / `sol_storage!` macros expand to `::alloy_*` extern-crate paths, so +# these must be direct dependencies (versions matched to stylus-sdk). +alloy-primitives = "1.6" +alloy-sol-types = "1.6" + +[dev-dependencies] +stylus-sdk = { version = "0.10.7", features = ["stylus-test"] } + +[features] +# `cargo stylus export-abi` needs this feature to emit the Solidity ABI. +export-abi = ["stylus-sdk/export-abi"] + +[lib] +crate-type = ["lib", "cdylib"] + +# The binary only exists to print the ABI; it must not be built for the WASM target. +[[bin]] +name = "polypay-multisig-stylus" +path = "src/main.rs" +required-features = ["export-abi"] + +# WASM size matters: Stylus rejects programs whose compressed code exceeds the limit. +# These flags keep the binary small. +[profile.release] +codegen-units = 1 +strip = true +lto = true +panic = "abort" +opt-level = "z" diff --git a/packages/stylus/NOTES.md b/packages/stylus/NOTES.md new file mode 100644 index 00000000..e3656531 --- /dev/null +++ b/packages/stylus/NOTES.md @@ -0,0 +1,181 @@ +# Arbitrum Stylus support — status + +Working notes for the `feat/arbitrum-support` branch. The Stylus port of +`MetaMultiSigWallet` is wired end-to-end: per-account wallets are created as +EIP-1167 minimal proxies in front of a single Stylus implementation, so account +creation and `execute` both flow through normal EVM tooling on Arbitrum. + +## Architecture + +- **Stylus impl** (`packages/stylus/src/lib.rs`) — deployed ONCE per chain via + `cargo stylus deploy`. Holds all the WASM logic (signer set, nonce/nullifier + tracking, ZK proof verification through zkVerify, batch transfers). Exposes + both `constructor(...)` (used at impl deploy by cargo-stylus) and `init(...)` + with identical args; an `initialized` storage flag guards against double + init. +- **Factory** (`packages/hardhat/contracts/MetaMultiSigWalletStylusFactory.sol`) + — deployed once, parameterized by the impl address. `createWallet(...)` + clones an EIP-1167 minimal proxy (~45 bytes of EVM bytecode, well under the + 24 KB cap) and atomically calls `init(...)` on the clone via delegatecall. + Bubbles up the underlying revert reason on failure. +- **Per account** — every PolyPay account on Arbitrum Sepolia is one EIP-1167 + proxy with its own storage (signers/nonces/nullifiers) delegating into the + shared impl's WASM. `execute(...)` calls go through the proxy and are + delegatecalled into the Stylus runtime, which sees the proxy's storage as + its own — confirmed compatible per the Stylus Saturdays "Writing proxies in + Arbitrum Stylus" issue (2024-09-21). + +## Why this shape + +- The Stylus impl is ~29 KB brotli-compressed (the on-chain form), above the + 24 KB EVM code-size limit, so cargo-stylus fragments it across two + contracts. That makes the single-bytecode `StylusDeployer.deploy(bytecode, + initData, ...)` path unusable for per-account creation: `cargo stylus + get-initcode` errors with "fragmented contracts not currently supported". +- Shrinking under 24 KB was not realistic: `wasm-opt -Oz` cut the raw wasm 97 KB + → 76 KB (-22%) but compressed size barely moved (30.5 KB → 29 KB) because + brotli already removes that redundancy, and dropping public getters / the + dynamic ABI codec only saved ~0.8 KB compressed. The bulk is core multisig + logic + alloy ABI codec for `ZkProof` + keccak + Stylus runtime. +- EIP-1167 sidesteps the limit entirely — the proxy is plain EVM bytecode, + unfragmented, and the impl is deployed exactly once. + +## Operational steps + +1. Deploy the Stylus impl: `cd packages/stylus && cargo stylus deploy + --no-verify --max-fee-per-gas-gwei 0.1 --constructor-args `. Use any + valid set of constructor args (e.g. the existing test args); the impl's own + storage is unused since all live state lives in proxies. +2. Update `stylusImplAddress` for chain 421614 in + `packages/shared/src/contracts/contracts-config.ts` with the new impl + address. +3. Deploy the factory: + `STYLUS_IMPL_ADDRESS=0x yarn deploy --tags StylusFactory --network arbitrumSepolia` +4. Update `stylusFactoryAddress` for chain 421614 in the same shared config. +5. Backend can now deploy accounts on Arbitrum Sepolia without any extra env + vars; an optional `STYLUS_FACTORY_ADDRESS` env override is available for + pointing at a custom factory. + +### On-chain reference addresses (Arbitrum Sepolia, chain 421614) + +- PoseidonT3 (deterministic): `0x3333333C0A88F9BE4fd23ed0536F9B6c427e3B93` + (deploy via `yarn deploy --tags PoseidonT3 --network arbitrumSepolia`) +- zkVerify aggregation (proxy): `0xd007494945580eEb25522c8e0b2fa798B3F0FDE2` +- Stylus impl: redeploy from this branch (has `init()` + `initialized` guard); + the previous test wallet at `0x1e8483112db2c393ef28185768a2aaa52a453b9b` was + the pre-proxy version. + +## Code map + +- Stylus impl + build/deploy guide: `packages/stylus/` (`src/lib.rs`, + `README.md`). +- Factory contract + deploy script: + `packages/hardhat/contracts/MetaMultiSigWalletStylusFactory.sol`, + `packages/hardhat/deploy/02_deploy_stylus_factory.ts`. +- Shared addresses + ABIs: `packages/shared/src/chains/arbitrumSepolia.ts`, + `contracts/contracts-config.ts` (421614 entry, + `stylusImplAddress`/`stylusFactoryAddress`), + `contracts/MetaMultiSigWalletStylus.ts` (factory ABI + `isStylusChain`). +- Backend relayer: `packages/backend/src/relayer-wallet/relayer-wallet.service.ts` + (`deployStylusAccount` now routes through `factory.createWallet`). +- Frontend: `packages/nextjs/scaffold.config.ts`, `utils/network.ts`. +- PoseidonT3 deploy script: `packages/hardhat/deploy/01_deploy_poseidon_t3.ts`. + +## Open issue — `execute()` self-call reverts with `WalletError("Tx failed")` + +Submitting an `add_signer` (or any onlySelf) transaction through `execute()` on +the Arbitrum proxy reverts with `0x78cd39ed` = `WalletError(string)` payload +`"Tx failed"`. That string only comes from the `.map_err(|_| err("Tx failed"))` +wrapper around the inner self-call in `execute()`, so the actual revert is +swallowed at that layer. + +### What we observed (not a confirmed root-cause — just a guess) + +`eth_call` probes on Arbitrum Sepolia against proxy +`0x44Fe2002723a7975cefc784DFeF101c1D523Ac91` (impl +`0x0907a7c0e73ef119d06e082914fc83aad1465aae`): + +- `addSigners(...)` direct, `from = proxy` → succeeds (so the function body + itself and `only_self()` are fine when `msg.sender == address(this)`). +- `addSigners(...)` direct, `from = impl` or `from = relayer EOA` → + `WalletError("Not Self")`. +- Full `execute(...)` end-to-end → `WalletError("Tx failed")` (= inner call + reverted, original reason hidden). + +### Working hypothesis + +When the Stylus impl runs in the proxy's delegatecall context and issues an +outgoing `CALL` via `Call::new_payable(self, value)` + `call(...)`, the +`msg.sender` of the new frame may not be `address(this)` (= proxy address) as +standard EVM semantics would dictate. If Stylus's CALL host uses a cached +"self address" set at activation (= impl address) instead of reading +`address(this)` at runtime, the inner call would arrive at the proxy with +`msg.sender = impl`, which delegatecalls back into the impl with that same +`msg.sender`, failing `only_self()`. + +**This is a guess, not verified.** We did NOT: +- Instrument the impl to log `msg.sender` of the inner frame +- Inspect Stylus SDK / Nitro source to confirm the host call sets `msg.sender` + to address(this) at runtime vs. a cached value +- File or find a matching upstream issue (issue #4114 on `OffchainLabs/nitro` + about Stylus-to-Stylus revert/return data being lost is in the same area but + isn't the same bug) + +The pattern works fine on the original Solidity contract (Horizen/Base), where +`address(this).call(data)` from a delegatecalled implementation correctly +delivers `msg.sender = address(this)`. + +### Status after the workaround + +On-chain results after deploying the new impl (with `dispatch_self_call`) and +factory: + +- **`batch_transfer` via `execute()` → PASS** on Arbitrum Sepolia. So the + internal dispatcher reaches the `*_internal` helpers and storage / external + CALLs from there work fine. +- **`add_signer` via `execute()` → still reverts with + `WalletError("Tx failed")`**. Same selector as before. We did not dig + further — left as an open core-team item. + +Possible directions (NOT investigated): +- Difference between `add_signers_internal` and `batch_transfer_internal` is + mostly that the former mutates `commitments: uint256[]` storage (push) and + emits an `Owner` event per element, while the latter makes external CALLs. + Maybe Stylus storage array push under delegatecall has an issue, or the ABI + decode of `uint256[]` in `dispatch_self_call` (hand-rolled) is wrong for + some encoding. +- Verify the decoded `(commitments, sig_required)` from the inner self-call + calldata matches what was submitted — could be off-by-one in the offset + math. +- Try `remove_signers` / `update_signatures_required` to narrow which + internal is broken. + +### Workaround (implemented in lib.rs — partially works) + +`execute()` detects `to == self.vm().contract_address()` and routes the call +through a Rust-level dispatcher (`dispatch_self_call`) that matches the +selector against the onlySelf functions and invokes their `*_internal` +helpers directly. This bypasses the EVM `CALL` round-trip entirely, so +whatever Stylus is doing wrong with `msg.sender` in delegatecall-then-CALL no +longer matters for self-calls. + +Each onlySelf public method (`add_signers`, `remove_signers`, +`update_signatures_required`, `batch_transfer`, `batch_transfer_multi`) is now +a thin wrapper that runs `only_self()` and delegates to its `*_internal` +sibling. External direct calls keep their `only_self()` protection unchanged; +only the in-process self-call from `execute()` bypasses it (and execute's own +ZK-proof gating provides the access control). + +`dispatch_self_call` hand-rolls Solidity ABI decoding for the static set of +parameter shapes used (`uint256`, `uint256[]`, `address[]`) to avoid pulling +the full alloy ABI codec into the WASM (the impl is already over the 24 KB +fragmentation threshold). + +Re-deploy is required (impl bytecode changed). Factory does not need to +change. Update `stylusImplAddress` in +`packages/shared/src/contracts/contracts-config.ts` after re-deploy. + +## Constraint reminder + +Arbitrum is **testnet-only** in PolyPay: zkVerify has a verifier on Arbitrum +Sepolia but not Arbitrum One mainnet, so this cannot go to production yet. diff --git a/packages/stylus/README.md b/packages/stylus/README.md new file mode 100644 index 00000000..eac7ba66 --- /dev/null +++ b/packages/stylus/README.md @@ -0,0 +1,147 @@ +# PolyPay MetaMultiSigWallet — Arbitrum Stylus port + +Rust/WASM port of `packages/hardhat/contracts/MetaMultiSigWallet.sol`, deployed on +Arbitrum Stylus. Used as the account contract on Stylus chains (Arbitrum Sepolia, +chain id `421614`). All other chains keep the Solidity contract. + +The exported Solidity ABI is identical to the EVM contract for runtime methods +(`execute`, `getTransactionHash`, `getCommitments`, ...), so the frontend (viem) +and backend relayer reuse `METAMULTISIG_ABI` unchanged. The only difference is the +constructor, which takes one extra arg `poseidonT3` (Stylus has no linked +libraries, so the wallet STATICCALLs PoseidonT3 by address): + +``` +constructor(address zkvContract, bytes32 vkHash, address poseidonT3, + uint256 chainId, uint256[] initialCommitments, uint256 signaturesRequired) +``` + +## Why Poseidon is an external call (and what's left as future work) + +To eliminate any risk of hash divergence, this port does **not** re-implement +Poseidon in Rust. It STATICCALLs the already-deployed `poseidon-solidity` +PoseidonT3 contract. A STATICCALL to a pure function returns the exact same value +as the Solidity contract's DELEGATECALL into the linked library, so on-chain +commitments match the Noir circuit's public inputs with zero risk. + +**Future work (the gas win):** move Poseidon into Rust (e.g. `ark-bn254` field +arithmetic with circom-compatible constants). Before trusting any native +implementation it **must** be checked against a known vector from the current +system, e.g. confirm `poseidonHash2(txHashAsUint, 1)` matches the value the +deployed Solidity contract returns for the same input. Until verified, keep the +external-call version. + +## Prerequisites + +```bash +rustup target add wasm32-unknown-unknown +cargo install cargo-stylus # match the version pinned in Cargo.toml +``` + +## Build & check + +```bash +cd packages/stylus + +# Compile checks (no cargo-stylus needed): +cargo check # native type-check +cargo build --release --target wasm32-unknown-unknown # ~101 KB WASM artifact +cargo run --features export-abi # print the Solidity ABI + +# Stylus-specific (needs cargo-stylus + an RPC endpoint): +cargo stylus check # validates WASM + compressed size limit +cargo stylus export-abi # same ABI, via the tool +``` + +Built against `stylus-sdk = "0.10.7"` + `alloy = "1.6"` to match `cargo-stylus` +0.10.x — required so the `#[constructor]` is detected and run on deploy (older SDKs +didn't emit it in a way the 0.10 tool reads). If `cargo stylus check` rejects the +WASM for size, tune `[profile.release]` in `Cargo.toml` (already `opt-level = "z"`, +`lto`, `strip`). + +Notes for `cargo-stylus >= 0.10`: +- A `Stylus.toml` is required (this repo ships one as a workspace manifest). +- `rust-toolchain.toml` must pin a **specific** version (not `stable`) for + reproducible builds — set to `1.94.1`; match it to your installed toolchain. + +Verified locally: `cargo stylus check` passes — contract size **30.7 KB**, +activation data fee ~0.000174 ETH on Arbitrum Sepolia. `cargo stylus constructor` +prints the 6-arg constructor (so deploy runs it via StylusDeployer). + +## Deploy dependencies on Arbitrum Sepolia + +The wallet calls two external contracts that must exist on the target chain: + +1. **PoseidonT3** — deploy to the deterministic address + `0x3333333C0A88F9BE4fd23ed0536F9B6c427e3B93` (CREATE2). A tagged hardhat script + does this: + ```bash + cd packages/hardhat + yarn deploy --tags PoseidonT3 --network arbitrumSepolia + ``` + It deploys the CREATE2 proxy (if absent) then PoseidonT3, idempotently. If the + address ends up different, update `poseidonT3Address` for `421614` in + `packages/shared/src/contracts/contracts-config.ts`. +2. **zkVerify aggregation** — already deployed by zkVerify on Arbitrum Sepolia at + `0xd007494945580eEb25522c8e0b2fa798B3F0FDE2` (proxy). Confirm this is the + address that exposes `verifyProofAggregation` and that Kurier relays + aggregations for `chainId 421614`. + +## Deploy the wallet (manual / single account) + +```bash +export RPC=https://sepolia-rollup.arbitrum.io/rpc +export PK=0x + +cargo stylus deploy \ + --endpoint $RPC \ + --private-key $PK \ + --constructor-args \ + "[...]" +``` + +`cargo stylus deploy` deploys + activates the program and runs the constructor via +the StylusDeployer. This deploys the **implementation** that all per-account +proxies will delegatecall into; the impl's own storage is unused, so any valid +constructor args are fine. + +Record the deployed impl address — you need it for the factory step below. + +## Deploy the EIP-1167 factory + +Per-account wallets are not deployed as fresh Stylus contracts (the impl is +~29 KB compressed, above the EVM 24 KB code-size limit, so `cargo stylus +get-initcode` errors with "fragmented contracts not currently supported"). +Instead each account is a tiny EIP-1167 minimal proxy that delegatecalls into +the impl. Deploy the factory once: + +```bash +STYLUS_IMPL_ADDRESS=0x \ + yarn deploy --tags StylusFactory --network arbitrumSepolia +``` + +Then update `stylusImplAddress` and `stylusFactoryAddress` for chain 421614 in +`packages/shared/src/contracts/contracts-config.ts`. + +## Wire the backend relayer + +With the factory address baked into `@polypay/shared`, the relayer needs no +extra Stylus env vars; it routes Stylus-chain deploys through +`factory.createWallet(...)`. + +Fund the relayer wallet (`RELAYER_WALLET_KEY`) with Arbitrum Sepolia ETH so it +can pay deploy + execute gas. + +## End-to-end test flow (staging/testnet) + +1. Set `NEXT_PUBLIC_NETWORK=testnet` (frontend) and `NETWORK=testnet` (backend) so + Arbitrum Sepolia appears in the network list. +2. Deploy PoseidonT3 + Stylus impl + factory on Arbitrum Sepolia (steps above), + and update the addresses in `packages/shared/src/contracts/contracts-config.ts`. +3. In the app: create an account, pick **Arbitrum Sepolia** → relayer calls the + factory and a new EIP-1167 proxy is created. Confirm the deployed address on + the Arbitrum Sepolia explorer. +4. Deposit ETH to the account, then submit a transfer. The flow: frontend builds + `getTransactionHash` → ZK proof → Kurier aggregation (`chainId 421614`) → + relayer calls `execute`. Confirm the tx succeeds on-chain. +5. Verify the same flows the EVM chains support: single transfer, batch transfer, + add/remove signer, update threshold. diff --git a/packages/stylus/Stylus.toml b/packages/stylus/Stylus.toml new file mode 100644 index 00000000..49dd3614 --- /dev/null +++ b/packages/stylus/Stylus.toml @@ -0,0 +1,6 @@ +# Stylus manifest (required by cargo-stylus >= 0.10). +# This crate is its own cargo workspace root, so cargo-stylus loads this file as +# the workspace manifest. Its mere presence next to Cargo.toml also marks the +# package as a Stylus contract. +[workspace.networks.arbitrum-sepolia] +endpoint = "https://sepolia-rollup.arbitrum.io/rpc" diff --git a/packages/stylus/rust-toolchain.toml b/packages/stylus/rust-toolchain.toml new file mode 100644 index 00000000..b47c6bd7 --- /dev/null +++ b/packages/stylus/rust-toolchain.toml @@ -0,0 +1,6 @@ +[toolchain] +# cargo-stylus requires a SPECIFIC version (not "stable") for reproducible builds. +# Match this to your installed toolchain. +channel = "1.94.1" +targets = ["wasm32-unknown-unknown"] +profile = "minimal" diff --git a/packages/stylus/src/lib.rs b/packages/stylus/src/lib.rs new file mode 100644 index 00000000..17df20f1 --- /dev/null +++ b/packages/stylus/src/lib.rs @@ -0,0 +1,694 @@ +// SPDX-License-Identifier: MIT +// +// MetaMultiSigWallet ported from Solidity to Arbitrum Stylus (Rust/WASM). +// +// Behaviour is kept byte-for-byte compatible with the original +// `packages/hardhat/contracts/MetaMultiSigWallet.sol` so that the rest of the +// stack (frontend viem calls, backend relayer execute path, the Noir circuit +// public-input ordering, and the zkVerify aggregation leaf format) keeps +// working unchanged. The exported Solidity ABI is identical except: +// - the constructor takes one extra arg `poseidonT3` (the deployed +// PoseidonT3 address) because Stylus has no linked-library mechanism, so we +// call the library by address instead of linking it at deploy time. +// +// Poseidon: instead of re-implementing the hash in Rust we STATICCALL the +// already-deployed `poseidon-solidity` PoseidonT3 contract. A STATICCALL to a +// pure function returns the exact same value as the Solidity contract's +// DELEGATECALL into the linked library, so commitments computed here match the +// circuit's public inputs with zero risk of divergence. Re-implementing +// Poseidon natively in Rust (for cheaper gas) is documented as future work in +// README.md and MUST be validated against a known vector before use. + +#![cfg_attr(not(any(test, feature = "export-abi")), no_main)] +extern crate alloc; + +use alloc::vec::Vec; + +use stylus_sdk::{ + abi::Bytes, + alloy_primitives::{uint, Address, B256, U256}, + alloy_sol_types::sol, + call::call, + crypto::keccak, + prelude::*, + stylus_core::calls::Call, +}; + +// BN254 scalar field prime, matching `BN254_PRIME` in the Solidity contract. +const BN254_PRIME: U256 = + uint!(21888242871839275222246405745257275088548364400416034343698204186575808495617_U256); + +// VERSION_HASH = sha256(abi.encodePacked("")) — sha256 of the empty byte string. +// Precomputed constant so we don't pull a sha256 implementation into the WASM. +const VERSION_HASH: B256 = B256::new([ + 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, + 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55, +]); + +sol! { + // Mirrors the Solidity `ZkProof` struct field order exactly — the ABI tuple + // ordering must not change or the relayer's encoded calldata won't decode. + // `AbiType` lets the struct be used as a Stylus method argument. + #[derive(AbiType)] + struct ZkProof { + uint256 commitment; + uint256 nullifier; + uint256 aggregationId; + uint256 domainId; + bytes32[] zkMerklePath; + uint256 leafCount; + uint256 index; + } + + event Deposit(address indexed sender, uint256 amount, uint256 balance); + event TransactionExecuted(uint256 indexed nonce, address to, uint256 value, bytes data, bytes result); + event Owner(uint256 indexed commitment, bool isAdded); + + error WalletError(string reason); +} + +#[derive(SolidityError)] +pub enum Error { + Wallet(WalletError), +} + +fn err(reason: &str) -> Error { + Error::Wallet(WalletError { reason: reason.into() }) +} + +sol_interface! { + interface IVerifyProofAggregation { + function verifyProofAggregation( + uint256 domainId, + uint256 aggregationId, + bytes32 leaf, + bytes32[] merklePath, + uint256 leafCount, + uint256 index + ) external view returns (bool); + } + + interface IPoseidonT3 { + function hash(uint256[2] inputs) external view returns (uint256); + } +} + +sol_storage! { + #[entrypoint] + pub struct MetaMultiSigWallet { + address zkv_contract; + bytes32 vk_hash; + address poseidon_t3; + uint256 chain_id; + uint256 signatures_required; + uint256[] commitments; + mapping(uint256 => bool) used_nonces; + mapping(uint256 => bool) used_nullifiers; + // Set to true on first successful constructor/init. Guards against + // double-init when this contract is used as an EIP-1167 clone target: + // the impl runs the constructor once at deploy (initialized=true on + // impl storage, which is unused), and each freshly-cloned proxy starts + // with initialized=false and must be initialized exactly once by the + // factory in the same transaction as the clone. + bool initialized; + } +} + +#[public] +impl MetaMultiSigWallet { + #[constructor] + pub fn constructor( + &mut self, + zkv_contract: Address, + vk_hash: B256, + poseidon_t3: Address, + chain_id: U256, + initial_commitments: Vec, + signatures_required: U256, + ) -> Result<(), Error> { + self.initialize_state( + zkv_contract, + vk_hash, + poseidon_t3, + chain_id, + initial_commitments, + signatures_required, + ) + } + + // Proxy-friendly initializer. Identical semantics to `constructor` but + // callable post-deploy through an EIP-1167 minimal proxy, which does not + // execute the impl's constructor. Reverts if already initialized. + pub fn init( + &mut self, + zkv_contract: Address, + vk_hash: B256, + poseidon_t3: Address, + chain_id: U256, + initial_commitments: Vec, + signatures_required: U256, + ) -> Result<(), Error> { + self.initialize_state( + zkv_contract, + vk_hash, + poseidon_t3, + chain_id, + initial_commitments, + signatures_required, + ) + } + + // ============ Main Execute Function ============ + pub fn execute( + &mut self, + nonce: U256, + to: Address, + value: U256, + data: Bytes, + proofs: Vec, + ) -> Result { + if self.used_nonces.get(nonce) { + return Err(err("Nonce already used")); + } + if U256::from(proofs.len()) < self.signatures_required.get() { + return Err(err("Not enough proofs")); + } + + let data_bytes: Vec = data.into(); + let tx_hash = self.compute_tx_hash(nonce, to, value, &data_bytes); + + for p in proofs.iter() { + if self.used_nullifiers.get(p.nullifier) { + return Err(err("Nullifier already used")); + } + if !self.is_current_signer(p.commitment) { + return Err(err("Not a current signer")); + } + if !self.verify_proof(tx_hash, p)? { + return Err(err("Invalid proof")); + } + self.used_nullifiers.insert(p.nullifier, true); + } + + self.used_nonces.insert(nonce, true); + + // Self-calls (onlySelf wallet management functions) are dispatched + // internally instead of going through an EVM CALL. Working theory: in + // Stylus's delegatecall context (impl running in proxy storage), the + // outbound CALL's msg.sender is not set to address(this) (= proxy) the + // way standard EVM semantics dictate, so the inner only_self() check + // in addSigners/removeSigners/etc. reverts. Routing the call through + // an internal Rust dispatch keeps the storage writes correct and + // avoids the EVM round-trip entirely. See packages/stylus/NOTES.md. + let result: Vec = if to == self.vm().contract_address() { + if !value.is_zero() { + return Err(err("Self-call: nonzero value")); + } + self.dispatch_self_call(&data_bytes)?; + Vec::new() + } else { + let context = Call::new_payable(self, value); + call(self.vm(), context, to, &data_bytes).map_err(|_| err("Tx failed"))? + }; + + self.vm().log(TransactionExecuted { + nonce, + to, + value, + data: data_bytes.into(), + result: result.clone().into(), + }); + + Ok(result.into()) + } + + // ============ Signer Management (onlySelf) ============ + // Public methods are thin wrappers around the *_internal helpers so that + // external direct calls still go through only_self(), while execute()'s + // self-call dispatcher (which can't rely on msg.sender under Stylus + // delegatecall) invokes the internals directly. See NOTES.md. + pub fn add_signers( + &mut self, + new_commitments: Vec, + new_sig_required: U256, + ) -> Result<(), Error> { + self.only_self()?; + self.add_signers_internal(new_commitments, new_sig_required) + } + + pub fn remove_signers( + &mut self, + commitments_to_remove: Vec, + new_sig_required: U256, + ) -> Result<(), Error> { + self.only_self()?; + self.remove_signers_internal(commitments_to_remove, new_sig_required) + } + + pub fn update_signatures_required(&mut self, new_sig_required: U256) -> Result<(), Error> { + self.only_self()?; + self.update_signatures_required_internal(new_sig_required) + } + + // ============ Batch transfers (onlySelf) ============ + pub fn batch_transfer( + &mut self, + recipients: Vec
, + amounts: Vec, + ) -> Result<(), Error> { + self.only_self()?; + self.batch_transfer_internal(recipients, amounts) + } + + pub fn batch_transfer_multi( + &mut self, + recipients: Vec
, + amounts: Vec, + token_addresses: Vec
, + ) -> Result<(), Error> { + self.only_self()?; + self.batch_transfer_multi_internal(recipients, amounts, token_addresses) + } + + // ============ View functions ============ + pub fn get_transaction_hash( + &self, + nonce: U256, + to: Address, + value: U256, + data: Bytes, + ) -> B256 { + self.compute_tx_hash(nonce, to, value, data.as_ref()) + } + + pub fn get_commitments(&self) -> Vec { + let len = self.commitments.len(); + let mut out = Vec::with_capacity(len); + for i in 0..len { + out.push(self.commitments.get(i).unwrap()); + } + out + } + + pub fn get_signers_count(&self) -> U256 { + U256::from(self.commitments.len()) + } + + pub fn signatures_required(&self) -> U256 { + self.signatures_required.get() + } + + // ============ Receive ETH ============ + #[receive] + #[payable] + pub fn receive(&mut self) -> Result<(), Vec> { + let sender = self.vm().msg_sender(); + let amount = self.vm().msg_value(); + let addr = self.vm().contract_address(); + let balance = self.vm().balance(addr); + self.vm().log(Deposit { sender, amount, balance }); + Ok(()) + } +} + +// Internal logic for the onlySelf methods + the self-call dispatcher used by +// execute(). Kept outside `#[public]` so they are not part of the Solidity ABI. +impl MetaMultiSigWallet { + fn add_signers_internal( + &mut self, + new_commitments: Vec, + new_sig_required: U256, + ) -> Result<(), Error> { + if new_commitments.is_empty() { + return Err(err("Empty array")); + } + if new_sig_required.is_zero() { + return Err(err("Must be non-zero sigs required")); + } + let total = U256::from(self.commitments.len() + new_commitments.len()); + if new_sig_required > total { + return Err(err("Sigs required too high")); + } + + for i in 0..new_commitments.len() { + let nc = new_commitments[i]; + if nc.is_zero() { + return Err(err("Invalid commitment")); + } + // Duplicate against existing signers. + if self.is_current_signer(nc) { + return Err(err("Commitment exists")); + } + // Duplicate within the input array. + for k in 0..i { + if new_commitments[k] == nc { + return Err(err("Duplicate in input")); + } + } + self.commitments.push(nc); + self.vm().log(Owner { commitment: nc, isAdded: true }); + } + + self.signatures_required.set(new_sig_required); + Ok(()) + } + + fn remove_signers_internal( + &mut self, + commitments_to_remove: Vec, + new_sig_required: U256, + ) -> Result<(), Error> { + if commitments_to_remove.is_empty() { + return Err(err("Empty array")); + } + if self.commitments.len() <= commitments_to_remove.len() { + return Err(err("Cannot remove all signers")); + } + if new_sig_required.is_zero() { + return Err(err("Must be non-zero sigs required")); + } + let remaining = U256::from(self.commitments.len() - commitments_to_remove.len()); + if new_sig_required > remaining { + return Err(err("Sigs required too high")); + } + + for target in commitments_to_remove.iter() { + let mut found = false; + let len = self.commitments.len(); + for j in 0..len { + if self.commitments.get(j).unwrap() == *target { + // Swap-and-pop, same as the Solidity version. + let last = self.commitments.get(len - 1).unwrap(); + self.commitments.setter(j).unwrap().set(last); + self.commitments.pop(); + found = true; + self.vm().log(Owner { commitment: *target, isAdded: false }); + break; + } + } + if !found { + return Err(err("Commitment not found")); + } + } + + self.signatures_required.set(new_sig_required); + Ok(()) + } + + fn update_signatures_required_internal(&mut self, new_sig_required: U256) -> Result<(), Error> { + if new_sig_required.is_zero() { + return Err(err("Must be non-zero sigs required")); + } + if new_sig_required > U256::from(self.commitments.len()) { + return Err(err("Sigs required too high")); + } + self.signatures_required.set(new_sig_required); + Ok(()) + } + + fn batch_transfer_internal( + &mut self, + recipients: Vec
, + amounts: Vec, + ) -> Result<(), Error> { + if recipients.len() != amounts.len() { + return Err(err("Length mismatch")); + } + if recipients.is_empty() { + return Err(err("Empty batch")); + } + for i in 0..recipients.len() { + if recipients[i].is_zero() { + return Err(err("Invalid recipient")); + } + let ctx = Call::new_payable(self, amounts[i]); + call(self.vm(), ctx, recipients[i], &[]).map_err(|_| err("Transfer failed"))?; + } + Ok(()) + } + + fn batch_transfer_multi_internal( + &mut self, + recipients: Vec
, + amounts: Vec, + token_addresses: Vec
, + ) -> Result<(), Error> { + if recipients.len() != amounts.len() || recipients.len() != token_addresses.len() { + return Err(err("Length mismatch")); + } + if recipients.is_empty() { + return Err(err("Empty batch")); + } + + for i in 0..recipients.len() { + if recipients[i].is_zero() { + return Err(err("Invalid recipient")); + } + + if token_addresses[i].is_zero() { + // Native ETH transfer. + let ctx = Call::new_payable(self, amounts[i]); + call(self.vm(), ctx, recipients[i], &[]) + .map_err(|_| err("ETH transfer failed"))?; + } else { + // ERC20 transfer via low-level call, tolerating non-standard + // tokens that return no data (same as the Solidity version). + // Manually packed (selector + padded address + amount) to avoid + // pulling the dynamic ABI codec into the WASM. + let mut calldata = Vec::with_capacity(68); + calldata.extend_from_slice(&[0xa9, 0x05, 0x9c, 0xbb]); // transfer(address,uint256) + calldata.extend_from_slice(&[0u8; 12]); // left-pad address to 32 bytes + calldata.extend_from_slice(recipients[i].as_slice()); + calldata.extend_from_slice(&amounts[i].to_be_bytes::<32>()); + + let ctx = Call::new_mutating(self); + let ret = call(self.vm(), ctx, token_addresses[i], &calldata) + .map_err(|_| err("ERC20 transfer failed"))?; + + // Accept empty return (non-standard tokens) or an ABI bool `true`. + let ok = ret.is_empty() || (ret.len() == 32 && ret[31] != 0); + if !ok { + return Err(err("ERC20 transfer failed")); + } + } + } + Ok(()) + } + + // Dispatch a self-call (to == address(this)) from execute() directly to the + // matching *_internal function. Mirrors the public Solidity selectors so + // the relayer's calldata works unchanged. + fn dispatch_self_call(&mut self, data: &[u8]) -> Result<(), Error> { + if data.len() < 4 { + return Err(err("Self-call: empty selector")); + } + let selector = [data[0], data[1], data[2], data[3]]; + let args = &data[4..]; + match selector { + // addSigners(uint256[],uint256) + [0xa8, 0xd2, 0xc8, 0x52] => { + let commitments = decode_u256_array(args, 0)?; + let sig_required = decode_u256(args, 32)?; + self.add_signers_internal(commitments, sig_required) + } + // removeSigners(uint256[],uint256) + [0x47, 0x91, 0xca, 0x34] => { + let commitments = decode_u256_array(args, 0)?; + let sig_required = decode_u256(args, 32)?; + self.remove_signers_internal(commitments, sig_required) + } + // updateSignaturesRequired(uint256) + [0x30, 0x34, 0xa7, 0x42] => { + let sig_required = decode_u256(args, 0)?; + self.update_signatures_required_internal(sig_required) + } + // batchTransfer(address[],uint256[]) + [0x88, 0xd6, 0x95, 0xb2] => { + let recipients = decode_address_array(args, 0)?; + let amounts = decode_u256_array(args, 32)?; + self.batch_transfer_internal(recipients, amounts) + } + // batchTransferMulti(address[],uint256[],address[]) + [0x64, 0x45, 0x12, 0x12] => { + let recipients = decode_address_array(args, 0)?; + let amounts = decode_u256_array(args, 32)?; + let tokens = decode_address_array(args, 64)?; + self.batch_transfer_multi_internal(recipients, amounts, tokens) + } + _ => Err(err("Self-call: unknown selector")), + } + } +} + +// Hand-rolled Solidity ABI decoders for the static handful of types used by +// dispatch_self_call(). Pulling the full alloy ABI codec into the WASM would +// bloat the compressed contract size, and Stylus is already over the 24 KB +// fragmentation threshold. +fn decode_u256(data: &[u8], offset: usize) -> Result { + if data.len() < offset + 32 { + return Err(err("Self-call: short uint256")); + } + Ok(U256::from_be_slice(&data[offset..offset + 32])) +} + +fn decode_address(data: &[u8], offset: usize) -> Result { + if data.len() < offset + 32 { + return Err(err("Self-call: short address")); + } + // Solidity left-pads addresses with 12 zero bytes inside a 32-byte word. + Ok(Address::from_slice(&data[offset + 12..offset + 32])) +} + +fn decode_offset(data: &[u8], offset_word: usize) -> Result { + let raw = decode_u256(data, offset_word)?; + // Calldata is bounded by gas; anything above u32::MAX is malformed. + if raw > U256::from(u32::MAX) { + return Err(err("Self-call: bad offset")); + } + Ok(raw.as_limbs()[0] as usize) +} + +fn decode_u256_array(data: &[u8], offset_word: usize) -> Result, Error> { + let head = decode_offset(data, offset_word)?; + let len = decode_offset(data, head)?; + let mut out = Vec::with_capacity(len); + for i in 0..len { + out.push(decode_u256(data, head + 32 + 32 * i)?); + } + Ok(out) +} + +fn decode_address_array(data: &[u8], offset_word: usize) -> Result, Error> { + let head = decode_offset(data, offset_word)?; + let len = decode_offset(data, head)?; + let mut out = Vec::with_capacity(len); + for i in 0..len { + out.push(decode_address(data, head + 32 + 32 * i)?); + } + Ok(out) +} + +// Internal (non-ABI) helpers. +impl MetaMultiSigWallet { + fn initialize_state( + &mut self, + zkv_contract: Address, + vk_hash: B256, + poseidon_t3: Address, + chain_id: U256, + initial_commitments: Vec, + signatures_required: U256, + ) -> Result<(), Error> { + if self.initialized.get() { + return Err(err("Already initialized")); + } + if zkv_contract.is_zero() { + return Err(err("Invalid zkv address")); + } + if poseidon_t3.is_zero() { + return Err(err("Invalid poseidon address")); + } + if signatures_required.is_zero() { + return Err(err("Must be non-zero sigs required")); + } + if initial_commitments.is_empty() { + return Err(err("Need at least 1 signer")); + } + if signatures_required > U256::from(initial_commitments.len()) { + return Err(err("Sigs required too high")); + } + + self.zkv_contract.set(zkv_contract); + self.vk_hash.set(vk_hash); + self.poseidon_t3.set(poseidon_t3); + self.chain_id.set(chain_id); + self.signatures_required.set(signatures_required); + + for c in initial_commitments.iter() { + if c.is_zero() { + return Err(err("Invalid commitment")); + } + self.commitments.push(*c); + self.vm().log(Owner { commitment: *c, isAdded: true }); + } + + self.initialized.set(true); + Ok(()) + } + + fn only_self(&self) -> Result<(), Error> { + if self.vm().msg_sender() != self.vm().contract_address() { + return Err(err("Not Self")); + } + Ok(()) + } + + fn is_current_signer(&self, commitment: U256) -> bool { + let len = self.commitments.len(); + for i in 0..len { + if self.commitments.get(i).unwrap() == commitment { + return true; + } + } + false + } + + // keccak256(abi.encodePacked(address(this), chainId, nonce, to, value, data)) + fn compute_tx_hash(&self, nonce: U256, to: Address, value: U256, data: &[u8]) -> B256 { + let mut packed: Vec = Vec::with_capacity(20 + 32 + 32 + 20 + 32 + data.len()); + packed.extend_from_slice(self.vm().contract_address().as_slice()); + packed.extend_from_slice(&self.chain_id.get().to_be_bytes::<32>()); + packed.extend_from_slice(&nonce.to_be_bytes::<32>()); + packed.extend_from_slice(to.as_slice()); + packed.extend_from_slice(&value.to_be_bytes::<32>()); + packed.extend_from_slice(data); + keccak(&packed) + } + + fn poseidon_hash2_internal(&mut self, a: U256, b: U256) -> Result { + let safe_a = a % BN254_PRIME; + let safe_b = b % BN254_PRIME; + let poseidon = IPoseidonT3::new(self.poseidon_t3.get()); + poseidon + .hash(self.vm(), Call::new(), [safe_a, safe_b]) + .map_err(|_| err("Poseidon call failed")) + } + + fn verify_proof(&mut self, tx_hash: B256, proof: &ZkProof) -> Result { + // tx_hash_commitment = poseidonHash2(uint256(txHash), 1) + let tx_hash_u = U256::from_be_bytes(tx_hash.0); + let tx_hash_commitment = self.poseidon_hash2_internal(tx_hash_u, U256::from(1))?; + + // Public inputs order: tx_hash_commitment, commitment, nullifier. + let mut encoded_inputs: Vec = Vec::with_capacity(96); + encoded_inputs.extend_from_slice(&tx_hash_commitment.to_be_bytes::<32>()); + encoded_inputs.extend_from_slice(&proof.commitment.to_be_bytes::<32>()); + encoded_inputs.extend_from_slice(&proof.nullifier.to_be_bytes::<32>()); + let inputs_hash = keccak(&encoded_inputs); + + // leaf = keccak256(abi.encodePacked(PROVING_SYSTEM_ID, vkHash, VERSION_HASH, keccak(encodedInputs))) + let proving_system_id = keccak(b"ultrahonk"); + let vk_hash = self.vk_hash.get(); + let mut leaf_pre: Vec = Vec::with_capacity(128); + leaf_pre.extend_from_slice(proving_system_id.as_slice()); + leaf_pre.extend_from_slice(vk_hash.as_slice()); + leaf_pre.extend_from_slice(VERSION_HASH.as_slice()); + leaf_pre.extend_from_slice(inputs_hash.as_slice()); + let leaf = keccak(&leaf_pre); + + let verifier = IVerifyProofAggregation::new(self.zkv_contract.get()); + let merkle_path: Vec = proof.zkMerklePath.clone(); + verifier + .verify_proof_aggregation( + self.vm(), + Call::new(), + proof.domainId, + proof.aggregationId, + leaf, + merkle_path, + proof.leafCount, + proof.index, + ) + .map_err(|_| err("Verifier call failed")) + } +} \ No newline at end of file diff --git a/packages/stylus/src/main.rs b/packages/stylus/src/main.rs new file mode 100644 index 00000000..cfe307c4 --- /dev/null +++ b/packages/stylus/src/main.rs @@ -0,0 +1,8 @@ +// Binary entrypoint used only for `cargo stylus export-abi` (or +// `cargo run --features export-abi`). For normal WASM builds there is no main. +#![cfg_attr(not(feature = "export-abi"), no_main)] + +#[cfg(feature = "export-abi")] +fn main() { + stylus_sdk::abi::export::print_from_args::(); +}