Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ docs/

# Dotenv file
.env

# Dependency directories
node_modules/
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Before being able to run any command, you need to create a .env file and set you

```shell
$ forge install
$ npm install
```

### Build
Expand Down Expand Up @@ -54,3 +55,15 @@ source .env && forge script script/DeployUserOpMultiSigVerifier.s.sol --rpc-url
source .env && forge script script/DeployUserOpWebAuthnVerifier.s.sol --rpc-url $BASE_RPC_URL --ledger --verify --broadcast
source .env && forge script script/DeployUserOpWebAuthnCosignVerifier.s.sol --rpc-url $BASE_RPC_URL --ledger --verify --broadcast
```

### Example scripts

The following commands are useful for users and application developers to work with the Keystore protocol.

#### Verify configuration

A minimal script to generate and verify a UCMT using the [openzeppelin Merkle tree library](https://github.com/OpenZeppelin/merkle-tree).

```shell
$ npm run examples:verify-ucmt
```
48 changes: 48 additions & 0 deletions examples/verify-ucmt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* Minimal script to generate a User Configuration Merkle Tree (UCMT) and verify
* its root and proofs.
*
* By design, the Keystore holds only the Merkle tree root hash onchain while the
* actual configuration is stored offchain. Consequently, all stakeholders of an
* account MUST have access to the UCMT in order to verify that the onchain root
* hash exactly matches the expected configuration. This prevents a bad actor from
* attempting to hide a malicious configuration within the Merkle tree.
*/
import { SimpleMerkleTree } from "@openzeppelin/merkle-tree";
import { AbiParameters, Hash } from "ox";

/**
* An example UCMT stored as an array of nodes. Each node is a tuple of the verifier
* address and the node configuration. When building the Merkle tree, each node is
* packed and hashed using `keccak256`.
*/
const USER_CONFIGURATION_MERKLE_TREE = [
["0x000000000000000000000000000000000000dEaD", "0xdeadbeef"],
["0x000000000000000000000000000000000000bEEF", "0x"],
["0x000000000000000000000000000000000000cafE", "0x0000000ff1ce"],
["0x000000000000000000000000000000000000F00D", "0xc0ffee"],
] as const;

function main() {
const merkleTree = SimpleMerkleTree.of(
USER_CONFIGURATION_MERKLE_TREE.map((node) =>
Hash.keccak256(AbiParameters.encodePacked(["address", "bytes"], node))
)
);

console.log("UCMT:", USER_CONFIGURATION_MERKLE_TREE);
console.log("UCMT root:", merkleTree.root);
console.log("UCMT proofs...");
USER_CONFIGURATION_MERKLE_TREE.forEach((_, i) =>
console.log(`node ${i + 1}:`, merkleTree.getProof(i))
);

console.log(
"\nVerify different configurations by changing the merkle tree in examples/verify-ucmt.ts."
);
console.log(
"Always check that your UCMT aligns with your account's onchain root hash."
);
}

main();
Loading