mirror of
https://github.com/3lLobo/zkAuth.git
synced 2026-01-09 12:27:55 -05:00
@@ -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/)
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
1
backend/.env.example
Normal file
1
backend/.env.example
Normal file
@@ -0,0 +1 @@
|
||||
PRIVATE_GOERLII_KEY=xxxx
|
||||
1
backend/.gitignore
vendored
1
backend/.gitignore
vendored
@@ -130,7 +130,6 @@ npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
circuits/build
|
||||
artifacts
|
||||
cache
|
||||
*.ptau
|
||||
deployments
|
||||
|
||||
@@ -1,13 +1,43 @@
|
||||
# This is the bacqend, the smart-contract crib
|
||||
# This is the smart-contract crib
|
||||
|
||||

|
||||
|
||||
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
BIN
backend/artifacts.zip
Normal file
Binary file not shown.
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
|
||||
}
|
||||
@@ -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": {}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
|
||||
}
|
||||
@@ -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": {}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"_format": "hh-sol-artifact-1",
|
||||
"contractName": "Pairing",
|
||||
"sourceName": "contracts/Verifiers/HashCheckVerifier.sol",
|
||||
"abi": [],
|
||||
"bytecode": "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220301e535f70771fb1ebdb277ad7a17a537e7f384028f52bf06ceec27f2cd7b18f64736f6c63430008110033",
|
||||
"deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220301e535f70771fb1ebdb277ad7a17a537e7f384028f52bf06ceec27f2cd7b18f64736f6c63430008110033",
|
||||
"linkReferences": {},
|
||||
"deployedLinkReferences": {}
|
||||
}
|
||||
@@ -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
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"_format": "hh-sol-artifact-1",
|
||||
"contractName": "Pairing",
|
||||
"sourceName": "contracts/Verifiers/OtpMerkleTreeVerifier.sol",
|
||||
"abi": [],
|
||||
"bytecode": "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220d256c30602e6e48efbe84b99f40e0d161521b4944a7b5a8e1a2e5317d7342f4564736f6c63430008110033",
|
||||
"deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220d256c30602e6e48efbe84b99f40e0d161521b4944a7b5a8e1a2e5317d7342f4564736f6c63430008110033",
|
||||
"linkReferences": {},
|
||||
"deployedLinkReferences": {}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
|
||||
}
|
||||
@@ -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": {}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
|
||||
}
|
||||
@@ -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": {}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
|
||||
}
|
||||
@@ -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": {}
|
||||
}
|
||||
@@ -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
@@ -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
4
backend/artifacts/hardhat/console.sol/console.dbg.json
Normal file
4
backend/artifacts/hardhat/console.sol/console.dbg.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../build-info/39a1d577a9c72981d482fd0d48782f19.json"
|
||||
}
|
||||
10
backend/artifacts/hardhat/console.sol/console.json
Normal file
10
backend/artifacts/hardhat/console.sol/console.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"_format": "hh-sol-artifact-1",
|
||||
"contractName": "console",
|
||||
"sourceName": "hardhat/console.sol",
|
||||
"abi": [],
|
||||
"bytecode": "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220807e774fad6b9164116dee996322ef499abe9e76c8bf8d870ea29d25538ea37464736f6c63430008110033",
|
||||
"deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220807e774fad6b9164116dee996322ef499abe9e76c8bf8d870ea29d25538ea37464736f6c63430008110033",
|
||||
"linkReferences": {},
|
||||
"deployedLinkReferences": {}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
export const address = {
|
||||
zkWalletFactory: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0",
|
||||
HashCheckVerifier: "0x5FbDB2315678afecb367f032d93F642f64180aa3",
|
||||
OtpMerkleTreeVerifier: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512",
|
||||
zkWalletFactory: "0xcaF6c8C45c4fA0d2F6BFcE0c904FBedE08c773f1",
|
||||
HashCheckVerifier: "0xDFD466d2A14cB2895f2C8BCacc67BDEF37C60De0",
|
||||
OtpMerkleTreeVerifier: "0x87469041b414E1f2dEC2e79e32f4E911E7f50622",
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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': {
|
||||
|
||||
587
backend/package-lock.json
generated
587
backend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -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",
|
||||
|
||||
@@ -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
File diff suppressed because one or more lines are too long
@@ -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'
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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')
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -18,7 +18,6 @@ interface DropdownProps {
|
||||
}
|
||||
|
||||
const DropdownAccount = (props: DropdownProps) => {
|
||||
const { deactivate } = useEthers()
|
||||
const { ens } = useLookupAddress(props.account)
|
||||
|
||||
return (
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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
BIN
res/fullDemo.mp4
Normal file
Binary file not shown.
Reference in New Issue
Block a user