From 3b3d197873d8935c77b4df1b219415fd4632a06d Mon Sep 17 00:00:00 2001 From: leo Sayous Date: Tue, 18 Jul 2023 23:02:37 +0200 Subject: [PATCH] feat: simplify configuration and request copied in frontend and contract --- abi/Airdrop.json | 87 --------------------------- front/src/app/components/Header.tsx | 15 +++-- front/src/app/page.tsx | 84 ++++---------------------- front/src/app/sismo-connect-config.ts | 78 ++++++++++++++++++++++++ src/Airdrop.sol | 71 ++++++---------------- 5 files changed, 115 insertions(+), 220 deletions(-) create mode 100644 front/src/app/sismo-connect-config.ts diff --git a/abi/Airdrop.json b/abi/Airdrop.json index 5c4491d..daaf078 100644 --- a/abi/Airdrop.json +++ b/abi/Airdrop.json @@ -375,93 +375,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "getSismoConnectRequest", - "outputs": [ - { - "components": [ - { - "internalType": "enum AuthType", - "name": "authType", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "userId", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "isAnon", - "type": "bool" - }, - { - "internalType": "bool", - "name": "isOptional", - "type": "bool" - }, - { - "internalType": "bool", - "name": "isSelectableByUser", - "type": "bool" - }, - { - "internalType": "bytes", - "name": "extraData", - "type": "bytes" - } - ], - "internalType": "struct AuthRequest[]", - "name": "", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "enum ClaimType", - "name": "claimType", - "type": "uint8" - }, - { - "internalType": "bytes16", - "name": "groupId", - "type": "bytes16" - }, - { - "internalType": "bytes16", - "name": "groupTimestamp", - "type": "bytes16" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "isOptional", - "type": "bool" - }, - { - "internalType": "bool", - "name": "isSelectableByUser", - "type": "bool" - }, - { - "internalType": "bytes", - "name": "extraData", - "type": "bytes" - } - ], - "internalType": "struct ClaimRequest[]", - "name": "", - "type": "tuple[]" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "getSismoConnectVerifiedResult", diff --git a/front/src/app/components/Header.tsx b/front/src/app/components/Header.tsx index 640813e..b7cc66d 100644 --- a/front/src/app/components/Header.tsx +++ b/front/src/app/components/Header.tsx @@ -24,19 +24,22 @@ const Header: React.FC = () => {

- src/front/app/page.tsx: Frontend - Queries contract to know Sismo Connect Configuration and Request, requests ZK Proofs from users via Sismo Connect Button + front/src/app/page.tsx: Frontend - Integrate Sismo Connect Button and make Sismo Connect request

- src/Airdrop.sol: Contract - Sets up the Sismo Connect Configuration and Request, verifies Sismo Connect response, - mints tokens and stores verified claims, auths and signed message + front/src/app/sismo-connect-config.ts: Sismo Connect configuration and requests +

+

+ src/Airdrop.sol: Contract - verifies Sismo Connect response and stores verified claims, auths and signed message

{" "} Notes:
- 1. If you are using metamask and transactions hang. Go to settings > advanced > clear activity and nonce data
- 2. First ZK Proof generation takes longer time, especially with bad internet as there is a + 1. You should exactly the same Configuration (AppId and impersonation), AuthRequests and ClaimsRequests in the frontend and in your contract
+ 2. If you are using metamask and transactions hang. Go to settings > advanced > clear activity and nonce data
+ 3. First ZK Proof generation takes longer time, especially with bad internet as there is a zkey file to download once in the data vault connection
- 3. The more proofs you request, the longer it takes to generate them (about 2 secs per + 4. The more proofs you request, the longer it takes to generate them (about 2 secs per proof)

diff --git a/front/src/app/page.tsx b/front/src/app/page.tsx index ffceeee..8196aa7 100644 --- a/front/src/app/page.tsx +++ b/front/src/app/page.tsx @@ -40,46 +40,14 @@ import { ClaimType, SismoConnectConfig, } from "@sismo-core/sismo-connect-react"; +import { AUTHS, CLAIMS, CONFIG } from "@/app/sismo-connect-config"; -/* ********************** Sismo Connect Config *************************** */ -// For development purposes insert the Data Sources that you want to impersonate -// Never use this in production -// the appId is not referenced here as it is set directly in the contract -export const CONFIG: Omit = { - vault: { - // For development purposes insert the Data Sources that you want to impersonate - // Never use this in production - impersonate: [ - // EVM Data Sources - "dhadrien.sismo.eth", - "0xA4C94A6091545e40fc9c3E0982AEc8942E282F38", - "0x1b9424ed517f7700e7368e34a9743295a225d889", - "0x82fbed074f62386ed43bb816f748e8817bf46ff7", - "0xc281bd4db5bf94f02a8525dca954db3895685700", - // Github Data Source - "github:dhadrien", - // Twitter Data Source - "twitter:dhadrien_", - // Telegram Data Source - "telegram:dhadrien", - ], - }, - // displayRawResponse: true, // this enables you to get access directly to the - // Sismo Connect Response in the vault instead of redirecting back to the app -}; /* ******************** Defines the chain to use *************************** */ const CHAIN = mumbaiFork; export default function Home() { const [pageState, setPageState] = useState("init"); - const [sismoConnectConfig, setSismoConnectConfig] = useState({ - appId: "", - }); - const [sismoConnectRequest, setSismoConnectRequest] = useState<{ - auths: AuthRequest[]; - claims: ClaimRequest[]; - } | null>(null); const [sismoConnectVerifiedResult, setSismoConnectVerifiedResult] = useState<{ verifiedClaims: VerifiedClaim[]; verifiedAuths: VerifiedAuth[]; @@ -100,34 +68,6 @@ export default function Home() { // Get the SismoConnectConfig and Sismo Connect Request from the contract // Set react state accordingly to display the Sismo Connect Button - useEffect(() => { - if (!isConnected) return; - if (chain?.id !== CHAIN.id) { - setSismoConnectRequest(null); - return; - } - async function getRequests() { - const appId = (await airdropContract.read.APP_ID()) as string; - const isImpersonationMode = (await airdropContract.read.IS_IMPERSONATION_MODE()) as boolean; - const sismoConnectRequest = (await airdropContract.read.getSismoConnectRequest()) as [ - AuthRequest[], - ClaimRequest[] - ]; - const { authRequests, claimRequests } = - getAuthRequestsAndClaimRequestsFromSismoConnectRequest(sismoConnectRequest); - - setSismoConnectConfig({ - appId, - // we impersonate accounts if the impersonation mode is set to true in the contract - vault: (isImpersonationMode === true ? CONFIG.vault : {}) as VaultConfig, - }); - setSismoConnectRequest({ - auths: authRequests, - claims: claimRequests, - }); - } - getRequests(); - }, [pageState, chain]); useEffect(() => { setClaimError(error); @@ -138,8 +78,6 @@ export default function Home() { /* ************************* Reset state **************************** */ function resetApp() { setPageState("init"); - setSismoConnectConfig({ appId: "" }); - setSismoConnectRequest(null); setSismoConnectVerifiedResult(null); setClaimError(""); const url = new URL(window.location.href); @@ -201,16 +139,16 @@ export default function Home() { Your airdrop destination address is: {address}

- {pageState == "init" && sismoConnectRequest && ( + {pageState == "init" && ( <> - {sismoConnectRequest?.auths?.map((auth, index) => ( + {AUTHS.map((auth, index) => ( {AuthType[auth.authType]} {auth.userId || "No userId requested"} @@ -362,7 +300,7 @@ export default function Home() { - {sismoConnectRequest?.claims?.map((claim, index) => ( + {CLAIMS.map((claim, index) => ( = 17 + groupId: "0x85c7ee90829de70d0d51f52336ea4722", + claimType: ClaimType.GTE, + value: 4, // impersonated dhadrien.sismo.eth has 17 votes, eligible + }, + { + // claim on Stand with Crypto NFT Minters Data Group membership: https://factory.sismo.io/groups-explorer?search=0xfae674b6cba3ff2f8ce2114defb200b1 + // Data Group members = minters of the Stand with Crypto NFT + // value for each group member = number of NFT minted + // request user to prove membership in the group with value = 10 + groupId: "0xfae674b6cba3ff2f8ce2114defb200b1", + claimType: ClaimType.EQ, + value: 10, // dhadrin.sismo.eth minted exactly 10, eligible + isSelectableByUser: true, // can reveal more than 15 if they want + isOptional: true, + }, +]; diff --git a/src/Airdrop.sol b/src/Airdrop.sol index cbea912..4788514 100644 --- a/src/Airdrop.sol +++ b/src/Airdrop.sol @@ -24,12 +24,6 @@ contract Airdrop is ERC20, SismoConnect { // it should be set to false for production bool private _isImpersonationMode = true; - // these requests should be queried by the app frontend - // Sismo Connect response's zk proofs will be checked against these requests. - // check _setRequests function to see how these requests are built - AuthRequest[] private _authRequests; - ClaimRequest[] private _claimRequests; - // Results of the verification of the Sismo Connect response. VerifiedAuth[] internal _verifiedAuths; VerifiedClaim[] internal _verifiedClaims; @@ -41,7 +35,15 @@ contract Airdrop is ERC20, SismoConnect { ) ERC20(name, symbol) SismoConnect(buildConfig(_appId, _isImpersonationMode)) { // Defining requests that will be queried by the app frontend to allow users to generate a Sismo Connect response in their Sismo Vault // The Sismo Connect Response holding the zk proofs will be checked against these requests in the claimWithSismo function below + } + /** + * @dev Claim the airdrop with a Sismo Connect response + * Sismo Connect response's zk proofs will be checked against the requests defined in the constructor above + * @param response Sismo Connect response + * @param to address to mint the airdrop to + */ + function claimWithSismo(bytes memory response, address to) public { // Request users to prove ownership of a Data Source (Wallet, Twitter, Github, Telegram, etc.) AuthRequest[] memory authRequests = new AuthRequest[](3); // Anonymous identifier of the vault for this app @@ -64,42 +66,34 @@ contract Airdrop is ERC20, SismoConnect { // Data Group members = contributors to sismo-core/sismo-hub // value for each group member = number of contributions // request user to prove membership in the group - claimRequests[0] = buildClaim({groupId: bytes16(0xda1c3726426d5639f4c6352c2c976b87)}); + claimRequests[0] = buildClaim({groupId: 0xda1c3726426d5639f4c6352c2c976b87}); // claim ENS DAO Voters Data Group membership: https://factory.sismo.io/groups-explorer?search=0x85c7ee90829de70d0d51f52336ea4722 // Data Group members = voters in ENS DAO // value for each group member = number of votes in ENS DAO // request user to prove membership in the group with value >= 4 - claimRequests[1] = buildClaim({groupId: bytes16(0x85c7ee90829de70d0d51f52336ea4722), value: 4}); + claimRequests[1] = buildClaim({ + groupId: 0x85c7ee90829de70d0d51f52336ea4722, + value: 4, + claimType: ClaimType.GTE + }); // claim on Stand with Crypto NFT Minters Data Group membership: https://factory.sismo.io/groups-explorer?search=0xfae674b6cba3ff2f8ce2114defb200b1 // Data Group members = minters of the Stand with Crypto NFT // value for each group member = number of NFT minted // request user to prove membership in the group with value = 10 claimRequests[2] = buildClaim({ - groupId: bytes16(0xfae674b6cba3ff2f8ce2114defb200b1), + groupId: 0xfae674b6cba3ff2f8ce2114defb200b1, value: 10, claimType: ClaimType.EQ, isOptional: true, isSelectableByUser: true }); - // storing auth and claim requests in storage - // the frontend will query the Sismo Connect request from the contract - _setSismoConnectRequest({auths: authRequests, claims: claimRequests}); - } - - /** - * @dev Claim the airdrop with a Sismo Connect response - * Sismo Connect response's zk proofs will be checked against the requests defined in the constructor above - * @param response Sismo Connect response - * @param to address to mint the airdrop to - */ - function claimWithSismo(bytes memory response, address to) public { SismoConnectVerifiedResult memory result = verify({ responseBytes: response, // checking response against requested auths - auths: _authRequests, + auths: authRequests, // checking response against requested claims - claims: _claimRequests, + claims: claimRequests, // checking response against a message signature // the message is the address to mint the airdrop to // this signature prevents front-running attacks @@ -126,17 +120,6 @@ contract Airdrop is ERC20, SismoConnect { emit SignedMessageVerified(result.signedMessage); } - /** - * @dev Get the Sismo Connect request that was defined in the constructor - */ - function getSismoConnectRequest() - external - view - returns (AuthRequest[] memory, ClaimRequest[] memory) - { - return (_authRequests, _claimRequests); - } - /** * @dev Get the verified auths, claims and the verified signature that was verified in the claimWithSismo function */ @@ -150,26 +133,6 @@ contract Airdrop is ERC20, SismoConnect { // helpers - function _setSismoConnectRequest( - AuthRequest[] memory auths, - ClaimRequest[] memory claims - ) private { - _setAuths(auths); - _setClaims(claims); - } - - function _setAuths(AuthRequest[] memory auths) private { - for (uint256 i = 0; i < auths.length; i++) { - _authRequests.push(auths[i]); - } - } - - function _setClaims(ClaimRequest[] memory claims) private { - for (uint256 i = 0; i < claims.length; i++) { - _claimRequests.push(claims[i]); - } - } - function _removePreviousVerifiedResults() private { _cleanVerifiedAuths(); _cleanVerifiedClaims();