Merge pull request #11 from danieljcss/workingDemo

Working demo
This commit is contained in:
3lLobo
2022-09-27 08:04:27 +02:00
committed by GitHub
55 changed files with 2166 additions and 525 deletions

View File

@@ -80,6 +80,9 @@ Each trustee has then the option to consent to the recovery-process by submittin
Once a predefined threshold (at least majority) of consents is reached, the user is able to recover his authentication contract by in a last step, providing the SNARK proofs of his personal passphrase.
[Live Demo](https://zkauth.netlify.app/)
![zkauthLogo](https://user-images.githubusercontent.com/25290565/192105366-ac07356c-594b-4353-a9c5-596ecd46551d.png)

1
backend/.env.example Normal file
View File

@@ -0,0 +1 @@
PRIVATE_GOERLII_KEY=xxxx

1
backend/.gitignore vendored
View File

@@ -130,7 +130,6 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
circuits/build
artifacts
cache
*.ptau
deployments

View File

@@ -1,13 +1,43 @@
# This is the bacqend, the smart-contract crib
# This is the smart-contract crib
![crib](https://user-images.githubusercontent.com/25290565/190274993-05c12f02-aa56-4041-af27-67ffda79bcf1.jpg)
We proudly present the TotpAuthenticator.
One step closer to zero trust and one step away from web2.
You can now use 2FA authentication for your business contacts your web-applications or even your IOTs without a centralized database storing your keys and authenticating users. The Blocqchain takes over!
We disclose the smart-logic, turing the wheels of the zkAuthenticator.
One step closer to zero trust and away from web2.
The zkAuth onchain authentication can be invoked by both wallets and contracts.
For optimal security and user-experience, incorporate it with 2nd gen Wallets (ERC 4337) or similar contracts supporting paymasters.
## The turing wheels
Here an walk-through of our complete contracts:
### zkWalletFactory
<!-- TODO: -->
Upon successfully setting up 2FA, the msg.sender gets assigned a personal `ZkSocialRecoveryWallet`.
The Factory takes on the tasks of creating those wallets, mapping addresses to wallets and connecting to the hash-verifier for social recovery.
### HashCheckVerifier
<!-- TODO: -->
The logic used to recover wa compromised wallet and reassign its owner.
### OtpMerkleTreeVerifier
<!-- TODO: -->
The logic to verify the wallet specific 2 factor authentication.
## Cyborg Run 🏃‍♂️
How to setup the project, compile the contracts, run the test and deploy.
@Rish check if you can scale scope the tests :)
Yarn, remix and hardhat:
```shell
@@ -18,7 +48,48 @@ yarn remixed -s . --remix-ide https://remix.ethereum.org
yarn hardhat test
```
## Hashing
## Optimism
A blocqchain with free lunch, I mean, free gas! How could we not choose for Optimism?
### Contracts on Optimism-Goerli
Last deployment: 26.9.2022
```js
export const address = {
zkWalletFactory: "0xcaF6c8C45c4fA0d2F6BFcE0c904FBedE08c773f1",
HashCheckVerifier: "0xDFD466d2A14cB2895f2C8BCacc67BDEF37C60De0",
OtpMerkleTreeVerifier: "0x87469041b414E1f2dEC2e79e32f4E911E7f50622",
}
```
<!-- Contract TotpAuthenticator deployed to Optimism Goerli:
```bash
0xfa99801Ec6BeFcbfC1eB2d12dc8255453574b276
# Deployment transaction hash
0x846528416731ddd42e37b8f2dc9fbac24aaf105ebe23d53707a680fc99d68ce0
``` -->
Deployer wallet:
```sh
0x369551E7c1D29756e18BA4Ed7f85f2E6663e1e8d
```
[Testnet Explorer](https://blockscout.com/optimism/goerli)
[Faucets](https://optimismfaucet.xyz/)
## Notes4devs
A collection of more and less relevant technical tips and hacqs for our fellow devs and future selfs.
### Onchain sha256 Hashing
How to calculate and submit hash:
@@ -32,36 +103,3 @@ That's it, now it should match the sha256 on-chain.
[bytes32](https://web3-type-converter.onbrn.com/)
[sha256 from hex](https://www.liavaag.org/English/SHA-Generator/)
## Optimism
A blocqchain with free lunch, I mean, free gas! How could we not choose for Optimism?
Contract TotpAuthenticator deployed to Optimism Goerli:
```bash
0xfa99801Ec6BeFcbfC1eB2d12dc8255453574b276
# Deployment transaction hash
0x846528416731ddd42e37b8f2dc9fbac24aaf105ebe23d53707a680fc99d68ce0
```
Also on Main Goerli bcs Opt Goerli goes not yet get indexed by theGraph:
```bash
0x5E9607EE52286732A5E3A0Fc57dF367bCb8adAa5
# Tx hash
0x1462f472eb8cda174a47529f6ea0be6a97965e175be9f7f3709a54844228f24a
```
It's the same address, ain't that funney 🤔
**Update** not the same anymore after debugging the contract and redeploying. Curious if the new contract would again give the same pub address on Optimism - nope.
Owner wallet:
```sh
0x369551E7c1D29756e18BA4Ed7f85f2E6663e1e8d
```
[Testnet Explorer](https://blockscout.com/optimism/goerli)
[Faucets](https://optimismfaucet.xyz/)

BIN
backend/artifacts.zip Normal file

Binary file not shown.

View File

@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
}

View File

@@ -0,0 +1,63 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "Ownable",
"sourceName": "@openzeppelin/contracts/access/Ownable.sol",
"abi": [
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
],
"bytecode": "0x",
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}

View File

@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
}

View File

@@ -0,0 +1,45 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "IERC721Receiver",
"sourceName": "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol",
"abi": [
{
"inputs": [
{
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "onERC721Received",
"outputs": [
{
"internalType": "bytes4",
"name": "",
"type": "bytes4"
}
],
"stateMutability": "nonpayable",
"type": "function"
}
],
"bytecode": "0x",
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}

View File

@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
}

View File

@@ -0,0 +1,10 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "Context",
"sourceName": "@openzeppelin/contracts/utils/Context.sol",
"abi": [],
"bytecode": "0x",
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
}

View File

@@ -0,0 +1,10 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "Pairing",
"sourceName": "contracts/Verifiers/HashCheckVerifier.sol",
"abi": [],
"bytecode": "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220301e535f70771fb1ebdb277ad7a17a537e7f384028f52bf06ceec27f2cd7b18f64736f6c63430008110033",
"deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220301e535f70771fb1ebdb277ad7a17a537e7f384028f52bf06ceec27f2cd7b18f64736f6c63430008110033",
"linkReferences": {},
"deployedLinkReferences": {}
}

View File

@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
}

View File

@@ -0,0 +1,10 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "Pairing",
"sourceName": "contracts/Verifiers/OtpMerkleTreeVerifier.sol",
"abi": [],
"bytecode": "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220d256c30602e6e48efbe84b99f40e0d161521b4944a7b5a8e1a2e5317d7342f4564736f6c63430008110033",
"deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220d256c30602e6e48efbe84b99f40e0d161521b4944a7b5a8e1a2e5317d7342f4564736f6c63430008110033",
"linkReferences": {},
"deployedLinkReferences": {}
}

View File

@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
}

