diff --git a/examples/CRISP/circuits/src/main.nr b/examples/CRISP/circuits/src/main.nr index 2ef2150b7c..f0ba056661 100644 --- a/examples/CRISP/circuits/src/main.nr +++ b/examples/CRISP/circuits/src/main.nr @@ -66,7 +66,7 @@ fn main( // Calculate the Merkle root. let merkle_root_calculated = get_merkle_root( - address, + slot_address, balance, merkle_proof_length, merkle_proof_indices, @@ -112,11 +112,12 @@ fn main( // Ensure that the ciphertext is valid assert(is_greco_valid); + // Verify the correct Merkle root. + assert(merkle_root_calculated == merkle_root); + // If the voter is eligible to vote, output the ciphertext. // Otherwise, output the sum of the ciphertexts. - if (is_signature_valid == true) - & (merkle_root_calculated == merkle_root) - & (slot_address == address) { + if (is_signature_valid == true) & (slot_address == address) { // Verify the correct coefficient values and that the vote is <= balance check_coefficient_values_with_balance(k1, params.crypto_params().q_mod_t, balance); diff --git a/examples/CRISP/client/libs/crispWorker.js b/examples/CRISP/client/libs/crispWorker.js index ac3d0bca3b..8b1b1a9f48 100755 --- a/examples/CRISP/client/libs/crispWorker.js +++ b/examples/CRISP/client/libs/crispWorker.js @@ -4,53 +4,34 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -import { - encryptVoteAndGenerateCRISPInputs, - generateProof, - VotingMode, - encodeVote, - encryptVote, - generateMerkleProof, - hashLeaf, - encodeSolidityProof, -} from '@crisp-e3/sdk' +import { hashLeaf, generateVoteProof, encodeSolidityProof } from '@crisp-e3/sdk' self.onmessage = async function (event) { const { type, data } = event.data switch (type) { case 'generate_proof': try { - const { voteId, publicKey, address, signature, message } = data + const { voteId, publicKey, address, signature } = data // voteId is either 0 or 1, so we need to encode the vote accordingly. // We are adapting to the current CRISP application. - const vote = voteId === 0 ? { yes: 0n, no: 1n } : { yes: 1n, no: 0n } const balance = 1n + const vote = voteId === 0 ? { yes: 0n, no: balance } : { yes: balance, no: 0n } - const leaf = hashLeaf(address.toLowerCase(), balance.toString()) - // TODO: get the leaves from the server (pass them from the client). - const merkleProof = generateMerkleProof(0n, balance, address.toLowerCase(), [ - leaf, + // todo: get the leaves from the server (pass them from the client). + const merkleLeaves = [ + hashLeaf(address, balance), 4720511075913887710172192848636076523165432993226978491435561065722130431597n, 14131255645332550266535358189863475289290770471998199141522479556687499890181n, - ]) + ] - const encodedVote = encodeVote(vote, VotingMode.GOVERNANCE, balance) - const encryptedVote = await encryptVote(encodedVote, publicKey) - - const inputs = await encryptVoteAndGenerateCRISPInputs({ - encodedVote, + const proof = await generateVoteProof({ + vote, publicKey, - previousCiphertext: encryptedVote, signature, - message, - merkleData: merkleProof, + merkleLeaves, balance, - slotAddress: address.toLowerCase(), - isFirstVote: true, }) - - const proof = await generateProof(inputs) const encodedProof = encodeSolidityProof(proof) self.postMessage({ diff --git a/examples/CRISP/client/package.json b/examples/CRISP/client/package.json index 08c8ab6f89..128fec51ae 100644 --- a/examples/CRISP/client/package.json +++ b/examples/CRISP/client/package.json @@ -18,7 +18,7 @@ "deploy": "gh-pages -d dist" }, "dependencies": { - "@crisp-e3/sdk": "0.3.0-test", + "@crisp-e3/sdk": "0.4.1", "@emotion/babel-plugin": "^11.11.0", "@emotion/react": "^11.11.4", "@phosphor-icons/react": "^2.1.4", diff --git a/examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts b/examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts index 3fd7363a6f..b34492fc8a 100644 --- a/examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts +++ b/examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts @@ -28,7 +28,7 @@ export type VoteManagementContextType = { getPastPolls: () => Promise setVotingRound: React.Dispatch> setUser: React.Dispatch> - generateProof: (voteId: bigint, publicKey: Uint8Array, address: string, signature: string, message: string) => Promise + generateProof: (voteId: bigint, publicKey: Uint8Array, address: string, signature: string) => Promise broadcastVote: (vote: BroadcastVoteRequest) => Promise getRoundStateLite: (roundCount: number) => Promise setPastPolls: React.Dispatch> diff --git a/examples/CRISP/client/src/hooks/voting/useVoteCasting.ts b/examples/CRISP/client/src/hooks/voting/useVoteCasting.ts index 74098154f9..485b0f529f 100644 --- a/examples/CRISP/client/src/hooks/voting/useVoteCasting.ts +++ b/examples/CRISP/client/src/hooks/voting/useVoteCasting.ts @@ -12,6 +12,7 @@ import { useVoteManagementContext } from '@/context/voteManagement' import { useNotificationAlertContext } from '@/context/NotificationAlert/NotificationAlert.context.tsx' import { Poll } from '@/model/poll.model' import { BroadcastVoteRequest } from '@/model/vote.model' +import { SIGNATURE_MESSAGE } from '@crisp-e3/sdk' export const useVoteCasting = () => { const { user, roundState, votingRound, generateProof, broadcastVote, setTxUrl } = useVoteManagementContext() @@ -22,9 +23,9 @@ export const useVoteCasting = () => { const [isLoading, setIsLoading] = useState(false) const handleProofGeneration = useCallback( - async (vote: Poll, address: string, signature: string, message: string) => { + async (vote: Poll, address: string, signature: string) => { if (!votingRound) throw new Error('No voting round available for proof generation') - return generateProof(BigInt(vote.value), new Uint8Array(votingRound.pk_bytes), address, signature, message) + return generateProof(BigInt(vote.value), new Uint8Array(votingRound.pk_bytes), address, signature) }, [generateProof, votingRound], ) @@ -46,11 +47,10 @@ export const useVoteCasting = () => { console.log('Processing vote...') // For now just sign and do not do nothing with the signature - const message = `Vote for round ${roundState.id}` - const signature = await signMessageAsync({ message }) + const signature = await signMessageAsync({ message: SIGNATURE_MESSAGE }) try { - const encodedProof = await handleProofGeneration(pollSelected, user.address, signature, message) + const encodedProof = await handleProofGeneration(pollSelected, user.address, signature) if (!encodedProof) { throw new Error('Failed to generate proof.') } diff --git a/examples/CRISP/client/src/hooks/wasm/useWebAssembly.tsx b/examples/CRISP/client/src/hooks/wasm/useWebAssembly.tsx index dc51072911..f3b371408d 100644 --- a/examples/CRISP/client/src/hooks/wasm/useWebAssembly.tsx +++ b/examples/CRISP/client/src/hooks/wasm/useWebAssembly.tsx @@ -23,13 +23,7 @@ export const useWebAssemblyHook = () => { } }, []) - const generateProof = async ( - voteId: bigint, - publicKey: Uint8Array, - address: string, - signature: string, - message: string, - ): Promise => { + const generateProof = async (voteId: bigint, publicKey: Uint8Array, address: string, signature: string): Promise => { if (!worker) { console.error('WebAssembly worker not initialized') return @@ -37,7 +31,7 @@ export const useWebAssemblyHook = () => { return new Promise((resolve, reject) => { setIsLoading(true) - worker.postMessage({ type: 'generate_proof', data: { voteId, publicKey, address, signature, message } }) + worker.postMessage({ type: 'generate_proof', data: { voteId, publicKey, address, signature } }) worker.onmessage = async (event) => { const { type, success, encodedProof, error } = event.data if (type === 'generate_proof') { diff --git a/examples/CRISP/package.json b/examples/CRISP/package.json index 7382e3acc0..37d5c723b3 100644 --- a/examples/CRISP/package.json +++ b/examples/CRISP/package.json @@ -26,8 +26,6 @@ "test:circuits:inputs": "node --test test/governanceCircuit.test.ts", "test:circuits": "cd circuits && nargo test", "compile:circuit": "bash ./scripts/compile_circuits.sh", - "test:sdk": "cd sdk && pnpm test", - "release:sdk": "cd sdk && pnpm release", "report": "playwright show-report", "publish:packages": "tsx scripts/publish.ts", "setup:testnet": "bash ./scripts/setup_testnet.sh" diff --git a/examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol b/examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol index 131cfb765a..a580ff9ddd 100644 --- a/examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol +++ b/examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol @@ -8,7 +8,7 @@ pragma solidity >=0.8.21; uint256 constant N = 262144; uint256 constant LOG_N = 18; uint256 constant NUMBER_OF_PUBLIC_INPUTS = 2066; -uint256 constant VK_HASH = 0x2116432a8071b45d4f2e0cec74a985a1ea1de1008309715fdb59de0707087fc2; +uint256 constant VK_HASH = 0x063c39e8bdbf5641b7e7da911a54f2e808b084120de6fec9cd1223ce6ef0da85; library HonkVerificationKey { function loadVerificationKey() internal pure returns (Honk.VerificationKey memory) { Honk.VerificationKey memory vk = Honk.VerificationKey({ @@ -16,76 +16,76 @@ library HonkVerificationKey { logCircuitSize: uint256(18), publicInputsSize: uint256(2066), ql: Honk.G1Point({ - x: uint256(0x1a7b36f05cef7bbf455873db9784a29f833916dc5aaec66352970e302061c914), - y: uint256(0x0f80256a61ab446a5a2dbda239e52a9dc4612566d9b57155ffb2dbaf896ee88a) + x: uint256(0x246e058a5ff7d94b72e2d8f1d273265644d4795cfb2a427bab835b180a5509fb), + y: uint256(0x221fc7eff2803fca12db033baa14646582610126778228307901d0db50748c5e) }), qr: Honk.G1Point({ - x: uint256(0x1d540f31fb58beab584c40ce6e44e8b400f0b0cd9f5ed8f71b27269167916477), - y: uint256(0x1d0f60d6bc410f430eeb967c817849dcb1f5fcb45acb45dddcd1c7306c46d58f) + x: uint256(0x08011cd886ba5fc7884098df37d58eecfa75f404fead14dbbe1708d9fba3a702), + y: uint256(0x0a76efd12734f504e19bf349e90d20fc19400dd97c238195c67b118c14a35dc9) }), qo: Honk.G1Point({ - x: uint256(0x0d01c3cf036f68eb05e2834a383eaf491e1b4aa843c656c95e89241ab91b20be), - y: uint256(0x2d85c7fa52638d3bc184768dde6db2de10517bb67b6354f97d789d1c6d64a94a) + x: uint256(0x03250bf94bfb59a296a7227fe1f7a6873ca063c4c581a7b725d6ab685c53440c), + y: uint256(0x0663423bdefc067e3f531e2760b73340a76365a28d7753db11af572e71a7f395) }), q4: Honk.G1Point({ - x: uint256(0x16727ccc1a7e6087d61c039c831ce6e35f5cd651defebe160e2a27b11d0c1f15), - y: uint256(0x17588e2f3eca2c4c3e02110b937ec015b5a05faff5eb0d06ba0d3d0001f6807b) + x: uint256(0x1db2b3316d4bba2799898fc14a80ee1a12fd9af0b6cf261b86a0e725737dd091), + y: uint256(0x0988609ce0b437fd1d5586ad60e05cc16f891e702fda15bfbbd79cf6ea306582) }), qm: Honk.G1Point({ - x: uint256(0x1fcd39a2deebf311e4d2ee6ca968cbcdcff11301f480a15d9e8e333c520e4675), - y: uint256(0x1f1fd8948d841a97f8b1a1ee522c1a9c36976bafd69a78eae5b5277ada8170f2) + x: uint256(0x1a1ddaefb0b108d39e35111ea8cab1f89d6fb1e6ca3d4d28ae1b6ad3acdb4c4f), + y: uint256(0x110c07c930f3fd905e11cf35db1b4e8d267f016d94ffc9f0b3833dd27641fd4d) }), qc: Honk.G1Point({ - x: uint256(0x14b308df277ab4a529e283968d9dd492894497202d2c7a1705a3baa46da22bf4), - y: uint256(0x0c053c7a09b99f2623559aa459bff68335b4f5a5cfa96f6cdb6f1e28736f3191) + x: uint256(0x24a1d61ec991a93d44d50980c43acae82f4013d66126daf568a854cbc88c5a88), + y: uint256(0x20327007b5abc8edee984da35d5c8b8f8565165d4708436627ba34a90ded8431) }), qLookup: Honk.G1Point({ x: uint256(0x205057a47479c3744023a35ca3d08d79c3499d9af48e264ecb31823713bbbca8), y: uint256(0x19b2541dcaae69df644bec1bb8ce13455719c73fcadac3763d81a6b1c70560f3) }), qArith: Honk.G1Point({ - x: uint256(0x08670013c484727f3f6403409aa693f057ffa2ebff47a46baac04a4fc534df86), - y: uint256(0x21231b3fe164af29a57dadd72611a977c9ceb0adacfb21707da1a7fce0a2fcc5) + x: uint256(0x06294dfc20c077df81e702e90386bca302a58eb9a8e42d116e88b4bcc7605f67), + y: uint256(0x06a35b9ed28d64b5c79f08a6ed5698a501e9a45e71cd515d3a89455ea711489d) }), qDeltaRange: Honk.G1Point({ - x: uint256(0x2d6d8c24ae1ff6b1b50818fb62f53e37bacde5e15637cf1d4a9f1bcd43996c03), - y: uint256(0x15d94db2dd8bbca416175f0986178aa8c31ff76d4eeb347714e329c5074a56f9) + x: uint256(0x21cb2b3ddedbbb4529c61e4586aa3913a975644620c112f1c892f1b0930633d8), + y: uint256(0x2b2d51a0dc545770c23b83eceb33b488e8217ed4af94bbecd3233520f1a09e36) }), qElliptic: Honk.G1Point({ - x: uint256(0x1db949cfaf913cba16771ea4d25c8c61fac22a4997abd0d82b1f04b2583839a5), - y: uint256(0x02804f2992af78447a4f46446c54b2ca316153accede32c59264d97a62165a20) + x: uint256(0x0b33cc711a57329b7a8532a68b487c08afc55c25843549a9f80a1a954c946c62), + y: uint256(0x068fcecd26322a8e6c9699ef0aaa0f2a0d309c5cb2bca51f14287d121c4694fa) }), qMemory: Honk.G1Point({ - x: uint256(0x1701619666d10f73d14baf14921415a2ae4fe904afc516361e7f68f5d546e77d), - y: uint256(0x14c78fcb02f92b527f6b4bd642d8f4ee1579aa7e23c83949b29497a7a6543a82) + x: uint256(0x12924d915fd97341729ab4a38d431bdb22555119117c62a2ee78941855604328), + y: uint256(0x253f6f540fea2a3f6d3b9f9d24d142b1e942c383fe5b45aea1306992c99fb094) }), qNnf: Honk.G1Point({ - x: uint256(0x23d505077a2f45f5375c4d97115598aa4786fd480daa58e9fe644c1987995fe5), - y: uint256(0x189d4e39e2419279e09ee6e8ea98d271c1dc23f12f14c87428a55956251f8c64) + x: uint256(0x23916c7db7b5ec14f6c4a90328e16fad9e03f0d36a7c22750a82bdb74925d008), + y: uint256(0x0d2d9f771a28305ef54fd924dbab1b7fd294e39f2e64b1884fec624a151a78cc) }), qPoseidon2External: Honk.G1Point({ - x: uint256(0x1c85ee1a141b05ef5df7bcc013ec60761f13bbc1cae6f4bd2a77acd5dfef24f9), - y: uint256(0x22c4ff8e4338cacfc1eb5fb512be1001ebb07802c71a9cda55c61a7d57cca39e) + x: uint256(0x277f77603f20d5d41e1149588bc2942ba2938ac9d9444622709ed99f1e207a4e), + y: uint256(0x214d57941547e7acf0f4db0ba32b3a80ccf3bc7195673d43a58e36b735df60e6) }), qPoseidon2Internal: Honk.G1Point({ - x: uint256(0x2113c7a6c03bd198a71e11df5b7051aa5adfde3ef9eed17465a6de8056584499), - y: uint256(0x214660396a999c68ec9e72b887fa3f65bd7c693d4ab805d07c3f4aa8f4fa6bf6) + x: uint256(0x09a0b5fbddaa5b0077595c630a0403f3de09ae31815145dae74c04ac7013cdd2), + y: uint256(0x1c8f6eebb7992fbbd7b84ef11585538f876749bedd8e61b70fd86a22f3f0c47d) }), s1: Honk.G1Point({ - x: uint256(0x114067cffd29c0983fae6e709b1acf5b4d6e15667af850a3ab748bd2ee5ebeda), - y: uint256(0x0a2a21e3ad07cdbdf9cdb7a0bdb59a509f5f6fc745714179b1a5a0ca67157431) + x: uint256(0x20dbaae9012430dfd99a8e15c41e5ce5e33abe943d4e6bcae2568196a6e2bf16), + y: uint256(0x164b7d011804aa4dbb49c6d96cb28e3b16af2c3532c2407f0ce12c52be461956) }), s2: Honk.G1Point({ - x: uint256(0x23c4429ccca13d58716a2c6c7970cbb99dd2b13095d32804a294cd0e38ce88d0), - y: uint256(0x1c3f97d8c4dc3c173320a0618a5821e8b80d7739c088bb23300400a6230fde4a) + x: uint256(0x1da71ffed08aa0fa2b5a58ab3fc27ffb7e2cf131547842780a24963048e2d5aa), + y: uint256(0x00ec65400c01cf5af83108cda478482094334d2ba594e370e47bb0bef1e30491) }), s3: Honk.G1Point({ - x: uint256(0x19a9e2fa7fd4475fb5eda1ae16c72d4c19092dc4bbfdbb2cb159209c860dcd26), - y: uint256(0x00a2e28e53cc3a626dceea4cd1cdb7452f1054612fa6f4fa326e1bdfa71d3fa8) + x: uint256(0x076d8ef37e5f6a8a967907da958538f3302bc2360c31614a5e1832a1f3ceb421), + y: uint256(0x1c83f5d0dda79e6f11f5969084b6dcddd1432a426dca69f83a1b1cee21c9e208) }), s4: Honk.G1Point({ - x: uint256(0x095bec0997e0a80fa5135eeafad26bf4d40307dcfad6d1b45b72fef4b74503c6), - y: uint256(0x2dee87ca275d32e8e7a2c51451e0d03e3c1149efaaa20ae8b8dae42a288c18b1) + x: uint256(0x0fbf35404645e90f9aa8a9a37507098b6a6332c214ba9b9d65f6e05a5ef82b26), + y: uint256(0x0a6e47c369491fe21fc51c7b254dbaad6a9b6fba5f5fc1e1d66b11a05aca1eb5) }), t1: Honk.G1Point({ x: uint256(0x08a5ba822823e5f21f5585f7d90f070aaad388561d817362c819850cccf82580), @@ -104,28 +104,28 @@ library HonkVerificationKey { y: uint256(0x1e5e5f5acbdcd05a0ebffacea7a5426da9ec26a79cbb95692c9e9a499ff0155a) }), id1: Honk.G1Point({ - x: uint256(0x04c94d6d300959fe9483fa91bfdff0f6167a2a718800ad1bbf0cd3759e8a57eb), - y: uint256(0x194f8fad06add0adcdd30f4337a73e9380d087c075d0a163c3023afc03bad8c4) + x: uint256(0x0fcc20437825949a4e696438aea909760b3db2d273bf5b17f5fbfe3a70f036fb), + y: uint256(0x210603917536ed64abdd44a319ea9341a3f30a789789230a7e9cf6214b4bce7e) }), id2: Honk.G1Point({ - x: uint256(0x069b8a17848adb8e056afb34f4f351aacb40b9164321a4990845b6a288240f99), - y: uint256(0x110494e3d7dd391ae6c41b16f810275b7dbe1a8e749cdf19e87f3ede984fc57b) + x: uint256(0x1ecfabef38de6cd4881366a1b917f8ff9f99a024f4b5087c0c0f566d2c3ea36b), + y: uint256(0x1dd57e4a465cfe220a85cafe9c22d18ea7500a73930a72a173882333424658fd) }), id3: Honk.G1Point({ - x: uint256(0x287fa9b1d6f14f25442f4b45aa6b8015d874e8ee32ce5b6c6b9d37c4c1af382d), - y: uint256(0x08037c54f284e0b070ce529ae47b842c5f0062deb629f22d9336de5efddf1660) + x: uint256(0x0c44be4c332daa7e6c1989b113af431bbbd1177a9e3b296182a038c4898c58b8), + y: uint256(0x07c0db6714c5c1aae2d785402c39e9d18b09e367033cfcb2aecbb6991da057b1) }), id4: Honk.G1Point({ - x: uint256(0x1797c469d204fbd6000ed31a8c65d2df08e9b2ed4155ae07a451221f75ff9282), - y: uint256(0x2e7f2c1496e92023c68efc470d5757d684659d10888f921f260acde0664f1d9d) + x: uint256(0x24443689861aa88435f69edc9782024e9207b659aab7df6694958fb85f6d4d5a), + y: uint256(0x19fa9eb82c3e56a745b7900324b2a205ab358a1dac89439011fc099408d21c96) }), lagrangeFirst: Honk.G1Point({ x: uint256(0x0000000000000000000000000000000000000000000000000000000000000001), y: uint256(0x0000000000000000000000000000000000000000000000000000000000000002) }), lagrangeLast: Honk.G1Point({ - x: uint256(0x251eb0b16450815cda5eaaef0ffa6cde8b0927ad0c8a195a940b9c3a468a542d), - y: uint256(0x0a214dd7528af9a23a272d8f0c608c50577c65d71e4f9031e731c526b610fae3) + x: uint256(0x11dc324ee0b909fa5ec049c5832d17f8ba51b9f2990874ea77384948fcaa6800), + y: uint256(0x243280a04dd209d1241eb79b76c07ccc3bf501dd5b79fa218d4669cfb30316f8) }) }); return vk; diff --git a/examples/CRISP/packages/crisp-contracts/package.json b/examples/CRISP/packages/crisp-contracts/package.json index 13e9365638..21360666b2 100644 --- a/examples/CRISP/packages/crisp-contracts/package.json +++ b/examples/CRISP/packages/crisp-contracts/package.json @@ -1,6 +1,6 @@ { "name": "@crisp-e3/contracts", - "version": "0.3.0-test", + "version": "0.4.1", "type": "module", "files": [ "contracts", diff --git a/examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts b/examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts index efd2412b04..59fa5ea80a 100644 --- a/examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts +++ b/examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts @@ -5,23 +5,19 @@ // or FITNESS FOR A PARTICULAR PURPOSE. import { zeroAddress } from 'viem' -import { ZKInputsGenerator } from '@crisp-e3/zk-inputs' import { - encryptVoteAndGenerateCRISPInputs, - generateProof, - VotingMode, - encodeVote, - MESSAGE, - generateMerkleProof, hashLeaf, + generatePublicKey, + SIGNATURE_MESSAGE, + generateVoteProof, + getAddressFromSignature, encodeSolidityProof, + generateMerkleTree, } from '@crisp-e3/sdk' import { expect } from 'chai' import { deployCRISPProgram, deployHonkVerifier, deployMockEnclave, nonZeroAddress, ethers } from './utils' -let zkInputsGenerator = ZKInputsGenerator.withDefaults() -let publicKey = zkInputsGenerator.generatePublicKey() -const previousCiphertext = zkInputsGenerator.encryptVote(publicKey, new BigInt64Array([0n])) +let publicKey = generatePublicKey() describe('CRISP Contracts', function () { describe('decode tally', () => { @@ -63,37 +59,23 @@ describe('CRISP Contracts', function () { // It needs some time to generate the proof. this.timeout(60000) - const [signer] = await ethers.getSigners() - const honkVerifier = await deployHonkVerifier() - - const slotAddress = signer.address.toLowerCase() as `0x${string}` + const [signer] = await ethers.getSigners() const vote = { yes: 10n, no: 0n } - const balance = vote.yes - const encodedVote = encodeVote(vote, VotingMode.GOVERNANCE, balance) + const balance = 100n + const signature = (await signer.signMessage(SIGNATURE_MESSAGE)) as `0x${string}` + const address = await getAddressFromSignature(signature) + const leaves = [...[10n, 20n, 30n], hashLeaf(address, balance)] - const signature = (await signer.signMessage(MESSAGE)) as `0x${string}` - const leaf = hashLeaf(slotAddress, balance.toString()) - const leaves = [...[10n, 20n], leaf] - - const threshold = 0n - const merkleProof = generateMerkleProof(threshold, balance, slotAddress, leaves) - - const inputs = await encryptVoteAndGenerateCRISPInputs({ - encodedVote, + const proof = await generateVoteProof({ + vote, publicKey, - previousCiphertext, signature, - message: MESSAGE, - merkleData: merkleProof, + merkleLeaves: leaves, balance, - slotAddress, - isFirstVote: true, }) - const proof = await generateProof(inputs) - const isValid = await honkVerifier.verify(proof.proof, proof.publicInputs) expect(isValid).to.be.true @@ -103,42 +85,30 @@ describe('CRISP Contracts', function () { // It needs some time to generate the proof. this.timeout(60000) - const [signer] = await ethers.getSigners() - const crispProgram = await deployCRISPProgram() - - const address = signer.address.toLowerCase() as `0x${string}` + const [signer] = await ethers.getSigners() const e3Id = 1n const vote = { yes: 10n, no: 0n } - const balance = vote.yes - const encodedVote = encodeVote(vote, VotingMode.GOVERNANCE, balance) - - const signature = (await signer.signMessage(MESSAGE)) as `0x${string}` - const leaf = hashLeaf(address, balance.toString()) - const leaves = [...[10n, 20n], leaf] - - const threshold = 0n - const merkleProof = generateMerkleProof(threshold, balance, address, leaves) - - const inputs = await encryptVoteAndGenerateCRISPInputs({ - encodedVote, + const balance = 100n + const signature = (await signer.signMessage(SIGNATURE_MESSAGE)) as `0x${string}` + const address = await getAddressFromSignature(signature) + const leaves = [...[10n, 20n, 30n], hashLeaf(address, balance)] + const merkleTree = generateMerkleTree(leaves) + + const proof = await generateVoteProof({ + vote, publicKey, - previousCiphertext, signature, - message: MESSAGE, - merkleData: merkleProof, + merkleLeaves: leaves, balance, - slotAddress: address, - isFirstVote: true, }) - const proof = await generateProof(inputs) const encodedProof = encodeSolidityProof(proof) // Call next functions with fake data for testing. - await crispProgram.setRoundData(e3Id, merkleProof.proof.root, nonZeroAddress, 1n) + await crispProgram.setRoundData(e3Id, merkleTree.root, nonZeroAddress, 1n) await crispProgram.validate(e3Id, 0n, '0x', '0x') // If it doesn't throw, the test is successful. diff --git a/examples/CRISP/packages/crisp-sdk/README.md b/examples/CRISP/packages/crisp-sdk/README.md index fef4afc62b..8b5feec2a2 100644 --- a/examples/CRISP/packages/crisp-sdk/README.md +++ b/examples/CRISP/packages/crisp-sdk/README.md @@ -1,18 +1,79 @@ # CRISP SDK -This package is CRISP's TypeScript SDK for interacting with CRISP and the CRISP server. +TypeScript SDK for interacting with CRISP (Coercion-Resistant Impartial Selection Protocol) and +the CRISP server. ## Installation ```bash -npm install @enclave/crisp-sdk +npm install @crisp-e3/sdk ``` -## Release +## Features -The SDK is published on npmjs and does not follow the same versioning as the main Enclave packages. -To release a new version, run the following command: +- **Round Management**: Fetch round details, token requirements, and voting parameters +- **Token Operations**: Query token balances and total supply at specific blocks +- **Merkle Tree Utilities**: Generate proofs for voter inclusion in the eligibility tree +- **Vote Proof Generation**: Create zero-knowledge proofs for votes and mask votes +- **Proof Verification**: Verify generated proofs using Noir circuits -```bash -pnpm release +## Usage + +### Get Round Details + +```typescript +import { getRoundDetails } from '@crisp-e3/sdk' + +const roundDetails = await getRoundDetails(serverUrl, e3Id) +``` + +### Get Token Balance + +```typescript +import { getBalanceAt } from '@crisp-e3/sdk' + +const balance = await getBalanceAt(voterAddress, tokenAddress, snapshotBlock, chainId) +``` + +### Generate Vote Proof + +```typescript +import { generateVoteProof } from '@crisp-e3/sdk' + +const proof = await generateVoteProof({ + vote: { yes: 100n, no: 0n }, + publicKey: publicKeyBytes, + signature: '0x...', + balance: 1000n, + merkleLeaves: [...], +}) +``` + +### Generate Mask Vote Proof + +```typescript +import { generateMaskVoteProof } from '@crisp-e3/sdk' + +const maskProof = await generateMaskVoteProof({ + balance: 1000n, + slotAddress: '0x...', + publicKey: publicKeyBytes, + merkleLeaves: [...], + previousCiphertext: previousCiphertextBytes, // optional +}) ``` + +### Verify Proof + +```typescript +import { verifyProof } from '@crisp-e3/sdk' + +const isValid = await verifyProof(proof) +``` + +## API + +- **State**: `getRoundDetails`, `getRoundTokenDetails` +- **Token**: `getBalanceAt`, `getTotalSupplyAt`, `getTreeData` +- **Vote**: `generateVoteProof`, `generateMaskVoteProof`, `verifyProof`, `decodeTally` +- **Utils**: `generateMerkleProof`, `generateMerkleTree`, `hashLeaf`, `getAddressFromSignature` diff --git a/examples/CRISP/packages/crisp-sdk/package.json b/examples/CRISP/packages/crisp-sdk/package.json index 1d5ceb377d..f64cfd1330 100644 --- a/examples/CRISP/packages/crisp-sdk/package.json +++ b/examples/CRISP/packages/crisp-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@crisp-e3/sdk", - "version": "0.3.0-test", + "version": "0.4.1", "type": "module", "author": { "name": "gnosisguild", @@ -24,8 +24,7 @@ "compile:circuit": "cd ../../circuits && nargo compile", "build:wasm": "pnpm -C ../crisp-zk-inputs build", "build": "pnpm build:wasm && pnpm compile:circuit && tsup", - "test": "pnpm build:wasm && pnpm compile:circuit && vitest --run", - "release": "pnpm build && pnpm publish --access public" + "test": "pnpm build:wasm && pnpm compile:circuit && vitest --run" }, "publishConfig": { "access": "public" diff --git a/examples/CRISP/packages/crisp-sdk/src/ERC20Votes.json b/examples/CRISP/packages/crisp-sdk/src/ERC20Votes.json deleted file mode 100644 index 6f4ff6ff0a..0000000000 --- a/examples/CRISP/packages/crisp-sdk/src/ERC20Votes.json +++ /dev/null @@ -1,847 +0,0 @@ -{ - "abi": [ - { - "type": "function", - "name": "CLOCK_MODE", - "inputs": [], - "outputs": [{ "name": "", "type": "string", "internalType": "string" }], - "stateMutability": "view" - }, - { - "type": "function", - "name": "DOMAIN_SEPARATOR", - "inputs": [], - "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], - "stateMutability": "view" - }, - { - "type": "function", - "name": "allowance", - "inputs": [ - { "name": "owner", "type": "address", "internalType": "address" }, - { "name": "spender", "type": "address", "internalType": "address" } - ], - "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], - "stateMutability": "view" - }, - { - "type": "function", - "name": "approve", - "inputs": [ - { "name": "spender", "type": "address", "internalType": "address" }, - { "name": "amount", "type": "uint256", "internalType": "uint256" } - ], - "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "balanceOf", - "inputs": [{ "name": "account", "type": "address", "internalType": "address" }], - "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], - "stateMutability": "view" - }, - { - "type": "function", - "name": "checkpoints", - "inputs": [ - { "name": "account", "type": "address", "internalType": "address" }, - { "name": "pos", "type": "uint32", "internalType": "uint32" } - ], - "outputs": [ - { - "name": "", - "type": "tuple", - "internalType": "struct ERC20VotesUpgradeable.Checkpoint", - "components": [ - { "name": "fromBlock", "type": "uint32", "internalType": "uint32" }, - { "name": "votes", "type": "uint224", "internalType": "uint224" } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "clock", - "inputs": [], - "outputs": [{ "name": "", "type": "uint48", "internalType": "uint48" }], - "stateMutability": "view" - }, - { - "type": "function", - "name": "decimals", - "inputs": [], - "outputs": [{ "name": "", "type": "uint8", "internalType": "uint8" }], - "stateMutability": "view" - }, - { - "type": "function", - "name": "decreaseAllowance", - "inputs": [ - { "name": "spender", "type": "address", "internalType": "address" }, - { "name": "subtractedValue", "type": "uint256", "internalType": "uint256" } - ], - "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "delegate", - "inputs": [{ "name": "delegatee", "type": "address", "internalType": "address" }], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "delegateBySig", - "inputs": [ - { "name": "delegatee", "type": "address", "internalType": "address" }, - { "name": "nonce", "type": "uint256", "internalType": "uint256" }, - { "name": "expiry", "type": "uint256", "internalType": "uint256" }, - { "name": "v", "type": "uint8", "internalType": "uint8" }, - { "name": "r", "type": "bytes32", "internalType": "bytes32" }, - { "name": "s", "type": "bytes32", "internalType": "bytes32" } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "delegates", - "inputs": [{ "name": "account", "type": "address", "internalType": "address" }], - "outputs": [{ "name": "", "type": "address", "internalType": "address" }], - "stateMutability": "view" - }, - { - "type": "function", - "name": "eip712Domain", - "inputs": [], - "outputs": [ - { "name": "fields", "type": "bytes1", "internalType": "bytes1" }, - { "name": "name", "type": "string", "internalType": "string" }, - { "name": "version", "type": "string", "internalType": "string" }, - { "name": "chainId", "type": "uint256", "internalType": "uint256" }, - { "name": "verifyingContract", "type": "address", "internalType": "address" }, - { "name": "salt", "type": "bytes32", "internalType": "bytes32" }, - { "name": "extensions", "type": "uint256[]", "internalType": "uint256[]" } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getPastTotalSupply", - "inputs": [{ "name": "timepoint", "type": "uint256", "internalType": "uint256" }], - "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getPastVotes", - "inputs": [ - { "name": "account", "type": "address", "internalType": "address" }, - { "name": "timepoint", "type": "uint256", "internalType": "uint256" } - ], - "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getVotes", - "inputs": [{ "name": "account", "type": "address", "internalType": "address" }], - "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], - "stateMutability": "view" - }, - { - "type": "function", - "name": "increaseAllowance", - "inputs": [ - { "name": "spender", "type": "address", "internalType": "address" }, - { "name": "addedValue", "type": "uint256", "internalType": "uint256" } - ], - "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "name", - "inputs": [], - "outputs": [{ "name": "", "type": "string", "internalType": "string" }], - "stateMutability": "view" - }, - { - "type": "function", - "name": "nonces", - "inputs": [{ "name": "owner", "type": "address", "internalType": "address" }], - "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], - "stateMutability": "view" - }, - { - "type": "function", - "name": "numCheckpoints", - "inputs": [{ "name": "account", "type": "address", "internalType": "address" }], - "outputs": [{ "name": "", "type": "uint32", "internalType": "uint32" }], - "stateMutability": "view" - }, - { - "type": "function", - "name": "permit", - "inputs": [ - { "name": "owner", "type": "address", "internalType": "address" }, - { "name": "spender", "type": "address", "internalType": "address" }, - { "name": "value", "type": "uint256", "internalType": "uint256" }, - { "name": "deadline", "type": "uint256", "internalType": "uint256" }, - { "name": "v", "type": "uint8", "internalType": "uint8" }, - { "name": "r", "type": "bytes32", "internalType": "bytes32" }, - { "name": "s", "type": "bytes32", "internalType": "bytes32" } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "symbol", - "inputs": [], - "outputs": [{ "name": "", "type": "string", "internalType": "string" }], - "stateMutability": "view" - }, - { - "type": "function", - "name": "totalSupply", - "inputs": [], - "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], - "stateMutability": "view" - }, - { - "type": "function", - "name": "transfer", - "inputs": [ - { "name": "to", "type": "address", "internalType": "address" }, - { "name": "amount", "type": "uint256", "internalType": "uint256" } - ], - "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "transferFrom", - "inputs": [ - { "name": "from", "type": "address", "internalType": "address" }, - { "name": "to", "type": "address", "internalType": "address" }, - { "name": "amount", "type": "uint256", "internalType": "uint256" } - ], - "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], - "stateMutability": "nonpayable" - }, - { - "type": "event", - "name": "Approval", - "inputs": [ - { "name": "owner", "type": "address", "indexed": true, "internalType": "address" }, - { "name": "spender", "type": "address", "indexed": true, "internalType": "address" }, - { "name": "value", "type": "uint256", "indexed": false, "internalType": "uint256" } - ], - "anonymous": false - }, - { - "type": "event", - "name": "DelegateChanged", - "inputs": [ - { "name": "delegator", "type": "address", "indexed": true, "internalType": "address" }, - { "name": "fromDelegate", "type": "address", "indexed": true, "internalType": "address" }, - { "name": "toDelegate", "type": "address", "indexed": true, "internalType": "address" } - ], - "anonymous": false - }, - { - "type": "event", - "name": "DelegateVotesChanged", - "inputs": [ - { "name": "delegate", "type": "address", "indexed": true, "internalType": "address" }, - { "name": "previousBalance", "type": "uint256", "indexed": false, "internalType": "uint256" }, - { "name": "newBalance", "type": "uint256", "indexed": false, "internalType": "uint256" } - ], - "anonymous": false - }, - { "type": "event", "name": "EIP712DomainChanged", "inputs": [], "anonymous": false }, - { - "type": "event", - "name": "Initialized", - "inputs": [{ "name": "version", "type": "uint8", "indexed": false, "internalType": "uint8" }], - "anonymous": false - }, - { - "type": "event", - "name": "Transfer", - "inputs": [ - { "name": "from", "type": "address", "indexed": true, "internalType": "address" }, - { "name": "to", "type": "address", "indexed": true, "internalType": "address" }, - { "name": "value", "type": "uint256", "indexed": false, "internalType": "uint256" } - ], - "anonymous": false - } - ], - "bytecode": { "object": "0x", "sourceMap": "", "linkReferences": {} }, - "deployedBytecode": { "object": "0x", "sourceMap": "", "linkReferences": {} }, - "methodIdentifiers": { - "CLOCK_MODE()": "4bf5d7e9", - "DOMAIN_SEPARATOR()": "3644e515", - "allowance(address,address)": "dd62ed3e", - "approve(address,uint256)": "095ea7b3", - "balanceOf(address)": "70a08231", - "checkpoints(address,uint32)": "f1127ed8", - "clock()": "91ddadf4", - "decimals()": "313ce567", - "decreaseAllowance(address,uint256)": "a457c2d7", - "delegate(address)": "5c19a95c", - "delegateBySig(address,uint256,uint256,uint8,bytes32,bytes32)": "c3cda520", - "delegates(address)": "587cde1e", - "eip712Domain()": "84b0196e", - "getPastTotalSupply(uint256)": "8e539e8c", - "getPastVotes(address,uint256)": "3a46b1a8", - "getVotes(address)": "9ab24eb0", - "increaseAllowance(address,uint256)": "39509351", - "name()": "06fdde03", - "nonces(address)": "7ecebe00", - "numCheckpoints(address)": "6fcfff45", - "permit(address,address,uint256,uint256,uint8,bytes32,bytes32)": "d505accf", - "symbol()": "95d89b41", - "totalSupply()": "18160ddd", - "transfer(address,uint256)": "a9059cbb", - "transferFrom(address,address,uint256)": "23b872dd" - }, - "rawMetadata": "{\"compiler\":{\"version\":\"0.8.29+commit.ab55807c\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"delegator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"fromDelegate\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"toDelegate\",\"type\":\"address\"}],\"name\":\"DelegateChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"delegate\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"previousBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"DelegateVotesChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"EIP712DomainChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CLOCK_MODE\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"pos\",\"type\":\"uint32\"}],\"name\":\"checkpoints\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fromBlock\",\"type\":\"uint32\"},{\"internalType\":\"uint224\",\"name\":\"votes\",\"type\":\"uint224\"}],\"internalType\":\"struct ERC20VotesUpgradeable.Checkpoint\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"clock\",\"outputs\":[{\"internalType\":\"uint48\",\"name\":\"\",\"type\":\"uint48\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"delegatee\",\"type\":\"address\"}],\"name\":\"delegate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"delegatee\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"delegateBySig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"delegates\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"eip712Domain\",\"outputs\":[{\"internalType\":\"bytes1\",\"name\":\"fields\",\"type\":\"bytes1\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"version\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"verifyingContract\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"salt\",\"type\":\"bytes32\"},{\"internalType\":\"uint256[]\",\"name\":\"extensions\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timepoint\",\"type\":\"uint256\"}],\"name\":\"getPastTotalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"timepoint\",\"type\":\"uint256\"}],\"name\":\"getPastVotes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"getVotes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"numCheckpoints\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's, and supports token supply up to 2^224^ - 1, while COMP is limited to 2^96^ - 1. NOTE: If exact COMP compatibility is required, use the {ERC20VotesComp} variant of this module. This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting power can be queried through the public accessors {getVotes} and {getPastVotes}. By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked. _Available since v4.2._\",\"events\":{\"Approval(address,address,uint256)\":{\"details\":\"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance.\"},\"DelegateChanged(address,address,address)\":{\"details\":\"Emitted when an account changes their delegate.\"},\"DelegateVotesChanged(address,uint256,uint256)\":{\"details\":\"Emitted when a token transfer or delegate change results in changes to a delegate's number of votes.\"},\"EIP712DomainChanged()\":{\"details\":\"MAY be emitted to signal that the domain could have changed.\"},\"Initialized(uint8)\":{\"details\":\"Triggered when the contract has been initialized or reinitialized.\"},\"Transfer(address,address,uint256)\":{\"details\":\"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.\"}},\"kind\":\"dev\",\"methods\":{\"CLOCK_MODE()\":{\"details\":\"Description of the clock\"},\"DOMAIN_SEPARATOR()\":{\"details\":\"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\"},\"allowance(address,address)\":{\"details\":\"See {IERC20-allowance}.\"},\"approve(address,uint256)\":{\"details\":\"See {IERC20-approve}. NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on `transferFrom`. This is semantically equivalent to an infinite approval. Requirements: - `spender` cannot be the zero address.\"},\"balanceOf(address)\":{\"details\":\"See {IERC20-balanceOf}.\"},\"checkpoints(address,uint32)\":{\"details\":\"Get the `pos`-th checkpoint for `account`.\"},\"clock()\":{\"details\":\"Clock used for flagging checkpoints. Can be overridden to implement timestamp based checkpoints (and voting).\"},\"decimals()\":{\"details\":\"Returns the number of decimals used to get its user representation. For example, if `decimals` equals `2`, a balance of `505` tokens should be displayed to a user as `5.05` (`505 / 10 ** 2`). Tokens usually opt for a value of 18, imitating the relationship between Ether and Wei. This is the default value returned by this function, unless it's overridden. NOTE: This information is only used for _display_ purposes: it in no way affects any of the arithmetic of the contract, including {IERC20-balanceOf} and {IERC20-transfer}.\"},\"decreaseAllowance(address,uint256)\":{\"details\":\"Atomically decreases the allowance granted to `spender` by the caller. This is an alternative to {approve} that can be used as a mitigation for problems described in {IERC20-approve}. Emits an {Approval} event indicating the updated allowance. Requirements: - `spender` cannot be the zero address. - `spender` must have allowance for the caller of at least `subtractedValue`.\"},\"delegate(address)\":{\"details\":\"Delegate votes from the sender to `delegatee`.\"},\"delegateBySig(address,uint256,uint256,uint8,bytes32,bytes32)\":{\"details\":\"Delegates votes from signer to `delegatee`\"},\"delegates(address)\":{\"details\":\"Get the address `account` is currently delegating to.\"},\"eip712Domain()\":{\"details\":\"See {EIP-5267}. _Available since v4.9._\"},\"getPastTotalSupply(uint256)\":{\"details\":\"Retrieve the `totalSupply` at the end of `timepoint`. Note, this value is the sum of all balances. It is NOT the sum of all the delegated votes! Requirements: - `timepoint` must be in the past\"},\"getPastVotes(address,uint256)\":{\"details\":\"Retrieve the number of votes for `account` at the end of `timepoint`. Requirements: - `timepoint` must be in the past\"},\"getVotes(address)\":{\"details\":\"Gets the current votes balance for `account`\"},\"increaseAllowance(address,uint256)\":{\"details\":\"Atomically increases the allowance granted to `spender` by the caller. This is an alternative to {approve} that can be used as a mitigation for problems described in {IERC20-approve}. Emits an {Approval} event indicating the updated allowance. Requirements: - `spender` cannot be the zero address.\"},\"name()\":{\"details\":\"Returns the name of the token.\"},\"nonces(address)\":{\"details\":\"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times.\"},\"numCheckpoints(address)\":{\"details\":\"Get number of checkpoints for `account`.\"},\"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\":{\"details\":\"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above.\"},\"symbol()\":{\"details\":\"Returns the symbol of the token, usually a shorter version of the name.\"},\"totalSupply()\":{\"details\":\"See {IERC20-totalSupply}.\"},\"transfer(address,uint256)\":{\"details\":\"See {IERC20-transfer}. Requirements: - `to` cannot be the zero address. - the caller must have a balance of at least `amount`.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"See {IERC20-transferFrom}. Emits an {Approval} event indicating the updated allowance. This is not required by the EIP. See the note at the beginning of {ERC20}. NOTE: Does not update the allowance if the current allowance is the maximum `uint256`. Requirements: - `from` and `to` cannot be the zero address. - `from` must have a balance of at least `amount`. - the caller must have allowance for ``from``'s tokens of at least `amount`.\"}},\"stateVariables\":{\"__gap\":{\"details\":\"This empty reserved space is put in place to allow future versions to add new variables without shifting down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20VotesUpgradeable.sol\":\"ERC20VotesUpgradeable\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@aragon/osx-commons-contracts/=lib/osx-commons/contracts/\",\":@aragon/osx/=lib/osx/packages/contracts/src/\",\":@aragon/token-voting-plugin/=node_modules/@aragon/token-voting-plugin/src/\",\":@enclave-e3/contracts/=node_modules/@enclave-e3/contracts/\",\":@ensdomains/buffer/=lib/buffer/\",\":@ensdomains/ens-contracts/=lib/ens-contracts/\",\":@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/\",\":ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/\",\":ens-contracts/=lib/ens-contracts/contracts/\",\":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\",\":openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":osx-commons/=lib/osx-commons/\",\":osx/=lib/osx/\"]},\"sources\":{\"lib/openzeppelin-contracts-upgradeable/contracts/governance/utils/IVotesUpgradeable.sol\":{\"keccak256\":\"0x2d600bbef9320309cd2a86c1d087eb9d6dbcc00430713ee54bbc5c5a2a11ba31\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://52a5380b861d676adef15f33f8f643e236a1acb2d9456beb4065307eaa22bc2a\",\"dweb:/ipfs/QmdwSfxrafQubVvCoQCU5T7bbPR8JDWU1WotSDXSiUdm33\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC5267Upgradeable.sol\":{\"keccak256\":\"0xe562dab443278837fa50faddb76743399e942181881db8dccaea3bd1712994db\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://79ebe0e661396045cefe94f4256398cf632756d779a6871319db374c9eb128c9\",\"dweb:/ipfs/QmfCTCivb9fFhyCX8hzushzcKunvKL2N9RDsnRNdvbd11M\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC5805Upgradeable.sol\":{\"keccak256\":\"0x19848eec9045c8b91f1ab6b1853966443e3e36bcbc307593ed37a9f0df179d69\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://a07972c1330ee99a5d051b393260e01412ac4c14c7bc4d75d80b7cce291a6412\",\"dweb:/ipfs/QmQx1ZiAo4AbSobN41c1xUEtyX1QejydWCmY7Sj3H5aDNv\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC6372Upgradeable.sol\":{\"keccak256\":\"0x3026befd6d69d1b46960bdc35a2ad37c0e1352f26983ee3728dd61fd32aa308a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c2001b7209fd4920ec7674f194db7fe163dfea7a7af2dd25fe6c0e5a94dc595c\",\"dweb:/ipfs/QmXX2zTFyiNWoDxivV3trKcKWifAENMqNAB34NgjWq5feX\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol\":{\"keccak256\":\"0x89be10e757d242e9b18d5a32c9fbe2019f6d63052bbe46397a430a1d60d7f794\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://f103ee2e4aecd37aac6ceefe670709cdd7613dee25fa2d4d9feaf7fc0aaa155e\",\"dweb:/ipfs/QmRiNZLoJk5k3HPMYGPGjZFd2ke1ZxjhJZkM45Ec9GH9hv\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol\":{\"keccak256\":\"0xa9311aeb22f459e57d4dac77ee76cf43fb28ad3215278456211b5852b0e9e970\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ebdf0d3e42bd25223e45a213311d6d7e177d56a2c541a78b58c0c9d10bbdfbf9\",\"dweb:/ipfs/QmfMyehJ6pxHrh7yL4793J6i7dofXnS2zH3cTtC8JdQMV9\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/IERC20Upgradeable.sol\":{\"keccak256\":\"0x0e1f0f5f62f67a881cd1a9597acbc0a5e4071f3c2c10449a183b922ae7272e3f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c25f742ff154998d19a669e2508c3597b363e123ce9144cd0fcf6521229f401f\",\"dweb:/ipfs/QmQXRuFzStEWqeEPbhQU6cAg9PaSowxJVo4PDKyRod7dco\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20PermitUpgradeable.sol\":{\"keccak256\":\"0x3d159b9049d4ef465c1fb41f7ff7620f18f52bf6f8f3018bae4ed95c2df537d3\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://38f7cfa624d878eec3c97e30dac64c6c00a79c65aa2799cebbf683e74488cd27\",\"dweb:/ipfs/QmdtMH3xSGXNqvBcndsxWCUfmjta6kebnUYwKasJZucTfP\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20VotesUpgradeable.sol\":{\"keccak256\":\"0x82d5c2e8d5c7209f5cd2e7a40807ba264cb8bc577db1b121eda5f14f62d609c2\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://024b99222ec16e75ff1b719c8f0dacf2d8e26250b3c076bd184ac1dadae47492\",\"dweb:/ipfs/QmP11f3Dumw3CYg4ZtBLJrh8juULgodSuQfCqqgX5DqpJE\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\":{\"keccak256\":\"0x605434219ebbe4653f703640f06969faa5a1d78f0bfef878e5ddbb1ca369ceeb\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://4c9c634f99dd02d73ce7498b03a6305e251c05eeebb71457306561c1fab0fa7d\",\"dweb:/ipfs/QmbYRBbZHy8YoaQKXdPryiL3CSS7uUaRfRYi1TUj9cTqJQ\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/IERC20PermitUpgradeable.sol\":{\"keccak256\":\"0x07e881de3b9f6d2c07909f193f24b96c7fe4ea60013260f3f25aecd8bab3c2f8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://1fed09b97ccb0ff9ba9b6a94224f1d489026bf6b4b7279bfe64fb6e8749dee4d\",\"dweb:/ipfs/QmcRAzaSP1UnGr4vrGkfJmB2L9aiTYoXfV1Lg9gqrVRWn8\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/AddressUpgradeable.sol\":{\"keccak256\":\"0x9c80f545915582e63fe206c6ce27cbe85a86fc10b9cd2a0e8c9488fb7c2ee422\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://310136ad60820af4177a11a61d77a3686faf5fca4942b600e08fc940db38396b\",\"dweb:/ipfs/QmbCzMNSTL7Zi7M4UCSqBrkHtp4jjxUnGbkneCZKdR1qeq\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol\":{\"keccak256\":\"0x75097e35253e7fb282ee4d7f27a80eaacfa759923185bf17302a89cbc059c5ef\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://8b06267c5f80bad727af3e48b1382333d591dad51376399ef2f6b0ee6d58bf95\",\"dweb:/ipfs/QmdU5La1agcQvghnfMpWZGDPz2TUDTCxUwTLKmuMRXBpAx\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/CountersUpgradeable.sol\":{\"keccak256\":\"0x798741e231b22b81e2dd2eddaaf8832dee4baf5cd8e2dbaa5c1dd12a1c053c4d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c41e8a7a906b8f362c8b760a44edadc61782008ea2ecf377ac5b5325bf6c3912\",\"dweb:/ipfs/QmcXr19zuH3YLzD6RZNE6UTzvsKSckdxZQnagPoDGkCHu2\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/StringsUpgradeable.sol\":{\"keccak256\":\"0xb96dc79b65b7c37937919dcdb356a969ce0aa2e8338322bf4dc027a3c9c9a7eb\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://f8613145881436fc0480fff22da4868d611e2b0c0c3da083334eb4362ce1945a\",\"dweb:/ipfs/QmPqpP3YeRbBdTJRe6Gv2eGsUaANf4J6RwTNRW36iYahfV\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/cryptography/ECDSAUpgradeable.sol\":{\"keccak256\":\"0xa014f65d84b02827055d99993ccdbfb4b56b2c9e91eb278d82a93330659d06e4\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://50a7e716a74f3d48a7f549086faa94afcd58b9f18ac8e9f74af4571f3a1d8d5c\",\"dweb:/ipfs/QmTkDNWkq5o9Cv2jS7s6JvSmsPBkeunZhPe7Z2njGL31wo\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/cryptography/EIP712Upgradeable.sol\":{\"keccak256\":\"0x7077d7f3369b21f286840c0d69b09a8a6d3d6e522fff67bfc240fd0a6cdf178c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0f59e7a19530bd6ee236285f9a87c930d27b73464f6b7398e29a6f4cfc2670ac\",\"dweb:/ipfs/QmVfN4gHvJNac7KiuhLhtgtbdDo5a6Mw5hMcwJkzYugq5R\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/math/MathUpgradeable.sol\":{\"keccak256\":\"0x2bc0007987c229ae7624eb29be6a9b84f6a6a5872f76248b15208b131ea41c4e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://2b2835c737d073ef8b82a4cc246495a9740f43e7ff2cf130906b2449ff9bfb91\",\"dweb:/ipfs/QmSCWfNoSvvTN57ic7o1RW6NqSxxGAqbBTnLKc7QHe27qB\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/math/SafeCastUpgradeable.sol\":{\"keccak256\":\"0xcef50f95b43b038aa40aed25b62fc45906c681a5c1d504a4fdcf3bc6330a8d4b\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ef883699a00970d5469e502514e2854704cd53d7a49825078aa807a2f056315c\",\"dweb:/ipfs/QmRjpN9oxgw6zHCVjfWNB9MzaYpNPPgqu7Rrwqwabmhpis\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/math/SignedMathUpgradeable.sol\":{\"keccak256\":\"0x88f6b7bba3ee33eeb741f9a0f5bc98b6e6e352d0fe4905377bb328590f84095a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://88ace2d60f265752f18903d839910be4e4e104340b2957678585b812447825d4\",\"dweb:/ipfs/QmXFkNxMc3AAGzhs2wUEZyErWQjsvoTGyYjuU5oZkFki5Z\"]}},\"version\":1}", - "metadata": { - "compiler": { "version": "0.8.29+commit.ab55807c" }, - "language": "Solidity", - "output": { - "abi": [ - { - "inputs": [ - { "internalType": "address", "name": "owner", "type": "address", "indexed": true }, - { "internalType": "address", "name": "spender", "type": "address", "indexed": true }, - { "internalType": "uint256", "name": "value", "type": "uint256", "indexed": false } - ], - "type": "event", - "name": "Approval", - "anonymous": false - }, - { - "inputs": [ - { "internalType": "address", "name": "delegator", "type": "address", "indexed": true }, - { "internalType": "address", "name": "fromDelegate", "type": "address", "indexed": true }, - { "internalType": "address", "name": "toDelegate", "type": "address", "indexed": true } - ], - "type": "event", - "name": "DelegateChanged", - "anonymous": false - }, - { - "inputs": [ - { "internalType": "address", "name": "delegate", "type": "address", "indexed": true }, - { "internalType": "uint256", "name": "previousBalance", "type": "uint256", "indexed": false }, - { "internalType": "uint256", "name": "newBalance", "type": "uint256", "indexed": false } - ], - "type": "event", - "name": "DelegateVotesChanged", - "anonymous": false - }, - { "inputs": [], "type": "event", "name": "EIP712DomainChanged", "anonymous": false }, - { - "inputs": [{ "internalType": "uint8", "name": "version", "type": "uint8", "indexed": false }], - "type": "event", - "name": "Initialized", - "anonymous": false - }, - { - "inputs": [ - { "internalType": "address", "name": "from", "type": "address", "indexed": true }, - { "internalType": "address", "name": "to", "type": "address", "indexed": true }, - { "internalType": "uint256", "name": "value", "type": "uint256", "indexed": false } - ], - "type": "event", - "name": "Transfer", - "anonymous": false - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "CLOCK_MODE", - "outputs": [{ "internalType": "string", "name": "", "type": "string" }] - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "DOMAIN_SEPARATOR", - "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }] - }, - { - "inputs": [ - { "internalType": "address", "name": "owner", "type": "address" }, - { "internalType": "address", "name": "spender", "type": "address" } - ], - "stateMutability": "view", - "type": "function", - "name": "allowance", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }] - }, - { - "inputs": [ - { "internalType": "address", "name": "spender", "type": "address" }, - { "internalType": "uint256", "name": "amount", "type": "uint256" } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "approve", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }] - }, - { - "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], - "stateMutability": "view", - "type": "function", - "name": "balanceOf", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }] - }, - { - "inputs": [ - { "internalType": "address", "name": "account", "type": "address" }, - { "internalType": "uint32", "name": "pos", "type": "uint32" } - ], - "stateMutability": "view", - "type": "function", - "name": "checkpoints", - "outputs": [ - { - "internalType": "struct ERC20VotesUpgradeable.Checkpoint", - "name": "", - "type": "tuple", - "components": [ - { "internalType": "uint32", "name": "fromBlock", "type": "uint32" }, - { "internalType": "uint224", "name": "votes", "type": "uint224" } - ] - } - ] - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "clock", - "outputs": [{ "internalType": "uint48", "name": "", "type": "uint48" }] - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "decimals", - "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }] - }, - { - "inputs": [ - { "internalType": "address", "name": "spender", "type": "address" }, - { "internalType": "uint256", "name": "subtractedValue", "type": "uint256" } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "decreaseAllowance", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }] - }, - { - "inputs": [{ "internalType": "address", "name": "delegatee", "type": "address" }], - "stateMutability": "nonpayable", - "type": "function", - "name": "delegate" - }, - { - "inputs": [ - { "internalType": "address", "name": "delegatee", "type": "address" }, - { "internalType": "uint256", "name": "nonce", "type": "uint256" }, - { "internalType": "uint256", "name": "expiry", "type": "uint256" }, - { "internalType": "uint8", "name": "v", "type": "uint8" }, - { "internalType": "bytes32", "name": "r", "type": "bytes32" }, - { "internalType": "bytes32", "name": "s", "type": "bytes32" } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "delegateBySig" - }, - { - "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], - "stateMutability": "view", - "type": "function", - "name": "delegates", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }] - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "eip712Domain", - "outputs": [ - { "internalType": "bytes1", "name": "fields", "type": "bytes1" }, - { "internalType": "string", "name": "name", "type": "string" }, - { "internalType": "string", "name": "version", "type": "string" }, - { "internalType": "uint256", "name": "chainId", "type": "uint256" }, - { "internalType": "address", "name": "verifyingContract", "type": "address" }, - { "internalType": "bytes32", "name": "salt", "type": "bytes32" }, - { "internalType": "uint256[]", "name": "extensions", "type": "uint256[]" } - ] - }, - { - "inputs": [{ "internalType": "uint256", "name": "timepoint", "type": "uint256" }], - "stateMutability": "view", - "type": "function", - "name": "getPastTotalSupply", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }] - }, - { - "inputs": [ - { "internalType": "address", "name": "account", "type": "address" }, - { "internalType": "uint256", "name": "timepoint", "type": "uint256" } - ], - "stateMutability": "view", - "type": "function", - "name": "getPastVotes", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }] - }, - { - "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], - "stateMutability": "view", - "type": "function", - "name": "getVotes", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }] - }, - { - "inputs": [ - { "internalType": "address", "name": "spender", "type": "address" }, - { "internalType": "uint256", "name": "addedValue", "type": "uint256" } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "increaseAllowance", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }] - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "name", - "outputs": [{ "internalType": "string", "name": "", "type": "string" }] - }, - { - "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }], - "stateMutability": "view", - "type": "function", - "name": "nonces", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }] - }, - { - "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], - "stateMutability": "view", - "type": "function", - "name": "numCheckpoints", - "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }] - }, - { - "inputs": [ - { "internalType": "address", "name": "owner", "type": "address" }, - { "internalType": "address", "name": "spender", "type": "address" }, - { "internalType": "uint256", "name": "value", "type": "uint256" }, - { "internalType": "uint256", "name": "deadline", "type": "uint256" }, - { "internalType": "uint8", "name": "v", "type": "uint8" }, - { "internalType": "bytes32", "name": "r", "type": "bytes32" }, - { "internalType": "bytes32", "name": "s", "type": "bytes32" } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "permit" - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "symbol", - "outputs": [{ "internalType": "string", "name": "", "type": "string" }] - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "totalSupply", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }] - }, - { - "inputs": [ - { "internalType": "address", "name": "to", "type": "address" }, - { "internalType": "uint256", "name": "amount", "type": "uint256" } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "transfer", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }] - }, - { - "inputs": [ - { "internalType": "address", "name": "from", "type": "address" }, - { "internalType": "address", "name": "to", "type": "address" }, - { "internalType": "uint256", "name": "amount", "type": "uint256" } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "transferFrom", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }] - } - ], - "devdoc": { - "kind": "dev", - "methods": { - "CLOCK_MODE()": { "details": "Description of the clock" }, - "DOMAIN_SEPARATOR()": { - "details": "Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}." - }, - "allowance(address,address)": { "details": "See {IERC20-allowance}." }, - "approve(address,uint256)": { - "details": "See {IERC20-approve}. NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on `transferFrom`. This is semantically equivalent to an infinite approval. Requirements: - `spender` cannot be the zero address." - }, - "balanceOf(address)": { "details": "See {IERC20-balanceOf}." }, - "checkpoints(address,uint32)": { "details": "Get the `pos`-th checkpoint for `account`." }, - "clock()": { - "details": "Clock used for flagging checkpoints. Can be overridden to implement timestamp based checkpoints (and voting)." - }, - "decimals()": { - "details": "Returns the number of decimals used to get its user representation. For example, if `decimals` equals `2`, a balance of `505` tokens should be displayed to a user as `5.05` (`505 / 10 ** 2`). Tokens usually opt for a value of 18, imitating the relationship between Ether and Wei. This is the default value returned by this function, unless it's overridden. NOTE: This information is only used for _display_ purposes: it in no way affects any of the arithmetic of the contract, including {IERC20-balanceOf} and {IERC20-transfer}." - }, - "decreaseAllowance(address,uint256)": { - "details": "Atomically decreases the allowance granted to `spender` by the caller. This is an alternative to {approve} that can be used as a mitigation for problems described in {IERC20-approve}. Emits an {Approval} event indicating the updated allowance. Requirements: - `spender` cannot be the zero address. - `spender` must have allowance for the caller of at least `subtractedValue`." - }, - "delegate(address)": { "details": "Delegate votes from the sender to `delegatee`." }, - "delegateBySig(address,uint256,uint256,uint8,bytes32,bytes32)": { "details": "Delegates votes from signer to `delegatee`" }, - "delegates(address)": { "details": "Get the address `account` is currently delegating to." }, - "eip712Domain()": { "details": "See {EIP-5267}. _Available since v4.9._" }, - "getPastTotalSupply(uint256)": { - "details": "Retrieve the `totalSupply` at the end of `timepoint`. Note, this value is the sum of all balances. It is NOT the sum of all the delegated votes! Requirements: - `timepoint` must be in the past" - }, - "getPastVotes(address,uint256)": { - "details": "Retrieve the number of votes for `account` at the end of `timepoint`. Requirements: - `timepoint` must be in the past" - }, - "getVotes(address)": { "details": "Gets the current votes balance for `account`" }, - "increaseAllowance(address,uint256)": { - "details": "Atomically increases the allowance granted to `spender` by the caller. This is an alternative to {approve} that can be used as a mitigation for problems described in {IERC20-approve}. Emits an {Approval} event indicating the updated allowance. Requirements: - `spender` cannot be the zero address." - }, - "name()": { "details": "Returns the name of the token." }, - "nonces(address)": { - "details": "Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times." - }, - "numCheckpoints(address)": { "details": "Get number of checkpoints for `account`." }, - "permit(address,address,uint256,uint256,uint8,bytes32,bytes32)": { - "details": "Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above." - }, - "symbol()": { "details": "Returns the symbol of the token, usually a shorter version of the name." }, - "totalSupply()": { "details": "See {IERC20-totalSupply}." }, - "transfer(address,uint256)": { - "details": "See {IERC20-transfer}. Requirements: - `to` cannot be the zero address. - the caller must have a balance of at least `amount`." - }, - "transferFrom(address,address,uint256)": { - "details": "See {IERC20-transferFrom}. Emits an {Approval} event indicating the updated allowance. This is not required by the EIP. See the note at the beginning of {ERC20}. NOTE: Does not update the allowance if the current allowance is the maximum `uint256`. Requirements: - `from` and `to` cannot be the zero address. - `from` must have a balance of at least `amount`. - the caller must have allowance for ``from``'s tokens of at least `amount`." - } - }, - "version": 1 - }, - "userdoc": { "kind": "user", "methods": {}, "version": 1 } - }, - "settings": { - "remappings": [ - "@aragon/osx-commons-contracts/=lib/osx-commons/contracts/", - "@aragon/osx/=lib/osx/packages/contracts/src/", - "@aragon/token-voting-plugin/=node_modules/@aragon/token-voting-plugin/src/", - "@enclave-e3/contracts/=node_modules/@enclave-e3/contracts/", - "@ensdomains/buffer/=lib/buffer/", - "@ensdomains/ens-contracts/=lib/ens-contracts/", - "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", - "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", - "ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/", - "ens-contracts/=lib/ens-contracts/contracts/", - "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", - "forge-std/=lib/forge-std/src/", - "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", - "openzeppelin-contracts/=lib/openzeppelin-contracts/", - "openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/", - "osx-commons/=lib/osx-commons/", - "osx/=lib/osx/" - ], - "optimizer": { "enabled": true, "runs": 200 }, - "metadata": { "bytecodeHash": "ipfs" }, - "compilationTarget": { - "lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20VotesUpgradeable.sol": "ERC20VotesUpgradeable" - }, - "evmVersion": "cancun", - "libraries": {} - }, - "sources": { - "lib/openzeppelin-contracts-upgradeable/contracts/governance/utils/IVotesUpgradeable.sol": { - "keccak256": "0x2d600bbef9320309cd2a86c1d087eb9d6dbcc00430713ee54bbc5c5a2a11ba31", - "urls": [ - "bzz-raw://52a5380b861d676adef15f33f8f643e236a1acb2d9456beb4065307eaa22bc2a", - "dweb:/ipfs/QmdwSfxrafQubVvCoQCU5T7bbPR8JDWU1WotSDXSiUdm33" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC5267Upgradeable.sol": { - "keccak256": "0xe562dab443278837fa50faddb76743399e942181881db8dccaea3bd1712994db", - "urls": [ - "bzz-raw://79ebe0e661396045cefe94f4256398cf632756d779a6871319db374c9eb128c9", - "dweb:/ipfs/QmfCTCivb9fFhyCX8hzushzcKunvKL2N9RDsnRNdvbd11M" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC5805Upgradeable.sol": { - "keccak256": "0x19848eec9045c8b91f1ab6b1853966443e3e36bcbc307593ed37a9f0df179d69", - "urls": [ - "bzz-raw://a07972c1330ee99a5d051b393260e01412ac4c14c7bc4d75d80b7cce291a6412", - "dweb:/ipfs/QmQx1ZiAo4AbSobN41c1xUEtyX1QejydWCmY7Sj3H5aDNv" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC6372Upgradeable.sol": { - "keccak256": "0x3026befd6d69d1b46960bdc35a2ad37c0e1352f26983ee3728dd61fd32aa308a", - "urls": [ - "bzz-raw://c2001b7209fd4920ec7674f194db7fe163dfea7a7af2dd25fe6c0e5a94dc595c", - "dweb:/ipfs/QmXX2zTFyiNWoDxivV3trKcKWifAENMqNAB34NgjWq5feX" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol": { - "keccak256": "0x89be10e757d242e9b18d5a32c9fbe2019f6d63052bbe46397a430a1d60d7f794", - "urls": [ - "bzz-raw://f103ee2e4aecd37aac6ceefe670709cdd7613dee25fa2d4d9feaf7fc0aaa155e", - "dweb:/ipfs/QmRiNZLoJk5k3HPMYGPGjZFd2ke1ZxjhJZkM45Ec9GH9hv" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol": { - "keccak256": "0xa9311aeb22f459e57d4dac77ee76cf43fb28ad3215278456211b5852b0e9e970", - "urls": [ - "bzz-raw://ebdf0d3e42bd25223e45a213311d6d7e177d56a2c541a78b58c0c9d10bbdfbf9", - "dweb:/ipfs/QmfMyehJ6pxHrh7yL4793J6i7dofXnS2zH3cTtC8JdQMV9" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/IERC20Upgradeable.sol": { - "keccak256": "0x0e1f0f5f62f67a881cd1a9597acbc0a5e4071f3c2c10449a183b922ae7272e3f", - "urls": [ - "bzz-raw://c25f742ff154998d19a669e2508c3597b363e123ce9144cd0fcf6521229f401f", - "dweb:/ipfs/QmQXRuFzStEWqeEPbhQU6cAg9PaSowxJVo4PDKyRod7dco" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20PermitUpgradeable.sol": { - "keccak256": "0x3d159b9049d4ef465c1fb41f7ff7620f18f52bf6f8f3018bae4ed95c2df537d3", - "urls": [ - "bzz-raw://38f7cfa624d878eec3c97e30dac64c6c00a79c65aa2799cebbf683e74488cd27", - "dweb:/ipfs/QmdtMH3xSGXNqvBcndsxWCUfmjta6kebnUYwKasJZucTfP" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20VotesUpgradeable.sol": { - "keccak256": "0x82d5c2e8d5c7209f5cd2e7a40807ba264cb8bc577db1b121eda5f14f62d609c2", - "urls": [ - "bzz-raw://024b99222ec16e75ff1b719c8f0dacf2d8e26250b3c076bd184ac1dadae47492", - "dweb:/ipfs/QmP11f3Dumw3CYg4ZtBLJrh8juULgodSuQfCqqgX5DqpJE" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol": { - "keccak256": "0x605434219ebbe4653f703640f06969faa5a1d78f0bfef878e5ddbb1ca369ceeb", - "urls": [ - "bzz-raw://4c9c634f99dd02d73ce7498b03a6305e251c05eeebb71457306561c1fab0fa7d", - "dweb:/ipfs/QmbYRBbZHy8YoaQKXdPryiL3CSS7uUaRfRYi1TUj9cTqJQ" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/IERC20PermitUpgradeable.sol": { - "keccak256": "0x07e881de3b9f6d2c07909f193f24b96c7fe4ea60013260f3f25aecd8bab3c2f8", - "urls": [ - "bzz-raw://1fed09b97ccb0ff9ba9b6a94224f1d489026bf6b4b7279bfe64fb6e8749dee4d", - "dweb:/ipfs/QmcRAzaSP1UnGr4vrGkfJmB2L9aiTYoXfV1Lg9gqrVRWn8" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/contracts/utils/AddressUpgradeable.sol": { - "keccak256": "0x9c80f545915582e63fe206c6ce27cbe85a86fc10b9cd2a0e8c9488fb7c2ee422", - "urls": [ - "bzz-raw://310136ad60820af4177a11a61d77a3686faf5fca4942b600e08fc940db38396b", - "dweb:/ipfs/QmbCzMNSTL7Zi7M4UCSqBrkHtp4jjxUnGbkneCZKdR1qeq" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol": { - "keccak256": "0x75097e35253e7fb282ee4d7f27a80eaacfa759923185bf17302a89cbc059c5ef", - "urls": [ - "bzz-raw://8b06267c5f80bad727af3e48b1382333d591dad51376399ef2f6b0ee6d58bf95", - "dweb:/ipfs/QmdU5La1agcQvghnfMpWZGDPz2TUDTCxUwTLKmuMRXBpAx" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/contracts/utils/CountersUpgradeable.sol": { - "keccak256": "0x798741e231b22b81e2dd2eddaaf8832dee4baf5cd8e2dbaa5c1dd12a1c053c4d", - "urls": [ - "bzz-raw://c41e8a7a906b8f362c8b760a44edadc61782008ea2ecf377ac5b5325bf6c3912", - "dweb:/ipfs/QmcXr19zuH3YLzD6RZNE6UTzvsKSckdxZQnagPoDGkCHu2" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/contracts/utils/StringsUpgradeable.sol": { - "keccak256": "0xb96dc79b65b7c37937919dcdb356a969ce0aa2e8338322bf4dc027a3c9c9a7eb", - "urls": [ - "bzz-raw://f8613145881436fc0480fff22da4868d611e2b0c0c3da083334eb4362ce1945a", - "dweb:/ipfs/QmPqpP3YeRbBdTJRe6Gv2eGsUaANf4J6RwTNRW36iYahfV" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/contracts/utils/cryptography/ECDSAUpgradeable.sol": { - "keccak256": "0xa014f65d84b02827055d99993ccdbfb4b56b2c9e91eb278d82a93330659d06e4", - "urls": [ - "bzz-raw://50a7e716a74f3d48a7f549086faa94afcd58b9f18ac8e9f74af4571f3a1d8d5c", - "dweb:/ipfs/QmTkDNWkq5o9Cv2jS7s6JvSmsPBkeunZhPe7Z2njGL31wo" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/contracts/utils/cryptography/EIP712Upgradeable.sol": { - "keccak256": "0x7077d7f3369b21f286840c0d69b09a8a6d3d6e522fff67bfc240fd0a6cdf178c", - "urls": [ - "bzz-raw://0f59e7a19530bd6ee236285f9a87c930d27b73464f6b7398e29a6f4cfc2670ac", - "dweb:/ipfs/QmVfN4gHvJNac7KiuhLhtgtbdDo5a6Mw5hMcwJkzYugq5R" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/contracts/utils/math/MathUpgradeable.sol": { - "keccak256": "0x2bc0007987c229ae7624eb29be6a9b84f6a6a5872f76248b15208b131ea41c4e", - "urls": [ - "bzz-raw://2b2835c737d073ef8b82a4cc246495a9740f43e7ff2cf130906b2449ff9bfb91", - "dweb:/ipfs/QmSCWfNoSvvTN57ic7o1RW6NqSxxGAqbBTnLKc7QHe27qB" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/contracts/utils/math/SafeCastUpgradeable.sol": { - "keccak256": "0xcef50f95b43b038aa40aed25b62fc45906c681a5c1d504a4fdcf3bc6330a8d4b", - "urls": [ - "bzz-raw://ef883699a00970d5469e502514e2854704cd53d7a49825078aa807a2f056315c", - "dweb:/ipfs/QmRjpN9oxgw6zHCVjfWNB9MzaYpNPPgqu7Rrwqwabmhpis" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/contracts/utils/math/SignedMathUpgradeable.sol": { - "keccak256": "0x88f6b7bba3ee33eeb741f9a0f5bc98b6e6e352d0fe4905377bb328590f84095a", - "urls": [ - "bzz-raw://88ace2d60f265752f18903d839910be4e4e104340b2957678585b812447825d4", - "dweb:/ipfs/QmXFkNxMc3AAGzhs2wUEZyErWQjsvoTGyYjuU5oZkFki5Z" - ], - "license": "MIT" - } - }, - "version": 1 - }, - "id": 48 -} diff --git a/examples/CRISP/packages/crisp-sdk/src/constants.ts b/examples/CRISP/packages/crisp-sdk/src/constants.ts index 1e42bc9b24..5300bd72c4 100644 --- a/examples/CRISP/packages/crisp-sdk/src/constants.ts +++ b/examples/CRISP/packages/crisp-sdk/src/constants.ts @@ -4,6 +4,8 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. +import { hashMessage } from 'viem' + export const CRISP_SERVER_TOKEN_TREE_ENDPOINT = 'state/token-holders' export const CRISP_SERVER_STATE_LITE_ENDPOINT = 'state/lite' @@ -22,6 +24,12 @@ export const HALF_LARGEST_MINIMUM_DEGREE = 28 export const MAXIMUM_VOTE_VALUE = BigInt(Math.pow(2, HALF_LARGEST_MINIMUM_DEGREE) - 1) /** - * Mock message for masking signature + * Message used by users to prove ownership of their Ethereum account + * This message is signed by the user's private key to authenticate their identity */ -export const MESSAGE = 'Vote for round 0' +export const SIGNATURE_MESSAGE = 'CRISP: Sign this message to prove ownership of your Ethereum account' +export const SIGNATURE_MESSAGE_HASH = hashMessage(SIGNATURE_MESSAGE) + +// Placeholder signature for masking votes. +export const MASK_SIGNATURE = + '0x8e7d77112641d59e9409ec3052041703bb9d9e6ed39bfcf75aefbcafe829ac6b21dd7648116ad5db0466fcb4bd468dcb28f6c069def8bc47cd9d859c85a016e31b' diff --git a/examples/CRISP/packages/crisp-sdk/src/index.ts b/examples/CRISP/packages/crisp-sdk/src/index.ts index 90506ac327..b121af9a15 100644 --- a/examples/CRISP/packages/crisp-sdk/src/index.ts +++ b/examples/CRISP/packages/crisp-sdk/src/index.ts @@ -6,18 +6,16 @@ export * from './token' export * from './state' -export * from './constants' -export * from './utils' -export * from './vote' -export * from './signature' +export { MERKLE_TREE_MAX_DEPTH, SIGNATURE_MESSAGE, MAXIMUM_VOTE_VALUE } from './constants' +export { hashLeaf, generateMerkleProof, generateMerkleTree, getAddressFromSignature } from './utils' +export { + decodeTally, + generateVoteProof, + generateMaskVoteProof, + verifyProof, + generatePublicKey, + encryptVote, + encodeSolidityProof, +} from './vote' -export { VotingMode } from './types' -export type { - IRoundDetails, - IRoundDetailsResponse, - ITokenDetails, - IMerkleProof, - IVote, - CRISPCircuitInputs, - NoirSignatureInputs, -} from './types' +export type { RoundDetails, RoundDetailsResponse, TokenDetails, Vote, MaskVoteProofInputs, VoteProofInputs } from './types' diff --git a/examples/CRISP/packages/crisp-sdk/src/signature.ts b/examples/CRISP/packages/crisp-sdk/src/signature.ts deleted file mode 100644 index d0351af1b3..0000000000 --- a/examples/CRISP/packages/crisp-sdk/src/signature.ts +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -// -// This file is provided WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. - -import type { NoirSignatureInputs } from './types' - -import { hashMessage, hexToBytes, recoverPublicKey } from 'viem' - -/** - * Given a message and its signed version, extract the signature components - * @param message The original message - * @param signedMessage The signed message (signature) - * @returns The extracted signature components - */ -export const extractSignature = async (message: string, signedMessage: `0x${string}`): Promise => { - const messageHash = hashMessage(message) - const messageBytes = hexToBytes(messageHash) - - const publicKey = await recoverPublicKey({ - hash: messageHash, - signature: signedMessage, - }) - - const publicKeyBytes = hexToBytes(publicKey) - const publicKeyX = publicKeyBytes.slice(1, 33) - const publicKeyY = publicKeyBytes.slice(33, 65) - - // Extract r and s from signature (remove v) - const sigBytes = hexToBytes(signedMessage) - const r = sigBytes.slice(0, 32) // First 32 bytes - const s = sigBytes.slice(32, 64) // Next 32 bytes - - const signatureBytes = new Uint8Array(64) - signatureBytes.set(r, 0) - signatureBytes.set(s, 32) - - return { - hashed_message: messageBytes, - pub_key_x: publicKeyX, - pub_key_y: publicKeyY, - signature: signatureBytes, - } -} diff --git a/examples/CRISP/packages/crisp-sdk/src/state.ts b/examples/CRISP/packages/crisp-sdk/src/state.ts index 3a926121e6..c9d4581605 100644 --- a/examples/CRISP/packages/crisp-sdk/src/state.ts +++ b/examples/CRISP/packages/crisp-sdk/src/state.ts @@ -6,12 +6,12 @@ import { CRISP_SERVER_STATE_LITE_ENDPOINT } from './constants' -import type { IRoundDetailsResponse, IRoundDetails, ITokenDetails } from './types' +import type { RoundDetailsResponse, RoundDetails, TokenDetails } from './types' /** * Get the details of a specific round */ -export const getRoundDetails = async (serverUrl: string, e3Id: number): Promise => { +export const getRoundDetails = async (serverUrl: string, e3Id: number): Promise => { const response = await fetch(`${serverUrl}/${CRISP_SERVER_STATE_LITE_ENDPOINT}`, { method: 'POST', headers: { @@ -20,7 +20,7 @@ export const getRoundDetails = async (serverUrl: string, e3Id: number): Promise< body: JSON.stringify({ round_id: e3Id }), }) - const data = (await response.json()) as IRoundDetailsResponse + const data = (await response.json()) as RoundDetailsResponse return { e3Id: BigInt(data.id), @@ -45,7 +45,7 @@ export const getRoundDetails = async (serverUrl: string, e3Id: number): Promise< * @param e3Id - The e3Id of the round * @returns The token address, balance threshold and snapshot block */ -export const getRoundTokenDetails = async (serverUrl: string, e3Id: number): Promise => { +export const getRoundTokenDetails = async (serverUrl: string, e3Id: number): Promise => { const roundDetails = await getRoundDetails(serverUrl, e3Id) return { tokenAddress: roundDetails.tokenAddress, diff --git a/examples/CRISP/packages/crisp-sdk/src/token.ts b/examples/CRISP/packages/crisp-sdk/src/token.ts index 5660189801..f0ff355488 100644 --- a/examples/CRISP/packages/crisp-sdk/src/token.ts +++ b/examples/CRISP/packages/crisp-sdk/src/token.ts @@ -6,8 +6,7 @@ import { CRISP_SERVER_TOKEN_TREE_ENDPOINT } from './constants' -import ERC20Votes from './ERC20Votes.json' -import { createPublicClient, http } from 'viem' +import { createPublicClient, http, parseAbi } from 'viem' import { localhost, sepolia } from 'viem/chains' /** @@ -64,7 +63,7 @@ export const getBalanceAt = async (voterAddress: string, tokenAddress: string, s const balance = (await publicClient.readContract({ address: tokenAddress as `0x${string}`, - abi: ERC20Votes.abi, + abi: parseAbi(['function getPastVotes(address, uint256) view returns (uint256)']), functionName: 'getPastVotes', args: [voterAddress as `0x${string}`, BigInt(snapshotBlock)], })) as bigint @@ -99,7 +98,7 @@ export const getTotalSupplyAt = async (tokenAddress: string, snapshotBlock: numb const totalSupply = (await publicClient.readContract({ address: tokenAddress as `0x${string}`, - abi: ERC20Votes.abi, + abi: parseAbi(['function getPastTotalSupply(uint256) view returns (uint256)']), functionName: 'getPastTotalSupply', args: [BigInt(snapshotBlock)], })) as bigint diff --git a/examples/CRISP/packages/crisp-sdk/src/types.ts b/examples/CRISP/packages/crisp-sdk/src/types.ts index 5183fe33ad..c313767983 100644 --- a/examples/CRISP/packages/crisp-sdk/src/types.ts +++ b/examples/CRISP/packages/crisp-sdk/src/types.ts @@ -7,9 +7,9 @@ import type { LeanIMTMerkleProof } from '@zk-kit/lean-imt' /** - * Interface representing the details of a specific round returned by the CRISP server + * Type representing the details of a specific round returned by the CRISP server */ -export interface IRoundDetailsResponse { +export type RoundDetailsResponse = { id: string chain_id: string enclave_address: string @@ -26,9 +26,9 @@ export interface IRoundDetailsResponse { } /** - * Interface representing the details of a specific round in a more convenient format + * Type representing the details of a specific round in a more convenient format */ -export interface IRoundDetails { +export type RoundDetails = { e3Id: bigint chainId: bigint enclaveAddress: string @@ -45,18 +45,18 @@ export interface IRoundDetails { } /** - * Interface representing the token details required for participation in a round + * Type representing the token details required for participation in a round */ -export interface ITokenDetails { +export type TokenDetails = { tokenAddress: string threshold: bigint snapshotBlock: bigint } /** - * Interface representing a Merkle proof + * Type representing a Merkle proof */ -export interface IMerkleProof { +export type MerkleProof = { leaf: bigint index: number proof: LeanIMTMerkleProof @@ -65,20 +65,9 @@ export interface IMerkleProof { } /** - * Enum representing the voting modes + * Type representing a vote with power for 'yes' and 'no' */ -export enum VotingMode { - /** - * Governance voting requires to spend all credits on one option - they cannot be split - */ - GOVERNANCE = 'GOVERNANCE', -} - -/** - * Interface representing a vote with power for 'yes' and 'no' - */ -export interface IVote { +export type Vote = { /** * The voting power for 'yes' votes */ @@ -90,25 +79,25 @@ export interface IVote { } /** - * Interface representing a vector with coefficients + * Type representing a vector with coefficients */ -export interface Polynomial { +export type Polynomial = { coefficients: string[] } /** - * Interface representing cryptographic parameters + * Type representing cryptographic parameters */ -export interface GrecoCryptographicParams { +export type GrecoCryptographicParams = { q_mod_t: string qis: string[] k0is: string[] } /** - * Interface representing Greco bounds + * Type representing Greco bounds */ -export interface GrecoBoundParams { +export type GrecoBoundParams = { e_bound: string u_bound: string k1_low_bound: string @@ -122,17 +111,17 @@ export interface GrecoBoundParams { } /** - * Interface representing Greco parameters + * Type representing Greco parameters */ -export interface GrecoParams { +export type GrecoParams = { crypto: GrecoCryptographicParams bounds: GrecoBoundParams } /** - * The inputs required for the CRISP circuit + * The inputs required for the CRISP circuit. */ -export interface CRISPCircuitInputs { +export type CircuitInputs = { // Ciphertext Addition Section. prev_ct0is: Polynomial[] prev_ct1is: Polynomial[] @@ -174,48 +163,28 @@ export interface CRISPCircuitInputs { is_first_vote: boolean } -/** - * Interface representing the BFV parameters - */ -export interface BFVParams { - degree: number - plaintextModulus: bigint - moduli: BigInt64Array +export type ProofInputs = { + vote: Vote + publicKey: Uint8Array + signature: `0x${string}` + balance: bigint + slotAddress: string + previousCiphertext?: Uint8Array + merkleProof: MerkleProof } -/** - * Interface representing the inputs for Noir signature verification - */ -export interface NoirSignatureInputs { - /** - * X coordinate of the public key - */ - pub_key_x: Uint8Array - /** - * Y coordinate of the public key - */ - pub_key_y: Uint8Array - /** - * The signature to verify - */ - signature: Uint8Array - /** - * The hashed message that was signed - */ - hashed_message: Uint8Array +export type MaskVoteProofInputs = { + previousCiphertext?: Uint8Array + merkleLeaves: string[] | bigint[] + publicKey: Uint8Array + balance: bigint + slotAddress: string } -/** - * Parameters for encryptVoteAndGenerateCRISPInputs function - */ -export interface EncryptVoteAndGenerateCRISPInputsParams { - encodedVote: string[] +export type VoteProofInputs = { + merkleLeaves: string[] | bigint[] publicKey: Uint8Array - previousCiphertext: Uint8Array - signature: `0x${string}` - message: string - merkleData: IMerkleProof balance: bigint - slotAddress: string - isFirstVote: boolean + vote: Vote + signature: `0x${string}` } diff --git a/examples/CRISP/packages/crisp-sdk/src/utils.ts b/examples/CRISP/packages/crisp-sdk/src/utils.ts index db6a388b6f..7fff375fab 100644 --- a/examples/CRISP/packages/crisp-sdk/src/utils.ts +++ b/examples/CRISP/packages/crisp-sdk/src/utils.ts @@ -6,9 +6,10 @@ import { poseidon2 } from 'poseidon-lite' import { LeanIMT } from '@zk-kit/lean-imt' - -import type { IMerkleProof } from './types' -import { MERKLE_TREE_MAX_DEPTH } from './constants' +import type { MerkleProof } from './types' +import { MERKLE_TREE_MAX_DEPTH, SIGNATURE_MESSAGE_HASH } from './constants' +import { publicKeyToAddress } from 'viem/utils' +import { hexToBytes, recoverPublicKey } from 'viem' /** * Hash a leaf node for the Merkle tree @@ -16,8 +17,8 @@ import { MERKLE_TREE_MAX_DEPTH } from './constants' * @param balance The voter's balance * @returns The hashed leaf as a bigint */ -export const hashLeaf = (address: string, balance: string): bigint => { - return poseidon2([address, balance]) +export const hashLeaf = (address: string, balance: bigint): bigint => { + return poseidon2([address.toLowerCase(), balance]) } /** @@ -31,25 +32,20 @@ export const generateMerkleTree = (leaves: bigint[]): LeanIMT => { /** * Generate a Merkle proof for a given address to prove inclusion in the voters' list - * @param threshold The minimum balance required to be eligible * @param balance The voter's balance * @param address The voter's address * @param leaves The leaves of the Merkle tree */ -export const generateMerkleProof = (threshold: bigint, balance: bigint, address: string, leaves: bigint[]): IMerkleProof => { - if (balance < threshold) { - throw new Error('Balance is below the threshold') - } - - const leaf = hashLeaf(address, balance.toString()) +export const generateMerkleProof = (balance: bigint, address: string, leaves: bigint[] | string[]): MerkleProof => { + const leaf = hashLeaf(address.toLowerCase(), balance) - const index = leaves.findIndex((l) => l === leaf) + const index = leaves.findIndex((l) => BigInt(l) === leaf) if (index === -1) { throw new Error('Leaf not found in the tree') } - const tree = generateMerkleTree(leaves) + const tree = generateMerkleTree(leaves.map((l) => BigInt(l))) const proof = tree.generateProof(index) @@ -84,3 +80,70 @@ export const toBinary = (number: bigint): string => { return number.toString(2) } + +/** + * Given a signature, extract the signature components for the Noir signature verification circuit. + * @param signature The signature to extract the components from. + * @returns The extracted signature components. + */ +export const extractSignatureComponents = async ( + signature: `0x${string}`, +): Promise<{ + messageHash: Uint8Array + publicKeyX: Uint8Array + publicKeyY: Uint8Array + signature: Uint8Array +}> => { + const publicKey = await recoverPublicKey({ hash: SIGNATURE_MESSAGE_HASH, signature }) + const publicKeyBytes = hexToBytes(publicKey) + const publicKeyX = publicKeyBytes.slice(1, 33) + const publicKeyY = publicKeyBytes.slice(33, 65) + + // Extract r and s from signature (remove v) + const sigBytes = hexToBytes(signature) + const r = sigBytes.slice(0, 32) // First 32 bytes + const s = sigBytes.slice(32, 64) // Next 32 bytes + + const signatureBytes = new Uint8Array(64) + signatureBytes.set(r, 0) + signatureBytes.set(s, 32) + + return { + messageHash: hexToBytes(SIGNATURE_MESSAGE_HASH), + publicKeyX: publicKeyX, + publicKeyY: publicKeyY, + signature: signatureBytes, + } +} + +export const getAddressFromSignature = async (signature: `0x${string}`): Promise => { + const publicKey = await recoverPublicKey({ hash: SIGNATURE_MESSAGE_HASH, signature }) + + return publicKeyToAddress(publicKey) +} + +/** + * Get optimal number of threads for proof generation + * Leaves at least 1 core free for other operations + * Works in both Node.js and browser environments + */ +export async function getOptimalThreadCount(): Promise { + // Node.js environment - use os module if available + if (typeof process !== 'undefined' && process.versions?.node) { + try { + const os = await import('os') + const cpuCount = typeof os.availableParallelism === 'function' ? os.availableParallelism() : os.cpus().length + return Math.max(1, cpuCount - 1) + } catch { + // Fall through to browser check or fallback + } + } + + // Browser environment + if (typeof navigator !== 'undefined' && navigator.hardwareConcurrency) { + return Math.max(1, navigator.hardwareConcurrency - 1) + } + + // Fallback + return 5 +} diff --git a/examples/CRISP/packages/crisp-sdk/src/vote.ts b/examples/CRISP/packages/crisp-sdk/src/vote.ts index b0532cd035..a453fc2fed 100644 --- a/examples/CRISP/packages/crisp-sdk/src/vote.ts +++ b/examples/CRISP/packages/crisp-sdk/src/vote.ts @@ -5,286 +5,133 @@ // or FITNESS FOR A PARTICULAR PURPOSE. import { ZKInputsGenerator } from '@crisp-e3/zk-inputs' -import { BFVParams, type CRISPCircuitInputs, type EncryptVoteAndGenerateCRISPInputsParams, type IVote, VotingMode } from './types' -import { toBinary } from './utils' -import { MAXIMUM_VOTE_VALUE, HALF_LARGEST_MINIMUM_DEGREE, MESSAGE } from './constants' -import { extractSignature } from './signature' +import { type CircuitInputs, type Vote, MaskVoteProofInputs, ProofInputs, VoteProofInputs } from './types' +import { generateMerkleProof, toBinary, extractSignatureComponents, getAddressFromSignature, getOptimalThreadCount } from './utils' +import { MAXIMUM_VOTE_VALUE, HALF_LARGEST_MINIMUM_DEGREE, MASK_SIGNATURE } from './constants' import { Noir, type CompiledCircuit } from '@noir-lang/noir_js' import { UltraHonkBackend, type ProofData } from '@aztec/bb.js' import circuit from '../../../circuits/target/crisp_circuit.json' -import { privateKeyToAccount } from 'viem/accounts' import { bytesToHex, encodeAbiParameters, parseAbiParameters, numberToHex, getAddress } from 'viem/utils' import { Hex } from 'viem' +// Initialize the ZKInputsGenerator. +const zkInputsGenerator: ZKInputsGenerator = ZKInputsGenerator.withDefaults() +const optimalThreadCount = await getOptimalThreadCount() + /** - * This utility function calculates the first valid index for vote options - * based on the total voting power and degree. - * @dev This is needed to calculate the decoded plaintext - * @dev Also, we will need to check in the circuit that anything within these indices is - * either 0 or 1. - * @param totalVotingPower The maximum vote amount (if a single voter had all of the power) - * @param degree The degree of the polynomial + * Encode a vote. + * @param vote The vote to encode. + * @returns The encoded vote as a BigInt64Array. */ -export const calculateValidIndicesForPlaintext = (totalVotingPower: bigint, degree: number): { yesIndex: number; noIndex: number } => { - // Sanity check: degree must be even and positive - if (degree <= 0 || degree % 2 !== 0) { - throw new Error('Degree must be a positive even number') +export const encodeVote = (vote: Vote): BigInt64Array => { + const bfvParams = zkInputsGenerator.getBFVParams() + const voteArray = [] + const length = bfvParams.degree + const halfLength = length / 2 + const yesBinary = toBinary(vote.yes).split('') + const noBinary = toBinary(vote.no).split('') + + // Fill first half with 'yes' binary representation (pad with leading 0s if needed) + for (let i = 0; i < halfLength; i++) { + const offset = halfLength - yesBinary.length + voteArray.push(i < offset ? '0' : yesBinary[i - offset]) } - // Calculate the number of bits needed to represent the total voting power - const bitsNeeded = totalVotingPower.toString(2).length - - const halfLength = Math.floor(degree / 2) - - // Check if bits needed exceed half the degree - if (bitsNeeded > halfLength) { - throw new Error('Total voting power exceeds maximum representable votes for the given degree') + // Fill second half with 'no' binary representation (pad with leading 0s if needed) + for (let i = 0; i < length - halfLength; i++) { + const offset = length - halfLength - noBinary.length + voteArray.push(i < offset ? '0' : noBinary[i - offset]) } - // For "yes": right-align in first half - // Start index = (half length) - (bits needed) - const yesIndex = halfLength - bitsNeeded - - // For "no": right-align in second half - // Start index = (full length) - (bits needed) - const noIndex = degree - bitsNeeded - - return { - yesIndex: yesIndex, - noIndex: noIndex, - } + return BigInt64Array.from(voteArray.map(BigInt)) } /** - * Encode a vote based on the voting mode - * @param vote The vote to encode - * @param votingMode The voting mode to use for encoding - * @param votingPower The voting power of the voter - * @param bfvParams The BFV parameters to use for encoding - * @returns The encoded vote as a string + * Decode an encoded tally into its decimal representation. + * @param tally The encoded tally to decode. + * @returns The decoded tally as an IVote. */ -export const encodeVote = (vote: IVote, votingMode: VotingMode, votingPower: bigint): string[] => { - const zkInputsGenerator = ZKInputsGenerator.withDefaults() - const bfvParams = zkInputsGenerator.getBFVParams() as BFVParams - - validateVote(votingMode, vote, votingPower) - - switch (votingMode) { - case VotingMode.GOVERNANCE: { - const voteArray = [] - const length = bfvParams.degree - const halfLength = length / 2 - const yesBinary = toBinary(vote.yes).split('') - const noBinary = toBinary(vote.no).split('') - - // Fill first half with 'yes' binary representation (pad with leading 0s if needed) - for (let i = 0; i < halfLength; i++) { - const offset = halfLength - yesBinary.length - voteArray.push(i < offset ? '0' : yesBinary[i - offset]) - } - - // Fill second half with 'no' binary representation (pad with leading 0s if needed) - for (let i = 0; i < length - halfLength; i++) { - const offset = length - halfLength - noBinary.length - voteArray.push(i < offset ? '0' : noBinary[i - offset]) - } - return voteArray - } - default: - throw new Error('Unsupported voting mode') +export const decodeTally = (tally: string[]): Vote => { + const HALF_D = tally.length / 2 + const START_INDEX_Y = HALF_D - HALF_LARGEST_MINIMUM_DEGREE + const START_INDEX_N = tally.length - HALF_LARGEST_MINIMUM_DEGREE + + // Extract only the relevant parts of the tally + const yesBinary = tally.slice(START_INDEX_Y, HALF_D) + const noBinary = tally.slice(START_INDEX_N, tally.length) + + let yes = 0n + let no = 0n + + // Convert yes votes (from START_INDEX_Y to HALF_D) + for (let i = 0; i < yesBinary.length; i += 1) { + const weight = 2n ** BigInt(yesBinary.length - 1 - i) + yes += BigInt(yesBinary[i]) * weight } -} -/** - * Given an encoded tally, decode it into its decimal representation - * @param tally The encoded tally to decode - * @param votingMode The voting mode - */ -export const decodeTally = (tally: string[], votingMode: VotingMode): IVote => { - switch (votingMode) { - case VotingMode.GOVERNANCE: { - const HALF_D = tally.length / 2 - const START_INDEX_Y = HALF_D - HALF_LARGEST_MINIMUM_DEGREE - const START_INDEX_N = tally.length - HALF_LARGEST_MINIMUM_DEGREE - - // Extract only the relevant parts of the tally - const yesBinary = tally.slice(START_INDEX_Y, HALF_D) - const noBinary = tally.slice(START_INDEX_N, tally.length) - - let yes = 0n - let no = 0n - - // Convert yes votes (from START_INDEX_Y to HALF_D) - for (let i = 0; i < yesBinary.length; i += 1) { - const weight = 2n ** BigInt(yesBinary.length - 1 - i) - yes += BigInt(yesBinary[i]) * weight - } - - // Convert no votes (from START_INDEX_N to D) - for (let i = 0; i < noBinary.length; i += 1) { - const weight = 2n ** BigInt(noBinary.length - 1 - i) - no += BigInt(noBinary[i]) * weight - } - - return { - yes, - no, - } - } - default: - throw new Error('Unsupported voting mode') + // Convert no votes (from START_INDEX_N to D) + for (let i = 0; i < noBinary.length; i += 1) { + const weight = 2n ** BigInt(noBinary.length - 1 - i) + no += BigInt(noBinary[i]) * weight } -} -/** - * Validate whether a vote is valid for a given voting mode - * @param votingMode The voting mode to validate against - * @param vote The vote to validate - * @param votingPower The voting power of the voter - */ -export const validateVote = (votingMode: VotingMode, vote: IVote, votingPower: bigint) => { - switch (votingMode) { - case VotingMode.GOVERNANCE: - if (vote.yes > 0n && vote.no > 0n) { - throw new Error('Invalid vote for GOVERNANCE mode: cannot spread votes between options') - } - - if (vote.yes > votingPower || vote.no > votingPower) { - throw new Error('Invalid vote for GOVERNANCE mode: vote exceeds voting power') - } - - if (vote.yes > MAXIMUM_VOTE_VALUE || vote.no > MAXIMUM_VOTE_VALUE) { - throw new Error('Invalid vote for GOVERNANCE mode: vote exceeds maximum allowed value') - } + return { + yes, + no, } } -export const encryptVote = async (encodedVote: string[], publicKey: Uint8Array): Promise => { - const zkInputsGenerator = ZKInputsGenerator.withDefaults() - - const vote = BigInt64Array.from(encodedVote.map(BigInt)) +export const encryptVote = (vote: Vote, publicKey: Uint8Array): Uint8Array => { + const encodedVote = encodeVote(vote) - return zkInputsGenerator.encryptVote(publicKey, vote) + return zkInputsGenerator.encryptVote(publicKey, encodedVote) } -export const generatePublicKey = async (): Promise => { - const zkInputsGenerator = ZKInputsGenerator.withDefaults() +export const generatePublicKey = (): Uint8Array => { return zkInputsGenerator.generatePublicKey() } -/** - * This is a wrapper around enclave-e3/sdk encryption functions as CRISP circuit will require some more - * input values which generic Greco do not need. - * @param encodedVote The encoded vote as string array - * @param publicKey The public key to use for encryption - * @param previousCiphertext The previous ciphertext to use for addition operation - * @param bfvParams The BFV parameters to use for encryption - * @param merkleData The merkle proof data - * @param message The message that was signed - * @param signature The signature of the message - * @param balance The voter's balance - * @param slotAddress The voter's slot address - * @param isFirstVote Whether this is the first vote for this slot - * @returns The CRISP circuit inputs - */ -export const encryptVoteAndGenerateCRISPInputs = async ({ - encodedVote, - publicKey, - previousCiphertext, - merkleData, - message, - signature, - balance, - slotAddress, - isFirstVote, -}: EncryptVoteAndGenerateCRISPInputsParams): Promise => { - const zkInputsGenerator: ZKInputsGenerator = ZKInputsGenerator.withDefaults() - - const bfvParams = zkInputsGenerator.getBFVParams() as BFVParams - - if (encodedVote.length !== bfvParams.degree) { - throw new RangeError(`encodedVote length ${encodedVote.length} does not match BFV degree ${bfvParams.degree}`) - } - - const vote = BigInt64Array.from(encodedVote.map(BigInt)) - - const crispInputs = (await zkInputsGenerator.generateInputs(previousCiphertext, publicKey, vote)) as CRISPCircuitInputs - - const { hashed_message, pub_key_x, pub_key_y, signature: extractedSignature } = await extractSignature(message, signature) - - return { - ...crispInputs, - hashed_message: Array.from(hashed_message).map((b) => b.toString()), - public_key_x: Array.from(pub_key_x).map((b) => b.toString()), - public_key_y: Array.from(pub_key_y).map((b) => b.toString()), - signature: Array.from(extractedSignature).map((b) => b.toString()), - merkle_proof_length: merkleData.length.toString(), - merkle_proof_indices: merkleData.indices.map((i) => i.toString()), - merkle_proof_siblings: merkleData.proof.siblings.map((s) => s.toString()), - merkle_root: merkleData.proof.root.toString(), - slot_address: slotAddress, - balance: balance.toString(), - is_first_vote: isFirstVote, - } +export const generateCircuitInputs = async (proofInputs: ProofInputs): Promise => { + const encodedVote = encodeVote(proofInputs.vote) + + let crispInputs = await zkInputsGenerator.generateInputs( + // If no previous ciphertext is provided, a placeholder ciphertext vote will be generated. + // This is safe because the circuit will not check the ciphertext addition if + // the previous ciphertext is not provided (is_first_vote is true). + proofInputs.previousCiphertext || encryptVote({ yes: 0n, no: 0n }, proofInputs.publicKey), + proofInputs.publicKey, + encodedVote, + ) + + const { messageHash, publicKeyX, publicKeyY, signature } = await extractSignatureComponents(proofInputs.signature) + + crispInputs.hashed_message = Array.from(messageHash).map((b) => b.toString()) + crispInputs.public_key_x = Array.from(publicKeyX).map((b) => b.toString()) + crispInputs.public_key_y = Array.from(publicKeyY).map((b) => b.toString()) + crispInputs.signature = Array.from(signature).map((b) => b.toString()) + crispInputs.slot_address = proofInputs.slotAddress.toLowerCase() + crispInputs.balance = proofInputs.balance.toString() + crispInputs.is_first_vote = !proofInputs.previousCiphertext + crispInputs.merkle_root = proofInputs.merkleProof.proof.root.toString() + crispInputs.merkle_proof_length = proofInputs.merkleProof.length.toString() + crispInputs.merkle_proof_indices = proofInputs.merkleProof.indices.map((i) => i.toString()) + crispInputs.merkle_proof_siblings = proofInputs.merkleProof.proof.siblings.map((s) => s.toString()) + + return crispInputs } -/** - * A function to generate the data required to mask a vote - * @param voter The voter's address - * @param publicKey The voter's public key - * @param previousCiphertext The previous ciphertext - * @param merkleRoot The merkle root of the census tree - * @param slotAddress The voter's slot address - * @param isFirstVote Whether this is the first vote for this slot - * @returns The CRISP circuit inputs for a mask vote - */ -export const generateMaskVote = async ( - publicKey: Uint8Array, - previousCiphertext: Uint8Array, - merkleRoot: bigint, - slotAddress: string, - isFirstVote: boolean, -): Promise => { - const zkInputsGenerator = ZKInputsGenerator.withDefaults() - - const plaintextVote: IVote = { - yes: 0n, - no: 0n, - } - - const encodedVote = encodeVote(plaintextVote, VotingMode.GOVERNANCE, 0n) - - const vote = BigInt64Array.from(encodedVote.map(BigInt)) - - const crispInputs = (await zkInputsGenerator.generateInputs(previousCiphertext, publicKey, vote)) as CRISPCircuitInputs +export const generateWitness = async (crispInputs: CircuitInputs): Promise => { + const noir = new Noir(circuit as CompiledCircuit) - // hardhat default private key - const privateKey = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' - const account = privateKeyToAccount(privateKey) - const signature = await account.signMessage({ message: MESSAGE }) - const { hashed_message, pub_key_x, pub_key_y, signature: extractedSignature } = await extractSignature(MESSAGE, signature) + const { witness } = await noir.execute(crispInputs as any) - return { - ...crispInputs, - hashed_message: Array.from(hashed_message).map((b) => b.toString()), - public_key_x: Array.from(pub_key_x).map((b) => b.toString()), - public_key_y: Array.from(pub_key_y).map((b) => b.toString()), - signature: Array.from(extractedSignature).map((b) => b.toString()), - merkle_proof_indices: Array.from({ length: 20 }, () => '0'), - merkle_proof_siblings: Array.from({ length: 20 }, () => '0'), - merkle_proof_length: '1', - merkle_root: merkleRoot.toString(), - slot_address: slotAddress, - balance: '0', - is_first_vote: isFirstVote, - } + return witness } -export const generateProof = async (crispInputs: CRISPCircuitInputs): Promise => { - const noir = new Noir(circuit as CompiledCircuit) - const backend = new UltraHonkBackend((circuit as CompiledCircuit).bytecode, { threads: 4 }) +export const generateProof = async (crispInputs: CircuitInputs): Promise => { + const witness = await generateWitness(crispInputs) + const backend = new UltraHonkBackend((circuit as CompiledCircuit).bytecode, { threads: optimalThreadCount }) - const { witness } = await noir.execute(crispInputs as any) const proof = await backend.generateProof(witness, { keccakZK: true }) await backend.destroy() @@ -292,30 +139,48 @@ export const generateProof = async (crispInputs: CRISPCircuitInputs): Promise => { - const noir = new Noir(circuit as CompiledCircuit) - const backend = new UltraHonkBackend((circuit as CompiledCircuit).bytecode, { threads: 4 }) +export const generateVoteProof = async (voteProofInputs: VoteProofInputs) => { + if (voteProofInputs.vote.yes > voteProofInputs.balance || voteProofInputs.vote.no > voteProofInputs.balance) { + throw new Error('Invalid vote: vote exceeds balance') + } - const { witness, returnValue } = await noir.execute(crispInputs as any) - const proof = await backend.generateProof(witness, { keccakZK: true }) + if (voteProofInputs.vote.yes > MAXIMUM_VOTE_VALUE || voteProofInputs.vote.no > MAXIMUM_VOTE_VALUE) { + throw new Error('Invalid vote: vote exceeds maximum allowed value') + } - await backend.destroy() + if (voteProofInputs.vote.yes < 0n || voteProofInputs.vote.no < 0n) { + throw new Error('Invalid vote: vote is negative') + } + + // The address slot of an actual vote always is the address of the public key that signed the message. + const address = await getAddressFromSignature(voteProofInputs.signature) + + const merkleProof = generateMerkleProof(voteProofInputs.balance, address, voteProofInputs.merkleLeaves) - return { returnValue, proof } + const crispInputs = await generateCircuitInputs({ + ...voteProofInputs, + slotAddress: address, + merkleProof, + }) + + return generateProof(crispInputs) } -export const getCircuitOutputValue = async (crispInputs: CRISPCircuitInputs): Promise<{ returnValue: unknown }> => { - const noir = new Noir(circuit as CompiledCircuit) +export const generateMaskVoteProof = async (maskVoteProofInputs: MaskVoteProofInputs) => { + const merkleProof = generateMerkleProof(maskVoteProofInputs.balance, maskVoteProofInputs.slotAddress, maskVoteProofInputs.merkleLeaves) - const { returnValue } = await noir.execute(crispInputs as any) + const crispInputs = await generateCircuitInputs({ + ...maskVoteProofInputs, + signature: MASK_SIGNATURE, + vote: { yes: 0n, no: 0n }, + merkleProof, + }) - return { returnValue } + return generateProof(crispInputs) } export const verifyProof = async (proof: ProofData): Promise => { - const backend = new UltraHonkBackend((circuit as CompiledCircuit).bytecode) + const backend = new UltraHonkBackend((circuit as CompiledCircuit).bytecode, { threads: optimalThreadCount }) const isValid = await backend.verifyProof(proof, { keccakZK: true }) diff --git a/examples/CRISP/packages/crisp-sdk/tests/constants.ts b/examples/CRISP/packages/crisp-sdk/tests/constants.ts index c1328cba4e..a7765d1ef5 100644 --- a/examples/CRISP/packages/crisp-sdk/tests/constants.ts +++ b/examples/CRISP/packages/crisp-sdk/tests/constants.ts @@ -4,30 +4,14 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -import { generateMerkleProof } from '../src' - export const CRISP_SERVER_URL = 'http://localhost:4000' - -export const MESSAGE = 'Vote for round 0' -export const SIGNATURE = - '0x1641431d0ed3fd86814f026da62e11434b53c6a85162fea7f99218bf3c307dec7f361c235f07b658780afd91a5c9d68d6a4b14d5eb0511f6688d3e91140eec121b' -export const VOTE = { yes: 10n, no: 0n } - +export const ECDSA_PRIVATE_KEY = '0x04da7c413e00d26569910a463c51ab514dca3bc5168c5ceb174b361cd33f9ecc' export const LEAVES = [ - 5744770974032406598001112375731623179326875761382288642755141437508907349272n, - 3427403932201889290042771220465494458496044723860771244846412090114641612933n, - 2345497045557010425836789889102383730351985634595867684180656101146305513188n, - 16333345332467701633145728130049893741621620444233378624735176290889202182510n, - 7181270461626747418571270128374653017252322331096300145108059576488978730010n, - 10652491433271864584861721641100216833021493709204436430564590071100900917428n, - 20897323534773557936302566533365152086278248537724825381610164527249213072770n, - 4720511075913887710172192848636076523165432993226978491435561065722130431597n, - 14131255645332550266535358189863475289290770471998199141522479556687499890181n, - 4935126455042678253283865781346660214959064333962120811317994370162001200675n, + // First leaf has been generated using the address of the private key above. + 18271417062681489396127637067161377206991493997437479705544007695491481029940n, + 21386066522994147417428722670584127893127936643085609370651005837318304141270n, + 1983869233929151201074336534851649337028918489325523209164772930983460428207n, + 19370325120536147692670316510448470434381674466568115984868372181385560126045n, + 16673264759365860972077611357899248038817564448666677924174132959085122318936n, + 1983869233929151201074336534851649337028918489325523209164772930983460428207n, ] - -export const MAX_DEPTH = 20 - -export const votingPowerLeaf = 1000n -export const testAddress = '0x1234567890123456789012345678901234567890' -export const merkleProof = generateMerkleProof(0n, votingPowerLeaf, testAddress, LEAVES) diff --git a/examples/CRISP/packages/crisp-sdk/tests/signature.test.ts b/examples/CRISP/packages/crisp-sdk/tests/signature.test.ts deleted file mode 100644 index c76da6a120..0000000000 --- a/examples/CRISP/packages/crisp-sdk/tests/signature.test.ts +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -// -// This file is provided WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. - -import { describe, it, expect } from 'vitest' - -import { extractSignature } from '../src/signature' -import { MESSAGE, SIGNATURE } from './constants' - -describe('Signature', () => { - describe('extractSignature', () => { - it('should extract signature components correctly', async () => { - const { hashed_message, pub_key_x, pub_key_y, signature: extractedSignature } = await extractSignature(MESSAGE, SIGNATURE) - - expect(hashed_message).toBeInstanceOf(Uint8Array) - expect(pub_key_x).toBeInstanceOf(Uint8Array) - expect(pub_key_y).toBeInstanceOf(Uint8Array) - expect(extractedSignature).toBeInstanceOf(Uint8Array) - }) - }) -}) diff --git a/examples/CRISP/packages/crisp-sdk/tests/state.test.ts b/examples/CRISP/packages/crisp-sdk/tests/state.test.ts index 5287ab4c37..7a89007eec 100644 --- a/examples/CRISP/packages/crisp-sdk/tests/state.test.ts +++ b/examples/CRISP/packages/crisp-sdk/tests/state.test.ts @@ -4,26 +4,99 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -import { describe, expect, it } from 'vitest' +import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest' import { getRoundDetails, getRoundTokenDetails } from '../src/state' import { CRISP_SERVER_URL } from './constants' +import { CRISP_SERVER_STATE_LITE_ENDPOINT } from '../src/constants' import { zeroAddress } from 'viem' +import type { RoundDetailsResponse } from '../src/types' describe('State', () => { + const mockRoundDetailsResponse: RoundDetailsResponse = { + id: '0', + chain_id: '11155111', + enclave_address: '0x1234567890123456789012345678901234567890', + status: 'active', + vote_count: '10', + start_time: '1000000', + duration: '86400', + expiration: '1086400', + start_block: '12345', + committee_public_key: ['0xabc', '0xdef'], + emojis: ['👍', '👎'], + token_address: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd', + balance_threshold: '1000', + } + + beforeEach(() => { + vi.clearAllMocks() + }) + + afterEach(() => { + vi.restoreAllMocks() + }) + describe('getRoundDetails', () => { it('should get the state for a given e3Id from the CRISP server', async () => { + const mockResponse = mockRoundDetailsResponse + + const mockFetchResponse = { + ok: true, + json: async () => mockResponse, + } as Response + + vi.spyOn(global, 'fetch').mockResolvedValue(mockFetchResponse) + const state = await getRoundDetails(CRISP_SERVER_URL, 0) + expect(state).toBeDefined() + expect(state.e3Id).toBe(0n) + expect(state.chainId).toBe(11155111n) + expect(state.enclaveAddress).toBe('0x1234567890123456789012345678901234567890') + expect(state.status).toBe('active') + expect(state.voteCount).toBe(10n) + expect(state.startTime).toBe(1000000n) + expect(state.duration).toBe(86400n) + expect(state.expiration).toBe(1086400n) + expect(state.startBlock).toBe(12345n) + expect(state.committeePublicKey).toEqual(['0xabc', '0xdef']) + expect(state.emojis).toEqual(['👍', '👎']) + expect(state.tokenAddress).toBe('0xabcdefabcdefabcdefabcdefabcdefabcdefabcd') + expect(state.balanceThreshold).toBe(1000n) + + expect(fetch).toHaveBeenCalledWith( + `${CRISP_SERVER_URL}/${CRISP_SERVER_STATE_LITE_ENDPOINT}`, + expect.objectContaining({ + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ round_id: 0 }), + }), + ) }) }) describe('getTokenDetails', () => { it('should return the details of the token for a given e3Id from the CRISP server', async () => { + const mockResponse = mockRoundDetailsResponse + + const mockFetchResponse = { + ok: true, + json: async () => mockResponse, + } as Response + + vi.spyOn(global, 'fetch').mockResolvedValue(mockFetchResponse) + const tokenDetails = await getRoundTokenDetails(CRISP_SERVER_URL, 0) + expect(tokenDetails.tokenAddress).not.toBe(zeroAddress) + expect(tokenDetails.tokenAddress).toBe('0xabcdefabcdefabcdefabcdefabcdefabcdefabcd') expect(tokenDetails.threshold).toBeGreaterThan(0) + expect(tokenDetails.threshold).toBe(1000n) expect(tokenDetails.snapshotBlock).toBeGreaterThan(0) + expect(tokenDetails.snapshotBlock).toBe(12345n) }) }) }) diff --git a/examples/CRISP/packages/crisp-sdk/tests/token.test.ts b/examples/CRISP/packages/crisp-sdk/tests/token.test.ts index 6bd95b68d7..a222879b23 100644 --- a/examples/CRISP/packages/crisp-sdk/tests/token.test.ts +++ b/examples/CRISP/packages/crisp-sdk/tests/token.test.ts @@ -4,15 +4,45 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -import { describe, expect, it } from 'vitest' +import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest' import { getTreeData } from '../src/token' import { CRISP_SERVER_URL } from './constants' +import { CRISP_SERVER_TOKEN_TREE_ENDPOINT } from '../src/constants' -// @notice To run these tests you will need to have an instance of CRISP running locally describe('Token data fetching', () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + afterEach(() => { + vi.restoreAllMocks() + }) + it('should fetch token data from the CRISP server', async () => { + const mockHashes = ['0x1234', '0x5678', '0x9abc'] + const mockResponse = { + ok: true, + json: async () => mockHashes, + } as Response + + vi.spyOn(global, 'fetch').mockResolvedValue(mockResponse) + const data = await getTreeData(CRISP_SERVER_URL, 0) - expect(data.length).toBeGreaterThan(0) + + expect(data).toHaveLength(3) + expect(data[0]).toBe(BigInt('0x1234')) + expect(data[1]).toBe(BigInt('0x5678')) + expect(data[2]).toBe(BigInt('0x9abc')) + expect(fetch).toHaveBeenCalledWith( + `${CRISP_SERVER_URL}/${CRISP_SERVER_TOKEN_TREE_ENDPOINT}`, + expect.objectContaining({ + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ round_id: 0 }), + }), + ) }) }) diff --git a/examples/CRISP/packages/crisp-sdk/tests/utils.test.ts b/examples/CRISP/packages/crisp-sdk/tests/utils.test.ts index 20890c53f2..4f8728ce73 100644 --- a/examples/CRISP/packages/crisp-sdk/tests/utils.test.ts +++ b/examples/CRISP/packages/crisp-sdk/tests/utils.test.ts @@ -5,34 +5,39 @@ // or FITNESS FOR A PARTICULAR PURPOSE. import { expect, describe, it } from 'vitest' -import { generateMerkleProof, generateMerkleTree, hashLeaf } from '../src/utils' +import { extractSignatureComponents, generateMerkleProof, generateMerkleTree, hashLeaf } from '../src/utils' import { LEAVES } from './constants' +import { MASK_SIGNATURE } from '../src/constants' describe('Utils', () => { describe('hashLeaf', () => { - it('should return a bigint hash of the two values', () => { - const leaf = hashLeaf('0x1234567890123456789012345678901234567890', '1000') + it('Should return a bigint hash of the two values', () => { + const leaf = hashLeaf('0x1234567890123456789012345678901234567890', 1000n) + expect(typeof leaf).toBe('bigint') + expect(leaf).toBe(5744770974032406598001112375731623179326875761382288642755141437508907349272n) }) }) describe('generateMerkleTree', () => { - it('should generate a merkle tree', () => { + it('Should generate a merkle tree', () => { const tree = generateMerkleTree(LEAVES) + expect(tree.root).toBeDefined() }) }) describe('generateMerkleProof', () => { - const address = '0x1234567890123456789012345678901234567890' - const balance = 1000n - it('should generate a valid merkle proof for a leaf', () => { + const address = '0x145B2260E2DAa2965F933A76f5ff5aE3be5A7e5a' + const balance = 100n + + it('Should generate a valid merkle proof for a leaf', () => { const tree = generateMerkleTree(LEAVES) - const proof = generateMerkleProof(0n, balance, address, LEAVES) - expect(proof.leaf).toBe(hashLeaf(address, balance.toString())) + const proof = generateMerkleProof(balance, address, LEAVES) + expect(proof.leaf).toBe(hashLeaf(address, balance)) - expect(proof.length).toBe(4) + expect(proof.length).toBe(3) // Unpad the proof for verification const unpaddedProof = { ...proof.proof, @@ -41,9 +46,21 @@ describe('Utils', () => { expect(tree.verifyProof(unpaddedProof)).toBe(true) }) - it('should throw if the leaf does not exist in the tree', () => { - expect(() => generateMerkleProof(0n, balance, address, [])).toThrow('Leaf not found in the tree') - expect(() => generateMerkleProof(0n, 999n, address, LEAVES)).toThrow('Leaf not found in the tree') + + it('Should throw if the leaf does not exist in the tree', () => { + expect(() => generateMerkleProof(balance, address, [])).toThrow('Leaf not found in the tree') + expect(() => generateMerkleProof(999n, address, LEAVES)).toThrow('Leaf not found in the tree') + }) + }) + + describe('extractSignatureComponents', () => { + it('Should extract signature components correctly', async () => { + const { messageHash, publicKeyX, publicKeyY, signature: extractedSignature } = await extractSignatureComponents(MASK_SIGNATURE) + + expect(messageHash).toBeInstanceOf(Uint8Array) + expect(publicKeyX).toBeInstanceOf(Uint8Array) + expect(publicKeyY).toBeInstanceOf(Uint8Array) + expect(extractedSignature).toBeInstanceOf(Uint8Array) }) }) }) diff --git a/examples/CRISP/packages/crisp-sdk/tests/utils.ts b/examples/CRISP/packages/crisp-sdk/tests/utils.ts deleted file mode 100644 index 624a8dbb6b..0000000000 --- a/examples/CRISP/packages/crisp-sdk/tests/utils.ts +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -// -// This file is provided WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. - -export function normalizeCoefficient(coeff: string): string { - if (coeff.startsWith('0x')) { - return BigInt(coeff).toString() - } - return coeff.toString() -} - -export function compareCoefficientsArrays(arr1: any[], arr2: any[]): boolean { - if (arr1.length !== arr2.length) return false - - for (let i = 0; i < arr1.length; i++) { - if (!arr1[i] || !arr2[i]) return false - - const coeff1 = arr1[i].coefficients - const coeff2 = arr2[i].coefficients - - if (!coeff1 || !coeff2) return false - if (coeff1.length !== coeff2.length) return false - - for (let k = 0; k < coeff1.length; k++) { - const normalized1 = normalizeCoefficient(coeff1[k]) - const normalized2 = normalizeCoefficient(coeff2[k]) - - if (normalized1 !== normalized2) return false - } - } - - return true -} diff --git a/examples/CRISP/packages/crisp-sdk/tests/vote.test.ts b/examples/CRISP/packages/crisp-sdk/tests/vote.test.ts index 2ea21f34c8..c15cc5fb90 100644 --- a/examples/CRISP/packages/crisp-sdk/tests/vote.test.ts +++ b/examples/CRISP/packages/crisp-sdk/tests/vote.test.ts @@ -4,45 +4,48 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -import { describe, it, expect } from 'vitest' -import { ZKInputsGenerator } from '@crisp-e3/zk-inputs' +import { describe, it, expect, beforeAll } from 'vitest' +import { Vote } from '../src/types' +import { MASK_SIGNATURE, SIGNATURE_MESSAGE_HASH, SIGNATURE_MESSAGE } from '../src/constants' +import { generateMerkleProof } from '../src/utils' import { - calculateValidIndicesForPlaintext, decodeTally, + encryptVote, + generateVoteProof, + generateMaskVoteProof, + generatePublicKey, + verifyProof, encodeVote, - encryptVoteAndGenerateCRISPInputs, - generateMaskVote, generateProof, - generateProofWithReturnValue, - getCircuitOutputValue, - validateVote, - verifyProof, + generateCircuitInputs, } from '../src/vote' -import { BFVParams, VotingMode } from '../src/types' -import { generateMerkleProof, hashLeaf, MAXIMUM_VOTE_VALUE } from '../src' - -import { LEAVES, merkleProof, MESSAGE, SIGNATURE, testAddress, VOTE, votingPowerLeaf } from './constants' -import { privateKeyToAccount } from 'viem/accounts' -import { compareCoefficientsArrays } from './utils' +import { publicKeyToAddress, signMessage } from 'viem/accounts' +import { Hex, recoverPublicKey } from 'viem' +import { ECDSA_PRIVATE_KEY, LEAVES } from './constants' describe('Vote', () => { - const votingPower = 10n - - let zkInputsGenerator = ZKInputsGenerator.withDefaults() - const DEFAULT_BFV_PARAMS = zkInputsGenerator.getBFVParams() as BFVParams - - let publicKey = zkInputsGenerator.generatePublicKey() - const previousCiphertext = zkInputsGenerator.encryptVote(publicKey, new BigInt64Array([0n])) - - describe('encodeVote', () => { - it('should work for valid votes', () => { - const encoded = encodeVote(VOTE, VotingMode.GOVERNANCE, votingPower) - expect(encoded.length).toBe(DEFAULT_BFV_PARAMS.degree) - }) + let vote: Vote + let signature: Hex + let balance: bigint + let address: string + let slotAddress: string + let publicKey: Uint8Array + let previousCiphertext: Uint8Array + + // Setup the test environment. + beforeAll(async () => { + vote = { yes: 10n, no: 0n } + signature = await signMessage({ message: SIGNATURE_MESSAGE, privateKey: ECDSA_PRIVATE_KEY }) + balance = 100n + address = publicKeyToAddress(await recoverPublicKey({ hash: SIGNATURE_MESSAGE_HASH, signature })) + // Address of the last leaf in the Merkle tree, used for mask votes. + slotAddress = '0x145B2260E2DAa2965F933A76f5ff5aE3be5A7e5a' + publicKey = generatePublicKey() + previousCiphertext = encryptVote(vote, publicKey) }) - describe('decode tally', () => { - it('should decode correctly', () => { + describe('decodeTally', () => { + it('Should decode an encoded tally into its decimal representation', () => { const tally = [ '0', '0', @@ -102,338 +105,187 @@ describe('Vote', () => { '1', ] - const decoded = decodeTally(tally, VotingMode.GOVERNANCE) + const decoded = decodeTally(tally) + expect(decoded.yes).toBe(22n) expect(decoded.no).toBe(1n) }) }) - describe('validateVote', () => { - const validVote = { yes: 10n, no: 0n } - const invalidVote = { yes: 5n, no: 5n } - - it('should throw an error for invalid GOVERNANCE votes', () => { - expect(() => { - validateVote(VotingMode.GOVERNANCE, invalidVote, votingPower) - }).toThrow('Invalid vote for GOVERNANCE mode: cannot spread votes between options') - }) - it('should work for valid GOVERNANCE votes', () => { - expect(() => { - validateVote(VotingMode.GOVERNANCE, validVote, votingPower) - }).not.toThrow() - }) - it('should not throw when vote does not exceed the maximum value supported', () => { - expect(() => { - validateVote(VotingMode.GOVERNANCE, { yes: 10n, no: 0n }, votingPower) - }).not.toThrow() - }) - it('should throw when the vote exceeds the maximum value supported', () => { - expect(() => { - validateVote(VotingMode.GOVERNANCE, { yes: MAXIMUM_VOTE_VALUE + 1n, no: 0n }, MAXIMUM_VOTE_VALUE + 1n) - }).toThrow('Invalid vote for GOVERNANCE mode: vote exceeds maximum allowed value') + describe('encodeVote', () => { + const decodeHalf = (encoded: BigInt64Array, isFirstHalf: boolean): bigint => { + const halfLength = encoded.length / 2 + const half = Array.from(isFirstHalf ? encoded.slice(0, halfLength) : encoded.slice(halfLength)) + const binaryString = half.map((b) => b.toString()).join('') + const trimmedBinary = binaryString.replace(/^0+/, '') || '0' + return BigInt('0b' + trimmedBinary) + } + + it('Should encode yes vote correctly in the first half', () => { + const encoded = encodeVote({ yes: 10n, no: 0n }) + + expect(decodeHalf(encoded, true)).toBe(10n) }) - }) - describe('calculateValidIndicesForPlaintext', () => { - it('should return the correct indices', () => { - const degree = 8192 - const totalVotingPower = 100n - - // bitsNeeded = 7 -> 1100100 = 100 in binary - // half length = 4096 - // first valid index for yes 4096 - 7 = 4089 - // first valid index for no 8192 - 7 = 8185 - expect(calculateValidIndicesForPlaintext(totalVotingPower, degree)).toEqual({ - yesIndex: 4089, - noIndex: 8185, - }) - }) - it('should throw if voting power is too high for degree', () => { - const degree = 16 - const totalVotingPower = 10000n + it('Should encode no vote correctly in the second half', () => { + const encoded = encodeVote({ yes: 0n, no: 5n }) - expect(() => { - calculateValidIndicesForPlaintext(totalVotingPower, degree) - }).toThrow('Total voting power exceeds maximum representable votes for the given degree') - }) - it('should throw when the degree is negative', () => { - expect(() => { - calculateValidIndicesForPlaintext(10n, -16) - }).toThrow('Degree must be a positive even number') - }) - it('should throw when the degree is not even', () => { - expect(() => { - calculateValidIndicesForPlaintext(10n, 15) - }).toThrow('Degree must be a positive even number') + expect(decodeHalf(encoded, false)).toBe(5n) }) - }) - describe('encryptVoteAndGenerateCRISPInputs', () => { - it('should encrypt a vote and generate the circuit inputs', async () => { - const encodedVote = encodeVote(VOTE, VotingMode.GOVERNANCE, votingPower) - const crispInputs = await encryptVoteAndGenerateCRISPInputs({ - encodedVote, - publicKey, - previousCiphertext, - signature: SIGNATURE, - message: MESSAGE, - merkleData: merkleProof, - balance: votingPowerLeaf, - slotAddress: testAddress, - isFirstVote: false, - }) + it('Should only contain binary digits (0 or 1)', () => { + const encoded = encodeVote({ yes: 255n, no: 128n }) - expect(crispInputs.prev_ct0is).toBeInstanceOf(Array) - expect(crispInputs.prev_ct1is).toBeInstanceOf(Array) - expect(crispInputs.sum_ct0is).toBeInstanceOf(Array) - expect(crispInputs.sum_ct1is).toBeInstanceOf(Array) - expect(crispInputs.sum_r0is).toBeInstanceOf(Array) - expect(crispInputs.sum_r1is).toBeInstanceOf(Array) - expect(crispInputs.params).toBeInstanceOf(Object) - expect(crispInputs.ct0is).toBeInstanceOf(Array) - expect(crispInputs.ct1is).toBeInstanceOf(Array) - expect(crispInputs.pk0is).toBeInstanceOf(Array) - expect(crispInputs.pk1is).toBeInstanceOf(Array) - expect(crispInputs.r1is).toBeInstanceOf(Array) - expect(crispInputs.r2is).toBeInstanceOf(Array) - expect(crispInputs.p1is).toBeInstanceOf(Array) - expect(crispInputs.hashed_message).toBeInstanceOf(Array) - expect(crispInputs.public_key_x).toBeInstanceOf(Array) - expect(crispInputs.public_key_y).toBeInstanceOf(Array) - expect(crispInputs.signature).toBeInstanceOf(Array) - expect(crispInputs.merkle_proof_indices).toBeDefined() - expect(crispInputs.merkle_proof_siblings).toBeDefined() - expect(crispInputs.merkle_proof_length).toBeDefined() - expect(crispInputs.merkle_root).toBeDefined() - expect(crispInputs.balance).toBe(votingPowerLeaf.toString()) + expect(Array.from(encoded).every((b) => b >= 0n && b <= 1n)).toBe(true) }) }) - describe('generateMaskVote', () => { - it('should generate a mask vote and the right circuit inputs', async () => { - const crispInputs = await generateMaskVote(publicKey, previousCiphertext, merkleProof.proof.root, testAddress, false) - - expect(crispInputs.prev_ct0is).toBeInstanceOf(Array) - expect(crispInputs.prev_ct1is).toBeInstanceOf(Array) - expect(crispInputs.sum_ct0is).toBeInstanceOf(Array) - expect(crispInputs.sum_ct1is).toBeInstanceOf(Array) - expect(crispInputs.sum_r0is).toBeInstanceOf(Array) - expect(crispInputs.sum_r1is).toBeInstanceOf(Array) - expect(crispInputs.params).toBeInstanceOf(Object) - expect(crispInputs.ct0is).toBeInstanceOf(Array) - expect(crispInputs.ct1is).toBeInstanceOf(Array) - expect(crispInputs.pk0is).toBeInstanceOf(Array) - expect(crispInputs.pk1is).toBeInstanceOf(Array) - expect(crispInputs.r1is).toBeInstanceOf(Array) - expect(crispInputs.r2is).toBeInstanceOf(Array) - expect(crispInputs.p1is).toBeInstanceOf(Array) - expect(crispInputs.hashed_message).toBeInstanceOf(Array) - expect(crispInputs.public_key_x).toBeInstanceOf(Array) - expect(crispInputs.public_key_y).toBeInstanceOf(Array) - expect(crispInputs.signature).toBeInstanceOf(Array) - expect(crispInputs.merkle_proof_indices).toBeDefined() - expect(crispInputs.merkle_proof_siblings).toBeDefined() - expect(crispInputs.merkle_proof_length).toBeDefined() - expect(crispInputs.merkle_root).toBeDefined() - expect(crispInputs.balance).toBeDefined() - }) - }) - - describe('generateProof/verifyProof', () => { - it('should generate a proof for a voter and verify it', { timeout: 100000 }, async () => { - const encodedVote = encodeVote(VOTE, VotingMode.GOVERNANCE, votingPower) + describe('generateProof', () => { + it('Should generate a proof where the output is the new ciphertext', { timeout: 100000 }, async () => { + // This test simulates a real vote (i.e. generateVoteProof). - // hardhat default private key - const privateKey = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' - const account = privateKeyToAccount(privateKey) - const signature = await account.signMessage({ message: MESSAGE }) - const leaf = hashLeaf(account.address.toLowerCase(), votingPowerLeaf.toString()) - const leaves = [...LEAVES, leaf] - const merkleProof = generateMerkleProof(0n, votingPowerLeaf, account.address.toLowerCase(), leaves) - - const inputs = await encryptVoteAndGenerateCRISPInputs({ - encodedVote, + // Using generateCircuitInputs directly to check the output of the circuit. + const merkleProof = generateMerkleProof(balance, address, LEAVES) + const crispInputs = await generateCircuitInputs({ + vote, publicKey, - previousCiphertext, signature, - message: MESSAGE, - merkleData: merkleProof, - balance: votingPowerLeaf, - slotAddress: account.address.toLowerCase(), - isFirstVote: false, + balance, + slotAddress: address, + merkleProof, }) - const proof = await generateProof(inputs) - const isValid = await verifyProof(proof) - - expect(isValid).toBe(true) - }) - - it('should generate a proof for a masking user and verify it', { timeout: 180000 }, async () => { - const encodedVote = encodeVote(VOTE, VotingMode.GOVERNANCE, votingPower) - const zkInputsGenerator = ZKInputsGenerator.withDefaults() - const vote = BigInt64Array.from(encodedVote.map(BigInt)) - const encryptedVote = zkInputsGenerator.encryptVote(publicKey, vote) - - let maskVote = await generateMaskVote(publicKey, encryptedVote, merkleProof.proof.root, testAddress, false) - - const proof = await generateProof(maskVote) - const isValid = await verifyProof(proof) - - expect(isValid).toBe(true) - }) - - it('should return ciphertext if masking a vote and it is the first operation on the slot', { timeout: 180000 }, async () => { - const encodedVote = encodeVote(VOTE, VotingMode.GOVERNANCE, votingPower) - const zkInputsGenerator = ZKInputsGenerator.withDefaults() - const vote = BigInt64Array.from(encodedVote.map(BigInt)) - const encryptedVote = zkInputsGenerator.encryptVote(publicKey, vote) - - let maskVote = await generateMaskVote(publicKey, encryptedVote, merkleProof.proof.root, testAddress, true) - - const { returnValue } = await generateProofWithReturnValue(maskVote) + const proof = await generateProof(crispInputs) - expect(compareCoefficientsArrays(maskVote.ct0is, (returnValue as any[])[0])).toBe(true) - expect(compareCoefficientsArrays(maskVote.ct1is, (returnValue as any[])[1])).toBe(true) - }) - - it('should return the sum if masking a vote and it is not the first operation on the slot', { timeout: 180000 }, async () => { - const encodedVote = encodeVote(VOTE, VotingMode.GOVERNANCE, votingPower) - const zkInputsGenerator = ZKInputsGenerator.withDefaults() - const vote = BigInt64Array.from(encodedVote.map(BigInt)) - const encryptedVote = zkInputsGenerator.encryptVote(publicKey, vote) - - let maskVote = await generateMaskVote(publicKey, encryptedVote, merkleProof.proof.root, testAddress, false) + expect(proof).toBeDefined() + expect(proof.proof).toBeDefined() + expect(proof.publicInputs).toBeDefined() - const { returnValue } = await generateProofWithReturnValue(maskVote) + const ct0is = crispInputs.ct0is.flatMap((p) => p.coefficients).map((b) => BigInt(b)) + const ct1is = crispInputs.ct1is.flatMap((p) => p.coefficients).map((b) => BigInt(b)) + const outputCiphertext = proof.publicInputs.slice(2).map((b) => BigInt(b)) - expect(compareCoefficientsArrays(maskVote.sum_ct0is, (returnValue as any[])[0])).toBe(true) - expect(compareCoefficientsArrays(maskVote.sum_ct1is, (returnValue as any[])[1])).toBe(true) + expect([...ct0is, ...ct1is]).toEqual(outputCiphertext) }) - it('should throw when the signature is invalid and it is a vote (no masking)', { timeout: 100000 }, async () => { - const encodedVote = encodeVote(VOTE, VotingMode.GOVERNANCE, votingPower) - - // hardhat default private key - const privateKey = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' - const account = privateKeyToAccount(privateKey) - const signature = await account.signMessage({ message: MESSAGE }) - const leaf = hashLeaf(account.address.toLowerCase(), votingPowerLeaf.toString()) - const leaves = [...LEAVES, leaf] - const merkleProof = generateMerkleProof(0n, votingPowerLeaf, account.address.toLowerCase(), leaves) + it( + 'Should generate a proof where the output is the ciphertext addition if there is a previous ciphertext and 0 vote', + { timeout: 100000 }, + async () => { + // This test simulates a mask vote (i.e. generateMaskVoteProof). + + // Using generateCircuitInputs directly to check the output of the circuit. + const merkleProof = generateMerkleProof(balance, slotAddress, LEAVES) + const crispInputs = await generateCircuitInputs({ + vote: { yes: 0n, no: 0n }, + publicKey, + previousCiphertext, + signature: MASK_SIGNATURE, + merkleProof, + balance, + slotAddress, + }) + + const proof = await generateProof(crispInputs) + + expect(proof).toBeDefined() + expect(proof.proof).toBeDefined() + expect(proof.publicInputs).toBeDefined() + + const sumCt0is = crispInputs.sum_ct0is.flatMap((p) => p.coefficients).map((b) => BigInt(b)) + const sumCt1is = crispInputs.sum_ct1is.flatMap((p) => p.coefficients).map((b) => BigInt(b)) + const outputCiphertext = proof.publicInputs.slice(2).map((b) => BigInt(b)) + + expect([...sumCt0is, ...sumCt1is]).toEqual(outputCiphertext) + }, + ) + + it( + 'Should generate a proof where the output is the ciphertext of a 0 vote if there is no previous ciphertext', + { timeout: 100000 }, + async () => { + // This test simulates a mask vote (i.e. generateMaskVoteProof). + + // Using generateCircuitInputs directly to check the output of the circuit. + const merkleProof = generateMerkleProof(balance, slotAddress, LEAVES) + const crispInputs = await generateCircuitInputs({ + vote: { yes: 0n, no: 0n }, + publicKey, + signature: MASK_SIGNATURE, + merkleProof, + balance, + slotAddress, + }) + + const proof = await generateProof(crispInputs) + + expect(proof).toBeDefined() + expect(proof.proof).toBeDefined() + expect(proof.publicInputs).toBeDefined() + + const ct0is = crispInputs.ct0is.flatMap((p) => p.coefficients).map((b) => BigInt(b)) + const ct1is = crispInputs.ct1is.flatMap((p) => p.coefficients).map((b) => BigInt(b)) + const outputCiphertext = proof.publicInputs.slice(2).map((b) => BigInt(b)) + + expect([...ct0is, ...ct1is]).toEqual(outputCiphertext) + }, + ) + }) - const inputs = await encryptVoteAndGenerateCRISPInputs({ - encodedVote, + describe('generateVoteProof', () => { + it('Should generate a valid vote proof', { timeout: 100000 }, async () => { + const proof = await generateVoteProof({ + vote, publicKey, - previousCiphertext, signature, - message: MESSAGE, - merkleData: merkleProof, - balance: votingPowerLeaf, - slotAddress: account.address.toLowerCase(), - isFirstVote: false, + merkleLeaves: LEAVES, + balance, }) - // invalidate signature - inputs.signature[0] = '0' - - await expect(getCircuitOutputValue(inputs)).rejects.toThrow() - }) - - it('should throw when the merkle tree inclusion proof is invalid and it is a vote (no masking)', { timeout: 100000 }, async () => { - const encodedVote = encodeVote(VOTE, VotingMode.GOVERNANCE, votingPower) - - // hardhat default private key - const privateKey = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' - const account = privateKeyToAccount(privateKey) - const signature = await account.signMessage({ message: MESSAGE }) - const leaf = hashLeaf(account.address.toLowerCase(), votingPowerLeaf.toString()) - const leaves = [...LEAVES, leaf] - const merkleProof = generateMerkleProof(0n, votingPowerLeaf, account.address.toLowerCase(), leaves) + expect(proof).toBeDefined() + expect(proof.proof).toBeDefined() + expect(proof.publicInputs).toBeDefined() - const inputs = await encryptVoteAndGenerateCRISPInputs({ - encodedVote, - publicKey, - previousCiphertext, - signature, - message: MESSAGE, - merkleData: merkleProof, - balance: votingPowerLeaf, - slotAddress: account.address.toLowerCase(), - isFirstVote: false, - }) - - // invalidate merkle root - inputs.merkle_root = '0' + const isValid = await verifyProof(proof) - await expect(getCircuitOutputValue(inputs)).rejects.toThrow() + expect(isValid).toBe(true) }) + }) - it('should succeed when the vote is the maximum value supported', { timeout: 100000 }, async () => { - const MAXIMUM_VOTE_VALUE = BigInt(Math.pow(2, 28) - 1) // 268,435,455 - const votingPowerLeaf = MAXIMUM_VOTE_VALUE // Balance at the limit - - // Vote exactly at the maximum - const VOTE = { - yes: MAXIMUM_VOTE_VALUE, - no: 0n, - } - - const encodedVote = encodeVote(VOTE, VotingMode.GOVERNANCE, votingPower) - - // hardhat default private key - const privateKey = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' - const account = privateKeyToAccount(privateKey) - const signature = await account.signMessage({ message: MESSAGE }) - const leaf = hashLeaf(account.address.toLowerCase(), votingPowerLeaf.toString()) - const leaves = [...LEAVES, leaf] - const merkleProof = generateMerkleProof(0n, votingPowerLeaf, account.address.toLowerCase(), leaves) - - const inputs = await encryptVoteAndGenerateCRISPInputs({ - encodedVote, + describe('generateMaskVoteProof', () => { + it('Should generate a valid mask vote proof with a previous ciphertext', { timeout: 100000 }, async () => { + const proof = await generateMaskVoteProof({ + balance, + slotAddress, publicKey, previousCiphertext, - signature, - message: MESSAGE, - merkleData: merkleProof, - balance: votingPowerLeaf, - slotAddress: account.address.toLowerCase(), - isFirstVote: false, + merkleLeaves: LEAVES, }) - // This should pass - vote equals balance - const proof = await generateProof(inputs) + expect(proof).toBeDefined() + expect(proof.proof).toBeDefined() + expect(proof.publicInputs).toBeDefined() + const isValid = await verifyProof(proof) + expect(isValid).toBe(true) }) - it('should throw when the vote is > balance', { timeout: 100000 }, async () => { - const encodedVote = encodeVote(VOTE, VotingMode.GOVERNANCE, votingPower) - - // hardhat default private key - const privateKey = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' - const account = privateKeyToAccount(privateKey) - const signature = await account.signMessage({ message: MESSAGE }) - const leaf = hashLeaf(account.address.toLowerCase(), votingPowerLeaf.toString()) - const leaves = [...LEAVES, leaf] - const merkleProof = generateMerkleProof(0n, votingPowerLeaf, account.address.toLowerCase(), leaves) - - const inputs = await encryptVoteAndGenerateCRISPInputs({ - encodedVote, + it('Should generate a valid mask vote proof without a previous ciphertext', { timeout: 100000 }, async () => { + const proof = await generateMaskVoteProof({ + balance, + slotAddress, publicKey, - previousCiphertext, - signature, - message: MESSAGE, - merkleData: merkleProof, - balance: votingPowerLeaf, - slotAddress: account.address.toLowerCase(), - isFirstVote: false, + merkleLeaves: LEAVES, }) - // set balance to 0 - inputs.balance = '0' + expect(proof).toBeDefined() + expect(proof.proof).toBeDefined() + expect(proof.publicInputs).toBeDefined() + + const isValid = await verifyProof(proof) - await expect(getCircuitOutputValue(inputs)).rejects.toThrow() + expect(isValid).toBe(true) }) }) }) diff --git a/examples/CRISP/packages/crisp-zk-inputs/package.json b/examples/CRISP/packages/crisp-zk-inputs/package.json index 392eacfd59..0c984be69c 100644 --- a/examples/CRISP/packages/crisp-zk-inputs/package.json +++ b/examples/CRISP/packages/crisp-zk-inputs/package.json @@ -2,7 +2,7 @@ "name": "@crisp-e3/zk-inputs", "type": "module", "description": "Core logic to pre-compute CRISP ZK inputs (WASM/JavaScript bindings).", - "version": "0.3.0-test", + "version": "0.4.1", "license": "LGPL-3.0-only", "repository": { "type": "git", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d14232cf59..085db3c2ca 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -143,7 +143,7 @@ importers: examples/CRISP/client: dependencies: '@crisp-e3/sdk': - specifier: 0.3.0-test + specifier: 0.4.1 version: link:../packages/crisp-sdk '@emotion/babel-plugin': specifier: ^11.11.0 @@ -165,7 +165,7 @@ importers: version: 1.13.2 connectkit: specifier: ^1.9.0 - version: 1.9.1(@babel/core@7.28.5)(@tanstack/react-query@5.90.6(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react-is@18.3.1)(react@18.3.1)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)) + version: 1.9.1(@babel/core@7.28.5)(@tanstack/react-query@5.90.6(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react-is@18.3.1)(react@18.3.1)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(wagmi@2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.12)) ethers: specifier: ^6.12.0 version: 6.15.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -186,7 +186,7 @@ importers: version: 15.6.6(react@18.3.1) viem: specifier: 2.38.6 - version: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + version: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) vite-plugin-node-polyfills: specifier: ^0.22.0 version: 0.22.0(rollup@4.52.5)(vite@5.4.21(@types/node@22.7.5)) @@ -198,7 +198,7 @@ importers: version: 4.3.2(typescript@5.8.3)(vite@5.4.21(@types/node@22.7.5)) wagmi: specifier: ^2.14.16 - version: 2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) + version: 2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.12) devDependencies: '@tailwindcss/typography': specifier: ^0.5.12 @@ -11103,16 +11103,16 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@base-org/account@2.4.0(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)': + '@base-org/account@2.4.0(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.12)': dependencies: '@coinbase/cdp-sdk': 1.38.5(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@noble/hashes': 1.4.0 clsx: 1.2.1 eventemitter3: 5.0.1 idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.8.3)(zod@3.25.76) + ox: 0.6.9(typescript@5.8.3)(zod@4.1.12) preact: 10.24.2 - viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) zustand: 5.0.3(@types/react@18.3.26)(immer@10.0.2)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) transitivePeerDependencies: - '@types/react' @@ -11215,26 +11215,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@coinbase/wallet-sdk@4.3.6(@types/react@18.3.26)(bufferutil@4.0.9)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@noble/hashes': 1.4.0 - clsx: 1.2.1 - eventemitter3: 5.0.1 - idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.8.3)(zod@3.25.76) - preact: 10.24.2 - viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - zustand: 5.0.3(@types/react@18.3.26)(immer@10.0.2)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) - transitivePeerDependencies: - - '@types/react' - - bufferutil - - immer - - react - - typescript - - use-sync-external-store - - utf-8-validate - - zod - '@coinbase/wallet-sdk@4.3.6(@types/react@18.3.26)(bufferutil@4.0.9)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: '@noble/hashes': 1.4.0 @@ -11939,14 +11919,6 @@ snapshots: '@semaphore-protocol/contracts': 4.14.0 solady: 0.1.4 - '@gemini-wallet/core@0.3.1(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))': - dependencies: - '@metamask/rpc-errors': 7.0.2 - eventemitter3: 5.0.1 - viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - supports-color - '@gemini-wallet/core@0.3.1(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))': dependencies: '@metamask/rpc-errors': 7.0.2 @@ -13013,17 +12985,6 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-common@1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - big.js: 6.2.2 - dayjs: 1.11.13 - viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - bufferutil - - typescript - - utf-8-validate - - zod - '@reown/appkit-common@1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: big.js: 6.2.2 @@ -13035,41 +12996,6 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-controllers@1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - valtio: 1.13.2(@types/react@18.3.26)(react@18.3.1) - viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod - '@reown/appkit-controllers@1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) @@ -13105,42 +13031,6 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-pay@1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@18.3.26)(react@18.3.1))(zod@3.25.76) - lit: 3.3.0 - valtio: 1.13.2(@types/react@18.3.26)(react@18.3.1) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod - '@reown/appkit-pay@1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) @@ -13181,43 +13071,6 @@ snapshots: dependencies: buffer: 6.0.3 - '@reown/appkit-scaffold-ui@1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@18.3.26)(react@18.3.1))(zod@3.25.76)': - dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@18.3.26)(react@18.3.1))(zod@3.25.76) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) - lit: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - valtio - - zod - '@reown/appkit-scaffold-ui@1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@18.3.26)(react@18.3.1))(zod@4.1.12)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) @@ -13255,41 +13108,6 @@ snapshots: - valtio - zod - '@reown/appkit-ui@1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) - lit: 3.3.0 - qrcode: 1.5.3 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod - '@reown/appkit-ui@1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) @@ -13325,44 +13143,6 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-utils@1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@18.3.26)(react@18.3.1))(zod@3.25.76)': - dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-polyfills': 1.7.8 - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@walletconnect/logger': 2.1.2 - '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - valtio: 1.13.2(@types/react@18.3.26)(react@18.3.1) - viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod - '@reown/appkit-utils@1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@18.3.26)(react@18.3.1))(zod@4.1.12)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) @@ -13412,49 +13192,6 @@ snapshots: - typescript - utf-8-validate - '@reown/appkit@1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-pay': 1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-polyfills': 1.7.8 - '@reown/appkit-scaffold-ui': 1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@18.3.26)(react@18.3.1))(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@18.3.26)(react@18.3.1))(zod@3.25.76) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@walletconnect/types': 2.21.0 - '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - bs58: 6.0.0 - valtio: 1.13.2(@types/react@18.3.26)(react@18.3.1) - viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod - '@reown/appkit@1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) @@ -13627,16 +13364,6 @@ snapshots: transitivePeerDependencies: - '@types/node' - '@safe-global/safe-apps-provider@0.18.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - events: 3.3.0 - transitivePeerDependencies: - - bufferutil - - typescript - - utf-8-validate - - zod - '@safe-global/safe-apps-provider@0.18.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) @@ -13647,16 +13374,6 @@ snapshots: - utf-8-validate - zod - '@safe-global/safe-apps-sdk@9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@safe-global/safe-gateway-typescript-sdk': 3.23.1 - viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - bufferutil - - typescript - - utf-8-validate - - zod - '@safe-global/safe-apps-sdk@9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: '@safe-global/safe-gateway-typescript-sdk': 3.23.1 @@ -15102,9 +14819,9 @@ snapshots: '@vue/shared@3.5.22': {} - '@wagmi/connectors@6.1.3(615998432ed1538eed571631714b7da2)': + '@wagmi/connectors@6.1.3(0b1a0c7e1852d0f2478f1048dd2722c1)': dependencies: - '@base-org/account': 2.4.0(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.12) + '@base-org/account': 2.4.0(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.12) '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.26)(bufferutil@4.0.9)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@4.1.12) '@gemini-wallet/core': 0.3.1(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)) '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -15113,7 +14830,7 @@ snapshots: '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.6)(@types/react@18.3.26)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)) '@walletconnect/ethereum-provider': 2.21.1(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - porto: 0.2.35(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.6)(@types/react@18.3.26)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)))(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(wagmi@2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.12)) + porto: 0.2.35(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.6)(@types/react@18.3.26)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)))(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(wagmi@2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.12)) viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) optionalDependencies: typescript: 5.8.3 @@ -15156,19 +14873,19 @@ snapshots: - ws - zod - '@wagmi/connectors@6.1.3(d4aa626e1ce01c77feebfbcfe6b62584)': + '@wagmi/connectors@6.1.3(615998432ed1538eed571631714b7da2)': dependencies: - '@base-org/account': 2.4.0(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) - '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.26)(bufferutil@4.0.9)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) - '@gemini-wallet/core': 0.3.1(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@base-org/account': 2.4.0(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.12) + '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.26)(bufferutil@4.0.9)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@4.1.12) + '@gemini-wallet/core': 0.3.1(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)) '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.6)(@types/react@18.3.26)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) - '@walletconnect/ethereum-provider': 2.21.1(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.6)(@types/react@18.3.26)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)) + '@walletconnect/ethereum-provider': 2.21.1(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - porto: 0.2.35(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.6)(@types/react@18.3.26)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)))(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)) - viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + porto: 0.2.35(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.6)(@types/react@18.3.26)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)))(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(wagmi@2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.12)) + viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -15210,21 +14927,6 @@ snapshots: - ws - zod - '@wagmi/core@2.22.1(@tanstack/query-core@5.90.6)(@types/react@18.3.26)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))': - dependencies: - eventemitter3: 5.0.1 - mipd: 0.0.7(typescript@5.8.3) - viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - zustand: 5.0.0(@types/react@18.3.26)(immer@10.0.2)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) - optionalDependencies: - '@tanstack/query-core': 5.90.6 - typescript: 5.8.3 - transitivePeerDependencies: - - '@types/react' - - immer - - react - - use-sync-external-store - '@wagmi/core@2.22.1(@tanstack/query-core@5.90.6)(@types/react@18.3.26)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))': dependencies: eventemitter3: 5.0.1 @@ -15240,50 +14942,6 @@ snapshots: - react - use-sync-external-store - '@walletconnect/core@2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@walletconnect/heartbeat': 1.2.2 - '@walletconnect/jsonrpc-provider': 1.0.14 - '@walletconnect/jsonrpc-types': 1.0.4 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@walletconnect/keyvaluestorage': 1.1.1 - '@walletconnect/logger': 2.1.2 - '@walletconnect/relay-api': 1.0.11 - '@walletconnect/relay-auth': 1.1.0 - '@walletconnect/safe-json': 1.0.2 - '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.0 - '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/window-getters': 1.0.1 - es-toolkit: 1.33.0 - events: 3.3.0 - uint8arrays: 3.1.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - ioredis - - typescript - - uploadthing - - utf-8-validate - - zod - '@walletconnect/core@2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: '@walletconnect/heartbeat': 1.2.2 @@ -15328,50 +14986,6 @@ snapshots: - utf-8-validate - zod - '@walletconnect/core@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@walletconnect/heartbeat': 1.2.2 - '@walletconnect/jsonrpc-provider': 1.0.14 - '@walletconnect/jsonrpc-types': 1.0.4 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@walletconnect/keyvaluestorage': 1.1.1 - '@walletconnect/logger': 2.1.2 - '@walletconnect/relay-api': 1.0.11 - '@walletconnect/relay-auth': 1.1.0 - '@walletconnect/safe-json': 1.0.2 - '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.1 - '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/window-getters': 1.0.1 - es-toolkit: 1.33.0 - events: 3.3.0 - uint8arrays: 3.1.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - ioredis - - typescript - - uploadthing - - utf-8-validate - - zod - '@walletconnect/core@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: '@walletconnect/heartbeat': 1.2.2 @@ -15420,47 +15034,6 @@ snapshots: dependencies: tslib: 1.14.1 - '@walletconnect/ethereum-provider@2.21.1(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@reown/appkit': 1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/jsonrpc-http-connection': 1.0.8 - '@walletconnect/jsonrpc-provider': 1.0.14 - '@walletconnect/jsonrpc-types': 1.0.4 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1 - '@walletconnect/sign-client': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/types': 2.21.1 - '@walletconnect/universal-provider': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - events: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod - '@walletconnect/ethereum-provider@2.21.1(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: '@reown/appkit': 1.7.8(@types/react@18.3.26)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) @@ -15595,42 +15168,6 @@ snapshots: dependencies: tslib: 1.14.1 - '@walletconnect/sign-client@2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@walletconnect/core': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/events': 1.0.1 - '@walletconnect/heartbeat': 1.2.2 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/logger': 2.1.2 - '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.0 - '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - events: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - ioredis - - typescript - - uploadthing - - utf-8-validate - - zod - '@walletconnect/sign-client@2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: '@walletconnect/core': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) @@ -15667,42 +15204,6 @@ snapshots: - utf-8-validate - zod - '@walletconnect/sign-client@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@walletconnect/core': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/events': 1.0.1 - '@walletconnect/heartbeat': 1.2.2 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/logger': 2.1.2 - '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.1 - '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - events: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - ioredis - - typescript - - uploadthing - - utf-8-validate - - zod - '@walletconnect/sign-client@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: '@walletconnect/core': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) @@ -15801,46 +15302,6 @@ snapshots: - ioredis - uploadthing - '@walletconnect/universal-provider@2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@walletconnect/events': 1.0.1 - '@walletconnect/jsonrpc-http-connection': 1.0.8 - '@walletconnect/jsonrpc-provider': 1.0.14 - '@walletconnect/jsonrpc-types': 1.0.4 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1 - '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/types': 2.21.0 - '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - es-toolkit: 1.33.0 - events: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - typescript - - uploadthing - - utf-8-validate - - zod - '@walletconnect/universal-provider@2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: '@walletconnect/events': 1.0.1 @@ -15881,46 +15342,6 @@ snapshots: - utf-8-validate - zod - '@walletconnect/universal-provider@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@walletconnect/events': 1.0.1 - '@walletconnect/jsonrpc-http-connection': 1.0.8 - '@walletconnect/jsonrpc-provider': 1.0.14 - '@walletconnect/jsonrpc-types': 1.0.4 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1 - '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/types': 2.21.1 - '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - es-toolkit: 1.33.0 - events: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - typescript - - uploadthing - - utf-8-validate - - zod - '@walletconnect/universal-provider@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: '@walletconnect/events': 1.0.1 @@ -15961,50 +15382,6 @@ snapshots: - utf-8-validate - zod - '@walletconnect/utils@2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@noble/ciphers': 1.2.1 - '@noble/curves': 1.8.1 - '@noble/hashes': 1.7.1 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1 - '@walletconnect/relay-api': 1.0.11 - '@walletconnect/relay-auth': 1.1.0 - '@walletconnect/safe-json': 1.0.2 - '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.0 - '@walletconnect/window-getters': 1.0.1 - '@walletconnect/window-metadata': 1.0.1 - bs58: 6.0.0 - detect-browser: 5.3.0 - query-string: 7.1.3 - uint8arrays: 3.1.0 - viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - ioredis - - typescript - - uploadthing - - utf-8-validate - - zod - '@walletconnect/utils@2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: '@noble/ciphers': 1.2.1 @@ -16049,50 +15426,6 @@ snapshots: - utf-8-validate - zod - '@walletconnect/utils@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@noble/ciphers': 1.2.1 - '@noble/curves': 1.8.1 - '@noble/hashes': 1.7.1 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1 - '@walletconnect/relay-api': 1.0.11 - '@walletconnect/relay-auth': 1.1.0 - '@walletconnect/safe-json': 1.0.2 - '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.1 - '@walletconnect/window-getters': 1.0.1 - '@walletconnect/window-metadata': 1.0.1 - bs58: 6.0.0 - detect-browser: 5.3.0 - query-string: 7.1.3 - uint8arrays: 3.1.0 - viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - ioredis - - typescript - - uploadthing - - utf-8-validate - - zod - '@walletconnect/utils@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: '@noble/ciphers': 1.2.1 @@ -16974,12 +16307,12 @@ snapshots: ini: 1.3.8 proto-list: 1.2.4 - connectkit@1.9.1(@babel/core@7.28.5)(@tanstack/react-query@5.90.6(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react-is@18.3.1)(react@18.3.1)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)): + connectkit@1.9.1(@babel/core@7.28.5)(@tanstack/react-query@5.90.6(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react-is@18.3.1)(react@18.3.1)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(wagmi@2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.12)): dependencies: '@tanstack/react-query': 5.90.6(react@18.3.1) buffer: 6.0.3 detect-browser: 5.3.0 - family: 0.1.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)) + family: 0.1.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(wagmi@2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.12)) framer-motion: 6.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) qrcode: 1.5.4 react: 18.3.1 @@ -16988,8 +16321,8 @@ snapshots: react-use-measure: 2.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1) resize-observer-polyfill: 1.5.1 styled-components: 5.3.11(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react-is@18.3.1)(react@18.3.1) - viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - wagmi: 2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) + viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + wagmi: 2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.12) transitivePeerDependencies: - '@babel/core' - react-is @@ -18164,12 +17497,12 @@ snapshots: eyes@0.1.8: {} - family@0.1.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)): + family@0.1.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(wagmi@2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.12)): optionalDependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - wagmi: 2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) + viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + wagmi: 2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.12) family@0.1.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(wagmi@2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.12)): optionalDependencies: @@ -20710,20 +20043,6 @@ snapshots: os-browserify@0.3.0: {} - ox@0.6.9(typescript@5.8.3)(zod@3.25.76): - dependencies: - '@adraffy/ens-normalize': 1.11.1 - '@noble/curves': 1.9.7 - '@noble/hashes': 1.8.0 - '@scure/bip32': 1.7.0 - '@scure/bip39': 1.6.0 - abitype: 1.1.1(typescript@5.8.3)(zod@3.25.76) - eventemitter3: 5.0.1 - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - zod - ox@0.6.9(typescript@5.8.3)(zod@4.1.12): dependencies: '@adraffy/ens-normalize': 1.11.1 @@ -21067,21 +20386,21 @@ snapshots: style-value-types: 5.0.0 tslib: 2.8.1 - porto@0.2.35(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.6)(@types/react@18.3.26)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)))(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)): + porto@0.2.35(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.6)(@types/react@18.3.26)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)))(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(wagmi@2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.12)): dependencies: - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.6)(@types/react@18.3.26)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.6)(@types/react@18.3.26)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)) hono: 4.10.4 idb-keyval: 6.2.2 mipd: 0.0.7(typescript@5.8.3) ox: 0.9.14(typescript@5.8.3)(zod@4.1.12) - viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) zod: 4.1.12 zustand: 5.0.8(@types/react@18.3.26)(immer@10.0.2)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) optionalDependencies: '@tanstack/react-query': 5.90.6(react@18.3.1) react: 18.3.1 typescript: 5.8.3 - wagmi: 2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) + wagmi: 2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.12) transitivePeerDependencies: - '@types/react' - immer @@ -23083,14 +22402,14 @@ snapshots: vscode-uri@3.1.0: {} - wagmi@2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76): + wagmi@2.19.2(@tanstack/query-core@5.90.6)(@tanstack/react-query@5.90.6(react@18.3.1))(@types/react@18.3.26)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.12): dependencies: '@tanstack/react-query': 5.90.6(react@18.3.1) - '@wagmi/connectors': 6.1.3(d4aa626e1ce01c77feebfbcfe6b62584) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.6)(@types/react@18.3.26)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@wagmi/connectors': 6.1.3(0b1a0c7e1852d0f2478f1048dd2722c1) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.6)(@types/react@18.3.26)(immer@10.0.2)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)) react: 18.3.1 use-sync-external-store: 1.4.0(react@18.3.1) - viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: