mirror of
https://github.com/getwax/wax.git
synced 2026-01-09 15:18:02 -05:00
Merge pull request #257 from getwax/update-repo-docs
Update Repo Documentation, archive older components, CI e2e tests
This commit is contained in:
6
.github/workflows/barebones.yml
vendored
6
.github/workflows/barebones.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: packages/barebones
|
||||
name: archive/barebones
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -6,11 +6,11 @@ on:
|
||||
- main
|
||||
pull_request:
|
||||
paths:
|
||||
- packages/barebones/**
|
||||
- archive/barebones/**
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./packages/barebones
|
||||
working-directory: ./archive/barebones
|
||||
|
||||
env:
|
||||
FOUNDRY_PROFILE: ci
|
||||
|
||||
48
.github/workflows/plugins.yml
vendored
48
.github/workflows/plugins.yml
vendored
@@ -29,28 +29,6 @@ jobs:
|
||||
with:
|
||||
version: nightly
|
||||
|
||||
# Uncomment the lines below to install & generate zk assets
|
||||
# - working-directory: ./packages/zkp/lib/circom
|
||||
# run: cargo build --release
|
||||
|
||||
# - working-directory: ./packages/zkp/lib/circom
|
||||
# run: cargo install --path circom
|
||||
|
||||
# - uses: actions/setup-node@v3
|
||||
# with:
|
||||
# node-version: "18.x"
|
||||
# cache: "yarn"
|
||||
# cache-dependency-path: packages/zkp/yarn.lock
|
||||
|
||||
# - working-directory: ./packages/zkp
|
||||
# run: yarn install --frozen-lockfile
|
||||
|
||||
# - working-directory: ./packages/zkp
|
||||
# run: yarn build
|
||||
|
||||
# - working-directory: ./packages/plugins
|
||||
# run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Run Forge build
|
||||
run: |
|
||||
forge --version
|
||||
@@ -81,24 +59,20 @@ jobs:
|
||||
cache: "yarn"
|
||||
cache-dependency-path: packages/plugins/yarn.lock
|
||||
|
||||
# Uncommment the lines below to install & generate zk assets
|
||||
# - working-directory: ./packages/zkp/lib/circom
|
||||
# run: cargo build --release
|
||||
|
||||
# - working-directory: ./packages/zkp/lib/circom
|
||||
# run: cargo install --path circom
|
||||
|
||||
# - working-directory: ./packages/zkp
|
||||
# run: yarn install --frozen-lockfile
|
||||
|
||||
# - working-directory: ./packages/zkp
|
||||
# run: yarn build
|
||||
|
||||
- name: Install Yarn dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Copy env file
|
||||
run: cp .env.example .env
|
||||
|
||||
- name: Run hardhat compile
|
||||
run: yarn hardhat compile
|
||||
- name: Run hardhat build
|
||||
run: yarn build
|
||||
|
||||
- name: Start geth node & bundler in background
|
||||
run: ./script/start.sh &
|
||||
|
||||
- name: Wait for bundler at port 3000
|
||||
run: RPC_URL='localhost:3000' SLEEP_DURATION_SECONDS=1 ./script/wait-for-rpc.sh
|
||||
|
||||
- name: Run hardhat integration tests
|
||||
run: yarn hardhat test
|
||||
|
||||
11
.gitmodules
vendored
11
.gitmodules
vendored
@@ -16,14 +16,11 @@
|
||||
[submodule "packages/plugins/lib/account-abstraction"]
|
||||
path = packages/plugins/lib/account-abstraction
|
||||
url = https://github.com/eth-infinitism/account-abstraction
|
||||
[submodule "packages/zkp/lib/circom"]
|
||||
path = packages/zkp/lib/circom
|
||||
url = https://github.com/iden3/circom.git
|
||||
[submodule "packages/barebones/lib/openzeppelin-contracts"]
|
||||
path = packages/barebones/lib/openzeppelin-contracts
|
||||
[submodule "archive/barebones/lib/openzeppelin-contracts"]
|
||||
path = archive/barebones/lib/openzeppelin-contracts
|
||||
url = https://github.com/openzeppelin/openzeppelin-contracts
|
||||
[submodule "packages/barebones/lib/forge-std"]
|
||||
path = packages/barebones/lib/forge-std
|
||||
[submodule "archive/barebones/lib/forge-std"]
|
||||
path = archive/barebones/lib/forge-std
|
||||
url = https://github.com/foundry-rs/forge-std
|
||||
[submodule "packages/plugins/lib/kernel"]
|
||||
path = packages/plugins/lib/kernel
|
||||
|
||||
62
README.md
62
README.md
@@ -1,36 +1,40 @@
|
||||
# Wallet Account eXperiments (WAX)
|
||||
WAX's goal is to deliver set of production-ready components that help developers easily utilise cryptographic primitives in smart accounts
|
||||
|
||||
We seek to achieve this with a three pronged approach:
|
||||
1. Showcase, via examples, the benefits of cryptographic primitives in smart accounts
|
||||
- including examples of novel use cases that compose smart account modules
|
||||
2. Develop an easy-to-use opinionated SDK that makes integrating these benefits easy for non-web3 devs
|
||||
3. Provide a focused dev environment for the integration of more primitives into smart accounts
|
||||

|
||||
|
||||
## Components **(diagram outdated)**
|
||||
The showcase dApps are comprised of application specific code (pink) that leverages the SDK (yellow).
|
||||
The SDK contains the off-chain companion of corresponding on-chain cryptographic primitives (grey).
|
||||
Existing smart accounts will be used to demonstrate integration of the primitives in 4337-compatible verification logic.
|
||||
|
||||
**Diagram**: current explorations and proposed development
|
||||
|
||||

|
||||
|
||||
- The green areas are WAX's focus.
|
||||
- Within the SDK there will be additions that enable projects to readily adopt novel features.
|
||||
- On-chain, between smart contracts and primitives, the verification data+logic will be designed to be composable. Smart accounts can then dynamically benefit from more than one primitive, and this will be developed in sync with broader smart account modularisation.
|
||||
Primary monorepo for the Wallet Account eXperiments (WAX) project, which focuses on integrating novel & useful cryptographic technologies into the Ethereum Account Abstraction (AA) ecosytem to improve the experience of using accounts. We build on top of [ERC-4337](https://eips.ethereum.org/EIPS/eip-4337) & related specs.
|
||||
|
||||
# Using this monorepo
|
||||
## packages/demos
|
||||
You're a web dev and want to bring the latest web3 capabilities to your product/users.
|
||||
Here you will not only find 'hello world' wrappers of base primitives, but also composite examples highlighting novel product features.
|
||||
Are you looking to build a plugin/module for the AA/ERC-4337 ecosystem and want examples & tooling? Check out [the plugins package](./packages/plugins/).
|
||||
|
||||
## packages/sdk
|
||||
The sdk is useful for:
|
||||
- non-web3 builders wanting to leverage the latest smart account capabiltiies
|
||||
- SDK devs who also want to support interaction with the bleeding edge of smart account verification capabilities
|
||||
Are you interested in compressing ERC-4337 data? Start with [the compression package](./packages/compression/)
|
||||
|
||||
## packages/plugins
|
||||
You're a smart account dev and would like to integrate new primitives
|
||||
New verification schemes are integrated into existing open smart accounts here.
|
||||
This is where modularised byte verification is developed.
|
||||
## Compression
|
||||
[packages/compression](./packages//compression/)
|
||||
|
||||
Contracts implementing compression for ERC-4337 accounts to reduce data being posted from rollups.
|
||||
|
||||
## Demos
|
||||
[packages/demos](./packages/demos/)
|
||||
|
||||
Demos showcasing WAX components.
|
||||
|
||||
## Deterministic Deployer
|
||||
[packages/deterministic-deployer](./packages/deterministic-deployer/)
|
||||
|
||||
Deploys contracts to deterministic addresses.
|
||||
|
||||
## Plugins
|
||||
[packages/plugins](./packages/plugins/)
|
||||
|
||||
Plugins/modules for smart contracts accounts, including test scaffolding.
|
||||
|
||||
## SDK
|
||||
[packages/sdk](./packages/sdk/)
|
||||
|
||||
SDK code to help with ERC-4337 interactions.
|
||||
|
||||
## Archive
|
||||
[archive](./archive/)
|
||||
|
||||
Work & projects that are no longer actively used but could be useful as references.
|
||||
|
||||
14
archive/README.md
Normal file
14
archive/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Archive
|
||||
This directory contains work & projects that are no longer active or maintained but could be useful as references
|
||||
|
||||
## Barebones
|
||||
|
||||
Lightweight Smart Account framework
|
||||
|
||||
## Images
|
||||
|
||||
Older technical diagrams for WAX project
|
||||
|
||||
## ZKP
|
||||
|
||||
Circuits related to ERC-4337 accounts & a TypeScript ZKEmail relayer
|
||||
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
@@ -2,6 +2,8 @@
|
||||
|
||||
Based on https://github.com/privacy-scaling-explorations/zkp-app-boilerplate/tree/main/circuits
|
||||
|
||||
Includes a protoype [TypeScript ZKEmail relayer](./relayer/).
|
||||
|
||||
WARNING: These circuits are unsafe and are currently not recommended for production use.
|
||||
|
||||
## Required
|
||||
@@ -11,17 +13,11 @@ WARNING: These circuits are unsafe and are currently not recommended for product
|
||||
|
||||
## Setup
|
||||
|
||||
**Step 1**: Download git submodules.
|
||||
Install circom following [these instructions](https://docs.circom.io/getting-started/installation/)
|
||||
|
||||
```sh
|
||||
git submodule update --init
|
||||
```
|
||||
The last working version was `v2.1.8`, [commit](https://github.com/iden3/circom/commit/f0deda416abe91e5dd906c55507c737cd9986ab5)
|
||||
|
||||
**Step 2**: Install circom.
|
||||
|
||||
Follow [these instructions](https://docs.circom.io/getting-started/installation/) replacing the git clone with `cd lib/circom`.
|
||||
|
||||
**Step 3**: Install NodeJS dependencies.
|
||||
**Step 2**: Install NodeJS dependencies.
|
||||
|
||||
```sh
|
||||
yarn
|
||||
@@ -42,4 +38,4 @@ yarn test
|
||||
|
||||
## Other Commands
|
||||
|
||||
See [package.json](./package.json)
|
||||
See [package.json](./package.json)
|
||||
@@ -1,25 +1,3 @@
|
||||
# Packages
|
||||
|
||||
## Barebones
|
||||
|
||||
Lightweight Smart Account
|
||||
|
||||
## Compression
|
||||
|
||||
Contracts implementing compression for ERC-4337 accounts
|
||||
|
||||
## Demos
|
||||
|
||||
Demos showcasing WAX components
|
||||
|
||||
## Plugins
|
||||
|
||||
Plugins for Smart Accounts
|
||||
|
||||
## SDK
|
||||
|
||||
(Prototype) SDK code to help with ERC-4337 interactions
|
||||
|
||||
## ZKP
|
||||
|
||||
Circuits related to ERC-4337 accounts and a typescript relayer
|
||||
See [top level README](../README.md)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# Compression for 4337
|
||||
# Compression for ERC-4337
|
||||
|
||||
Contracts implementing compression for 4337 wallets.
|
||||
Contracts implementing compression for ERC-4337 accountss. This work is compatible with ERC-4337 v0.6.
|
||||
|
||||
See https://hackmd.io/@voltrevo/Bkz8syuUp for more details & performance.
|
||||
|
||||
## Performance
|
||||
|
||||
|
||||
@@ -1 +1,14 @@
|
||||
# Demos
|
||||
# Demos
|
||||
Demos of WAX modules & functionality
|
||||
|
||||
[Email Recovery](./email-recovery/)
|
||||
|
||||
Demo of account recovery via email using https://github.com/zkemail/email-recovery
|
||||
|
||||
[Fee Calculator](./fee-calculator/)
|
||||
|
||||
Calculator to assist in determing if it is cheaper to use BLS + compression on rollups vs. a normal transaction/UserOp
|
||||
|
||||
[In Page](./email-recovery/)
|
||||
|
||||
Showcase of experimental modules bult by WAX team.
|
||||
|
||||
5
packages/deterministic-deployer/README.md
Normal file
5
packages/deterministic-deployer/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Determinisitic Deployer
|
||||
|
||||
Deploys contracts to deterministic addresses
|
||||
|
||||
Based on create2 and the deployer contract from https://github.com/Arachnid/deterministic-deployment-proxy
|
||||
@@ -1,8 +1,27 @@
|
||||
# Plugins
|
||||
|
||||
Please note, these plugins are in a pre-alpha state and are not ready for production use. In their current state, the plugins are meant for testing and experimentation.
|
||||
Experimental plugins, modules, components for use with [ERC-4337](https://eips.ethereum.org/EIPS/eip-4337) (`v0.7.0`) compatible smart contract accounts. Most are currently built on top of Safe.
|
||||
These plugins are in a pre-alpha state and are not ready for production use. They are intended for experimentation.
|
||||
|
||||
# Getting Started
|
||||
This package is a hybrid Foundry & Hardhat project. Foundry is used for unit & integration testing, with Hardhat for end-to-end testing & examples of using a plugin in JavaScript/TypeScript runtime.
|
||||
|
||||
## When you should use this package
|
||||
|
||||
- If you are building a ERC-4337 plugin, module, or component and want end-to-end tooling & testing harnesses to make sure your it is compatible within the ERC-4337/Ethereum AA ecosystem. These can include but are not limited to:
|
||||
- Validation
|
||||
- Account Recovery
|
||||
- Paymasters
|
||||
- If you are building a module for an ERC-4437 Safe.
|
||||
- If you are interested in experimenting with calldata compression. See also [the compression package](../compression/).
|
||||
- If you have an interesting idea to integrate a novel cryptographic primitive or zero knowledge proof into the Ethereum AA ecosystem and want a place to start.
|
||||
|
||||
## When you shouldn't use this package
|
||||
|
||||
If you are developing a plugin/module for use with an ERC-4337 module spec, such as:
|
||||
- ERC-7579, use https://docs.rhinestone.wtf/modulekit as a base instead.
|
||||
- ERC-6900, use https://www.erc6900.io/build-a-plugin as a base instead.
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. `cd packages/plugins`
|
||||
2. Run `yarn submodules` to initialize git submodules
|
||||
@@ -10,21 +29,21 @@ Please note, these plugins are in a pre-alpha state and are not ready for produc
|
||||
4. Run `forge install` to install foundry dependencies
|
||||
5. Run `cp .env.example .env` to create an `.env` file with the values from `.env.example`
|
||||
|
||||
## Build & generate Typechain definitions
|
||||
### Build & generate Typechain definitions
|
||||
|
||||
```bash
|
||||
yarn build
|
||||
```
|
||||
|
||||
## Forge tests
|
||||
### Forge tests
|
||||
|
||||
```bash
|
||||
forge test --no-match-path test/unit/safe/SafeZkEmailRecoveryPlugin.t.sol -vvv
|
||||
```
|
||||
|
||||
## Hardhat tests
|
||||
### Hardhat tests
|
||||
|
||||
To run the hardhat tests, you'll need to run a node and a bundler as some of them are integration tests:
|
||||
To run the hardhat tests, you'll need to run a geth node & bundler as some of them are integration tests:
|
||||
|
||||
1. Start a geth node, fund accounts, deploy Safe contracts, and start a bundler:
|
||||
|
||||
@@ -39,3 +58,8 @@ To run the hardhat tests, you'll need to run a node and a bundler as some of the
|
||||
```bash
|
||||
yarn hardhat test
|
||||
```
|
||||
|
||||
### Things to keep in mind
|
||||
|
||||
- When writing Hardhat tests in the [e2e directory](./test/e2e/), DO NOT USE the `hre` ([Hardhat Runtime Environment](https://hardhat.org/hardhat-runner/docs/advanced/hardhat-runtime-environment)) when deploying contracts & interacting on chain. We do not use the normal internal Hardhat runtime as we need to run against a local geth instance & bundler to fully simulate the ERC-4337 flow end-to-end.
|
||||
- Be mindful of the [opcode & storage limitations imposed by ERC-4337](https://eips.ethereum.org/EIPS/eip-7562).
|
||||
|
||||
@@ -11,9 +11,6 @@
|
||||
"build": "hardhat compile",
|
||||
"lint": "eslint . --ext js,jsx,ts,tsx --report-unused-disable-directives --max-warnings 0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@getwax/circuits": "../zkp"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@account-abstraction/contracts": "0.7.0",
|
||||
"@account-abstraction/utils": "^0.6.0",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import fs from "fs/promises";
|
||||
import { ethers } from "ethers";
|
||||
import {
|
||||
HDNodeWallet,
|
||||
JsonRpcProvider,
|
||||
NonceManager,
|
||||
Signer,
|
||||
Wallet,
|
||||
} from "ethers";
|
||||
import DeterministicDeployer, {
|
||||
ContractFactoryConstructor,
|
||||
DeployParams,
|
||||
@@ -15,37 +21,38 @@ import {
|
||||
SafeL2__factory,
|
||||
Safe__factory,
|
||||
EntryPoint__factory,
|
||||
BLSSignatureAggregator__factory,
|
||||
// BLSSignatureAggregator__factory,
|
||||
BLSOpen__factory,
|
||||
HandleOpsCaller__factory,
|
||||
HandleAggregatedOpsCaller__factory,
|
||||
// HandleAggregatedOpsCaller__factory,
|
||||
AddressRegistry__factory,
|
||||
} from "../typechain-types";
|
||||
import makeDevFaster from "../test/e2e/utils/makeDevFaster";
|
||||
import { TokenCallbackHandler__factory } from "../typechain-types/factories/lib/safe-contracts/contracts/handler/TokenCallbackHandler__factory";
|
||||
import bundlerConfig from "./../config/bundler.config.json";
|
||||
// import bundlerConfig from "./../config/bundler.config.json";
|
||||
|
||||
// 'test '.repeat(11) + 'absent'
|
||||
const testAbsentAddress = "0xe8250207B79D7396631bb3aE38a7b457261ae0B6";
|
||||
|
||||
async function deploy() {
|
||||
const { NODE_URL, MNEMONIC } = process.env;
|
||||
const provider = new ethers.JsonRpcProvider(NODE_URL);
|
||||
const provider = new JsonRpcProvider(NODE_URL);
|
||||
await makeDevFaster(provider);
|
||||
const hdNode = ethers.HDNodeWallet.fromPhrase(MNEMONIC!);
|
||||
const wallet = new ethers.Wallet(hdNode.privateKey, provider);
|
||||
const hdNode = HDNodeWallet.fromPhrase(MNEMONIC!);
|
||||
const wallet = new Wallet(hdNode.privateKey, provider);
|
||||
const nonceMgr = new NonceManager(wallet);
|
||||
|
||||
const recordingDeployer = await RecordingDeployer.init(wallet);
|
||||
const recordingDeployer = await RecordingDeployer.init(nonceMgr);
|
||||
|
||||
const linkedAggregator = DeterministicDeployer.link(
|
||||
BLSSignatureAggregator__factory,
|
||||
[
|
||||
{
|
||||
"lib/account-abstraction/contracts/samples/bls/lib/BLSOpen.sol:BLSOpen":
|
||||
recordingDeployer.deployer.calculateAddress(BLSOpen__factory, []),
|
||||
},
|
||||
],
|
||||
);
|
||||
// const linkedAggregator = DeterministicDeployer.link(
|
||||
// BLSSignatureAggregator__factory,
|
||||
// [
|
||||
// {
|
||||
// "lib/account-abstraction/contracts/samples/bls/lib/BLSOpen.sol:BLSOpen":
|
||||
// recordingDeployer.deployer.calculateAddress(BLSOpen__factory, []),
|
||||
// },
|
||||
// ],
|
||||
// );
|
||||
|
||||
const deployments = [
|
||||
["SimulateTxAccessor", SimulateTxAccessor__factory],
|
||||
@@ -117,9 +124,9 @@ class RecordingDeployer {
|
||||
public safeDeployer: DeterministicDeployer,
|
||||
) {}
|
||||
|
||||
static async init(wallet: ethers.Wallet): Promise<RecordingDeployer> {
|
||||
const deployer = await DeterministicDeployer.init(wallet);
|
||||
const safeDeployer = await DeterministicDeployer.initSafeVersion(wallet);
|
||||
static async init(signer: Signer): Promise<RecordingDeployer> {
|
||||
const deployer = await DeterministicDeployer.init(signer);
|
||||
const safeDeployer = await DeterministicDeployer.initSafeVersion(signer);
|
||||
|
||||
try {
|
||||
await fs.rename(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
RPC_URL="${RPC_URL:=localhost:8545}"
|
||||
SLEEP_DURATION_SECONDS="${SLEEP_DURATION_SECONDS:=0.1}"
|
||||
|
||||
max_tries=100
|
||||
counter=0
|
||||
@@ -14,7 +15,7 @@ function check_rpc() {
|
||||
}
|
||||
|
||||
while ! check_rpc; do
|
||||
sleep 0.1
|
||||
sleep $SLEEP_DURATION_SECONDS
|
||||
counter=$((counter + 1))
|
||||
if (( counter >= max_tries )); then
|
||||
echo "Error: Reached max_tries waiting for $RPC_URL to be available" >&2
|
||||
|
||||
@@ -1,365 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {BasePlugin} from "erc6900-reference-implementation/plugins/BasePlugin.sol";
|
||||
import {IPluginExecutor} from "erc6900-reference-implementation/interfaces/IPluginExecutor.sol";
|
||||
import {ManifestFunction, ManifestAssociatedFunctionType, ManifestAssociatedFunction, PluginManifest, PluginMetadata, IPlugin} from "erc6900-reference-implementation/interfaces/IPlugin.sol";
|
||||
import {MockGroth16Verifier} from "../safe/utils/MockGroth16Verifier.sol";
|
||||
import {MockDKIMRegsitry} from "../safe/utils/MockDKIMRegsitry.sol";
|
||||
import {IDKIMRegsitry} from "../safe/interface/IDKIMRegsitry.sol";
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
THIS CONTRACT IS STILL IN ACTIVE DEVELOPMENT. NOT FOR PRODUCTION USE
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
struct RecoveryRequest {
|
||||
bytes32 recoveryHash;
|
||||
bytes32 dkimPublicKeyHash;
|
||||
uint256 executeAfter;
|
||||
address pendingNewOwner;
|
||||
}
|
||||
|
||||
/// @title ZK Email Recovery Plugin
|
||||
/// @author Wax
|
||||
/// @notice This plugin recovers a ERC 6900 account via zk email guardians
|
||||
contract ERC6900ZkEmailRecoveryModule is BasePlugin {
|
||||
// metadata used by the pluginMetadata() method down below
|
||||
string public constant NAME = "ZK Email Recovery Plugin";
|
||||
string public constant VERSION = "1.0.0";
|
||||
string public constant AUTHOR = "Wax";
|
||||
|
||||
// this is a constant used in the manifest, to reference our only dependency: the single owner plugin
|
||||
// since it is the first, and only, plugin the index 0 will reference the single owner plugin
|
||||
// we can use this to tell the modular account that we should use the single owner plugin to validate our user op
|
||||
// in other words, we'll say "make sure the person calling the recovery functions is an owner of the account using our single plugin" // TODO: revisit this - recovery is more complicated as the owner is compromised
|
||||
uint256
|
||||
internal constant _MANIFEST_DEPENDENCY_INDEX_OWNER_USER_OP_VALIDATION =
|
||||
0;
|
||||
|
||||
/** Default DKIM public key hashes registry */
|
||||
IDKIMRegsitry public immutable defaultDkimRegistry;
|
||||
|
||||
/** verifier */
|
||||
MockGroth16Verifier public immutable verifier;
|
||||
|
||||
/** Default delay has been set to a large timeframe on purpose. Please use a default delay suited to your specific context */
|
||||
uint256 public constant defaultDelay = 2 weeks;
|
||||
|
||||
/** recovery hash domain */
|
||||
bytes32 immutable RECOVERY_HASH_DOMAIN;
|
||||
|
||||
/** recovery request */
|
||||
RecoveryRequest public recoveryRequest;
|
||||
|
||||
/** custom recovery delay */
|
||||
uint256 public recoveryDelay;
|
||||
|
||||
/** dkim registry address */
|
||||
address public dkimRegistry;
|
||||
|
||||
error RECOVERY_ALREADY_INITIATED();
|
||||
error RECOVERY_NOT_CONFIGURED();
|
||||
error INVALID_DKIM_KEY_HASH(
|
||||
address account,
|
||||
string emailDomain,
|
||||
bytes32 dkimPublicKeyHash
|
||||
);
|
||||
error INVALID_PROOF();
|
||||
error RECOVERY_NOT_INITIATED();
|
||||
error DELAY_NOT_PASSED();
|
||||
|
||||
event RecoveryConfigured(
|
||||
address indexed account,
|
||||
address indexed owner,
|
||||
bytes32 recoveryHash,
|
||||
bytes32 dkimPublicKeyHash,
|
||||
address dkimRegistry,
|
||||
uint256 customDelay
|
||||
);
|
||||
event RecoveryInitiated(
|
||||
address indexed account,
|
||||
address newOwner,
|
||||
uint256 executeAfter
|
||||
);
|
||||
event AccountRecovered(address indexed account, address newOwner);
|
||||
event RecoveryCancelled(address indexed account);
|
||||
event RecoveryDelaySet(address indexed account, uint256 delay);
|
||||
|
||||
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
// ┃ Execution functions ┃
|
||||
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
|
||||
/**
|
||||
* @notice Initiates a recovery for an account using a zk email proof.
|
||||
* @dev Rotates the account owner address to a new address. Uses the
|
||||
* default delay period if no custom delay has been set. This is the second
|
||||
* function that should be called in the recovery process - after configureRecovery
|
||||
* @param newOwner The new owner address of the account
|
||||
* @param emailDomain Domain name of the sender's email
|
||||
* @param a Part of the proof
|
||||
* @param b Part of the proof
|
||||
* @param c Part of the proof
|
||||
*/
|
||||
function initiateRecovery(
|
||||
address newOwner,
|
||||
string memory emailDomain,
|
||||
uint256[2] memory a,
|
||||
uint256[2][2] memory b,
|
||||
uint256[2] memory c
|
||||
) external {
|
||||
address account = msg.sender;
|
||||
|
||||
if (recoveryRequest.recoveryHash == bytes32(0)) {
|
||||
revert RECOVERY_NOT_CONFIGURED();
|
||||
}
|
||||
|
||||
if (recoveryRequest.executeAfter > 0) {
|
||||
revert RECOVERY_ALREADY_INITIATED();
|
||||
}
|
||||
|
||||
if (
|
||||
!this.isDKIMPublicKeyHashValid(
|
||||
emailDomain,
|
||||
recoveryRequest.dkimPublicKeyHash
|
||||
)
|
||||
) {
|
||||
revert INVALID_DKIM_KEY_HASH(
|
||||
account,
|
||||
emailDomain,
|
||||
recoveryRequest.dkimPublicKeyHash
|
||||
);
|
||||
}
|
||||
|
||||
uint256[4] memory publicSignals = [
|
||||
uint256(uint160(account)),
|
||||
uint256(recoveryRequest.recoveryHash),
|
||||
uint256(uint160(newOwner)),
|
||||
uint256(recoveryRequest.dkimPublicKeyHash)
|
||||
];
|
||||
|
||||
// verify proof
|
||||
bool verified = verifier.verifyProof(a, b, c, publicSignals);
|
||||
if (!verified) revert INVALID_PROOF();
|
||||
|
||||
uint256 executeAfter = block.timestamp + recoveryDelay;
|
||||
|
||||
recoveryRequest.executeAfter = executeAfter;
|
||||
recoveryRequest.pendingNewOwner = newOwner;
|
||||
|
||||
emit RecoveryInitiated(account, newOwner, executeAfter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Recovers an account using a zk email proof.
|
||||
* @dev Rotates the account owner address to a new address.
|
||||
* This function is the third and final function that needs to be called in the
|
||||
* recovery process. After configureRecovery & initiateRecovery
|
||||
*/
|
||||
function recoverAccount() public {
|
||||
address account = msg.sender;
|
||||
|
||||
if (recoveryRequest.executeAfter == 0) {
|
||||
revert RECOVERY_NOT_INITIATED();
|
||||
}
|
||||
|
||||
if (block.timestamp > recoveryRequest.executeAfter) {
|
||||
delete recoveryRequest;
|
||||
|
||||
// TODO: implement recovery logic for 6900 owner plugin
|
||||
// owner = recoveryRequest.pendingNewOwner;
|
||||
|
||||
emit AccountRecovered(account, recoveryRequest.pendingNewOwner);
|
||||
} else {
|
||||
revert DELAY_NOT_PASSED();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Cancels the recovery process of the sender if it exits.
|
||||
* @dev Deletes the recovery request accociated with a account. Assumes
|
||||
* the msg.sender is the account that the recovery request is being deleted for
|
||||
*/
|
||||
function cancelRecovery() external {
|
||||
address account = msg.sender;
|
||||
delete recoveryRequest;
|
||||
emit RecoveryCancelled(account);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Sets a custom delay for recovering the account.
|
||||
* @dev Custom delay is used instead of the default delay when recovering the
|
||||
* account. Custom delays should be configured with care as they can be
|
||||
* used to bypass the default delay.
|
||||
* @param delay The custom delay to be used when recovering the account
|
||||
*/
|
||||
function setRecoveryDelay(uint256 delay) external {
|
||||
address account = msg.sender;
|
||||
recoveryDelay = delay;
|
||||
emit RecoveryDelaySet(account, delay);
|
||||
}
|
||||
|
||||
/// @notice Return the DKIM public key hash for a given email domain and account address
|
||||
/// @param emailDomain Email domain for which the DKIM public key hash is to be returned
|
||||
function isDKIMPublicKeyHashValid(
|
||||
string memory emailDomain,
|
||||
bytes32 publicKeyHash
|
||||
) public view returns (bool) {
|
||||
if (dkimRegistry == address(0)) {
|
||||
return
|
||||
defaultDkimRegistry.isDKIMPublicKeyHashValid(
|
||||
emailDomain,
|
||||
publicKeyHash
|
||||
);
|
||||
} else {
|
||||
return
|
||||
IDKIMRegsitry(dkimRegistry).isDKIMPublicKeyHashValid(
|
||||
emailDomain,
|
||||
publicKeyHash
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
// ┃ Plugin interface functions ┃
|
||||
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
|
||||
/// @inheritdoc BasePlugin
|
||||
function onInstall(bytes calldata data) external override {
|
||||
(
|
||||
bytes32 recoveryHash,
|
||||
bytes32 dkimPublicKeyHash,
|
||||
address _dkimRegistry,
|
||||
uint256 customDelay
|
||||
) = abi.decode(data, (bytes32, bytes32, address, uint256));
|
||||
|
||||
address account = msg.sender;
|
||||
|
||||
if (recoveryRequest.executeAfter > 0) {
|
||||
revert RECOVERY_ALREADY_INITIATED();
|
||||
}
|
||||
|
||||
if (customDelay > 0) {
|
||||
recoveryDelay = customDelay;
|
||||
} else {
|
||||
recoveryDelay = defaultDelay;
|
||||
}
|
||||
|
||||
recoveryRequest = RecoveryRequest({
|
||||
recoveryHash: recoveryHash,
|
||||
dkimPublicKeyHash: dkimPublicKeyHash,
|
||||
executeAfter: 0,
|
||||
pendingNewOwner: address(0)
|
||||
});
|
||||
dkimRegistry = _dkimRegistry; // FIXME: could be zero
|
||||
|
||||
emit RecoveryConfigured(
|
||||
account,
|
||||
msg.sender,
|
||||
recoveryHash,
|
||||
dkimPublicKeyHash,
|
||||
dkimRegistry,
|
||||
customDelay
|
||||
);
|
||||
}
|
||||
|
||||
/// @inheritdoc BasePlugin
|
||||
function onUninstall(bytes calldata) external pure override {}
|
||||
|
||||
/// @inheritdoc BasePlugin
|
||||
function pluginManifest()
|
||||
external
|
||||
pure
|
||||
override
|
||||
returns (PluginManifest memory)
|
||||
{
|
||||
PluginManifest memory manifest;
|
||||
|
||||
// since we are using the modular account, we will specify one depedency
|
||||
// which will handle the user op validation for ownership
|
||||
// you can find this depedency specified in the installPlugin call in the tests
|
||||
manifest.dependencyInterfaceIds = new bytes4[](1);
|
||||
manifest.dependencyInterfaceIds[0] = type(IPlugin).interfaceId;
|
||||
|
||||
// we have several execution functions that can be called, here we define
|
||||
// those functions on the manifest as something that can be called during execution
|
||||
manifest.executionFunctions = new bytes4[](5);
|
||||
manifest.executionFunctions[0] = this.initiateRecovery.selector;
|
||||
manifest.executionFunctions[1] = this.recoverAccount.selector;
|
||||
manifest.executionFunctions[2] = this.cancelRecovery.selector;
|
||||
manifest.executionFunctions[3] = this.setRecoveryDelay.selector;
|
||||
manifest.executionFunctions[4] = this.isDKIMPublicKeyHashValid.selector;
|
||||
|
||||
// you can think of ManifestFunction as a reference to a function somewhere,
|
||||
// we want to say "use this function" for some purpose - in this case,
|
||||
// we'll be using the user op validation function from the single owner dependency
|
||||
// and this is specified by the depdendency index
|
||||
ManifestFunction
|
||||
memory ownerUserOpValidationFunction = ManifestFunction({
|
||||
functionType: ManifestAssociatedFunctionType.DEPENDENCY,
|
||||
functionId: 0, // unused since it's a dependency
|
||||
dependencyIndex: _MANIFEST_DEPENDENCY_INDEX_OWNER_USER_OP_VALIDATION
|
||||
});
|
||||
|
||||
// here we will link together the recovery functions with the single owner user op validation
|
||||
// this basically says "use this user op validation function and make sure everythings okay before calling the recovery functions"
|
||||
// this will ensure that only an owner of the account can call the recovery functions
|
||||
manifest.userOpValidationFunctions = new ManifestAssociatedFunction[](
|
||||
1
|
||||
);
|
||||
manifest.userOpValidationFunctions[0] = ManifestAssociatedFunction({
|
||||
executionSelector: this.initiateRecovery.selector,
|
||||
associatedFunction: ownerUserOpValidationFunction
|
||||
});
|
||||
// TODO: recoverAccount should be permissionless if threshold is met
|
||||
manifest.userOpValidationFunctions[1] = ManifestAssociatedFunction({
|
||||
executionSelector: this.recoverAccount.selector,
|
||||
associatedFunction: ownerUserOpValidationFunction
|
||||
});
|
||||
manifest.userOpValidationFunctions[2] = ManifestAssociatedFunction({
|
||||
executionSelector: this.cancelRecovery.selector,
|
||||
associatedFunction: ownerUserOpValidationFunction
|
||||
});
|
||||
manifest.userOpValidationFunctions[3] = ManifestAssociatedFunction({
|
||||
executionSelector: this.setRecoveryDelay.selector,
|
||||
associatedFunction: ownerUserOpValidationFunction
|
||||
});
|
||||
manifest.userOpValidationFunctions[4] = ManifestAssociatedFunction({
|
||||
executionSelector: this.isDKIMPublicKeyHashValid.selector,
|
||||
associatedFunction: ownerUserOpValidationFunction
|
||||
});
|
||||
|
||||
// TODO: research best way to utilise this part of the manifest
|
||||
// finally here we will always deny runtime calls to the initiateRecovery function as we will only call it through user ops
|
||||
// this avoids a potential issue where a future plugin may define
|
||||
// a runtime validation function for it and unauthorized calls may occur due to that
|
||||
manifest.preRuntimeValidationHooks = new ManifestAssociatedFunction[](
|
||||
1
|
||||
);
|
||||
manifest.preRuntimeValidationHooks[0] = ManifestAssociatedFunction({
|
||||
executionSelector: this.initiateRecovery.selector,
|
||||
associatedFunction: ManifestFunction({
|
||||
functionType: ManifestAssociatedFunctionType
|
||||
.PRE_HOOK_ALWAYS_DENY,
|
||||
functionId: 0,
|
||||
dependencyIndex: 0
|
||||
})
|
||||
});
|
||||
|
||||
return manifest;
|
||||
}
|
||||
|
||||
/// @inheritdoc BasePlugin
|
||||
function pluginMetadata()
|
||||
external
|
||||
pure
|
||||
virtual
|
||||
override
|
||||
returns (PluginMetadata memory)
|
||||
{
|
||||
PluginMetadata memory metadata;
|
||||
metadata.name = NAME;
|
||||
metadata.version = VERSION;
|
||||
metadata.author = AUTHOR;
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,8 @@ import {MockDKIMRegsitry} from "./safe/utils/MockDKIMRegsitry.sol";
|
||||
import {IDKIMRegsitry} from "./safe/interface/IDKIMRegsitry.sol";
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
THIS CONTRACT IS STILL IN ACTIVE DEVELOPMENT. NOT FOR PRODUCTION USE
|
||||
THIS CONTRACT IS OUTDATED. NOT FOR PRODUCTION USE
|
||||
It is recomended you use https://github.com/zkemail/email-recovery instead.
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
struct RecoveryRequest {
|
||||
|
||||
@@ -1,276 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {IValidator, VALIDATION_SUCCESS, VALIDATION_FAILED, MODULE_TYPE_VALIDATOR} from "erc7579-implementation/src/interfaces/IERC7579Module.sol";
|
||||
import {ModeLib, ModeCode, CallType, CALLTYPE_SINGLE} from "erc7579-implementation/src/lib/ModeLib.sol";
|
||||
import {IERC7579Account} from "erc7579-implementation/src/interfaces/IERC7579Account.sol";
|
||||
import {ExecutionLib} from "erc7579-implementation/src/lib/ExecutionLib.sol";
|
||||
import {PackedUserOperation} from "account-abstraction/interfaces/IEntryPoint.sol";
|
||||
import {ValidationData} from "account-abstraction/core/Helpers.sol";
|
||||
import {MockGroth16Verifier} from "../safe/utils/MockGroth16Verifier.sol";
|
||||
import {MockDKIMRegsitry} from "../safe/utils/MockDKIMRegsitry.sol";
|
||||
import {IDKIMRegsitry} from "../safe/interface/IDKIMRegsitry.sol";
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
THIS CONTRACT IS STILL IN ACTIVE DEVELOPMENT. NOT FOR PRODUCTION USE
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
struct RecoveryRequest {
|
||||
bytes32 recoveryHash;
|
||||
bytes32 dkimPublicKeyHash;
|
||||
uint256 executeAfter;
|
||||
address pendingNewOwner;
|
||||
}
|
||||
|
||||
contract ERC7579ZkEmailRecoveryModule is IValidator {
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
CONSTANTS & STORAGE
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/** Default DKIM public key hashes registry */
|
||||
IDKIMRegsitry public immutable defaultDkimRegistry;
|
||||
|
||||
/** verifier */
|
||||
MockGroth16Verifier public immutable verifier;
|
||||
|
||||
/** Default delay has been set to a large timeframe on purpose. Please use a default
|
||||
delay suited to your specific context */
|
||||
uint256 public constant defaultDelay = 2 weeks;
|
||||
|
||||
/** recovery hash domain */
|
||||
bytes32 immutable RECOVERY_HASH_DOMAIN;
|
||||
|
||||
/** recovery request */
|
||||
RecoveryRequest public recoveryRequest;
|
||||
|
||||
/** custom recovery delay */
|
||||
uint256 public recoveryDelay;
|
||||
|
||||
/** dkim registry address */
|
||||
address public dkimRegistry;
|
||||
|
||||
mapping(address => bool) internal initialized;
|
||||
|
||||
error RECOVERY_ALREADY_INITIATED();
|
||||
error RECOVERY_NOT_CONFIGURED();
|
||||
error INVALID_DKIM_KEY_HASH(
|
||||
address account,
|
||||
string emailDomain,
|
||||
bytes32 dkimPublicKeyHash
|
||||
);
|
||||
error INVALID_PROOF();
|
||||
error RECOVERY_NOT_INITIATED();
|
||||
error DELAY_NOT_PASSED();
|
||||
error UNSUPPORTED_OPERATION();
|
||||
|
||||
event RecoveryConfigured(
|
||||
address indexed account,
|
||||
address indexed owner,
|
||||
bytes32 recoveryHash,
|
||||
bytes32 dkimPublicKeyHash,
|
||||
address dkimRegistry,
|
||||
uint256 customDelay
|
||||
);
|
||||
event RecoveryInitiated(
|
||||
address indexed account,
|
||||
address newOwner,
|
||||
uint256 executeAfter
|
||||
);
|
||||
event AccountRecovered(address indexed account, address newOwner);
|
||||
event RecoveryCancelled(address indexed account);
|
||||
event RecoveryDelaySet(address indexed account, uint256 delay);
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
CONFIG
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
function onInstall(bytes calldata data) external override {
|
||||
if (isInitialized(msg.sender)) revert AlreadyInitialized(msg.sender);
|
||||
|
||||
(
|
||||
bytes32 recoveryHash,
|
||||
bytes32 dkimPublicKeyHash,
|
||||
address _dkimRegistry,
|
||||
uint256 customDelay
|
||||
) = abi.decode(data, (bytes32, bytes32, address, uint256));
|
||||
|
||||
address account = msg.sender;
|
||||
|
||||
if (recoveryRequest.executeAfter > 0) {
|
||||
revert RECOVERY_ALREADY_INITIATED();
|
||||
}
|
||||
|
||||
if (customDelay > 0) {
|
||||
recoveryDelay = customDelay;
|
||||
} else {
|
||||
recoveryDelay = defaultDelay;
|
||||
}
|
||||
|
||||
recoveryRequest = RecoveryRequest({
|
||||
recoveryHash: recoveryHash,
|
||||
dkimPublicKeyHash: dkimPublicKeyHash,
|
||||
executeAfter: 0,
|
||||
pendingNewOwner: address(0)
|
||||
});
|
||||
dkimRegistry = _dkimRegistry; // FIXME: could be zero
|
||||
|
||||
initialized[msg.sender] = true;
|
||||
|
||||
emit RecoveryConfigured(
|
||||
account,
|
||||
msg.sender,
|
||||
recoveryHash,
|
||||
dkimPublicKeyHash,
|
||||
dkimRegistry,
|
||||
customDelay
|
||||
);
|
||||
}
|
||||
|
||||
function onUninstall(bytes calldata) external override {
|
||||
if (!isInitialized(msg.sender)) revert NotInitialized(msg.sender);
|
||||
initialized[msg.sender] = false;
|
||||
}
|
||||
|
||||
function isInitialized(address smartAccount) public view returns (bool) {
|
||||
return initialized[smartAccount];
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
MODULE LOGIC
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
function validateUserOp(
|
||||
PackedUserOperation calldata userOp,
|
||||
bytes32 userOpHash
|
||||
) external override returns (uint256) {
|
||||
address account = address(this);
|
||||
|
||||
(
|
||||
address newOwner,
|
||||
string memory emailDomain,
|
||||
uint256[2] memory a,
|
||||
uint256[2][2] memory b,
|
||||
uint256[2] memory c
|
||||
) = abi.decode(
|
||||
userOp.signature,
|
||||
(address, string, uint256[2], uint256[2][2], uint256[2])
|
||||
);
|
||||
|
||||
// Check if the execution is allowed
|
||||
bool isAllowedExecution;
|
||||
bytes4 selector = bytes4(userOp.callData[0:4]);
|
||||
if (selector == IERC7579Account.execute.selector) {
|
||||
// Decode and check the execution
|
||||
// Only single executions to installed validators are allowed
|
||||
isAllowedExecution = _decodeAndCheckExecution(userOp.callData);
|
||||
}
|
||||
|
||||
if (recoveryRequest.recoveryHash == bytes32(0)) {
|
||||
return VALIDATION_FAILED;
|
||||
}
|
||||
|
||||
if (recoveryRequest.executeAfter > 0) {
|
||||
return VALIDATION_FAILED;
|
||||
}
|
||||
|
||||
if (
|
||||
!this.isDKIMPublicKeyHashValid(
|
||||
emailDomain,
|
||||
recoveryRequest.dkimPublicKeyHash
|
||||
)
|
||||
) {
|
||||
return VALIDATION_FAILED;
|
||||
}
|
||||
|
||||
uint256[4] memory publicSignals = [
|
||||
uint256(uint160(account)),
|
||||
uint256(recoveryRequest.recoveryHash),
|
||||
uint256(uint160(newOwner)),
|
||||
uint256(recoveryRequest.dkimPublicKeyHash)
|
||||
];
|
||||
|
||||
// verify proof
|
||||
bool verified = verifier.verifyProof(a, b, c, publicSignals);
|
||||
if (!verified) return VALIDATION_FAILED;
|
||||
|
||||
uint256 executeAfter = block.timestamp + recoveryDelay;
|
||||
recoveryRequest.executeAfter = executeAfter;
|
||||
recoveryRequest.pendingNewOwner = newOwner;
|
||||
|
||||
emit RecoveryInitiated(account, newOwner, executeAfter);
|
||||
return VALIDATION_SUCCESS;
|
||||
}
|
||||
|
||||
function isValidSignatureWithSender(
|
||||
address,
|
||||
bytes32 hash,
|
||||
bytes calldata data
|
||||
) external view override returns (bytes4) {
|
||||
// ERC-1271 not supported for recovery
|
||||
revert UNSUPPORTED_OPERATION();
|
||||
}
|
||||
|
||||
/// @notice Return the DKIM public key hash for a given email domain and account address
|
||||
/// @param emailDomain Email domain for which the DKIM public key hash is to be returned
|
||||
function isDKIMPublicKeyHashValid(
|
||||
string memory emailDomain,
|
||||
bytes32 publicKeyHash
|
||||
) public view returns (bool) {
|
||||
if (dkimRegistry == address(0)) {
|
||||
return
|
||||
defaultDkimRegistry.isDKIMPublicKeyHashValid(
|
||||
emailDomain,
|
||||
publicKeyHash
|
||||
);
|
||||
} else {
|
||||
return
|
||||
IDKIMRegsitry(dkimRegistry).isDKIMPublicKeyHashValid(
|
||||
emailDomain,
|
||||
publicKeyHash
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
INTERNAL
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
function _decodeAndCheckExecution(
|
||||
bytes calldata callData
|
||||
) internal returns (bool isAllowedExecution) {
|
||||
// Get the mode and call type
|
||||
ModeCode mode = ModeCode.wrap(bytes32(callData[4:36]));
|
||||
CallType calltype = ModeLib.getCallType(mode);
|
||||
|
||||
if (calltype == CALLTYPE_SINGLE) {
|
||||
// Decode the calldata
|
||||
(address to, , ) = ExecutionLib.decodeSingle(callData[100:]);
|
||||
|
||||
// Check if the module is installed as a validator
|
||||
return
|
||||
IERC7579Account(msg.sender).isModuleInstalled(
|
||||
MODULE_TYPE_VALIDATOR,
|
||||
to,
|
||||
""
|
||||
);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
METADATA
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
function name() external pure returns (string memory) {
|
||||
return "SocialRecoveryValidator";
|
||||
}
|
||||
|
||||
function version() external pure returns (string memory) {
|
||||
return "0.0.1";
|
||||
}
|
||||
|
||||
function isModuleType(uint256 typeID) external view returns (bool) {
|
||||
return typeID == MODULE_TYPE_VALIDATOR;
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
pragma solidity >=0.7.0 <0.9.0;
|
||||
pragma abicoder v2;
|
||||
|
||||
import {Safe} from "safe-contracts/contracts/Safe.sol";
|
||||
import {SafeProxyFactory} from "safe-contracts/contracts/proxies/SafeProxyFactory.sol";
|
||||
import {SafeProxy} from "safe-contracts/contracts/proxies/SafeProxy.sol";
|
||||
|
||||
import {EntryPoint} from "account-abstraction/core/EntryPoint.sol";
|
||||
|
||||
import {SafeZKPPasswordPlugin} from "./SafeZKPPasswordPlugin.sol";
|
||||
import {IGroth16Verifier} from "./interface/IGroth16Verifier.sol";
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
THIS CONTRACT IS STILL IN ACTIVE DEVELOPMENT. NOT FOR PRODUCTION USE
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
contract SafeZKPPasswordFactory {
|
||||
function create(
|
||||
Safe safeSingleton,
|
||||
EntryPoint entryPoint,
|
||||
address owner,
|
||||
uint256 saltNonce,
|
||||
IGroth16Verifier verifier
|
||||
) external returns (SafeZKPPasswordPlugin) {
|
||||
bytes32 salt = keccak256(abi.encodePacked(owner, saltNonce));
|
||||
|
||||
Safe safe = Safe(
|
||||
payable(new SafeProxy{salt: salt}(address(safeSingleton)))
|
||||
);
|
||||
|
||||
address[] memory owners = new address[](1);
|
||||
owners[0] = owner;
|
||||
|
||||
SafeZKPPasswordPlugin plugin = new SafeZKPPasswordPlugin{salt: salt}(
|
||||
address(entryPoint),
|
||||
verifier
|
||||
);
|
||||
|
||||
safe.setup(
|
||||
owners,
|
||||
1,
|
||||
address(plugin),
|
||||
abi.encodeCall(SafeZKPPasswordPlugin.enableMyself, (owner)),
|
||||
address(plugin),
|
||||
address(0),
|
||||
0,
|
||||
payable(address(0))
|
||||
);
|
||||
|
||||
return SafeZKPPasswordPlugin(address(safe));
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
pragma solidity >=0.7.0 <0.9.0;
|
||||
pragma abicoder v2;
|
||||
|
||||
import {IGroth16Verifier} from "./interface/IGroth16Verifier.sol";
|
||||
import {ISafe} from "./interface/ISafe.sol";
|
||||
import {Safe4337Base, SIG_VALIDATION_FAILED} from "./utils/Safe4337Base.sol";
|
||||
import {IEntryPoint, PackedUserOperation} from "account-abstraction/interfaces/IEntryPoint.sol";
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
THIS CONTRACT IS STILL IN ACTIVE DEVELOPMENT. NOT FOR PRODUCTION USE
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
struct ZKPPasswordOwnerStorage {
|
||||
address owner;
|
||||
}
|
||||
|
||||
contract SafeZKPPasswordPlugin is Safe4337Base {
|
||||
mapping(address => ZKPPasswordOwnerStorage) public zkpPasswordOwnerStorage;
|
||||
|
||||
address public immutable myAddress; // Module address
|
||||
address private immutable _entryPoint;
|
||||
IGroth16Verifier private immutable _verifier;
|
||||
|
||||
address internal constant _SENTINEL_MODULES = address(0x1);
|
||||
|
||||
event OWNER_UPDATED(
|
||||
address indexed safe,
|
||||
address indexed oldOwner,
|
||||
address indexed newOwner
|
||||
);
|
||||
|
||||
constructor(address entryPointAddress, IGroth16Verifier verifier) {
|
||||
myAddress = address(this);
|
||||
_entryPoint = entryPointAddress;
|
||||
_verifier = verifier;
|
||||
}
|
||||
|
||||
function getOwner(address safe) external view returns (address owner) {
|
||||
owner = zkpPasswordOwnerStorage[safe].owner;
|
||||
}
|
||||
|
||||
function execTransaction(
|
||||
address to,
|
||||
uint256 value,
|
||||
bytes calldata data
|
||||
) external payable {
|
||||
_requireFromEntryPoint();
|
||||
|
||||
bool success = _currentSafe().execTransactionFromModule(
|
||||
to,
|
||||
value,
|
||||
data,
|
||||
0
|
||||
);
|
||||
|
||||
require(success, "tx failed");
|
||||
}
|
||||
|
||||
function enableMyself(address ownerKey) public {
|
||||
// Called during safe setup as a delegatecall. This is why we use `this`
|
||||
// to refer to the safe instead of `msg.sender` / _currentSafe().
|
||||
|
||||
ISafe(address(this)).enableModule(myAddress);
|
||||
|
||||
// Enable the safe address with the defined key
|
||||
bytes memory _data = abi.encodePacked(ownerKey);
|
||||
SafeZKPPasswordPlugin(myAddress).enable(_data);
|
||||
}
|
||||
|
||||
function entryPoint() public view override returns (IEntryPoint) {
|
||||
return IEntryPoint(_entryPoint);
|
||||
}
|
||||
|
||||
function enable(bytes calldata _data) external payable {
|
||||
address newOwner = address(bytes20(_data[0:20]));
|
||||
address oldOwner = zkpPasswordOwnerStorage[msg.sender].owner;
|
||||
zkpPasswordOwnerStorage[msg.sender].owner = newOwner;
|
||||
emit OWNER_UPDATED(msg.sender, oldOwner, newOwner);
|
||||
}
|
||||
|
||||
function _validateSignature(
|
||||
PackedUserOperation calldata userOp,
|
||||
bytes32 userOpHash
|
||||
) internal view override returns (uint256 validationData) {
|
||||
// TODO (merge-ok) There is likely a more efficient way to encode this
|
||||
// to save on space, which would be especially desirable on rollups.
|
||||
uint256[2] memory a;
|
||||
uint256[2][2] memory b;
|
||||
uint256[2] memory c;
|
||||
(a, b, c) = abi.decode(
|
||||
userOp.signature,
|
||||
(uint256[2], uint256[2][2], uint256[2])
|
||||
);
|
||||
uint256[1] memory pubSignals = [bytesToUint(userOpHash)];
|
||||
bool result = _verifier.verifyProof(a, b, c, pubSignals);
|
||||
if (!result) {
|
||||
return SIG_VALIDATION_FAILED;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// From https://ethereum.stackexchange.com/a/51234
|
||||
function bytesToUint(bytes32 b) internal pure returns (uint256) {
|
||||
uint256 number;
|
||||
for (uint i = 0; i < b.length; i++) {
|
||||
number =
|
||||
number +
|
||||
uint(uint8(b[i])) *
|
||||
(2 ** (8 * (b.length - (i + 1))));
|
||||
}
|
||||
return number;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import {SafeProxy} from "safe-contracts/contracts/proxies/SafeProxy.sol";
|
||||
|
||||
import {EntryPoint} from "account-abstraction/core/EntryPoint.sol";
|
||||
|
||||
import {SafeAnonAadhaarPlugin} from "./SafeAnonAadhaarPlugin.sol";
|
||||
import {SafeAnonAadhaarPlugin} from "../validators/SafeAnonAadhaarPlugin.sol";
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
THIS CONTRACT IS STILL IN ACTIVE DEVELOPMENT. NOT FOR PRODUCTION USE
|
||||
@@ -8,8 +8,8 @@ import {SafeProxy} from "safe-contracts/contracts/proxies/SafeProxy.sol";
|
||||
|
||||
import {EntryPoint} from "account-abstraction/core/EntryPoint.sol";
|
||||
|
||||
import {SafeCompressionPlugin} from "./SafeCompressionPlugin.sol";
|
||||
import {IDecompressor} from "../compression/decompressors/IDecompressor.sol";
|
||||
import {SafeCompressionPlugin} from "../validators/SafeCompressionPlugin.sol";
|
||||
import {IDecompressor} from "../../compression/decompressors/IDecompressor.sol";
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
THIS CONTRACT IS STILL IN ACTIVE DEVELOPMENT. NOT FOR PRODUCTION USE
|
||||
@@ -8,7 +8,7 @@ import {SafeProxy} from "safe-contracts/contracts/proxies/SafeProxy.sol";
|
||||
|
||||
import {EntryPoint} from "account-abstraction/core/EntryPoint.sol";
|
||||
|
||||
import {SafeECDSAPlugin} from "./SafeECDSAPlugin.sol";
|
||||
import {SafeECDSAPlugin} from "../validators/SafeECDSAPlugin.sol";
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
THIS CONTRACT IS STILL IN ACTIVE DEVELOPMENT. NOT FOR PRODUCTION USE
|
||||
@@ -1,12 +1,13 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {ISafe} from "./utils/Safe4337Base.sol";
|
||||
import {ISafe} from "../utils/Safe4337Base.sol";
|
||||
import {EmailAccountRecoveryRouter} from "./EmailAccountRecoveryRouter.sol";
|
||||
import {EmailAccountRecovery} from "ether-email-auth/packages/contracts/src/EmailAccountRecovery.sol";
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
THIS CONTRACT IS STILL IN ACTIVE DEVELOPMENT. NOT FOR PRODUCTION USE
|
||||
THIS CONTRACT IS OUTDATED. NOT FOR PRODUCTION USE
|
||||
It is recomended you use https://github.com/zkemail/email-recovery instead.
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
struct RecoveryRequest {
|
||||
@@ -28,7 +29,7 @@ struct SafeAccountInfo {
|
||||
|
||||
/**
|
||||
* A safe plugin that recovers a safe owner via a zkp of an email.
|
||||
* NOT FOR PRODUCTION USE
|
||||
* NOT FOR PRODUCTION USE, use https://github.com/zkemail/email-recovery instead
|
||||
*/
|
||||
contract SafeZkEmailRecoveryPlugin is EmailAccountRecovery {
|
||||
/** Default delay has been set to a large timeframe on purpose. Please use a default delay suited to your specific context */
|
||||
@@ -2,9 +2,9 @@
|
||||
pragma solidity >=0.7.0 <0.9.0;
|
||||
pragma abicoder v2;
|
||||
|
||||
import {Safe4337Base, SIG_VALIDATION_FAILED} from "./utils/Safe4337Base.sol";
|
||||
import {Safe4337Base, SIG_VALIDATION_FAILED} from "../utils/Safe4337Base.sol";
|
||||
import {IEntryPoint, PackedUserOperation} from "account-abstraction/interfaces/IEntryPoint.sol";
|
||||
import {IAnonAadhaar} from "./utils/anonAadhaar/interfaces/IAnonAadhaar.sol";
|
||||
import {IAnonAadhaar} from "../utils/anonAadhaar/interfaces/IAnonAadhaar.sol";
|
||||
|
||||
interface ISafe {
|
||||
function enableModule(address module) external;
|
||||
@@ -8,7 +8,7 @@ import {IEntryPoint, PackedUserOperation} from "account-abstraction/interfaces/I
|
||||
import {BLS} from "account-abstraction/samples/bls/lib/hubble-contracts/contracts/libs/BLS.sol";
|
||||
import {IBLSAccount} from "account-abstraction/samples/bls/IBLSAccount.sol";
|
||||
|
||||
import {Safe4337Base, ISafe} from "./utils/Safe4337Base.sol";
|
||||
import {Safe4337Base, ISafe} from "../utils/Safe4337Base.sol";
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
THIS CONTRACT IS STILL IN ACTIVE DEVELOPMENT. NOT FOR PRODUCTION USE
|
||||
@@ -9,9 +9,9 @@ import {BLS} from "account-abstraction/samples/bls/lib/hubble-contracts/contract
|
||||
import {IBLSAccount} from "account-abstraction/samples/bls/IBLSAccount.sol";
|
||||
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
|
||||
|
||||
import {Safe4337Base, ISafe, SIG_VALIDATION_FAILED} from "./utils/Safe4337Base.sol";
|
||||
import {WaxLib as W} from "../compression/WaxLib.sol";
|
||||
import {IDecompressor} from "../compression/decompressors/IDecompressor.sol";
|
||||
import {Safe4337Base, ISafe, SIG_VALIDATION_FAILED} from "../utils/Safe4337Base.sol";
|
||||
import {WaxLib as W} from "../../compression/WaxLib.sol";
|
||||
import {IDecompressor} from "../../compression/decompressors/IDecompressor.sol";
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
THIS CONTRACT IS STILL IN ACTIVE DEVELOPMENT. NOT FOR PRODUCTION USE
|
||||
@@ -2,7 +2,7 @@
|
||||
pragma solidity >=0.7.0 <0.9.0;
|
||||
pragma abicoder v2;
|
||||
|
||||
import {Safe4337Base, SIG_VALIDATION_FAILED} from "./utils/Safe4337Base.sol";
|
||||
import {Safe4337Base, SIG_VALIDATION_FAILED} from "../utils/Safe4337Base.sol";
|
||||
import {IEntryPoint, PackedUserOperation} from "account-abstraction/interfaces/IEntryPoint.sol";
|
||||
import {PackedUserOperation} from "account-abstraction/interfaces/IEntryPoint.sol";
|
||||
|
||||
@@ -4,9 +4,9 @@ pragma solidity >=0.8.0 <0.9.0;
|
||||
import {HandlerContext} from "safe-contracts/contracts/handler/HandlerContext.sol";
|
||||
import {BaseAccount} from "account-abstraction/core/BaseAccount.sol";
|
||||
import {IEntryPoint, PackedUserOperation} from "account-abstraction/interfaces/IEntryPoint.sol";
|
||||
import {WebAuthn} from "../primitives/WebAuthn.sol";
|
||||
import {WebAuthn} from "../../primitives/WebAuthn.sol";
|
||||
|
||||
import {Safe4337Base, SIG_VALIDATION_FAILED} from "./utils/Safe4337Base.sol";
|
||||
import {Safe4337Base, SIG_VALIDATION_FAILED} from "../utils/Safe4337Base.sol";
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
THIS CONTRACT IS STILL IN ACTIVE DEVELOPMENT. NOT FOR PRODUCTION USE
|
||||
@@ -1,135 +0,0 @@
|
||||
// import { ERC4337ZKPPasswordClient } from "@getwax/circuits";
|
||||
import { expect } from "chai";
|
||||
import { resolveProperties, ethers } from "ethers";
|
||||
import sendUserOpAndWait from "./utils/sendUserOpAndWait";
|
||||
import receiptOf from "./utils/receiptOf";
|
||||
import {
|
||||
MockGroth16Verifier__factory,
|
||||
SafeZKPPasswordFactory__factory,
|
||||
SafeZKPPasswordPlugin__factory,
|
||||
} from "../../typechain-types";
|
||||
import { setupTests } from "./utils/setupTests";
|
||||
import { createUserOperation } from "./utils/createUserOp";
|
||||
import { getUserOpHash } from "./utils/userOpUtils";
|
||||
|
||||
describe.skip("SafeZKPPasswordPlugin", () => {
|
||||
it("should pass the ERC4337 validation", async () => {
|
||||
const {
|
||||
bundlerProvider,
|
||||
provider,
|
||||
admin,
|
||||
owner,
|
||||
entryPointAddress,
|
||||
deployer,
|
||||
safeSingleton,
|
||||
} = await setupTests();
|
||||
|
||||
// const zkpClient = await ERC4337ZKPPasswordClient.create();
|
||||
|
||||
// Deploy zk password plugin
|
||||
const safeZKPPasswordFactory = await deployer.connectOrDeploy(
|
||||
SafeZKPPasswordFactory__factory,
|
||||
[],
|
||||
);
|
||||
|
||||
const signer = await provider.getSigner();
|
||||
// TODO (merge-ok) Use real verifier from zkp dir
|
||||
// https://github.com/getwax/wax/issues/143
|
||||
const groth16Verifier = await new MockGroth16Verifier__factory(
|
||||
signer,
|
||||
).deploy();
|
||||
|
||||
const createArgs = [
|
||||
safeSingleton,
|
||||
entryPointAddress,
|
||||
await owner.getAddress(),
|
||||
0,
|
||||
groth16Verifier,
|
||||
] satisfies Parameters<typeof safeZKPPasswordFactory.create.staticCall>;
|
||||
|
||||
const accountAddress = await safeZKPPasswordFactory.create.staticCall(
|
||||
...createArgs,
|
||||
);
|
||||
|
||||
await receiptOf(safeZKPPasswordFactory.create(...createArgs));
|
||||
|
||||
// Native tokens for the pre-fund
|
||||
await receiptOf(
|
||||
admin.sendTransaction({
|
||||
to: accountAddress,
|
||||
value: ethers.parseEther("100"),
|
||||
}),
|
||||
);
|
||||
|
||||
// Construct userOp
|
||||
const to = "0x42ef9B061d2B8416387FaA738Af7251668b0b142"; // Random address
|
||||
const value = ethers.parseEther("1");
|
||||
const data = "0x";
|
||||
|
||||
const userOpCallData =
|
||||
SafeZKPPasswordPlugin__factory.createInterface().encodeFunctionData(
|
||||
"execTransaction",
|
||||
[to, value, data],
|
||||
);
|
||||
|
||||
const encoder = ethers.AbiCoder.defaultAbiCoder();
|
||||
const dummySignature = encoder.encode(
|
||||
["uint256[2]", "uint256[2][2]", "uint256[2]"],
|
||||
[
|
||||
[0, 0],
|
||||
[
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
],
|
||||
[0, 0],
|
||||
],
|
||||
);
|
||||
|
||||
// Note: factoryParams is not used because we need to create both the safe
|
||||
// proxy and the plugin, and 4337 currently only allows one contract
|
||||
// creation in this step. Since we need an extra step anyway, it's simpler
|
||||
// to do the whole create outside of 4337.
|
||||
const factoryParams = {
|
||||
factory: "0x",
|
||||
factoryData: "0x",
|
||||
};
|
||||
|
||||
const unsignedUserOperation = await createUserOperation(
|
||||
provider,
|
||||
bundlerProvider,
|
||||
accountAddress,
|
||||
factoryParams,
|
||||
userOpCallData,
|
||||
entryPointAddress,
|
||||
dummySignature,
|
||||
);
|
||||
|
||||
const resolvedUserOp = await resolveProperties(unsignedUserOperation);
|
||||
const userOpHash = getUserOpHash(
|
||||
resolvedUserOp,
|
||||
entryPointAddress,
|
||||
Number((await provider.getNetwork()).chainId),
|
||||
);
|
||||
|
||||
const emojiPassword = "👻🎃🕸🦇🕷🪦";
|
||||
// const { signature } = await zkpClient.proveUserOp(
|
||||
// emojiPassword,
|
||||
// userOpHash,
|
||||
// );
|
||||
|
||||
const userOp = {
|
||||
...unsignedUserOperation,
|
||||
// signature,
|
||||
};
|
||||
|
||||
const recipientBalanceBefore = await provider.getBalance(to);
|
||||
|
||||
// Send userOp
|
||||
await sendUserOpAndWait(userOp, entryPointAddress, bundlerProvider);
|
||||
|
||||
const recipientBalanceAfter = await provider.getBalance(to);
|
||||
|
||||
const expectedRecipientBalance = recipientBalanceBefore + value;
|
||||
expect(recipientBalanceAfter).to.equal(expectedRecipientBalance);
|
||||
});
|
||||
});
|
||||
@@ -4,8 +4,8 @@ pragma solidity ^0.8.12;
|
||||
import "forge-std/Test.sol";
|
||||
import "forge-std/console2.sol";
|
||||
import {TestHelper} from "../../unit/utils/TestHelper.sol";
|
||||
import {SafeZkEmailRecoveryPlugin, RecoveryRequest, GuardianRequest} from "../../../src/safe/SafeZkEmailRecoveryPlugin.sol";
|
||||
import {IEmailAccountRecovery} from "../../../src/safe/EmailAccountRecoveryRouter.sol";
|
||||
import {SafeZkEmailRecoveryPlugin, RecoveryRequest, GuardianRequest} from "../../../src/safe/recovery/SafeZkEmailRecoveryPlugin.sol";
|
||||
import {IEmailAccountRecovery} from "../../../src/safe/recovery/EmailAccountRecoveryRouter.sol";
|
||||
import {MockGroth16Verifier} from "../../../src/safe/utils/MockGroth16Verifier.sol";
|
||||
import {Safe} from "safe-contracts/contracts/Safe.sol";
|
||||
import {SafeProxy} from "safe-contracts/contracts/proxies/SafeProxy.sol";
|
||||
|
||||
@@ -5,7 +5,7 @@ import "forge-std/Test.sol";
|
||||
import "forge-std/console2.sol";
|
||||
import {TestHelper} from "../utils/TestHelper.sol";
|
||||
import {SafeBlsPluginHarness} from "../utils/SafeBlsPluginHarness.sol";
|
||||
import {SafeBlsPlugin} from "../../../src/safe/SafeBlsPlugin.sol";
|
||||
import {SafeBlsPlugin} from "../../../src/safe/validators/SafeBlsPlugin.sol";
|
||||
import {Safe4337Base} from "../../../src/safe/utils/Safe4337Base.sol";
|
||||
import {BLSSignatureAggregator} from "account-abstraction/samples/bls/BLSSignatureAggregator.sol";
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import "forge-std/Test.sol";
|
||||
import "forge-std/console2.sol";
|
||||
import {TestHelper} from "../utils/TestHelper.sol";
|
||||
import {SafeECDSAPluginHarness} from "../utils/SafeECDSAPluginHarness.sol";
|
||||
import {SafeECDSAPlugin} from "../../../src/safe/SafeECDSAPlugin.sol";
|
||||
import {SafeECDSAPlugin} from "../../../src/safe/validators/SafeECDSAPlugin.sol";
|
||||
import {Safe4337Base} from "../../../src/safe/utils/Safe4337Base.sol";
|
||||
|
||||
/* solhint-disable func-name-mixedcase */
|
||||
|
||||
@@ -4,8 +4,8 @@ pragma solidity ^0.8.12;
|
||||
import "forge-std/Test.sol";
|
||||
import "forge-std/console2.sol";
|
||||
import {TestHelper} from "../utils/TestHelper.sol";
|
||||
import {SafeECDSARecoveryPlugin, ECDSARecoveryStorage} from "../../../src/safe/SafeECDSARecoveryPlugin.sol";
|
||||
import {SafeECDSAPlugin} from "../../../src/safe/SafeECDSAPlugin.sol";
|
||||
import {SafeECDSARecoveryPlugin, ECDSARecoveryStorage} from "../../../src/safe/recovery/SafeECDSARecoveryPlugin.sol";
|
||||
import {SafeECDSAPlugin} from "../../../src/safe/validators/SafeECDSAPlugin.sol";
|
||||
import {Safe} from "safe-contracts/contracts/Safe.sol";
|
||||
import {SafeProxy} from "safe-contracts/contracts/proxies/SafeProxy.sol";
|
||||
import {ECDSA} from "openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol";
|
||||
|
||||
@@ -5,7 +5,7 @@ import "forge-std/Test.sol";
|
||||
import "forge-std/console2.sol";
|
||||
import {TestHelper} from "../utils/TestHelper.sol";
|
||||
import {SafeWebAuthnPluginHarness} from "../utils/SafeWebAuthnPluginHarness.sol";
|
||||
import {SafeWebAuthnPlugin} from "../../../src/safe/SafeWebAuthnPlugin.sol";
|
||||
import {SafeWebAuthnPlugin} from "../../../src/safe/validators/SafeWebAuthnPlugin.sol";
|
||||
import {Safe4337Base} from "../../../src/safe/utils/Safe4337Base.sol";
|
||||
import {PackedUserOperation} from "account-abstraction/interfaces/IEntryPoint.sol";
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ pragma solidity ^0.8.12;
|
||||
import "forge-std/Test.sol";
|
||||
import "forge-std/console2.sol";
|
||||
import {TestHelper} from "../utils/TestHelper.sol";
|
||||
import {SafeZkEmailRecoveryPlugin, RecoveryRequest} from "../../../src/safe/SafeZkEmailRecoveryPlugin.sol";
|
||||
import {SafeZkEmailRecoveryPlugin, RecoveryRequest} from "../../../src/safe/recovery/SafeZkEmailRecoveryPlugin.sol";
|
||||
import {SafeZkEmailRecoveryPluginHarness} from "../utils/SafeZkEmailRecoveryPluginHarness.sol";
|
||||
import {Safe} from "safe-contracts/contracts/Safe.sol";
|
||||
import {SafeProxy} from "safe-contracts/contracts/proxies/SafeProxy.sol";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.12;
|
||||
|
||||
import {SafeBlsPlugin} from "../../../src/safe/SafeBlsPlugin.sol";
|
||||
import {SafeBlsPlugin} from "../../../src/safe/validators/SafeBlsPlugin.sol";
|
||||
|
||||
/** Helper contract to expose internal functions for testing */
|
||||
contract SafeBlsPluginHarness is SafeBlsPlugin {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.12;
|
||||
|
||||
import {SafeECDSAPlugin} from "../../../src/safe/SafeECDSAPlugin.sol";
|
||||
import {SafeECDSAPlugin} from "../../../src/safe/validators/SafeECDSAPlugin.sol";
|
||||
|
||||
/** Helper contract to expose internal functions for testing */
|
||||
contract SafeECDSAPluginHarness is SafeECDSAPlugin {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
pragma solidity ^0.8.12;
|
||||
|
||||
import {PackedUserOperation} from "account-abstraction/interfaces/IEntryPoint.sol";
|
||||
import {SafeWebAuthnPlugin} from "../../../src/safe/SafeWebAuthnPlugin.sol";
|
||||
import {SafeWebAuthnPlugin} from "../../../src/safe/validators/SafeWebAuthnPlugin.sol";
|
||||
|
||||
/** Helper contract to expose internal functions for testing */
|
||||
contract SafeWebAuthnPluginHarness is SafeWebAuthnPlugin {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.12;
|
||||
|
||||
import {SafeZkEmailRecoveryPlugin} from "../../../src/safe/SafeZkEmailRecoveryPlugin.sol";
|
||||
import {SafeZkEmailRecoveryPlugin} from "../../../src/safe/recovery/SafeZkEmailRecoveryPlugin.sol";
|
||||
|
||||
/** Helper contract to expose internal functions for testing */
|
||||
contract SafeZkEmailRecoveryPluginHarness is SafeZkEmailRecoveryPlugin {
|
||||
|
||||
@@ -846,14 +846,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d"
|
||||
integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==
|
||||
|
||||
"@getwax/circuits@../zkp":
|
||||
version "0.0.1"
|
||||
dependencies:
|
||||
circomlib "2.0.5"
|
||||
circomlibjs "0.1.7"
|
||||
ethers "^6.11.1"
|
||||
snarkjs "0.7.3"
|
||||
|
||||
"@humanwhocodes/module-importer@^1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
|
||||
@@ -2316,13 +2308,6 @@ circom_runtime@0.1.21:
|
||||
dependencies:
|
||||
ffjavascript "0.2.56"
|
||||
|
||||
circom_runtime@0.1.24:
|
||||
version "0.1.24"
|
||||
resolved "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.1.24.tgz#60ca8a31c3675802fbab5a0bcdeb02556e510733"
|
||||
integrity sha512-H7/7I2J/cBmRnZm9docOCGhfxzS61BEm4TMCWcrZGsWNBQhePNfQq88Oj2XpUfzmBTCd8pRvRb3Mvazt3TMrJw==
|
||||
dependencies:
|
||||
ffjavascript "0.2.60"
|
||||
|
||||
circom_runtime@0.1.25:
|
||||
version "0.1.25"
|
||||
resolved "https://registry.yarnpkg.com/circom_runtime/-/circom_runtime-0.1.25.tgz#62a33b371f4633f30238db7a326c43d988e3a170"
|
||||
@@ -2330,11 +2315,6 @@ circom_runtime@0.1.25:
|
||||
dependencies:
|
||||
ffjavascript "0.3.0"
|
||||
|
||||
circomlib@2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/circomlib/-/circomlib-2.0.5.tgz#183c703e53ed7d011811842dbeeeb9819f4cc1d6"
|
||||
integrity sha512-O7NQ8OS+J4eshBuoy36z/TwQU0YHw8W3zxZcs4hVwpEll3e4hDm3mgkIPqItN8FDeLEKZFK3YeT/+k8TiLF3/A==
|
||||
|
||||
circomlibjs@0.1.7, circomlibjs@^0.1.7:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/circomlibjs/-/circomlibjs-0.1.7.tgz#9f5a7d9a23323744b11ee456b05b0cd81f48b554"
|
||||
@@ -3215,19 +3195,6 @@ ethers@^5.5.3, ethers@^5.7.0:
|
||||
"@ethersproject/web" "5.7.1"
|
||||
"@ethersproject/wordlists" "5.7.0"
|
||||
|
||||
ethers@^6.11.1:
|
||||
version "6.11.1"
|
||||
resolved "https://registry.npmjs.org/ethers/-/ethers-6.11.1.tgz#96aae00b627c2e35f9b0a4d65c7ab658259ee6af"
|
||||
integrity sha512-mxTAE6wqJQAbp5QAe/+o+rXOID7Nw91OZXvgpjDa1r4fAbq2Nu314oEZSbjoRLacuCzs7kUC3clEvkCQowffGg==
|
||||
dependencies:
|
||||
"@adraffy/ens-normalize" "1.10.1"
|
||||
"@noble/curves" "1.2.0"
|
||||
"@noble/hashes" "1.3.2"
|
||||
"@types/node" "18.15.13"
|
||||
aes-js "4.0.0-beta.5"
|
||||
tslib "2.4.0"
|
||||
ws "8.5.0"
|
||||
|
||||
ethers@^6.4.0, ethers@^6.7.0:
|
||||
version "6.13.1"
|
||||
resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.13.1.tgz#2b9f9c7455cde9d38b30fe6589972eb083652961"
|
||||
@@ -3317,24 +3284,6 @@ ffjavascript@0.2.56:
|
||||
wasmcurves "0.2.0"
|
||||
web-worker "^1.2.0"
|
||||
|
||||
ffjavascript@0.2.60:
|
||||
version "0.2.60"
|
||||
resolved "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.60.tgz#4d8ae613d6bf4e98b3cc29ba10c626f5853854cf"
|
||||
integrity sha512-T/9bnEL5xAZRDbQoEMf+pM9nrhK+C3JyZNmqiWub26EQorW7Jt+jR54gpqDhceA4Nj0YctPQwYnl8xa52/A26A==
|
||||
dependencies:
|
||||
wasmbuilder "0.0.16"
|
||||
wasmcurves "0.2.2"
|
||||
web-worker "^1.2.0"
|
||||
|
||||
ffjavascript@0.2.63:
|
||||
version "0.2.63"
|
||||
resolved "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.63.tgz#0c1216a1f123dc9181df69e144473704d2f115eb"
|
||||
integrity sha512-dBgdsfGks58b66JnUZeZpGxdMIDQ4QsD3VYlRJyFVrKQHb2kJy4R2gufx5oetrTxXPT+aEjg0dOvOLg1N0on4A==
|
||||
dependencies:
|
||||
wasmbuilder "0.0.16"
|
||||
wasmcurves "0.2.2"
|
||||
web-worker "1.2.0"
|
||||
|
||||
ffjavascript@0.3.0, ffjavascript@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.3.0.tgz#442cd8fbb1ee4cbb1be9d26fd7b2951a1ea45d6a"
|
||||
@@ -5165,16 +5114,6 @@ r1csfile@0.0.41:
|
||||
fastfile "0.0.20"
|
||||
ffjavascript "0.2.56"
|
||||
|
||||
r1csfile@0.0.47:
|
||||
version "0.0.47"
|
||||
resolved "https://registry.npmjs.org/r1csfile/-/r1csfile-0.0.47.tgz#ed95a0dc8e910e9c070253906f7a31bd8c5333c8"
|
||||
integrity sha512-oI4mAwuh1WwuFg95eJDNDDL8hCaZkwnPuNZrQdLBWvDoRU7EG+L/MOHL7SwPW2Y+ZuYcTLpj3rBkgllBQZN/JA==
|
||||
dependencies:
|
||||
"@iden3/bigarray" "0.0.2"
|
||||
"@iden3/binfileutils" "0.0.11"
|
||||
fastfile "0.0.20"
|
||||
ffjavascript "0.2.60"
|
||||
|
||||
r1csfile@0.0.48:
|
||||
version "0.0.48"
|
||||
resolved "https://registry.yarnpkg.com/r1csfile/-/r1csfile-0.0.48.tgz#a317fc75407a9da92631666c75bdfc13f0a7835a"
|
||||
@@ -5584,22 +5523,6 @@ slice-ansi@^4.0.0:
|
||||
astral-regex "^2.0.0"
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
|
||||
snarkjs@0.7.3:
|
||||
version "0.7.3"
|
||||
resolved "https://registry.npmjs.org/snarkjs/-/snarkjs-0.7.3.tgz#7f703d05b810235255f2d0a70d8a9b8b3ea916e5"
|
||||
integrity sha512-cDLpWqdqEJSCQNc+cXYX1XTKdUZBtYEisuOsgmXf/HUsN5WmGN+FO7HfCS+cMQT1Nzbm1a9gAEpKH6KRtDtS1Q==
|
||||
dependencies:
|
||||
"@iden3/binfileutils" "0.0.11"
|
||||
bfj "^7.0.2"
|
||||
blake2b-wasm "^2.4.0"
|
||||
circom_runtime "0.1.24"
|
||||
ejs "^3.1.6"
|
||||
fastfile "0.0.20"
|
||||
ffjavascript "0.2.63"
|
||||
js-sha3 "^0.8.0"
|
||||
logplease "^1.2.15"
|
||||
r1csfile "0.0.47"
|
||||
|
||||
snarkjs@^0.7.3:
|
||||
version "0.7.4"
|
||||
resolved "https://registry.yarnpkg.com/snarkjs/-/snarkjs-0.7.4.tgz#b9ad5813f055ab84d33f1831a6f1f34a71b6cd46"
|
||||
@@ -6443,11 +6366,6 @@ ws@8.17.1:
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b"
|
||||
integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==
|
||||
|
||||
ws@8.5.0:
|
||||
version "8.5.0"
|
||||
resolved "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f"
|
||||
integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==
|
||||
|
||||
ws@^7.4.6:
|
||||
version "7.5.10"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9"
|
||||
|
||||
3
packages/sdk/README.md
Normal file
3
packages/sdk/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# SDK
|
||||
|
||||
Utilities to aid in ERC-4337 interactions & using WAX plugins.
|
||||
6
packages/tools/README.md
Normal file
6
packages/tools/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# Tools
|
||||
|
||||
## Fee Measurer
|
||||
[fee-measurer](./fee-measurer/)
|
||||
|
||||
Facilitates direct measurement of L2 fees.
|
||||
Submodule packages/zkp/lib/circom deleted from f0deda416a
BIN
waxGreenLogo.png
Normal file
BIN
waxGreenLogo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
Reference in New Issue
Block a user