View File

@@ -0,0 +1,45 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "IOtpMerkleTreeVerifier",
"sourceName": "contracts/ZkOtpValidator.sol",
"abi": [
{
"inputs": [
{
"internalType": "uint256[2]",
"name": "a",
"type": "uint256[2]"
},
{
"internalType": "uint256[2][2]",
"name": "b",
"type": "uint256[2][2]"
},
{
"internalType": "uint256[2]",
"name": "c",
"type": "uint256[2]"
},
{
"internalType": "uint256[2]",
"name": "input",
"type": "uint256[2]"
}
],
"name": "verifyProof",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
}
],
"bytecode": "0x",
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}

View File

@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
}

View File

@@ -0,0 +1,61 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "ZkOtpValidator",
"sourceName": "contracts/ZkOtpValidator.sol",
"abi": [
{
"inputs": [
{
"internalType": "uint256",
"name": "_root",
"type": "uint256"
},
{
"internalType": "address",
"name": "_verifier",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [
{
"internalType": "uint256[2]",
"name": "a",
"type": "uint256[2]"
},
{
"internalType": "uint256[2][2]",
"name": "b",
"type": "uint256[2][2]"
},
{
"internalType": "uint256[2]",
"name": "c",
"type": "uint256[2]"
},
{
"internalType": "uint256[2]",
"name": "input",
"type": "uint256[2]"
}
],
"name": "verifyOTP",
"outputs": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
}
],
"bytecode": "0x60c060405234801561001057600080fd5b5060405161053438038061053483398101604081905261002f91610046565b6080919091526001600160a01b031660a052610083565b6000806040838503121561005957600080fd5b825160208401519092506001600160a01b038116811461007857600080fd5b809150509250929050565b60805160a05161048d6100a7600039600061016101526000605e015261048d6000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063a9f3402c14610030575b600080fd5b61004361003e3660046102da565b610057565b604051901515815260200160405180910390f35b80516000907f0000000000000000000000000000000000000000000000000000000000000000146100cf5760405162461bcd60e51b815260206004820152600e60248201527f496e636f6f7265637420726f6f7400000000000000000000000000000000000060448201526064015b60405180910390fd5b6000546020830151116101245760405162461bcd60e51b815260206004820152600960248201527f4f6c642050726f6f66000000000000000000000000000000000000000000000060448201526064016100c6565b6040517ff5c9d69e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063f5c9d69e9061019c9088908890889088906004016103a3565b602060405180830381865afa1580156101b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101dd919061042e565b6102295760405162461bcd60e51b815260206004820152600d60248201527f496e76616c69642070726f6f660000000000000000000000000000000000000060448201526064016100c6565b506020015160005550600192915050565b6040805190810167ffffffffffffffff81118282101715610284577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405290565b600082601f83011261029b57600080fd5b6102a361023a565b8060408401858111156102b557600080fd5b845b818110156102cf5780358452602093840193016102b7565b509095945050505050565b60008060008061014085870312156102f157600080fd5b6102fb868661028a565b9350604086605f87011261030e57600080fd5b61031661023a565b8060c088018981111561032857600080fd5b8389015b8181101561034d5761033e8b8261028a565b8452602090930192840161032c565b5081965061035b8a8261028a565b95505050505061036f86610100870161028a565b905092959194509250565b8060005b600281101561039d57815184526020938401939091019060010161037e565b50505050565b61014081016103b2828761037a565b6040808301866000805b60028082106103cb5750610405565b835185845b838110156103ee5782518252602092830192909101906001016103d0565b5050509385019350602092909201916001016103bc565b505050505061041760c083018561037a565b61042561010083018461037a565b95945050505050565b60006020828403121561044057600080fd5b8151801515811461045057600080fd5b939250505056fea26469706673582212206395795d36789e7a9b6888bfe90d51af8eaca0172948c5706e44adf31974fadf64736f6c63430008110033",
"deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063a9f3402c14610030575b600080fd5b61004361003e3660046102da565b610057565b604051901515815260200160405180910390f35b80516000907f0000000000000000000000000000000000000000000000000000000000000000146100cf5760405162461bcd60e51b815260206004820152600e60248201527f496e636f6f7265637420726f6f7400000000000000000000000000000000000060448201526064015b60405180910390fd5b6000546020830151116101245760405162461bcd60e51b815260206004820152600960248201527f4f6c642050726f6f66000000000000000000000000000000000000000000000060448201526064016100c6565b6040517ff5c9d69e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063f5c9d69e9061019c9088908890889088906004016103a3565b602060405180830381865afa1580156101b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101dd919061042e565b6102295760405162461bcd60e51b815260206004820152600d60248201527f496e76616c69642070726f6f660000000000000000000000000000000000000060448201526064016100c6565b506020015160005550600192915050565b6040805190810167ffffffffffffffff81118282101715610284577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405290565b600082601f83011261029b57600080fd5b6102a361023a565b8060408401858111156102b557600080fd5b845b818110156102cf5780358452602093840193016102b7565b509095945050505050565b60008060008061014085870312156102f157600080fd5b6102fb868661028a565b9350604086605f87011261030e57600080fd5b61031661023a565b8060c088018981111561032857600080fd5b8389015b8181101561034d5761033e8b8261028a565b8452602090930192840161032c565b5081965061035b8a8261028a565b95505050505061036f86610100870161028a565b905092959194509250565b8060005b600281101561039d57815184526020938401939091019060010161037e565b50505050565b61014081016103b2828761037a565b6040808301866000805b60028082106103cb5750610405565b835185845b838110156103ee5782518252602092830192909101906001016103d0565b5050509385019350602092909201916001016103bc565b505050505061041760c083018561037a565b61042561010083018461037a565b95945050505050565b60006020828403121561044057600080fd5b8151801515811461045057600080fd5b939250505056fea26469706673582212206395795d36789e7a9b6888bfe90d51af8eaca0172948c5706e44adf31974fadf64736f6c63430008110033",
"linkReferences": {},
"deployedLinkReferences": {}
}

View File

@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
}

View File

@@ -0,0 +1,45 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "IHashCheckVerifier",
"sourceName": "contracts/ZkSocialRecoveryWallet.sol",
"abi": [
{
"inputs": [
{
"internalType": "uint256[2]",
"name": "a",
"type": "uint256[2]"
},
{
"internalType": "uint256[2][2]",
"name": "b",
"type": "uint256[2][2]"
},
{
"internalType": "uint256[2]",
"name": "c",
"type": "uint256[2]"
},
{
"internalType": "uint256[1]",
"name": "input",
"type": "uint256[1]"
}
],
"name": "verifyProof",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
}
],
"bytecode": "0x",
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}

View File

@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
}

View File

@@ -0,0 +1,10 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "console",
"sourceName": "hardhat/console.sol",
"abi": [],
"bytecode": "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220807e774fad6b9164116dee996322ef499abe9e76c8bf8d870ea29d25538ea37464736f6c63430008110033",
"deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220807e774fad6b9164116dee996322ef499abe9e76c8bf8d870ea29d25538ea37464736f6c63430008110033",
"linkReferences": {},
"deployedLinkReferences": {}
}

View File

@@ -1,5 +1,5 @@
export const address = {
zkWalletFactory: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0",
HashCheckVerifier: "0x5FbDB2315678afecb367f032d93F642f64180aa3",
OtpMerkleTreeVerifier: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512",
zkWalletFactory: "0xcaF6c8C45c4fA0d2F6BFcE0c904FBedE08c773f1",
HashCheckVerifier: "0xDFD466d2A14cB2895f2C8BCacc67BDEF37C60De0",
OtpMerkleTreeVerifier: "0x87469041b414E1f2dEC2e79e32f4E911E7f50622",
}

View File

@@ -1,160 +0,0 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
// Uncomment this line to use console.log
// import 'hardhat/console.sol';
import '@openzeppelin/contracts/access/Ownable.sol';
struct AuthData {
// fist five digits of the 6-digit totp code tail-padded with a zero and finally parsed to a single number
uint256 totp5;
// Teh sha256 hash of the complete code parsed to a single number.
bytes32 totp6hash;
// time-stamp of TOTP code creation.
uint256 time;
}
struct Authentication {
bool isValid;
uint256 time;
}
contract TotpAuthenticator is Ownable {
// Counter provides requestId and increments with each request
uint256 public requestCounter;
// Maps a requestId to the requestor/validator and to the auth requested address
mapping(uint256 => address[2]) public requests;
// Maps a requestId to a address and its response.
mapping(uint256 => AuthData) public responses;
// Maps requestId to completes authentication
// TODO: make this private and create a function to get this value, which initially checks if the requested Id is below the current counter. Otherwise collisions can happen after reset.
mapping(uint256 => Authentication) public completedAuth;
// Events to index with theGraph in order to notify both parties
event EventAuthRequest(address requestor, address target, uint256 requestId);
event EventAuthResponse(
address responder,
uint256 requestId,
AuthData response
);
event EventAuthValid(uint256 requestId, Authentication authentication);
event EventResetContract(uint256 time);
// Create a request for a wallet to authenticate.
function setRequest(address _target) public {
uint256 _currentCount = requestCounter;
requests[_currentCount] = [msg.sender, _target];
requestCounter++;
emit EventAuthRequest(msg.sender, _target, _currentCount);
}
// Submit a repsonse to an authentication request
function setResponse(
uint256 _requestId,
uint256 _totp5,
bytes32 _totp6hash,
uint256 _time
) public {
// require reqId lover than count
require(_requestId < requestCounter, 'ResuestId too high');
require(
requests[_requestId][1] == msg.sender,
'This Auth requestId does not match this wallet'
);
require(completedAuth[_requestId].time == 0, 'Request already authorized');
require(responses[_requestId].totp5 == 0, 'Response already submitted');
AuthData memory _authData = AuthData(_totp5, _totp6hash, _time);
responses[_requestId] = _authData;
emit EventAuthResponse(msg.sender, _requestId, _authData);
}
// // The Requestor can get the repsonse data. Preferably though the event indexer graph
// function getResponses(uint256 _requestId, address _responder)
// public
// view
// returns (AuthData memory)
// {
// // Assert that caller created the AuthRequest
// require(isValidator(_requestId), 'U did not submit this request');
// // Don't think it's allowed to return a mapping
// return responses[_requestId][_responder];
// }
// @param _requestId the id of the request
// @_responseAddress the address which submitted the valid response
function authenticate(uint256 _requestId, uint256 _lastDigit) public {
// Assert that caller created the AuthRequest
require(isValidator(_requestId), 'Validation only by requestor');
require(
responses[_requestId].time > 0,
'No auth response from this wallet'
);
AuthData memory _authData = responses[_requestId];
bool _isValid = checkHash(_authData.totp5, _lastDigit, _authData.totp6hash);
require(_isValid, 'On-chain validation failed');
Authentication memory authentication = Authentication(
_isValid,
block.timestamp
);
completedAuth[_requestId] = authentication;
emit EventAuthValid(_requestId, authentication);
}
// Returns the authentication details for a completed requestId
function getAuthentication(uint256 _requestId)
public
view
returns (Authentication memory)
{
return completedAuth[_requestId];
}
// Reset the contract by deleting all data
function resetAuthenticator() public onlyOwner {
requestCounter = 0;
// TODO: create zero AuthResponse and set the responses[_requestId] = zeroAuthResponse each time a request is initalized.
// How do we empty the mappings?
emit EventResetContract(block.timestamp);
}
// Check if the sender also submitted the request
function isValidator(uint256 _requestId) private view returns (bool) {
return msg.sender == requests[_requestId][0];
}
function toBytes(uint256 x) private pure returns (bytes memory b) {
b = new bytes(32);
assembly {
mstore(add(b, 32), x)
}
}
// Multiply the 5 didgit response by 10 (smiliar to padding with zero) and add the 6st digit. Then compare the hashes.
function checkHash(
uint256 _totp5,
uint256 _lastDigit,
bytes32 _totp6hash
) private pure returns (bool) {
uint256 _totp6 = _totp5 * 10 + _lastDigit;
// console.log('number totp6');
// console.log(_totp6);
// bytes memory bytestotp6 = toBytes(_totp6);
// console.log('bytes of totp6');
// console.logBytes(bytestotp6);
// bytes32 shatotp6 = sha256(toBytes(_totp6));
// console.log('Sha shatotp6');
// console.logBytes32(shatotp6);
// console.log('original _totp6hash');
// console.logBytes32(_totp6hash);
return sha256(toBytes(_totp6)) == _totp6hash;
}
}

View File

@@ -15,7 +15,7 @@ interface IHashCheckVerifier {
) external view returns (bool);
}
contract ZkSocialRecoveryWallet is IERC721Receiver {
contract ZkSocialRecoveryWallet is IERC721Receiver, ZkOtpValidator {
address hashCheckVerifier;
address public owner;
@@ -39,9 +39,6 @@ contract ZkSocialRecoveryWallet is IERC721Receiver {
bool public isRecoveryOn;
address public otpVerifierAddress;
ZkOtpValidator otpVerifier;
struct RecoveryProcedure {
uint256 numberOfVotesInSupport;
address newOwnerProposed;
@@ -109,17 +106,14 @@ contract ZkSocialRecoveryWallet is IERC721Receiver {
uint256 _ownerPasswordHash,
uint256 _thresholdForRecovery,
uint256 _root,
address _otpVerifier
) {
address _otpMerkleTreeVerifier
) ZkOtpValidator(_root, _otpMerkleTreeVerifier) {
require(_hashCheckVerifier != address(0), 'Zero address verifier');
hashCheckVerifier = _hashCheckVerifier;
owner = msg.sender;
ownerPasswordHash = _ownerPasswordHash;
thresholdForRecovery = _thresholdForRecovery;
otpVerifierAddress = _otpVerifier;
otpVerifier = new ZkOtpValidator(_root, _otpVerifier);
}
// To set trustees after deployment
@@ -131,7 +125,7 @@ contract ZkSocialRecoveryWallet is IERC721Receiver {
Trustees = _trustees;
numberTrustees = _trustees.length;
}
// Set trustees password after deployment
function setTrusteesPasswords(uint256[] memory _passwordHashes) external isOwner {
require(
@@ -265,7 +259,7 @@ function setTrusteesPasswords(uint256[] memory _passwordHashes) external isOwner
address callee,
uint256 value
) external isOwner returns (bytes memory result) {
require(otpVerifier.verifyOTP(a, b, c, input), 'Proof failed');
require(verifyOTP(a, b, c, input), 'Proof failed');
(bool success, bytes memory result) = callee.call{value: value}("");
require(success, 'external call reverted');
// emit TransactionExecuted(callee, value, data);

View File

@@ -4,6 +4,7 @@ import 'hardhat-deploy-ethers'
import '@typechain/hardhat'
import '@nomicfoundation/hardhat-toolbox'
require('dotenv').config()
const config: HardhatUserConfig = {
solidity: {
@@ -26,7 +27,7 @@ const config: HardhatUserConfig = {
// for testnet
'optimism-goerli': {
url: 'https://goerli.optimism.io',
//accounts: [privateKey1, ]
accounts: [process.env.PRIVATE_GOERLII_KEY ?? ''],
},
// for the local dev environment
'optimism-local': {

File diff suppressed because it is too large Load Diff

View File

@@ -35,7 +35,6 @@
"@typechain/hardhat": "^6.1.3",
"chai": "^4.3.6",
"ethers": "^5.7.1",
"hardhat": "^2.11.1",
"hardhat-deploy-ethers": "^0.3.0-beta.13",
"hardhat-gas-reporter": "^1.0.9",
"prettier": "^2.7.1",
@@ -52,10 +51,8 @@
"circomlib-ml": "^1.1.0",
"circomlibjs": "^0.1.7",
"dotenv": "^16.0.1",
"hardhat": "^2.11.2",
"hardhat-contract-sizer": "^2.4.0",
"hardhat-deploy": "^0.10.4",
"hardhat-gas-reporter": "^1.0.7",
"snarkjs": "^0.4.24",
"solidity-coverage": "^0.8.2",
"totp-generator": "^0.0.13",

View File

@@ -37,11 +37,11 @@ export interface ZkSocialRecoveryWalletInterface extends utils.Interface {
"isRecoveryOn()": FunctionFragment;
"numberTrustees()": FunctionFragment;
"onERC721Received(address,address,uint256,bytes)": FunctionFragment;
"otpVerifierAddress()": FunctionFragment;
"owner()": FunctionFragment;
"setTrustees(address[])": FunctionFragment;
"setTrusteesPasswords(uint256[])": FunctionFragment;
"startRecovery(uint256[2],uint256[2][2],uint256[2],uint256[1],address)": FunctionFragment;
"verifyOTP(uint256[2],uint256[2][2],uint256[2],uint256[2])": FunctionFragment;
"voteInRecovery(uint256[2],uint256[2][2],uint256[2],uint256[1],uint256)": FunctionFragment;
};
@@ -55,11 +55,11 @@ export interface ZkSocialRecoveryWalletInterface extends utils.Interface {
| "isRecoveryOn"
| "numberTrustees"
| "onERC721Received"
| "otpVerifierAddress"
| "owner"
| "setTrustees"
| "setTrusteesPasswords"
| "startRecovery"
| "verifyOTP"
| "voteInRecovery"
): FunctionFragment;
@@ -128,10 +128,6 @@ export interface ZkSocialRecoveryWalletInterface extends utils.Interface {
PromiseOrValue<BytesLike>
]
): string;
encodeFunctionData(
functionFragment: "otpVerifierAddress",
values?: undefined
): string;
encodeFunctionData(functionFragment: "owner", values?: undefined): string;
encodeFunctionData(
functionFragment: "setTrustees",
@@ -154,6 +150,18 @@ export interface ZkSocialRecoveryWalletInterface extends utils.Interface {
PromiseOrValue<string>
]
): string;
encodeFunctionData(
functionFragment: "verifyOTP",
values: [
[PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
[
[PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
[PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>]
],
[PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
[PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>]
]
): string;
encodeFunctionData(
functionFragment: "voteInRecovery",
values: [
@@ -194,10 +202,6 @@ export interface ZkSocialRecoveryWalletInterface extends utils.Interface {
functionFragment: "onERC721Received",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "otpVerifierAddress",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "owner", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "setTrustees",
@@ -211,6 +215,7 @@ export interface ZkSocialRecoveryWalletInterface extends utils.Interface {
functionFragment: "startRecovery",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "verifyOTP", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "voteInRecovery",
data: BytesLike
@@ -361,8 +366,6 @@ export interface ZkSocialRecoveryWallet extends BaseContract {
overrides?: CallOverrides
): Promise<[string]>;
otpVerifierAddress(overrides?: CallOverrides): Promise<[string]>;
owner(overrides?: CallOverrides): Promise<[string]>;
setTrustees(
@@ -387,6 +390,17 @@ export interface ZkSocialRecoveryWallet extends BaseContract {
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<ContractTransaction>;
verifyOTP(
a: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
b: [
[PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
[PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>]
],
c: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
input: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<ContractTransaction>;
voteInRecovery(
a: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
b: [
@@ -456,8 +470,6 @@ export interface ZkSocialRecoveryWallet extends BaseContract {
overrides?: CallOverrides
): Promise<string>;
otpVerifierAddress(overrides?: CallOverrides): Promise<string>;
owner(overrides?: CallOverrides): Promise<string>;
setTrustees(
@@ -482,6 +494,17 @@ export interface ZkSocialRecoveryWallet extends BaseContract {
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<ContractTransaction>;
verifyOTP(
a: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
b: [
[PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
[PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>]
],
c: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
input: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<ContractTransaction>;
voteInRecovery(
a: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
b: [
@@ -551,8 +574,6 @@ export interface ZkSocialRecoveryWallet extends BaseContract {
overrides?: CallOverrides
): Promise<string>;
otpVerifierAddress(overrides?: CallOverrides): Promise<string>;
owner(overrides?: CallOverrides): Promise<string>;
setTrustees(
@@ -577,6 +598,17 @@ export interface ZkSocialRecoveryWallet extends BaseContract {
overrides?: CallOverrides
): Promise<BigNumber>;
verifyOTP(
a: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
b: [
[PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
[PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>]
],
c: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
input: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
overrides?: CallOverrides
): Promise<boolean>;
voteInRecovery(
a: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
b: [
@@ -689,8 +721,6 @@ export interface ZkSocialRecoveryWallet extends BaseContract {
overrides?: CallOverrides
): Promise<BigNumber>;
otpVerifierAddress(overrides?: CallOverrides): Promise<BigNumber>;
owner(overrides?: CallOverrides): Promise<BigNumber>;
setTrustees(
@@ -715,6 +745,17 @@ export interface ZkSocialRecoveryWallet extends BaseContract {
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<BigNumber>;
verifyOTP(
a: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
b: [
[PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
[PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>]
],
c: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
input: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<BigNumber>;
voteInRecovery(
a: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
b: [
@@ -787,10 +828,6 @@ export interface ZkSocialRecoveryWallet extends BaseContract {
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
otpVerifierAddress(
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
owner(overrides?: CallOverrides): Promise<PopulatedTransaction>;
setTrustees(
@@ -815,6 +852,17 @@ export interface ZkSocialRecoveryWallet extends BaseContract {
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<PopulatedTransaction>;
verifyOTP(
a: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
b: [
[PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
[PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>]
],
c: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
input: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<PopulatedTransaction>;
voteInRecovery(
a: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>],
b: [

File diff suppressed because one or more lines are too long

View File

@@ -3,7 +3,7 @@ import { Dialog, Transition } from '@headlessui/react'
import { MinusIcon, XMarkIcon } from '@heroicons/react/24/outline'
import { ethers } from 'ethers'
import { AlchemyProvider } from '@ethersproject/providers'
import { shortenAddress, useEthers, useResolveName } from '@usedapp/core'
import { shortenAddress, useEthers } from '@usedapp/core'
import { CheckIcon } from '@heroicons/react/20/solid'
import { ThreeDots } from 'react-loader-spinner'
import { useTheme } from 'next-themes'

View File

@@ -70,22 +70,6 @@ const ConnectWalletButton = () => {
}
}, [web3Modal, activate])
// Set up provider if already connected
useEffect(() => {
const { ethereum } = window
const checkMetaMaskConnected = async () => {
var provider = new ethers.providers.Web3Provider(ethereum)
const accounts = await provider.listAccounts()
const connected = accounts.length > 0
if (connected) {
activate(provider)
}
}
if (ethereum && !library) {
checkMetaMaskConnected()
}
})
if (!loaded) return null
return (

View File

@@ -18,8 +18,11 @@ const LogInBox = () => {
if (provider && account) {
try {
const zkWalletFactory = connectFactory(provider)
console.log("🚀 ~ file: LogInBox.tsx ~ line 21 ~ loadInfo ~ zkWalletFactory", zkWalletFactory.userAddressToWalletAddress(account))
console.log("🚀 ~ file: LogInBox.tsx ~ line 24 ~ loadInfo ~ account", account)
const walletAddress =
await zkWalletFactory.userAddressToWalletAddress(account)
console.log(walletAddress)
if (walletAddress !== ethers.constants.AddressZero) {
router.push('./dashboard')
}

View File

@@ -10,9 +10,7 @@ import { ModalVerifyTotp, QrCodeAuth } from './'
import { prepareMerkleTree, generateInput } from '../../helpers/utils'
import {
connectFactory,
connectTOTPVerifier,
deployZkOTPValidator,
connectZkWallet,
deployZkWallet,
zkTimestampProof,
} from '../../helpers/contracts'
@@ -57,9 +55,8 @@ const TotpSetup = (props: TotpSetupProps) => {
if (tree) {
const [URI, _, root, encrypted] = tree
ceramicData.set({ MerkleTree: encrypted })
connectFactory(provider)
const otpValidator = await deployZkOTPValidator(root, provider)
await deployZkWallet(otpValidator, root, provider)
await deployZkWallet(root, provider)
setUri(URI)
setBlur('')
@@ -84,7 +81,7 @@ const TotpSetup = (props: TotpSetupProps) => {
const encryptedHashes = ceramicData.content.MerkleTree
const totpObject = await generateInput(pin.join(''), encryptedHashes)
if (totpObject) {
connectTOTPVerifier(provider, account)
await connectZkWallet(provider, account)
try {
const tx = await zkTimestampProof(totpObject)
await tx.wait()

View File

@@ -18,7 +18,6 @@ interface DropdownProps {
}
const DropdownAccount = (props: DropdownProps) => {
const { deactivate } = useEthers()
const { ens } = useLookupAddress(props.account)
return (

View File

@@ -1,4 +1,5 @@
import { useEthers } from '@usedapp/core'
import { ethers } from 'ethers'
import { useTheme } from 'next-themes'
import Image from 'next/image'
import Link from 'next/link'
@@ -6,7 +7,7 @@ import { useEffect, useState } from 'react'
import { DropdownAccount, ToggleColorMode } from '.'
const Navbar = () => {
const { account } = useEthers()
const { account, library, activate } = useEthers()
const { theme } = useTheme()
const [loaded, setLoaded] = useState(false)
useEffect(() => {
@@ -15,6 +16,23 @@ const Navbar = () => {
}
})
// Set up provider if already connected
useEffect(() => {
const { ethereum } = window
const checkMetaMaskConnected = async () => {
if (ethereum && !library) {
var provider = new ethers.providers.Web3Provider(ethereum)
const accounts = await provider.listAccounts()
const connected = accounts.length > 0
if (connected) {
activate(provider)
}
}
}
checkMetaMaskConnected()
}, [library])
return (
<nav className="px-4 py-4">
<div className="container flex flex-wrap justify-between items-center mx-auto max-w-6xl">

View File

@@ -5,44 +5,11 @@ import { buildPoseidon } from 'circomlibjs'
import zkWalletFactoryJson from '../../backend/artifacts/contracts/ZkWalletFactory.sol/ZkWalletFactory.json'
import ZkOtpValidatorJson from '../../backend/artifacts/contracts/ZkOtpValidator.sol/ZkOtpValidator.json'
import ZkWalletJson from '../../backend/artifacts/contracts/ZkSocialRecoveryWallet.sol/ZkSocialRecoveryWallet.json'
let zkWalletFactory: ethers.Contract
let ZkOtpValidator: ethers.Contract
let ZkWallet: ethers.Contract
export async function connectTOTPVerifier(
provider: ethers.providers.JsonRpcProvider,
account: string
) {
let signer = provider.getSigner()
// We connect to get wallet address
const ifaceFactory = new ethers.utils.Interface(zkWalletFactoryJson.abi)
zkWalletFactory = new ethers.Contract(
address['zkWalletFactory'],
ifaceFactory,
signer
)
const walletAddress = await zkWalletFactory.userAddressToWalletAddress(
account
)
// We retrieve zk totp verificator address
const ifaceWallet = new ethers.utils.Interface(ZkWalletJson.abi)
const zkWallet = new ethers.Contract(walletAddress, ifaceWallet, signer)
const zkOtpValidatorAddress = await zkWallet.otpVerifierAddress()
const iface = new ethers.utils.Interface(ZkOtpValidatorJson.abi)
ZkOtpValidator = new ethers.Contract(zkOtpValidatorAddress, iface, signer)
console.log('Connect to zkOTP Contract:', ZkOtpValidator)
}
export function connectFactory(provider: ethers.providers.JsonRpcProvider) {
let signer = provider.getSigner()
@@ -57,89 +24,50 @@ export function connectFactory(provider: ethers.providers.JsonRpcProvider) {
return zkWalletFactory
}
export async function deployZkOTPValidator(
root: BigInt,
provider: ethers.providers.JsonRpcProvider
) {
const iface = new ethers.utils.Interface(ZkOtpValidatorJson.abi)
let signer = provider.getSigner()
const ZkOTPValidatorFactory = new ethers.ContractFactory(
iface,
ZkOtpValidatorJson.bytecode,
signer
)
const ZkOTPValidator = await ZkOTPValidatorFactory.deploy(
root,
address['OtpMerkleTreeVerifier']
)
localStorage.setItem('ZkOTPValidator Address', ZkOTPValidator.address)
return ZkOTPValidator.address
}
export async function deployZkWallet(
otpVerifier: string,
root: BigInt,
provider: ethers.providers.JsonRpcProvider
) {
connectFactory(provider)
const zkWalletFactoryContract = await zkWalletFactory.deployWallet(
await zkWalletFactory.deployWallet(
0,
0,
otpVerifier,
address['OtpMerkleTreeVerifier'],
root
)
return zkWalletFactoryContract.address
}
export function connectZkWallet(
export async function connectZkWallet(
provider: ethers.providers.JsonRpcProvider,
walletAddress: string
userAddress: string
) {
//connect to factory to retrive wallet address
connectFactory(provider)
console.log("🚀 ~ file: contracts.ts ~ line 47 ~ provider", provider)
console.log("🚀 ~ file: contracts.ts ~ line 61 ~ userAddress", userAddress)
console.log("🚀 ~ file: contracts.ts ~ line 50 ~ zkWalletFactory", zkWalletFactory)
const walletAddress = await zkWalletFactory.userAddressToWalletAddress(
userAddress
)
let signer = provider.getSigner()
const iface = new ethers.utils.Interface(ZkWalletJson.abi)
if (walletAddress == ethers.constants.AddressZero) {
return undefined
}
ZkWallet = new ethers.Contract(walletAddress, iface, signer)
console.log('Connect to ZkWallet Contract:', ZkWallet)
console.log('Connected to ZkWallet Contract:', ZkWallet)
return ZkWallet
}
// export async function zkProof(input: Object) {
// let calldata = await generateCalldata(input);
// let tx;
// if (calldata) {
// tx = await otp.naiveApproval(calldata[0], calldata[1], calldata[2], calldata[3])
// .catch((error: any) => {
// console.log(error);
// let errorMsg;
// if (error.reason) {
// errorMsg = error.reason;
// } else if (error.data.message) {
// errorMsg = error.data.message;
// } else {
// errorMsg = "Unknown error."
// }
// throw errorMsg;
// });
// } else {
// throw new Error("Witness generation failed.");
// }
// return tx;
// }
export async function zkTimestampProof(input: Object) {
let calldata = await generateCalldata(input, 'otp_verification')
let tx
if (calldata) {
tx = await ZkOtpValidator.verifyOTP(
tx = await ZkWallet.verifyOTP(
calldata[0],
calldata[1],
calldata[2],

View File

@@ -3,6 +3,9 @@ require("dotenv").config()
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
images: {
unoptimized: true,
},
webpack: (config) => {
config.resolve.fallback = { fs: false }
config.resolve.extensions = ['*', '.mjs', '.js', 'jsx', '.ts', '.tsx', '.json']

View File

@@ -6,6 +6,7 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"export": "next export",
"lint": "next lint",
"prettier": "prettier --write . --config ../.prettierrc",
"postinstall": "patch-package"

View File

@@ -2,10 +2,36 @@ import '../styles/globals.css'
import type { AppProps } from 'next/app'
import { Layout } from '../components'
import { ThemeProvider } from 'next-themes'
import { DAppProvider } from '@usedapp/core'
import { DAppProvider, Localhost, Chain } from '@usedapp/core'
import { Provider as CeramicProvider } from '@self.id/react'
const config = {}
export const OptimismGoerli: Chain = {
chainId: 420,
chainName: 'Optimism Goerli Testnet',
isTestChain: true,
isLocalChain: false,
multicallAddress: '0x0000000000000000000000000000000000000000',
getExplorerAddressLink: (address: string) =>
`https://blockscout.com/optimism/goerli//address/${address}`,
getExplorerTransactionLink: (transactionHash: string) =>
`https://blockscout.com/optimism/goerli//tx/${transactionHash}`,
// Optional parameters:
rpcUrl: 'https://goerli.optimism.io',
blockExplorerUrl: 'https://blockscout.com/optimism/goerli',
nativeCurrency: {
name: 'Optimism Goerli Testnet',
symbol: 'ETH',
decimals: 18,
},
}
const config: any = {
readOnlyChainId: OptimismGoerli.chainId,
readOnlyUrls: {
[OptimismGoerli.chainId]: OptimismGoerli.rpcUrl,
},
networks: [OptimismGoerli],
}
function MyApp({ Component, pageProps }: AppProps) {
return (

View File

@@ -1,5 +1,4 @@
import { useEthers } from '@usedapp/core'
import { info } from 'console'
import { ethers } from 'ethers'
import { motion } from 'framer-motion'
import type { NextPage } from 'next'
@@ -13,7 +12,7 @@ import {
BoxSocialRecovery,
BoxPendingTransaction,
} from '../components'
import { connectFactory, connectZkWallet } from '../helpers/contracts'
import { connectZkWallet } from '../helpers/contracts'
const containerUpperBoxes = {
hidden: {},
@@ -69,24 +68,7 @@ const txBox = {
}
const Dashboard: NextPage = () => {
const { activate, library, account } = useEthers()
// Set up provider if already connected
const checkMetaMaskConnected = useCallback(async () => {
const { ethereum } = window
if (ethereum && !library) {
var provider = new ethers.providers.Web3Provider(ethereum)
const accounts = await provider.listAccounts()
const connected = accounts.length > 0
if (connected) {
activate(provider)
}
}
}, [activate])
useEffect(() => {
checkMetaMaskConnected()
}, [checkMetaMaskConnected])
const { library, account } = useEthers()
// Load blockchain info
const router = useRouter()
@@ -98,17 +80,12 @@ const Dashboard: NextPage = () => {
useEffect(() => {
const loadData = async () => {
if (library && account) {
//load factory
const zkWalletFactory = connectFactory(library)
const walletAddress = await zkWalletFactory.userAddressToWalletAddress(
account
)
if (walletAddress == ethers.constants.AddressZero) {
//load wallet
const zkWallet = await connectZkWallet(library, account)
if (!zkWallet) {
router.push('./login')
return
}
//load wallet
const zkWallet = connectZkWallet(library, walletAddress)
const numberTrustees = (await zkWallet.numberTrustees()).toString()
const trustees = [] //await zkWallet.Trustees(1)
setInfo({ ...info, numberTrustees: numberTrustees })

BIN
res/fullDemo.mp4 Normal file

Binary file not shown.