From de4bf207eeaddfc775e9612e19be314e1c00e5f8 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer <98749896+remicolin@users.noreply.github.com> Date: Mon, 16 Jun 2025 06:14:19 -0400 Subject: [PATCH 1/5] merge dev branch into main (#624) * remove sdk/tests (#622) * remove sdk/tests * chore: update yarn.lock --------- Co-authored-by: Ayman * fix: add range check on paddedInLength of shaBytesDynamic (#623) * fix ci (#626) --------- Co-authored-by: Ayman Co-authored-by: Vishalkulkarni45 <109329073+Vishalkulkarni45@users.noreply.github.com> --- .github/actions/mobile-setup/action.yml | 1 + .github/actions/yarn-install/action.yml | 3 +- .github/workflows/artifacts.yml | 8 +- .../hasher/shaBytes/shaBytesDynamic.circom | 10 +- package.json | 1 - sdk/tests/api-server/.env.sample | 2 - sdk/tests/api-server/.gitignore | 44 - sdk/tests/api-server/README.md | 15 - sdk/tests/api-server/bun.lockb | Bin 258250 -> 0 bytes sdk/tests/api-server/package.json | 32 - sdk/tests/api-server/src/app.routes.ts | 8 - sdk/tests/api-server/src/app.ts | 31 - .../infrastructure/contracts.controller.ts | 52 - sdk/tests/api-server/tsconfig.json | 15 - sdk/tests/web-app/.env.sample | 2 - sdk/tests/web-app/.eslintrc.json | 3 - sdk/tests/web-app/.gitignore | 38 - sdk/tests/web-app/.yarnrc.yml | 1 - sdk/tests/web-app/README.md | 36 - sdk/tests/web-app/next.config.mjs | 4 - sdk/tests/web-app/package.json | 35 - sdk/tests/web-app/postcss.config.mjs | 8 - sdk/tests/web-app/src/app/api/verify/route.ts | 55 - sdk/tests/web-app/src/app/disclose/logo.ts | 1 - sdk/tests/web-app/src/app/disclose/page.tsx | 42 - sdk/tests/web-app/src/app/favicon.ico | Bin 25931 -> 0 bytes .../web-app/src/app/fonts/GeistMonoVF.woff | Bin 67864 -> 0 bytes sdk/tests/web-app/src/app/fonts/GeistVF.woff | Bin 66268 -> 0 bytes sdk/tests/web-app/src/app/globals.css | 27 - sdk/tests/web-app/src/app/layout.tsx | 31 - sdk/tests/web-app/src/app/page.tsx | 41 - .../web-app/src/app/verified/page.module.css | 51 - sdk/tests/web-app/src/app/verified/page.tsx | 23 - .../web-app/src/app/verified/skeleton.gif | Bin 228243 -> 0 bytes sdk/tests/web-app/tailwind.config.ts | 19 - sdk/tests/web-app/tsconfig.json | 26 - yarn.lock | 5213 +---------------- 37 files changed, 148 insertions(+), 5730 deletions(-) delete mode 100644 sdk/tests/api-server/.env.sample delete mode 100644 sdk/tests/api-server/.gitignore delete mode 100644 sdk/tests/api-server/README.md delete mode 100755 sdk/tests/api-server/bun.lockb delete mode 100644 sdk/tests/api-server/package.json delete mode 100644 sdk/tests/api-server/src/app.routes.ts delete mode 100644 sdk/tests/api-server/src/app.ts delete mode 100644 sdk/tests/api-server/src/contracts/infrastructure/contracts.controller.ts delete mode 100644 sdk/tests/api-server/tsconfig.json delete mode 100644 sdk/tests/web-app/.env.sample delete mode 100644 sdk/tests/web-app/.eslintrc.json delete mode 100644 sdk/tests/web-app/.gitignore delete mode 100644 sdk/tests/web-app/.yarnrc.yml delete mode 100644 sdk/tests/web-app/README.md delete mode 100644 sdk/tests/web-app/next.config.mjs delete mode 100644 sdk/tests/web-app/package.json delete mode 100644 sdk/tests/web-app/postcss.config.mjs delete mode 100644 sdk/tests/web-app/src/app/api/verify/route.ts delete mode 100644 sdk/tests/web-app/src/app/disclose/logo.ts delete mode 100644 sdk/tests/web-app/src/app/disclose/page.tsx delete mode 100644 sdk/tests/web-app/src/app/favicon.ico delete mode 100644 sdk/tests/web-app/src/app/fonts/GeistMonoVF.woff delete mode 100644 sdk/tests/web-app/src/app/fonts/GeistVF.woff delete mode 100644 sdk/tests/web-app/src/app/globals.css delete mode 100644 sdk/tests/web-app/src/app/layout.tsx delete mode 100644 sdk/tests/web-app/src/app/page.tsx delete mode 100644 sdk/tests/web-app/src/app/verified/page.module.css delete mode 100644 sdk/tests/web-app/src/app/verified/page.tsx delete mode 100644 sdk/tests/web-app/src/app/verified/skeleton.gif delete mode 100644 sdk/tests/web-app/tailwind.config.ts delete mode 100644 sdk/tests/web-app/tsconfig.json diff --git a/.github/actions/mobile-setup/action.yml b/.github/actions/mobile-setup/action.yml index 82429762c..291c0598f 100644 --- a/.github/actions/mobile-setup/action.yml +++ b/.github/actions/mobile-setup/action.yml @@ -52,5 +52,6 @@ runs: run: | cd ${{ inputs.app_path }} corepack enable + yarn set version 4.6.0 yarn install yarn install-app:deploy diff --git a/.github/actions/yarn-install/action.yml b/.github/actions/yarn-install/action.yml index 11e4fc824..24eb20f27 100644 --- a/.github/actions/yarn-install/action.yml +++ b/.github/actions/yarn-install/action.yml @@ -15,7 +15,8 @@ runs: shell: bash run: | corepack enable - corepack prepare yarn@4.5.0 --activate + corepack prepare yarn@4.6.0 --activate + yarn set version 4.6.0 - name: Setup Node.js uses: actions/setup-node@v4 diff --git a/.github/workflows/artifacts.yml b/.github/workflows/artifacts.yml index d5827be3a..8c434c7ec 100644 --- a/.github/workflows/artifacts.yml +++ b/.github/workflows/artifacts.yml @@ -40,7 +40,9 @@ jobs: - name: Install dependencies run: | - npm i -g yarn && cd circuits && yarn + corepack enable + yarn set version 4.6.0 + cd circuits && yarn - name: Setup Rust uses: dtolnay/rust-toolchain@stable @@ -58,8 +60,8 @@ jobs: - name: Build cpp circuits run: | chmod +x circuits/scripts/build/build_cpp.sh && \ - ./circuits/scripts/build/build_cpp.sh register && - ./circuits/scripts/build/build_cpp.sh disclose && + ./circuits/scripts/build/build_cpp.sh register && + ./circuits/scripts/build/build_cpp.sh disclose && ./circuits/scripts/build/build_cpp.sh dsc - name: Upload Artifact diff --git a/circuits/circuits/utils/crypto/hasher/shaBytes/shaBytesDynamic.circom b/circuits/circuits/utils/crypto/hasher/shaBytes/shaBytesDynamic.circom index 1803f0130..51b302cca 100644 --- a/circuits/circuits/utils/crypto/hasher/shaBytes/shaBytesDynamic.circom +++ b/circuits/circuits/utils/crypto/hasher/shaBytes/shaBytesDynamic.circom @@ -3,6 +3,8 @@ pragma circom 2.1.9; include "./dynamic/sha1Bytes.circom"; include "./dynamic/sha224Bytes.circom"; include "@openpassport/zk-email-circuits/lib/sha.circom"; +include "@openpassport/zk-email-circuits/utils/array.circom"; +include "circomlib/circuits/bitify.circom"; include "./dynamic/sha384Bytes.circom"; include "./dynamic/sha512Bytes.circom"; @@ -19,6 +21,10 @@ template ShaBytesDynamic(hashLen, max_num_bytes) { signal output hash_bits[hashLen]; + // Assert `in_len_padded_bytes` fits in `ceil(log2(max_num_bytes * 8))` + component rangeCheck = Num2Bits(log2Ceil(max_num_bytes * 8)); + rangeCheck.in <== in_len_padded_bytes; + if (hashLen == 512) { hash_bits <== Sha512Bytes(max_num_bytes)(in_padded, in_len_padded_bytes); } @@ -28,11 +34,11 @@ template ShaBytesDynamic(hashLen, max_num_bytes) { if (hashLen == 256) { hash_bits <== Sha256Bytes(max_num_bytes)(in_padded, in_len_padded_bytes); } - if (hashLen == 224) { + if (hashLen == 224) { hash_bits <== Sha224Bytes(max_num_bytes)(in_padded, in_len_padded_bytes); } if (hashLen == 160) { hash_bits <== Sha1Bytes(max_num_bytes)(in_padded, in_len_padded_bytes); } -} \ No newline at end of file +} diff --git a/package.json b/package.json index bf160db6d..ef991d10a 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,6 @@ "circuits", "contracts", "sdk/*", - "sdk/tests/*", "prover/tests" ], "scripts": { diff --git a/sdk/tests/api-server/.env.sample b/sdk/tests/api-server/.env.sample deleted file mode 100644 index d6a1d35a5..000000000 --- a/sdk/tests/api-server/.env.sample +++ /dev/null @@ -1,2 +0,0 @@ -RPC_URL=https://forno.celo.org -SCOPE=test-scope \ No newline at end of file diff --git a/sdk/tests/api-server/.gitignore b/sdk/tests/api-server/.gitignore deleted file mode 100644 index fb94ae776..000000000 --- a/sdk/tests/api-server/.gitignore +++ /dev/null @@ -1,44 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# local env files -.env.local -.env.development.local -.env.test.local -.env.production.local - -# vercel -.vercel - -**/*.trace -**/*.zip -**/*.tar.gz -**/*.tgz -**/*.log -package-lock.json -**/*.bun - -.env \ No newline at end of file diff --git a/sdk/tests/api-server/README.md b/sdk/tests/api-server/README.md deleted file mode 100644 index 688c87e69..000000000 --- a/sdk/tests/api-server/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Elysia with Bun runtime - -## Getting Started -To get started with this template, simply paste this command into your terminal: -```bash -bun create elysia ./elysia-example -``` - -## Development -To start the development server run: -```bash -bun run dev -``` - -Open http://localhost:3000/ with your browser to see the result. \ No newline at end of file diff --git a/sdk/tests/api-server/bun.lockb b/sdk/tests/api-server/bun.lockb deleted file mode 100755 index dea8b1fcbd8c8aafbb57e4328bee1648e010a56f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 258250 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
6V-gSuM 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 BT-*Qv diff --git a/sdk/tests/api-server/package.json b/sdk/tests/api-server/package.json deleted file mode 100644 index 8dc306cbd..000000000 --- a/sdk/tests/api-server/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "backend-api", - "version": "1.0.50", - "module": "index.ts", - "scripts": { - "dev": "bun run --watch src/app.ts", - "init": "bash scripts/copy_abi.sh && bash scripts/copy_deployedAddress.sh", - "start:daemon": "bun run src/app.ts > app.log 2>&1 &", - "stop:daemon": "pkill -f 'bun run src/app.ts'", - "test": "echo \"Error: no test specified\" && exit 1", - "types": "tsc --noEmit" - }, - "dependencies": { - "@elysiajs/swagger": "^1.2.0", - "@openpassport/zk-kit-imt": "^0.0.5", - "@openpassport/zk-kit-lean-imt": "^0.0.6", - "@selfxyz/core": "^0.0.3", - "dotenv": "^16.4.7", - "elysia": "latest", - "logixlysia": "^4.1.1", - "pg": "^8.13.1", - "poseidon-lite": "^0.3.0", - "snarkjs": "^0.7.5", - "swagger": "^0.7.5", - "viem": "^2.22.23" - }, - "devDependencies": { - "@types/pg": "^8.11.11", - "bun-types": "latest", - "typescript": "^5.8.3" - } -} diff --git a/sdk/tests/api-server/src/app.routes.ts b/sdk/tests/api-server/src/app.routes.ts deleted file mode 100644 index 3870e30ed..000000000 --- a/sdk/tests/api-server/src/app.routes.ts +++ /dev/null @@ -1,8 +0,0 @@ -import Elysia from 'elysia'; - -import { ContractsController } from './contracts/infrastructure/contracts.controller'; - -const routes = new Elysia({ prefix: 'api/v1' }) - .use(ContractsController); - -export { routes as AppRoutes }; \ No newline at end of file diff --git a/sdk/tests/api-server/src/app.ts b/sdk/tests/api-server/src/app.ts deleted file mode 100644 index 34f2c3836..000000000 --- a/sdk/tests/api-server/src/app.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Elysia } from "elysia"; -import swagger from "@elysiajs/swagger"; -import logger from "logixlysia"; -import { AppRoutes } from "./app.routes.js"; -import dotenv from "dotenv"; - -dotenv.config(); - -const app = new Elysia() - .use(logger()) - .use( - swagger({ - exclude: ['/swagger'], - autoDarkMode: true, - documentation: { - info: { - title: 'backend-api', - description: - 'backend api to interact with the contracts', - version: '1.0.0', - }, - }, - }), - ) - .use(AppRoutes); - -app.listen({ port: process.env.PORT }); - -console.log( - `🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`, -); \ No newline at end of file diff --git a/sdk/tests/api-server/src/contracts/infrastructure/contracts.controller.ts b/sdk/tests/api-server/src/contracts/infrastructure/contracts.controller.ts deleted file mode 100644 index 17aca6cff..000000000 --- a/sdk/tests/api-server/src/contracts/infrastructure/contracts.controller.ts +++ /dev/null @@ -1,52 +0,0 @@ -import Elysia, { t } from 'elysia'; -import { SelfBackendVerifier } from "@selfxyz/core"; - -export const ContractsController = new Elysia() - .post( - 'verify-vc-and-disclose-proof', - async (request: any) => { - try { - const selfBackendVerifier = new SelfBackendVerifier( - process.env.RPC_URL as string, - process.env.SCOPE as string, - ); - - const result = await selfBackendVerifier.verify( - request.body.proof, - request.body.publicSignals - ); - console.log(result); - - return { - status: "success", - result: result.isValid, - }; - } catch (error) { - return { - status: "error", - message: error instanceof Error ? error.message : "Unknown error", - }; - } - }, - { - body: t.Object({ - proof: t.Any(), - publicSignals: t.Any(), - }), - response: { - 200: t.Object({ - status: t.String(), - result: t.Boolean(), - }), - 500: t.Object({ - status: t.String(), - message: t.String(), - }), - }, - detail: { - tags: ['Contracts'], - summary: 'Verify a VC and disclose a proof', - description: 'Verify a VC and disclose a proof', - }, - }, - ); diff --git a/sdk/tests/api-server/tsconfig.json b/sdk/tests/api-server/tsconfig.json deleted file mode 100644 index 9facb1cae..000000000 --- a/sdk/tests/api-server/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2021", - "module": "NodeNext", - "moduleResolution": "nodenext", - "types": [ - "bun-types" - ], - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true, - "resolveJsonModule": true - } -} diff --git a/sdk/tests/web-app/.env.sample b/sdk/tests/web-app/.env.sample deleted file mode 100644 index 61b90ed7e..000000000 --- a/sdk/tests/web-app/.env.sample +++ /dev/null @@ -1,2 +0,0 @@ -END_POINT= -SCOPE= \ No newline at end of file diff --git a/sdk/tests/web-app/.eslintrc.json b/sdk/tests/web-app/.eslintrc.json deleted file mode 100644 index 372241854..000000000 --- a/sdk/tests/web-app/.eslintrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": ["next/core-web-vitals", "next/typescript"] -} diff --git a/sdk/tests/web-app/.gitignore b/sdk/tests/web-app/.gitignore deleted file mode 100644 index b9f8d23e8..000000000 --- a/sdk/tests/web-app/.gitignore +++ /dev/null @@ -1,38 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js -.yarn/install-state.gz - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# local env files -.env*.local - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts - -.env \ No newline at end of file diff --git a/sdk/tests/web-app/.yarnrc.yml b/sdk/tests/web-app/.yarnrc.yml deleted file mode 100644 index 3186f3f07..000000000 --- a/sdk/tests/web-app/.yarnrc.yml +++ /dev/null @@ -1 +0,0 @@ -nodeLinker: node-modules diff --git a/sdk/tests/web-app/README.md b/sdk/tests/web-app/README.md deleted file mode 100644 index e215bc4cc..000000000 --- a/sdk/tests/web-app/README.md +++ /dev/null @@ -1,36 +0,0 @@ -This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). - -## Getting Started - -First, run the development server: - -```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev -``` - -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. - -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. - -This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. - -## Learn More - -To learn more about Next.js, take a look at the following resources: - -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. - -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! - -## Deploy on Vercel - -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. - -Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/sdk/tests/web-app/next.config.mjs b/sdk/tests/web-app/next.config.mjs deleted file mode 100644 index 4678774e6..000000000 --- a/sdk/tests/web-app/next.config.mjs +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('next').NextConfig} */ -const nextConfig = {}; - -export default nextConfig; diff --git a/sdk/tests/web-app/package.json b/sdk/tests/web-app/package.json deleted file mode 100644 index f0b5ac853..000000000 --- a/sdk/tests/web-app/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "test-web-app", - "version": "0.1.0", - "private": true, - "type": "module", - "scripts": { - "build": "next build", - "dev": "next dev", - "lint": "next lint", - "start": "next start", - "types": "yarn build" - }, - "dependencies": { - "@emotion/react": "^11.13.3", - "@emotion/styled": "^11.13.0", - "@mui/material": "^6.0.2", - "@selfxyz/common": "workspace:^", - "@selfxyz/qrcode": "workspace:^", - "axios": "^1.7.7", - "next": "14.2.8", - "react": "^18", - "react-dom": "^18", - "uuid": "^11.1.0" - }, - "devDependencies": { - "@types/node": "^20", - "@types/react": "^18", - "@types/react-dom": "^18", - "eslint": "^8", - "eslint-config-next": "14.2.8", - "postcss": "^8", - "tailwindcss": "^3.4.1", - "typescript": "^5" - } -} diff --git a/sdk/tests/web-app/postcss.config.mjs b/sdk/tests/web-app/postcss.config.mjs deleted file mode 100644 index 1a69fd2a4..000000000 --- a/sdk/tests/web-app/postcss.config.mjs +++ /dev/null @@ -1,8 +0,0 @@ -/** @type {import('postcss-load-config').Config} */ -const config = { - plugins: { - tailwindcss: {}, - }, -}; - -export default config; diff --git a/sdk/tests/web-app/src/app/api/verify/route.ts b/sdk/tests/web-app/src/app/api/verify/route.ts deleted file mode 100644 index 3a84e9b45..000000000 --- a/sdk/tests/web-app/src/app/api/verify/route.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { SelfBackendVerifier } from '@selfxyz/core'; -import { NextResponse } from 'next/server'; -import { countries } from '@selfxyz/common/constants/countries'; - -export async function POST(request: Request) { - try { - const body = await request.json(); - const { proof, publicSignals } = body; - - if (!proof || !publicSignals) { - return NextResponse.json( - { message: 'Proof and publicSignals are required' }, - { status: 400 } - ); - } - - const configuredVerifier = new SelfBackendVerifier( - 'https://forno.celo.org', - "self-workshop", - 'uuid', - ) - .setMinimumAge(18) - .excludeCountries( - countries.RUSSIA, - countries.CHINA, - countries.NORTH_KOREA, - countries.IRAN - ) - .setNationality(countries.JAPAN); - - const result = await configuredVerifier.verify(proof, publicSignals); - console.log("Verification result:", result); - - if (result.isValid) { - return NextResponse.json({ - status: 'success', - result: result.isValid, - credentialSubject: result.credentialSubject - }); - } else { - return NextResponse.json({ - status: 'error', - result: result.isValid, - message: 'Verification failed', - details: result.isValidDetails - }, { status: 400 }); - } - } catch (error) { - console.error('Error verifying proof:', error); - return NextResponse.json({ - message: 'Error verifying proof', - error: error instanceof Error ? error.message : 'Unknown error' - }, { status: 500 }); - } -} diff --git a/sdk/tests/web-app/src/app/disclose/logo.ts b/sdk/tests/web-app/src/app/disclose/logo.ts deleted file mode 100644 index 99557e1f6..000000000 --- a/sdk/tests/web-app/src/app/disclose/logo.ts +++ /dev/null @@ -1 +0,0 @@ -export const logo = "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"; \ No newline at end of file diff --git a/sdk/tests/web-app/src/app/disclose/page.tsx b/sdk/tests/web-app/src/app/disclose/page.tsx deleted file mode 100644 index c4b777945..000000000 --- a/sdk/tests/web-app/src/app/disclose/page.tsx +++ /dev/null @@ -1,42 +0,0 @@ -'use client'; - -import SelfQRcodeWrapper, { SelfAppBuilder } from '@selfxyz/qrcode'; -import { v4 } from 'uuid'; -import {logo} from './logo'; - -export default function Prove() { - const userId = v4(); - - const selfApp = new SelfAppBuilder({ - appName: "Mock App2", - scope: "test-scope", - endpoint: "https://8ea8-157-131-196-195.ngrok-free.app/api/v1/verify-vc-and-disclose-proof", - logoBase64: logo, - userId, - disclosures: { - name: true, - nationality: true, - date_of_birth: true, - passport_number: true, - minimumAge: 20, - excludedCountries: [ - "AFG", "ALA", "ALB", "DZA", "ASM", "AND", "AGO", "AIA", "ATA", "ATG", "ARG", "ARM", "ABW", "AUS", "AZE", "BHS", - "BHR", "BGD", "BRB", "BLR", "BEL", "BMU", "BLZ", "BEN", "BMU", "BTN", "BOL", "BRN", "CPV", "KHM", "CAN", "CHN", - "EST", "DNK", "VUT", "ZWE", "ZMB", "YEM", "ESH", "USA" - ], - ofac: true, - } - }).build(); - - return ( -
- { - window.location.href = '/success'; - }} - onError={console.error} - /> -
- ); -} diff --git a/sdk/tests/web-app/src/app/favicon.ico b/sdk/tests/web-app/src/app/favicon.ico deleted file mode 100644 index 718d6fea4835ec2d246af9800eddb7ffb276240c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25931 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 LrJugUA?W`A8`#=m diff --git a/sdk/tests/web-app/src/app/fonts/GeistMonoVF.woff b/sdk/tests/web-app/src/app/fonts/GeistMonoVF.woff deleted file mode 100644 index f2ae185cbfd16946a534d819e9eb03924abbcc49..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67864 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ϣ%UY8`RWp~V-U_7 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 CLkb=M diff --git a/sdk/tests/web-app/src/app/fonts/GeistVF.woff b/sdk/tests/web-app/src/app/fonts/GeistVF.woff deleted file mode 100644 index 1b62daacff96dad6584e71cd962051b82957c313..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66268 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 >-Aun5A4Gp>4U0IQJ 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 G)cz05(PHWV diff --git a/sdk/tests/web-app/src/app/globals.css b/sdk/tests/web-app/src/app/globals.css deleted file mode 100644 index 13d40b892..000000000 --- a/sdk/tests/web-app/src/app/globals.css +++ /dev/null @@ -1,27 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -:root { - --background: #ffffff; - --foreground: #171717; -} - -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; - } -} - -body { - color: var(--foreground); - background: var(--background); - font-family: Arial, Helvetica, sans-serif; -} - -@layer utilities { - .text-balance { - text-wrap: balance; - } -} diff --git a/sdk/tests/web-app/src/app/layout.tsx b/sdk/tests/web-app/src/app/layout.tsx deleted file mode 100644 index 2807dd219..000000000 --- a/sdk/tests/web-app/src/app/layout.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import type { Metadata } from 'next'; -import localFont from 'next/font/local'; -import './globals.css'; - -const geistSans = localFont({ - src: './fonts/GeistVF.woff', - variable: '--font-geist-sans', - weight: '100 900', -}); -const geistMono = localFont({ - src: './fonts/GeistMonoVF.woff', - variable: '--font-geist-mono', - weight: '100 900', -}); - -export const metadata: Metadata = { - title: 'Create Next App', - description: 'Generated by create next app', -}; - -export default function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return ( - - {children} - - ); -} diff --git a/sdk/tests/web-app/src/app/page.tsx b/sdk/tests/web-app/src/app/page.tsx deleted file mode 100644 index 3e736c76d..000000000 --- a/sdk/tests/web-app/src/app/page.tsx +++ /dev/null @@ -1,41 +0,0 @@ -'use client'; - -import SelfQRcodeWrapper, { SelfAppBuilder, countries } from '@selfxyz/qrcode'; -import { v4 } from 'uuid'; - -export default function Home() { - const userId = v4(); - - const selfApp = new SelfAppBuilder({ - appName: "Self Workshop", - scope: "self-workshop", - endpoint: "https://1770-133-3-201-47.ngrok-free.app/api/verify", - logoBase64: "https://pluspng.com/img-png/images-owls-png-hd-owl-free-download-png-png-image-485.png", - userId, - disclosures: { - date_of_birth: true, - nationality: true, - excludedCountries: [ - countries.RUSSIA, - countries.CHINA, - countries.NORTH_KOREA, - countries.IRAN - ], - minimumAge: 18, - ofac: true, - } - }).build(); - - return ( -
- { - window.location.href = '/verified'; - }} - onError={console.error} - /> -
- ); -} diff --git a/sdk/tests/web-app/src/app/verified/page.module.css b/sdk/tests/web-app/src/app/verified/page.module.css deleted file mode 100644 index dd743a3a3..000000000 --- a/sdk/tests/web-app/src/app/verified/page.module.css +++ /dev/null @@ -1,51 +0,0 @@ -.rotatingTitle { - font-size: 4rem; - /* Increased from 3rem */ - font-weight: bold; - /* Gradient color for text only */ - background: linear-gradient(45deg, #1e40af, #7c3aed); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; - /* Removed text-shadow to prevent blur */ - animation: rotate3D 3s infinite linear; - /* Faster: 5s → 3s */ - transform-style: preserve-3d; - perspective: 800px; - /* Increased from 500px for more dramatic effect */ - padding: 1.5rem; - /* Increased padding */ - position: relative; - display: inline-block; -} - -/* Remove the ::before element that created a background */ -.rotatingTitle::before { - display: none; -} - -@keyframes rotate3D { - 0% { - transform: rotateY(0deg) rotateX(0deg); - } - - 25% { - transform: rotateY(30deg) rotateX(15deg); - /* Increased angles for more dramatic rotation */ - } - - 50% { - transform: rotateY(0deg) rotateX(0deg); - } - - 75% { - transform: rotateY(-30deg) rotateX(-15deg); - /* Increased angles */ - } - - 100% { - transform: rotateY(0deg) rotateX(0deg); - } -} - -/* Remove the hover styles completely */ \ No newline at end of file diff --git a/sdk/tests/web-app/src/app/verified/page.tsx b/sdk/tests/web-app/src/app/verified/page.tsx deleted file mode 100644 index 77a96c5e8..000000000 --- a/sdk/tests/web-app/src/app/verified/page.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import Image from 'next/image'; -import styles from './page.module.css'; -import skeleton from './skeleton.gif'; - -export default function HomePage() { - return ( -
-
-

Identity Verified!

-
- -
- Loading animation -
-
- ); -} \ No newline at end of file diff --git a/sdk/tests/web-app/src/app/verified/skeleton.gif b/sdk/tests/web-app/src/app/verified/skeleton.gif deleted file mode 100644 index 0646ce778253f7b66127967e50313e0b06da0d42..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 228243 zcmYg%byQnV@Glk;LZHDNf)#fwQX1SLxYOWT+@-}`f;&Zv6$n2QnR9pde6EU`@)JqxI;?!G+f6JQHZB@AZdx`rIyQPbHa2=T zIu8%E(&g5HXdOvUJ)@qL3VyY7GW_SVKH7&F)A@B5iu!A zNm+Rrd6}njyieuCpUO)=Q+%eRDy6Khq^cpQuBD=_tEp?Cq-UUMWcp9^OiYx_EDS8n zH7#untdQnb)~e5~g^*V2Hg@Lr_J)p*8jddJPA)dCu7<8|e6DU5u5PyOUTW@MhVEYW z?%uW@-j1FgX5PMbK0X#c|3*I-zaUS4e>eYN*MLCvpdiy=fBWE2w~!FKkWjbKFz?VX zzpzOAut>MCNS~Ks&tFCwy$aKR6&~~|!t7O)dibkn5n=X`FI^&|U816GqN07GqJ5*H zL!zVHqN8P^V?v^1B4QGJV-nqB5`$wC?c)+O;u1{alU^mn`XnSpCnfnNC5I#@yCf%v zq$K;LB>ShN*ra5Hq+~j#qV!TTd{Q$_)6yd|Qi3zG!ZI^8Gc&_7vm&!{W3uyHa`Fsw z@`7^npXV2)6coQIEQ&3vcu`#DUtFG0Qf5<9k@mXGq~c9RRkd|hb>f>^|C+k^y0=*k z==_G}u!dIuhSs>oCb!1s40L-{OIvw8Xt{Fm8CNbMDi}jje3@$85@KiW*w*gc!Gj zv-aYOQ2!u%S`G#kRhFPo@7>c)K@m=Egd{zi5F;Z^es(k!JEyO&X+mtUqq7V%BmJlI z_dy{p^o(?LY;3xe<)Rpz#ny4`V%s&@=B8)85>Ji`S zX}v#Mo;4TP?I+dV?J@Z@3Sp$a6_uUr4LVGVt01nfYrZ-;UuBjaWsOx!|LQ9>`hcVS zzW4t7(RS5yf%6YQuy@Gx>u1kAaS0e?OW|JhlT!~^f8)l&afgJKBNAyOqDW{YkCE&c zITKTL%Uu!Nr$QDLBt}J9I2yd~KC_ey3}!i%2Xi*&GA0cC-Y@5C7PU|YkZkcn0QPbHn!pRfqz@M&udwk^9NLDVSZ5V(op z?4%-9c#rmJ981Bh>@PRebKsiYqLu?+bRFAMyBS4%kqkt69h)xf6E|Q2{V)LGnw^nX zXVtYs%ry3{w}QA^qn&K{oKkDmAKTwC6EMfT9e`tnegj;z^~{b%5J``qhSF8}6LAAk zsdDpKpm(vRkCdR?h5?@&3-L6^N9#*-oPO^maFwWLD3SkKwpJ#$$0|}~nVI2Ur!bB; z5)|>w+8Y%X#UPYe^6fHIX{H0y}_Xi7t znJsStkwRo~UzGH-0f!%e;x<#5u)KK{jz(YkgnnfSn+4UkiVW?%Z&wq~g%x@Am0N<` zUf_@4Z<{A^D;}ur0H|au4Vc2-{ceN2fR^I3rP>V_u5L3wQ!)$dc;|ogyYc2(7xN}%mTZyY1_Yph^uMu9j>l0O3#Ia>Vkux&rRji3$_eVNYhth}R^F^Mzb=5%CJF4{X+8^Xnn1W+Yw-Ckk7+ zJqql1iGe(eCN!o-;VMj&Q+7;@g7px=aBv0nIA^19!BsMunk}tPO`APB9Grj}?l*gq zsez89+?c3fbiPV7xSJ=9z$zhMSDGkNyF`8PnWX05gIHbe)1)25h(NrE?O}De=izdM z`3{e~vCtsrni47%(?MPbk6`~!Smj4mWwE&t4TWi{#RJZ`)>YC+u^<3bz^RJm=M2gZ zmsOmwy$+%&J9ZFvs_=80A~HJ=N%={IXw`i(;`0b;EjpU)1g5fVcot6MgoX27bO&pIl?k!*3jkaLisE_wsj()qDQI2EP&d2wJ7k_vlGmr!VEO zt>nd%UL8`_2d{MclXywlmJp&1B1ywbafjgHb{ra}ec)kS+Ro4NIRmD0qz3h+VfE&j zj<}=DbvXWp;V#D0W*`Hs2$sAt`Q%Jh{)ZbkZW=Z>t$^u`A=->5NetL_=F&!;hVO8~ z#jG5w1}vDPZ@MrkjlR`9X2aVz-5s-B#Quq@`oxqWJob&`X9PpR+ef{4mvE#)S9(~+ zLEmLcQz&z#&e>okuPgP4-SW_mhG3+$o!9FdHu=cA(%S)$a+8p{XKcTpT|YF|Q$1CZ zvz2;C=d@Un zOj%c+BV`7JpF3(0_wW)_Bk31V339E{4CDbATjX!;| z>nWUM@73OIB=TkG!8_ybMD?PDsVYu7V2V`4PCAjkw?;z37HgjjCr$80RL4Fe_af(d zI2Yq=t{>Y$~gTJ?CPPD!H z!}EyflgVJ6r?j128ELtk(qpHX#7L@MBTDm;QSo<|aY4)^by&5$BhXZL{qy~K&w=*2 zyBgNed_5M=YcYKK^g&Xv;6y|A%%_OQ^N!S;7Wrg#)Uct9@H54r<&^mF*A%ID(4 zNK-`mQYh7L#>Q#_kJrfrAN%78w#o7x$RA67kc;~u*(ZOwql9`ikl`@xue*8_CiB`o=C%%7-ivS1J%m(px^d%q?=^a@0*9v1H0K+ z`2CXaJ#xQyD~<4P|1kXfO=_f<8swXh=Z)iB#A!yksS>=P6YRkA`r{H65x{VyJTVT2 z$C^mZDr4#LqSMj*OWin}#`9g>JbP8c;{D)$2;#H(iU1GyJdlDE2duMd#x#P*YAEw6 zZgqwE%#g`k$8Q*7Lre0&U+O8Xa}T?z!urAY8~Lauw$wezKHlf}RmbFQ)*XA5!mg9c z@4q_>IaD_Unc@D?rJlIB0IN$ii32ZoamQ+?jzpVoMV5(J1!P-JR!9#xiFv7%jXkl; zWdH|d>@u^NfbVbsv`F*KL(7d;?K=tOx8za6ftpm0^=supf4|8K8i0g#3FdYo1yIty zEW&}0DoP+#>E>6r?a{YOG6_et260-!qA^1Uh{h{5A4S|76r{MEN!rFxSIp#IB36(S zWWr3?0EdUctuGc<^H!VLPH00n&oLiZ+RV9v`|& z#!uBAZ$X9M`QQs~xpbRFfFwZxsZyuk>9(f1+BVE22iX#(6Y=Fw5~&Y4YZc|B1?gj1 z)q^-qwtgh0M8(&Ui&zMAxRSDl!Gju{o+9H7``9Vq;WQRX*rRal$z8P=l)TKH_X_*d z*(#;Y_Q+-XSC()|DNnUVTuEnH5b<< z+sN53=!KHyQdQ(!1s?+{HRI4MH#;zN$*f*X;?aT3hOaBHed-}+5IMC)Ubbi;#mr6%&yDcl(A$eDk|Q`nc4|RN;K~1M~1AUc%%8} z-wtg_T4?!!S)Q@kg_j_1UFI*DI6OC5PNw97M^s{$$c#ZsdLio=QU?d?Soizv=lA5^ zm-eR%H0HXrNM|6+uCKFco_})=aL+j0TjZ&}jp*2Or#IGK3Dk=bfTwrX&z32e@F{t` zo9 z^+Atg@RFFV#WB^6LkVNJkTXtrT_@yVGEcoJX#@4jExV+7ts;$| zSjy#HdK^Jm0mG?3Drvki9&P3nT_;Mp!BK)bOPTS@j^G+$WqCPM&)<{uOy;Z5FfJ-T zK0amPU8uxAb7oqAWMGIcuXx8!OMj5iOT@%w;*#Zc65pWNWY84}gR(_JFm0T2wIGTB znta-$r}m`P-cr>o?;dyTKK8JQ99sYi4wO8LsM3`PEIf%MkgV7w^)_9Iw*!kPKJ2sY zVf)tN@V=7|8_}y>rgVA1;v3ZM>&C*8S;`{-uIWn`78b;(Xcjs2XKQYUTgRa~jZ!K) zoE9&!ONO}O*IiXFac+m1ERB3lhn?^B#H|gJ$EZ1KFc3foNZ&J{#2c5vHWD^et55Eg zyAIyMGJ-(s$_uD=#FJ)BIJ3Q<*&o)W%NN&iH?kZH2YM1{zY(Qq70ke5u7r8wR7+x@ zyd9)~@nxHYjcnI?v)kk-bLX~ zeJv8&MeWoq*@zYul~7TH2|>mo38gO}aBM?Qf|>z{FyX(69<8z=T*n zftxQ01QA|e*U&`g;^BrtTLj!bhkTmo8ub(Yr)+XV)tWs>&3w!PBs|UCVtBRH znw<9{`3j=S!|X0eJ~gD#rI%4Cx~@4a-}-Q0E6*+u^VTt1jzM7pk(LI5M2jImgC{PD z7VGiG@Mqs_jaC7jE%B1#@eyja3Re0W_400+X0mVLJe?V0esN-E6EQFaA>2ZuORPXj zw6Q{&F+Chd7z^*yp-u=I5Z2ReoztAW7F{RZse0d?tMBvrAxDmpQ3VV?T35*_m}F5-Yy#rFjEmIwj6vF&u>1MJ6i>x>f&>P; zYCh(QVk0r+=#`CwpeNgL@X=H`Br{UJaQyw!W*vfjFm0lQ8htd zga-~lV2Mwu0}Re0l-h}zPY4#&rK^$f9^SFu&FS}=H3y060e3(y1E8oU?o>uHCUlnc zilmo3!Kt%&0AI8}JB@1vFL@V&*WlRRigT1>N{f7i7~xHT%pu?)YfsKbHA|Yc$Yj;n zo6rwr>B*Ubq7!wZAF9LeKGV#h5C)w@1P|F-5qS79c5kF+qjl~y3om2AhZ?9-Kx_d` zp{U>o72;Q}X-}8bf3PjEy;yjcwP2nU^%n=zZZLy_E()h0ddYMAO}q`bbn7!mrtIil zkp#jGgd%;2^^aO0Rbr)Vm;426aQ-A)L!&MqiBW`Ib%cDmiUwJ;yNgU5!KlW9sOE@) z=EHcb&Jb$Dm!R!ZRnBsakOH&}#m``wFY0q0_Qct1Ps(mx`E0QMCT!hdJ_>go{JQkr zO6Z&K(Lh!^p!{8|H)ot`yz+I?WI1x}J)dU#WX6zIpmeWpP1t6&mSnCoVL&%8qV%Ic zDQ=gc-s?c+`Fib2lf(>#jlPSxoQFRU@fUUTnTZEl+iMM52(1ste4K*7gw{oZIHag} z?z)q@dPvAlcW2W2Q&n`n!%wy5Ue&Z8D+AvwHZzAoxZEt7b+KnDI}zp?WiPZzC|nEd zKE<$u2~?`|SAP`WDhsWF?0 zRdB#{>2MG?Nlx~VYF^5NEY*iyduvsEjGbEQ+rhn-A?lA29-}S~%_}xRi)=BcN9Wj~ zb9K45$IlrL2~BZXVAyNiMNJRcCy6f)MwWU56dL&&Q5eus{K!!AO+PgMc&O``tjknj z(ufRjz|VO0X7uDwAXD|WSrcG@hczX|**lZ>sQ(c4rsRMWaqdzfEc?auX7!xNIdC=4 z*i1&Eo^}{}rkgv^yqUOun*RWjpGHhziZz+i@qVah?mTiXy%KQ1^mp!wh5FQcR0G|Y z7{Wt6{^Nai)gK>qGRsj7gT`mA!$ya_vCdx-3uH;$oZZxZbsHpS{YkSiNa`jom*YzC|MzKET=&WBDMk!qdbY?jW~`(9@5H69 zWw|P9#;hN{$8zB+CXn(!tkM{$s6Q03kGStf6e>MXXk)Me0-3gH1wy4d&Nn$E_>`ZM zo}<^^m_D*G(#u}HDiUMDIfZ=_oT8hQr24vzYy3gt@y(BQ=He{V6u)~>#++hmkIJe{ zJeiDZ=}BNY7q!l#ACZr-pJBeL=%hGc7i%yTBlj4thG?Q*UCGs0bHwHsu4VFB>vkI8 z2EV!w`AQe|l}gwstL+~D3GSsI(=D4W&Cl`NWoH{%D#xS`g@2d6vW(%)+1$52|FyMD zHH5+|6|l2iF3_E(R(=?}Tk)cxNWy(1(6qf%I5ShN`9mHiVLvbMN8sj*>n`=3vn_eK zw{|;oR{F#J*A>+_43Ti)(~oU5b@{3{!S(bn@LfwzCd(NttM1SLe(f*1ilb-0`Tl)} zK7OE>u0JU4AF{kyRr#R zQBjTg6SB$NBES^ELPux)A>cBs^1~IoH7W0?9&fH$wMbUA_fTbLe1AX>dV))0RAFo9 zTp{j^uODAj`(gTr{nNh%tb;jbyrc4u{iGCvxH)pwS;E5m?fV;)d+L(+yUC>47v-LX z%oHWo)xTZ` ze{3{y$urLFsUIF-lMOL|D;BAjjOw|JE3XjN_e&3T%$#WLb-Q*buMWR<@`+*Fie!7O zw?o;?Uip9!b1oE6@cmnziq_+l)5q1Qb?>J$_U@s{aXKDYEr&fC`@U2!S0R1+6rJS>M%v zYt+C6J&J0D1PDFWXb{xHEA5e9jI_vguPDIgC#!!YCr?RfUM!pKda2iE5J90(Lj=Gtocq|PtC_wdw-A^G z^GyoxP}HE~q&Jxr<5an?Iyq{ak^OS9tT`La4u+7~p+SaETf{qrBskvL))UlVG1rt5 z)R1^$b9j163qn?e+zGvI3tFNRs)EZ|fu{|!z7k`FCo7^I^e?mpun?VhfYxacbe)a_~z>R`a*w zW0I(s{PGl6Rb#qxK+7H8Y8hi56P7t$6*3J8lLX~n|JeY6^1)E@-*`3E{(3n9qbEEz zIE48q$Ova!Uxc_zYj6Gg!!a@h^G7+?G1nL3^05YizxSez+4pC(@eN)GNe1>E|H2bh zk*fBQQct2csI9*{H*8)2!R!g!EUJ2krMol5yW)oOM#X8dUa`{j0Ul;npZG0HFIw`d zr4aWHJ25jlcZ!npA}ei!FQ+x_6WFgaO_^4S-(0%M60-WCV|vO$x_z*j2l^@D5}nD@ ze4kGNZUgHdWL7jL(O(7pubgRa`tbVD;hEYuoMQA;50bbO4(d?AW`d>WvvT<05GD-7r&55rbS4Vti>k<##A{q_!;Po0>hZ6JHswm<$v8#dCxwL5z8JB^R``cQQd5&0 zoJAf_vk{rhng=XyBlh_dK^X=LHmhx-BD4O3;h$3d@B? zgBfiF&;iQrB|0{n8h;YBXj#0P$&=&W9CY#E{oELSdb5LP&X90ANmz|V*HD42u_O{}6uUoh+grR+`$`o_BUsVGu!R|jIewq>JTLGy}h-7vK%YTOFCH+wQb z<&}lJtKhK) zW&ZrsC}Q@yTt%!aPtq!0=0hi5{88y45pL9^WMs zE$dj!)<2IsX5+%}RQY#SKYdFawRTE`F2-KOt$p13fCNpSXch6fGNSj#wAL&8W=N9d zWk8sIdXUA%lBY@B@b8EI&zy}xI;hJH#ZHyo;HZ zXvtc>C}0($gCWk3voD}i?+J}oe=%XmH6$L!#UhzO%$xKvW%I&rkL2_EnSQKJio}yH zopPvFY_V1j+=|6u>uH8w-DKR$lem{pG|Abxy5CNVaqU-Z?M}Q{zd7A567ku^iCVhY zJ$;G4+P8gRhlu^Np}2}zdJv&6Jv?G@e>#z}InMAM$1IHR>4XHg+{J;;-No*?rR39` z>~bjhXY?X>`#DQv{5c=OU)jwY$=~ebT43;fwk%!`UzaJAbje z_LN@7ud|6N;qp&A))p%Z@%cg9_C5nArEGaM*6JqBUd_qT3E#f$ZS&AROGCJPWy<6l z;T}n&9uyE3$5ZMY2*zD)J6kyXo@c8&x1Yf2o;mTx_XMMNZBHP{(lPZ#W_|C#e`pc(-kqb$~FKZBI z<#3$bedEGLE?Pv@gkWPNMGzg=;W69k(kLzrohqXJDfckua`kX!?xNk$I-pAY|O zg8eD%bZ7{DbY}9X#vOa%ePI9X>7dUSFUDhPi<4Tv^Q4#O`Rzw-SLg`#BpKdQZne{B z;OEeiz=D?+e;$5KoR7x8mpvO{?oTOUTI5I7DSb}LPDC-D256mTHzo`aqq2XbELo)w zvl5|xhxFfuRPvwoX}AC4EUGOz#c^)Cl-PCuan$0jO8AzVSH?J>0=uBmH1J0nqaftp zfs})3wHnf9=pMvpM`{ZcVoRlWZsl&7Qzt z3rf69aTZe@B+T$Vzh%~!^GVjzPmJyH*LT*$=f{k(#Xk~$;NfFq{~y}S(Ep>&VEv=b zU}Hg*|D(--$SCQN0};v8{N$t-WYy)xUetcOm-C9#j0&-gmZSvEWNMn6>~$7h3(Cp9 zypK3hYNh{ZGdK>66L0iOKIC6|9@(jpGtU+gP$E~$hGHPm6clQPqMQgrS=-B+!SQTu z1LeF*GpX9z8q;iNyLedQb&YwM=f)VtgwDWPD^+Ao9;esmH(D(SS({2R2!oKx<CvYWdv48_W}-5CLb-Sen{@9y1_zoI>PG&|mxN-5sU9F%M|j`9 z&n{+K3HU}h|L}>!Bfxo_GId`1_WYqIEX43?j{%ol{8VtoROc%@^+!|i5LE#{5?!fG zpJ>;i_Pq7SvAL?9ZIEB)K+JxUU?e`wPTVP;KrWfOQd2@9R@crJT|88g4bY7r zXNv8`Vo}M(0OJu}`nA77mTYo#RTLP4n zc0MWsa^!qk5;%5w?2pXwh05YF&oeVJ3vpAcrBPQFrxn9lxa5Mz9)2#qmF;se!lA94 z((?rVh%%wn6cj3>^nFrJ=b37jXUXv{Ir_0R{fm!=blK~ZcEKTyi#P6<>f8 zxHh#a@ojv4*~jvu=o3DBR9bvX=>7gOk{uO2hc(=`lo(LkUZ%yJ95NO3uAu|S${tCq z`nk@jWs@LSr6%Uf)o0eC_z|_fx3e1wc}SAjjRx7-+Wbj=8x6B|U$34QQ+(%ak#Rgr zuG}O2k}Ox&UwZFVSYO4Hf5j*aYb53sxG7APDaj3lYfZ%5e*HLG_1OlOI27>~M%o~x zYLfC^n!qz^Kktk3FZl>X*!`9T!F-u#Xb!Ibn!1>?(fDuStZkPE>>9y%EXhsSJ>L7e zjjj7Tm3YOstsa=L6JF8H7f~!z^Jz=>l~V!d#U0xOA_q1?MAtU~D=x_#H7$=^z12rx z4rMb$N_c-9`f^(rrk>Zei0vK`kZKAp;S>2mpA8EfG+Yw=GRVbdjo)}9*ua&6_z)Xm z=X0)hlde_f`qMLn$L5Tf1|mZfB{ntSv%Px>Odb2ZJ<`HD*Cti#eKYW7IgLrN6oT7|Dg%r7*6WCaYSpPtya()^8~QejD6r@V>o!5XIOhk<5<&J#hyPF;*VpGmdam}sL`Pc>!Bu9w!jHE%I#weec*B!-xu!0s~ zUv~lg+9c%^2rOicTfXr9#EipK8vpuKa)VVqbc1&cnDJH{(xC7rsxuN+@|*3k#G3MR z83n51xA@F?$Ta+kQ?p6mW8vd9x$f{wXYi9T(c0q&?r7LiaK@$sdph8a$!=tk8=K=3 zDq2n6`3SraMF-(iHQi^+mDJ@M$Bh)(fvB$Vu&voBJv z3xcrvInOJP?`$hlAQzdg7X34;46=n!8#IV#ry35g{%o=J+g|KMsiwdzpIZJ}40pm) z{YmXaY96>{%qr`;`aKpm!b=WX!JYk7Kr8%26B#Al`J=(p@BBv{H+>NWdq~$mE5yMI z;_vs9zjDT#>|BAZF6BwjP{&oAiSyxoV6I9y_M?6E*iQBAH-Fp`tbaSSA*k_aF>uu< z_RWZ_R71+)kq9oaIQ1S&a=_!j!I@2U&glnYLZS{p4rM2Xg6;P}1ygZiT5P=#*GqL8 zX;t?(uc`_ z$iYprSTVFJkJ>(3oxL*<_`G&{X8|l$louT<@OWPDqI`jmC|y}X78dC)de=c9DnF`< zUHjc^^|f)0oc!jr_3b+siv$r3lm70czseo7oG)4B;BMXGaV=?XO4)8 zAb|GwmZ>sz2Srx{D&{S82y2aGI7T2Nv%N2S#)gvThFeF=Wj`jBjFzuN@v%vdNs^R6 z0;#2q5>@Hyu`fAL09{3}+)PYv0Dr*S)oS(NQQn5}901BlDGKWLtpZN^C~BI-bXe(# z-yH_MFxlRCPdlty%1-)NaRa60F)X>*&SQ3Uz(l*gsY`ijOq4-j5Lix{0qfv#4;Q?M zgf5D1?@;`UHM^-CJRv5>e zEqUq7lbR`4@U-lR^<|TU~qeemf*&lL;KHO z3G+r0U;DVyuQc8{$cd{F){$SW*jOD^eVqa%!xjX`Ed>gx=*?d|oE;U4iJ@jg_G;h% zW5`t8@g{0tXWvCu_Fr~!2nzutdCjQnosQ+XU8)WBy2m7p)K=@?pC;B)&9?da7d?ui zd>$XaVb|{?FFQt1M%K5l_~Ezl3v5EetRXV>=fMf{UNd7aX%1h#I*K%szY~Qpo)Z}F zeJ0-_3Zn}>v_wph!F{3HqU9vyDx-Y7&j>%P41GKL;yi9mlJp^pG0$U1iFHaaJTorH zyq04M0;!;l<{1$j9AbXp>nlXD?i_)!(BfG>=UL{Y%+)nGZt zP~|vR%3R+nD4~L}Q#lnOp0&zQcyL&5Fc$}jr+8GuJ8y^+ey5n@Ynzvv^2WD@(2W87 zopJo=aBvSL0Z$pYF&wNG7c{*affzI7Q1$JD3G#vb^6?SCD@!pLllWaQ;RFR}5Q%q% z%@pp|c!M($4q+0+)ujO14?%VZ2z*vRickRQp1U$NKomu^2FIO7gE~s1^#Tc9MD@5M zbp0}dMJWAVJyesH=HPtFb!drJ+8?z2@CKU+{U{w9_rn|F7k9CE*g(5*+^|chG$Wwm z0M;nxk&cLh1}o$x0!ZQuokkH9qoBp(L2@1Rm)8Mdx75#sqBUWBPVb26VJ^-NIHfoY z@hfbAGHgIIlA@H@2_qzN9a3XLU_X#ZgEYV(qnjrnGvSa?&(xE^BzEeU$Yp<_J>hHL zuq?{(1(TPPIc^IXI8&SnmaEB++N_K#q0K+=PvZirp@h^5adqKI#c*tc0o)rn?p~ni zlBeiJE@X07OLjbU2pLb14oX6j*8$T6^TJ52eQs;uqn$Wx1M-W|mqWUo#v>VK3pgxT zxHS*{<}7k%o$xrH01)0h$b*$c1s8aON(T%=)Kv6otFQ=wvDN`;gYp`IZ`k(+iLX)F zW|Q*dwrsD%3GtOc7ZOR~7@$KJ#Qr|SUigt_d<2{f;JF5(o6K5Nl)(4;cXyGYaS1q) z=astCGvtDJ=$S^r!K@U7VS+#d1irmsl0$e@zyKr(4GIg78`_Oc4F{uOS)C{DSMR{& zD!F=#WYq9jYW(aj!(>e^;?6P`mjiGyIu8MdCYu60^MRQJAWZ_>(nX;DF{pdrNK?I<4G12E%A(VfB_K* z{2jGIL&1CzMf&GaVEa>mRcWae8j{il>f(f0!MH9ZGuXLwsZmf*|L_e;{6F|1!!6I| zaY~JAvsa?=o_!a}z<>}~0Ppb9WJ#c17s!PRG6R#0!Vu43f$R|gKzhmdTo5^TGRQ_J zmAYKc8k=2^fnYF$4XJ_H3yT~Ve7c*QwVKAjoYf;9CczC%CIGy|%IN2aJD{$-G%CtR z=HQV4WWb>QT%ah79wz1BCnu2tN&}ZBfI9KS2ugX^aGahn8$3j69ouT`x4K26qcafs zt!jm*`Jjsx&`U(o$km(CNrv@25Qrqh84xuZMMUhG`ROw29t$P1R?x-4%$XQ|a!i~y zMbYi@(gFUa7+EV}234#{$-E3HFeQ*v2YdO5(zQls6%f7oXqqL& zDh-7#;m6*B@U@_sdTS(4>Re0EAk$r-9jd}_prUBE;ybX~Ba^9l!s*~m9G+ZGb#QP} zwwR$y6}N8kGr{N@(|W^P>QBK`K1Pj4b!EP*#SR3ZuRj~tLC&B-@EnZrEvC6U3JkWc z`zzlNP(jSHixW6WdelKblNY}0;)9w;BPHIv*>(E$unzo1nmy61H4%ac(6IWCRfZZPo%UbYL^!W>#^+8n$NY8HAY&j#s4 zH_u_UwF-tQUZy|cA*uRaqLEFevC%d+K{BnHAk5*vzlRr^@H$3V!6&Xz%oUtj~?4sujuq*o_#B7|jUgyW9};?Kt# zoqJ%Z7}kgMhZL6o?CC!>Y;=Kx_LrUL3h=i~@m$CtOmWSCy$EI10Ebe6ovxBY*I+#f zXDS#ha-F516Ssa|H!m=}gKFrQ-C7TYTgfBKNndLNV)*NtWAV$W7*T5v?=tYLkXd)9 zTZ?Xlc6mAvkj%JTz{!sSH80;(WYf?8! zvDR?7Y;cva@YFH0=e={gGJQynz!(#-P53V(&))W&rRlMm#g#EEoW^Yk_PVlk7qIqrsJe& zdmP$RFBf{q@dRl>JT_G+l5rPXgfBsCYf#Ax4_9O8>BXW0!@Py(@-6keW3xGF`bQGZ zJn#VqBNX)uOxTNzd@~SK1#KAZB{eA?F@5n`^amhTE6}BQHF0ZHA~&vdy#0&C^!L)C zN0uvyt&le`LON6YKbS|a8b~Agh{B7D+RkQQ_N>ZVE|(NR>G>e1i4{M@R=C^-_^zl$ zW*NeYHmVec6?(j1F@^AkLeQPyMPz(!55(EO< zJiqoXreT{DJ-BquRBwz7V9}J0sP7StX+k3{afDG8T5{_+DVyJ3tjE8Y|4_V2no|Li zBNz;-IF;GBDRjU@fV_9Nyx}e`zAEIqYi9`TlMAe~S?uAbOma{h)>4f26<1XV)pw$) zU#>frzcKExtlP8pX2JZk#0qruJF&HVDVMO4psBbc8 z?UDR3$L51f`e}i&@%{!v2}1lB{~pvbbl$2tW*~`a3kk#vfDVG1^@918@m9LOFwh+M zjUUy&pTbfu2^~kkB&Nf_c^ic15?v{_AOj9Roau)yj(Ojn{Pr==xi{7shB8X^iUCiW z4I=k&12oViF#?9@djkS4#q2l0{kM63g1$wLQ-69sij1Giw5=3z5bku5_;CaeP2nKu zcN&3xzAp}5&PAy+p5OME8_M9vXrCurt#4cS{QPAk!$WxBBRYc|Fu(#)9D}*s@y~is zpYm~I2ElAqYmHDjD~{mbVXwnhvB^k4!DTopy|{A>UyeA=5BQn7gVEb&R+J(qNq=Jt zmHavaSpQ%b-pBxsxjh^b0NoUa)5HtjL^K#iqy7TO1WfK2w(K7e+Jz6efMYwHU{hT| zwY-j-WWT%(x$0hzF?S*Px^Z>>_log3Nn>I8vr8%DVEEp{6Ob@-T)&*=z6D?cH^+)jnJs z>(T{(xDp7tcB(lcaK!i61hFm=J_Zp!@9-e+(|OTGA)dZ{7hI(Bl^komraGfyZth?qFvlGBo<3{ z);WskMbojr_Tr;vYW|4zG96%a6#ng#Ruu4?)gXW6!A zkGt5=rq+INF9UZ{G_q7Ok)O28p5n-ZRYvOo?q4RnTc*6B{KVl$zL&amRi zcu2gMZmm=!YHGckj7cW=euj8B66gZIaOH`8ZUm+iZd`(!;DmDL5Li_1u8{CzR>z}< zo?>+nAR?+=>elDk?Ntg|;ih57<>$%Y>(GZ-N8v=9HCH(`P=iNKGk)|!J5dvopa}(@ zLle|l*JJWui!>2BzC+?V4u9>gafaPi?N;4@dO*^44degfzq{6XxHfIR_MrZgqyRF> z$cjcn4UnJ&9PKWc*$e<&yILJ_u=I*Z@>(E>I+=lbILi?ZYTVIe3-p;$h<^9)9;sOFPIW;=K+G{5PIMYr7a`*CsyEj*|1gXfq%ru;KtjA9qykRP2o##pv72Vzr0p3i6ROG zu7wk}!3puw!T-iK6k*P8a14;wmy3z*q4?lmBvvk8`Wmm}{#x3s;=G(FRBlJI?gS@qhnZY8a7k%( zW8cYf#W~9T-vIsxp$TQEH-B|)KC4NCKeR#2yBi1D#UjUGIjqidhpZb`>v~L7#S`q z=N_#6diJ0sN7(j1)$}jsu3g%@M?nsnx$!)Z12oRffbF3cg!19ptrh3P?Un~Bg8H8( z=4-HFGPEhP8a+$;pJ4>F>GHqD`2Bq#>9VUk$o`8Xo!#mgiH zw$r~2#*RN3OCorj(+^E)}ap#-CloO5Wt^dRJE7je=A-`_QZJbHk662 z0eTo#k1KJyWcBpwWAAEG!)l8A&%P4;f3>sYVoe?qj!MUGj5GY#KD8+Dzij=>^FOqm zU~~B}%71QrK=+=%&b|=%Pq&6|2Q(kN^Kcftvwo7|eqNwV?t#V76b@aPx?MU7p7F$A z`mpS91)1&5FkSl_@r9fVv-j=AON4CT&eUEg^ISs~zB4B5a%0);4|n1J;_5A+qWYq? zafX^_y%ErzrAdG>Sm-sjA{=bk%%bqC(aJhzxVLm2Ufu$1;j?A$saHKg+~TAbBa2WrNb zp-^TsIB%CRUW$~{cI*W+>FRzKAuwXalj{v2irm|b7NdKM(%tbUzhvL{sadq|4$r8Q zu8yT2D9*2It$D@lc*))o?eQh7k-QUO^h*hQ5biq_et9U$TsfJr@(_iWXE=WdJ5+P< zi}iDhmBa$Q`<)UY@`9A7z2*yl)mZWPk**%Z?nLY@9vaS&d*M_d; z$GQ8=fC^yc+W~gvT!s}Q1U2p>{)9|9^qo?_T2#3@#rbpi!f;+?XX4XCb7^*SR==rO ze!Vjh=nr^E!`VflVaGkb<~_$V z^`Vvdvl3R){qXHUuL(%9mB;U0qMfg~42R$IXBRCEZ1PmVi)=fj_I?qAE6h8!>-_E6 zOyF#zld`+(^P3aEj%te8!Tig?Pe-Se8W7%?0E&~v@3wxQOYqm@c1jrty;o&3?uin= zIMc|=z>tn%JSG;~XG{6Zj|=cA>ZW?L?DT?nv?h(d?&@-5J+pY^Jbk0*G5jO55035l zf_?S#bMy}?<9_^+8Z!g)2dzQ82luNuNdVd|WJ{5J$H^*vuD`#ViQVK>?pDerX8`Tw zH+Pjr{i67Dm$l%e&~Sd2W#8N<%k_6C#$nHOz6y`IC20x$15wV?)+fc>m^F~kllTqd zoSkn!@mOPCvwsE1UYVBQKRIwX3(F8+>1bPfBrLO;<;G);`)>w**>4{L4QPNF>xxR? z=8m@ll`{|;1%5ovuU$~yKQGo66DRVwzq3moy9%&|ULNAv)BK3JSXU*#Q3BGh?TKdC zrzpX#-_G{>n6%x8}o2 zH4iETP`Bky7}c%REUlq%`WQfcMrrmBkq6SuN{@rmzThvihlrSW<8(2>!tG8UBC1PL zR_=uVurh=%*^K;YnJ^MN$fe&YJzryHc0Hma@Z=xyqMrZ^^h{31)nL0hKuuEkUnguG%@nFEOMVZ#$re6nv2Ee$w%;U-V ztvq8d9o+6);>HIiVBmY{ZGA#)QzSJ?^Wj$-y#48dG}7;A8|Jw3*q!exI}H@}evhOM z03XtfyO+32`?PjW(rF#%2ayZtM>zOO6tMsW)2KyTX}gPy`y0rkJ^%RK%#{_EQGw_4 zKb$691$Jh5F}r0jOJ@>_@?OHl`W6`ylFtTzu#2qx*fREC>Bdtf_l{kS_sXx1Oda+h z@o?DOLV;iJDZU^a`RO5QN1bdn{2{N^U^$I{%l4(d+!fXLmnD-8DL^0n4MEm-Q)D8rO~Y^g%o)Q9O&o#Jh&JCZ}|nJH9PbKr@V05y1WO(3?rc z>e9Ft(pfyfc!fi9t@5qMAW*{m1g17X9YDZ5b}~4~He0*sSAs%cw|O$(Abq7d@?u8I zFwJ04{(i)s?EJA%%S6-M768}G2rqVEJYkV=$oJRk-w<#n!rp13KD`s%&lBe-LU8AwUh>QOq%pFwxi4vZ$*%=1fYF<39PdUVbj#o>+ z^i>Dn;Ktny7Wow{LXKY0ZXS1%y#SUs0Mma!m|44H4eQKej|oxKcZI92yO6H=Rvew+ z0iGZcn8Vuk<=_%Gy5fqiLX~QM90g;!b!TLOCL45jYMBGwd(nI9%!;u!JYJMOX1;PX z-3hpj=tJP>v#7^*k>Chif?%+nB_mc`rIgz^&9E?BggVG_3gt}bnlw3;J>V&lH~I1RHmFn=$G!9q=vXmL#}l+_$C&Vo za-O2ww}0K_{q;q-f!_&NaREKb#%3zH;wo^w{ctDA^dgXyTtxkXp=I$CUHl%!;GhW$ z#-M2;UnLOvH(?&3PqleUC-r_Ei5!hoXSa;t0 zlpIR4Ofta#+tYFR|Lp02Advs|bg)oiOv7cu72BtT4)SxmqT>m-t-pW#AjfNag#Ywo z!N)$O1ocAYK9^5y4@^_3_M}}od++-T$F1DObOzz#1wonRua823CSHYvR~5A8slQe% z$;%Fc-nQN{UzKrwJz4g)H7xWagq-z(Z4IhT?k-U;l1Kkr?D@v8yeR)aZUxg?roCbh z14)@WP+X@)c%6!O#1+;Cj_kE+=B_Lbnu@^Pd%!_BV(a zHQzPeck0pNBLauG-qT{LzxQnJYor7hIsSlFX`b49lInL3eM25&#UhUkO|@62D!m8A zd@W%XB99^12^E%;MZz}LJP(N(&k4cZVFLMha^Y=8s7zCW!uY`CKeNLqdfpPbmK4O#~ zd8#WgqQPdY5)uLl7#vJaV-LdVrlDXR6@vJtB#iz@Qcj|lC)v#BT8-v^`f3XA{z*iN z?2DJ-p>&@#G+86_P0Yzt3}51ZX7U%__4H2;d~&W2mZYX1l$8-S3fcHXB4 z5-CnTDtdY=`p7w)`bjHJ2W6qemr+AggiPSW8#4*q>8gU{GSJ(e0s3EJR*TBMG#_rX zi(MsK*cQFaeD~e&@*M_J>~N>RToG-!IGgk4O1ih*t+)f1?Q%QZ^WJ7G1_>EieiB(pxX1jeX0Xmh7EId9p|->N z@O9}8o{yEdzBg-^f}%GI1TOChWTCzVY*o(h3~qlTV+vg4th1NvaceC zPyD0y^QtJwj#RPjweuQ{kI6~#zjo0(`P3GHajkn`w3@0)!e=r1oMQFg+Uyl@DH!zM zSbbDmh*v0CU_HWtRD0A7;m>d_cv1AWOZu942L2%leDO4xoqj0@){j7CBU%(gA34-Y z5b$72Z?%t~4o1ko2}KC1lTfqlMy~B48BleNcgG=u!WXJ>SHUu5G-R%KBgb-5J&IIg zmdu`vF;YzS5^EuIR3lv3si-Fd$bE8jHF=W>n}dUy2J@m-z7R6QyE=r}V=0*{pD@V1 zcx=?mZs;V8TrxVyrupH3<5s+=|KJ{{*gLg&=U!ZxF}ml=EIh%eGnpfVFqAhnhs^WY z3j1W8Y$AC(%M|(z)3J!$V$8z*K1y7Mod7w=9d5l~63h#(t|v_IaZQW1f>|#Xh_t72 zX|K#~@Y&WA>t_T(8@DWQhw&=es3YEJ<4g@o5^*taS_D7&ftRFy8=>mSPFWg2AS!c& zjkdcg3z;!b>-mxp=XCTXsruJz*qCtUw3slsor&}QV0a~C;+Ho*b-LX3T^a&4>{;b# zD=E1j!+D@LvA)Y|@@9J~hMdF?mxK}9573{|e!L7CbAADwp*CU`w3l0HVo6%&7G)cD zKr?w`Lq2dX`n5!L$k*1-d=7gW+@1V!gwM$yg|Y{QkaJ5ICOv9mryVna4l85Q)_?F) zrE6KP`$-i>YviSAemeX9QB}oSU>!>QOg;#z({H039fU*fb6Acd&{2szQ0EBf%%gms z&ShL4L`O9U&+ANv+b>q=A>7K)kP^e>w9)2J(T}BEUBkxiT>(!e)`$90=>|ko|^~}lHP)k2NFWWOYDbjo5_VCKl^8%Fqx7+k0`ZeL&T6q;1HZ-#*)uv&tD$h z^ZU{#phiDln5*a57P|2Gfzx7?yl_XQ*ic0r#|28KZn8ZjJ1|V2Cx$FNo8TAnOOn+t z9?zT9P7AXRQ&)!cXh~7M5%%{rKA)u$wyCqeS;*c{Z;RATJsr3&x??2MFr%#Ajvb8d zmAO+cVO~-ykGC*lK%8K=!tudXuVc&+xOJ1sJ&7(JZ-7*NS#9I@_)bmpHpKW+Fw{ah zFwHVd*5-MjnQD<~RrOSr4P|2FDrXRZ_9xd&veCdL2%GTQW9cN7gcT`{w=H#_`J&vS zUhsh?&Ek)OX(=iql$F^SyRwm@FIovTL-eRKj*8PJXDo^D)>64>9Tt*P1eHhf5tUtm z{)pbP<#2R(S6{kOk~a{SEujm4{*szqKSxTZQ=F`GD113oeVvwmrSzTP7RbhbcEiD>mUawZz!qj1h{S2qgE6o2UI!@!!_ zo#+eyv+Yhxqzq1(P+ed31hYZ?vO997im^%gB5fy8{wM;I)xm9ibRb2{)Y0_0k*VpK=QO zmoZ-OD_p%uJQ1J1%j#=x^gM_B<1 zqH`L3_Wfy1u}3)PQj$pHqXz}T)GbQqp%46Ts)d*7U#;S#LI%)2crVPX!l3=Fj@IEM z@59yd!6rU8pEsf*jgM~0T2YY(fY^|@LMS}s0)8DWD?3+ENR2lS(l)Zke7iP?_l2qG zs-kSA!7g>c_Z9GfQ*dHJaO)GOE{be(iRXQ|D_V>AY8ll*O`H^9$6syV`31y+aATc- zbBKj%$_LT3dsn(U=-l$*OEt8^0h@{vjfXi3uDOVc1q`4FR-6bv3KHJ|<3Z(J`w<}- z6Ke2vltNvIaz5zh0`8k9xW2NA&&49@?`b98)%_w%_CZs1N87&zd#J&C?AoaXrg3+) znhGYNBQSp(tPx<26$R(3hs$|}pM``#<&A0Oao`J}`v@%wbwmJNM2J}Qy+7o4(cbbH z6Ynr%`pK6M(BKIw;&jePLG4$TVgct`t{Nz_%yPj2B+-Bl6p^f!m!jq~PUMRu&3h4e zWFgjs|AYdGt78(e(l3Z=!Gwd8fDaAANwM~IQ#;m* zjNOfo#sMFp9lOdVT}#Vk?xJU+RbvAS7iAPFROTxVVw&-TI%5TX)hK@}$;ricf> z#3FX4yw&f)V8=YuPUg3{%;H7EzEfF8t3%3#Uuz&q`>+eI%(_WXsgQ>XuafDk-v`K# z(M6?%zYeW5nded^ZjIVnXWI?~p3T8U6h!O@Ch@+|Sa}=$Cl$tw2JP$M#i5Anob=F~ zkv((?cj>LgdtW=ji5zab>mq|Kkaq6YDdFk?WPMM=5%F{d_5t^BS;ZnEaHakPc?Rg{ z>R59?mJ@&NCaZgxFSkN-EQoVuV?;c|lAMAwB7-xCz!vJ(M(P9~719J#z#51&^fCU4 z7PNN3qTx@<9NjZAMBJ|kt{*s3+wMU}37)sr6%ECrt%#yfmG1OlD`F_mY61dkI) zXmm-W6;%o+A-r%>H*Uj`g;?rcrPXfdGM}D%dA2>yeI_PsR{0>oDdQu;%W^>x zHl0r@LH1aXz)`#)d6U|*ljvBBKwU8H$BV>Xb;Il)gNj$c52z^8#h0br{3q(U4Lv$L z)}L0+?w4_b?~Oq}!ioHL^Nlx)G~sC(dc_0f#r-z4&fkeL0zUMk%P!MiXGxTddU#>z zpDpiu%!yU(zbA$$!A~p)?b2mC@kd#$C3rSa$S7 zgR8$dK(Kg@D2MQ!9nbFD(-op;@cZuA8g>om@{QZ6)U@Pu(V-f3o^AC(H(!*>Di!fK z;kh8pYIZAfU*3ZeflD6CQ{jc>Rl4Zhf8+En`%)qe=O+(JiG&IV@6bji5sjOqnTNh< z*dqudcB^1tPh8Q`qKc;B{9F;v<-oC-XQ^(<(m~{g#Q%dAc6?xDi4;1#r)-j1T^{rS z*6_K1p_-quru7k-=Q6a!$?j=j39KDPw=2+oyH?MW^6Zw2Q?z6>7e6l&KLoAo=T;|@ z!!5G`R1r!Rl7545U&CQesZIW$hE@B#iz8F75o#kHp_sPjRtK^jH#c zay!c5~bkc;w#JYeXT|3B|Ag;yBc%t#{ffyQ`l`Z9WSf`2lw8Rr!Hyurv z;cUkaW}5lBgwyh<0dnT$4(i8&qsWf$6MsPB&wtmGh%UV3q2h6B(0x@zRNTtOSw-vJ zG1V`v@V)t*8@w0Q82MD?{H$n;zH~!IXf+xSVMi!LXx%5+1XHg!+X(v=5Ow~G>LmrP zvP8vrdh)9xE4{iJCp88Oz=Ka`wtub2--)p~!*8k^=&* zZ-m8XY6%eODh)THV|M48J(bK`+ zq*UyXe8L1Ov!d0wz#Rlv7pQ^z^>&{{PZr^vYUt?vRprd zk;yV$K~O+bH(7A9P9eHi}9dwl5 z-k2%J0HWsOU3k&w`=kCZM)fX7dz%P!yomImouTNjrJchsoh1CDKj1e{6g3sFJ}_Fs z3Cl#9?ZZK&_Jn62pjP2IPwdAGmPMGm1A|`?QaaOw*=szzv{DXlc(5BTtu(rLWYbfe z-%9W>{dT8$Nv9K1Hr>)BZ(u?{rN?BYvw&WyG$8<|N4He4E8|Z)6AC07JMv}FL{$uT zjaH+FO(xuzR3oj!ur=|)0}^jpMHa5<5RZY9$B~5cj{4`#3Od%kjq%}aORSosD%dv{T8DzYr;J!9@P@p;#@khyKhcY&j) z?G5;w&w;TPj)qT#q5OME3Q1o}8vEu2FtqN?{JID05C|R)V)Fwr)~#|Z%=w+n`ErG_ zS1buX#W1z$TwczzC@$}{V`|SM%5mBr_|@?-_Z)dF8*67eTpE*AtNUKr`0U_4b0R43 zG&p-n{2UwLu6IG@H@Qx{yU6&0SLf=-D+bJ4KU@xe+^6yw-Ya_{RcSr=X0Bgro&LAa zPMhfk1;Vl1ulWd>F2G5aA2Ly}i7jIvhhGw*zh(%)5UbdTQhu6xMt`~0B)?VP%XPh- zE)_mJV!tBy*60+Kn zS)o};o1uqj_n0;x6wwfpm_hCO&K}cmdXDBDQjvk(LBos7)g@EHAKD(}2%<=M)8-fU zMr`13GWe1lA6fU;Kr-@O4)ngH@dnO3{D%{hwcx0M%JP%>-49<6j=(W_ERmKvYc_Gz zQ3-oLoemj?_tw9HaU53I)&8KQX5LWeuBa0xsYkJz5x-Xl3l76bkeM^Ln~_Wc}sz`LsbZ8Bq#-v?0#&PEagr_wQyK_jwv4F&#SKjCKm_Lj9IqsEHo z%-(pOHwXRrEx@RLtdw;Lcq(0w4gZ0_0erO*xQJ{00DDzZF?Te^2%@uIUvr!D-4CNa(W;>s$BUW}jXp7A;}DR+^dPKRBv9 znIbN{cjp5NqD6^|(p|b?v?`*ukzj-i6~Ht3ioe%#T0eZw0(#*05etC6BEKPFG9^9g z=8kqVmU}b!uo^aeQI>G1i-ppc?G>Pie)+>>d47oToGO42CUP~@L zci7h@Jr`Zrl3>N(e=ywio4otNlP?0>D#ay{Lm4(Zu+$#|nqF4CHb`8*dr=>7$bf}L zp_qO+;S<`UIp=YCaqvQmH46~|Ni@)c1qto14L)=D8qbdCXm0r*{j7h4qrpvg*IgGHSAt6V6&i3k1o$1b_0jMj!Z&Ubf321 zSeL(q5*?A0;SfoneS8H|h z#RonMd%&&#hJ?cg0CzSqg8(#Y0dsb_P$5m4_~_MydH5$B<8Qpg4Z9@6yU+x|bB;pX z=SHhHRhRly&#PO`8?hS;4O3qorvS5tR#VkV1VVbRu)hZ)Ss_DZ#0+J`x><)zWJJQH z^JW9BtPfOBG?r3!q{9J+dRQo{06v@g>J8N;cGYtLWaIC0V%Bb3bWTtq);WO2Fc0gD zstrS^OduhkQ!LZPrtMA+F)QTnfMp$)q4xrjmluKCXM?ocNW3nIk9@ZR(h<<6U6O|E zYq-}Ea9D*R;>KBe&A)Vw)p#aNxudlhdnOeMgu}J`hJ)Xm$E>6n` z>+&Eui2wXynBQXtLXtw%p>!TY)yVwp?U-y@Gy+QW`G5S$CT7gK4z9q3DDDLiFyTJ7%rSg;9 z6QWm0NIDj^^B+%teb9|RRmz5uvk_DZ?D}TS)=3>kKMZYc@*84Q{6-ceK2o>a)mB!D zb%tMDTQ9?^#X|1i;jjYDXcf*w?S$1F*MT6vk%%h$A4Y&&NMVH}K8*X3a1IowI}XFG zBmE6Q>8Ds=RNVvE+E_0D0j!<<&S~}^d~wkxh{XTqEBs2=4q3yY^=}yd84Ngl zi?d!vcdncG*BVPJ4#_}EG4@;y92y`T_p^;I3Hyos+FDx{wuNl`_s5ILt%c_0qdpVqh<45PSRne6|YNCKECje@hzaP{O=BcKas>yt*dOem+t}9 zZukK77cpRY;4abGkG6l#|N8{Yj+*42m3&KiV6-gqSDui1&ww$ehyRb+DjdSsr0-gE zXZ)mwn^>{AU;U2Bu8BB{2hZX1kPmSFXV!5ljQIjE>;BV^<;yp@_YEuA4TVJwD}wyy zPBOXI{{MxG1~^6%y9;ha&+PAJp4b0AykoSSYgF;ux%GNj0AU5YE6JXHYqR^u0_z1( zuCMLd*4hf@s};3QW`#}<yGMI-@5^1GIet>7L|>AuT5u7nQ zU1H^Xu({V zsmvH`7MPi*0tZTQZtHy4aWky*XmOGL;@G0SE2IXq0(D?CL{w2#-9J2X*H-& zqQ$z~6<=DxLYy8nI$qCMHBth`EZ2$vm0&yXR$k^&5No}6z4T055OiR34L_7@pw-Ts zmKIBm4V9PqMW=)Zg4SL^+Wl0UY!n2<3>IR6S;O*+s*GEQ_+bB&hQb5CtK zbi+SrED`SlPPPXpt2lRL{0q|9lLlMs7xhW!10Wbp%3^QUK z{MKk>AVI=KK(zS%J}#mAPYqD{Pb?G_DBJE{R_R_20V;rRHCEnH)i3Sm2zsnwyVV%L zAH@1Gpj&IatUP=GNGNc`R-R5&7w4y~y3)DCxXg~a%YGo})L{d^Xj^M~4(v=}yW`;N znEHwVmUN`)CxBM)3-1~aXWw$cE&+KLROrp-=v#Bg4vXVJXaKsWWCJy|i8ZwtrED76 zB}klp#I^bkCUW?I<5eqTed0e^MuVk%qy~NbAK!1)9h|S54Qj&zp&ow%fWF2({6N3x z?!S)hS%9JVtJe3o@7jYPD_FV(bOav^dO(`re{N)0`#0HIBh@y`cVd{DuHjxw+|U2| z>pS3hcM{qI=Kow;#cy%V*ZA%~)<73c*DW2qgYpEWN&a)yR&{y${fX`SYj1n(!KbID zQ(S+wL`WmEPLx{?##*lJgP168Prh|Q?AY$$!+w?nVz(0rGytNe)?0?{!>A366YvF; z0jOa91r(9LGcem%hcUV^dBHOSakS4(#k6B08SF7MxJdI*Dw- zO8oH_&cgzVEJE{ zwthlSo;c0|M+TO_>`P(xbALN-!~hH4n)q{(_a}Qygkgw>7Lml(d|*JgrnbYT6oZXD zr^LrryFj56x+Q`{%opU>x}`AH1sl7ou6<=}eY{^}OPnW?)ub8q8U;IY#5xQe)U07_ z-=8a%Vu0dmPa1S@tQ$EnT3^-&kmaC?1-2~9N~T7Z9h_&Z^?k(HNFGMEbcE$&u$kv| z@fEsQ6zuq!I-pCrf^h)SyX?AG z8~$Y>IPRKwuaJ^d2!e1)y@+zf2I!hr?ppm|=J?JId88CRGwf~EtkawOHSVQ^@8h{y(seX*Zk z9EbZIJuC}9a031o?37tF&0fXh&cGg*T za(4gu^Y0TdST{eS{T-+1#Dwcv*LuZs>56jStP`03z%;NPDZ}hv98X6lamzIEe7KW@ zKV|eFRo>B?v-x667qfFVhzOJuVqm zhOq&bF2H|%R5f)$fIiP%-hkQPYxm-6teAlB>;GqP0A3qOK=4)*G%4`REFgw58cV)9 z%j$y%!M(c|&eyAssrP-rf?|v0?KKXw_CVNf2|$MllR-H?^e?UdhZlAP38!8AxgaQd z3xt*gZSnoQ@Xou<(h3^b1^lUx-`noGTZAbJ5JY1@TQFT4tXE;gcD8vv;B~4-hZm#BmQ6*Rcp-Dl3z`p2o98Sq4 z^iY(13%{b=n|g-JV^{5wj( zX#Y&ZHRLA={B#?p&buBs7NKEo7k2HiEZ5a7}laj)3;xd<2Zl-vtF4ZYV2a z<%;?u9h(7aC|7do{0E4bPKHR|u1hz`8+Oq>HX0H`P9Ja=#PnvuUr8!#K*zQO{8 zUv9?rvI6))TAw8e#PCjm6@mu$-Q4d;`U8GRERaDxTRN;cm}bY^0tzfJ?>uA0lBS>g zWgTnkF71nfC=*uQe_z|#`TKLoH~yTo@$}lD6t;rq;CgBJ2bare1_(L;gN+0B2uohS zaa}}7qqpJSe{K!W?_dGtMV9Wr`qz<+-SBHU7kBz|%l{A8`)=SHxgtz^NG*Ei{NHp4 zEJ#XI&!=aPVfU8-MIy5CYb_wEfucZGab2id#;yOZ^RK(~s{%e9fT@J(df_DBlDLzI zRd4BBidK0mK^kmHM}Xf8G4$a`-yrfcg}_JtaAuHP->1=@4t(IRb9k*?HI8i@R2= z82LXZW{v*u-Ibq+{=I09klM36v740r$y?DUW5ODyPoijqtbNQO@u_SwK4a)WbJ%-i zifExh!QSis6voqh={p}R2YD4_k%H!DEHSdlEQ^XUc3CK7d-n9K5#5ovU8NcQpNTEM+YtIDLkdM~zm%Ia z_=rUeH8ejiPLyziPVyTyn)gu>Tii2A^-&0jA*z6ut7Vav#cPHp4Z6Va$VO*|fV zeBy|;Q_?;^k_s~~GA64`%HRs|`kkicFIjdzY%Xrv9t0Bl&?$CnApr7(7XNXAr#3Tl z%FV!dvLDVK6rPK11p2xpg~fdG6Rmq`??sDu2+WuiJ7BO9vM97xtUNsdGc)Kp6EJwp zV9E32!_G{3eA`wEf4yxg73+h(x&+T^icp}oDtbAKw!RE7L}LojvPw3}MNuXt)}GnN zvu3suk60K=xjzh0Pm4ZP$Z7c8Xq&6QV+w&%QSmrxCaIo{;frr+%oZyg6>SzW8}XPV z#zBO+lp9Nk(si|WTV*nQ#VCjysT_$6*jOJYs5Ud*5)P2y5BT^*l2Xz3&kIS@DTL}{ zFD0vX=&flCE9T47y}_mjlu;=U2bBcOaq#&L(2wsm;+V<*a&^=qJwi~tDLiGYd_QLy zO+yu69bFhW5OBMa0X>+R_@!BoXyt7CnJuR;fI)Ux( zgbEIzXj$agbvOGPt8v{0&F{Tm^#RVMsrhO7$Lw@9)yl74P~k$X(whBYW>?l(oW$YW z$5VKnq3#PME1u$*RHydLvAMp^=({^&We2e?9V>4N9bBJd-y5osDP$b*Z_YEa_L}n`Me{324qP zrbV2|65c&nq>7`Q#{)J8>US+ssl$;3+sVR97CX4#M-~Xh=_3A2;XisQn7N3>Z)e=l zFr~Q3pf5n@8Eq`K7pdO#F49XVOUox0VxP_iTMQQ`^N|jhSYgv+;^Z%;USiApsdvlZ z(bt2U=+N>20$~iKOQP@>bA!wXg|iS;4i4hhvr|NK-URNugS0jhe|R1om2m2)8Ej3d z&*fT0Dd;3oCfj8*JFXIgyDMm3R+&-hPATxvu;Imm%n^f{Ao2_xf_sUSboB4OY$TF{ z$+_Qc>9r{-#Rs-7fe{|T+ z{=h_2eJGb&p}NTE*k&?*NF%hm5-j9(R9Qq}i=$P5gqe0tb&GCf@x#{jAXd-DU{NX6 zF18$8iQyKSIV7%pg)dmSNA||63rOr11b#u)_F~C$SrNr|VL#tkV~<)Z>bkajZ``Ng z8>{;ADh>bCvjCdiK3-|m+hOof1NvPth~7d+mL=?4=h(!fDkh6fnP3K94Ejh2f(jsv zO8EJw``f3)5|HTY?0#Jd+}sQ6>NGp$&oPV^xaRsw8>4;+cS5XUG%=O6q84TQMR<`3nWTy ztd!)18PaG=BXl%(sr#O6`IDaTD0yCXsL&N5Z8*(hV6QwKv(u{1@=KF@ViQGr`HVN% z#w7Geztu(eeo_BbG{Y+pL?HYb-}NEL44W!W9{{h6js7uta{?Dj^W@>$4F|YD7PW5L zaT+pdk_}gzbeZ4)HKzq09N(u%HfrRozzF(4oER%Oc~(vqD_7*&z>ZX^pu z%|Y)}UiGO$X@ohxo-!%*k%yYs8ZJQzh)NbjWFCtv`CZS+5FYW`!`|ptJvSdakuX^< zl2ANi-{52F`6l?~MJ2=yme_R*%)e(n)HMTu!-=Zd;QhJQ>T)HJO?lA`rIe|+n z4rwg1i_1MYD$EMOIGw$xep5nQT(SK-QGSlcZ@c0?`9)$qEV?^voN=8xp><-9&@=~j zIXnt+dZ{ajH*ugsu$>qbXv(q|0cO#2y46lRY7sV?GH0)N;Y0H=-!o<(cfms5tF(=` zv(P?dCn#nC29tjEEgoTE(VI5Bvtu82R~al`4zj)ZMus^bd3=IwrvI4gi0{K3roXHL0e z@kSGAIMQk?9puog_*)!)3b3@J?>~1cKtnhazp^T#g>(%|KKK<$-nXoK8 z&4g2oEz9Tlm*QCuSzna5f7^Bq5BeFbN639~8Cry{!9FhIKUcan+4(c9YIG6hEtY_{ zyb?fGSE5efeM6>Igr=H4-`+AYOF#M%B|Sp|^`P8~;F?zgyDslNZ2e66eAOYa5bdM| zk7zXVRi6DL;C(!@MDq8*gP)xO;6Z-n-a$7xrr`wdT3>3R?ell-J|T?5obc$;{#QLV zckyw6{gWN)a88qea4q)(gzxSVuBN3&yCyXGD9C5h3v|zL#ltLP+?Rz;qjt@&?GfmC z_DhWfh~h2FL`&28N#GtU{ws}O(Ow}jE_yaN9ujfq;fYQfZMceH_)9uFzFn6umV`;! zVr?&p|E${K)4p5+N4!4rVghShw30|!7;I`2{>IjlX&~(yX(Qjz5ga`yFhUaHkrRg` zkhJFtb6Dx@?BmcafY?yDjiwo9^z4*RmTDz1$`XFGO~67N^2cG zI&P6H>c?OmVZiAb2@k?7y&x2UAl+h;#mGEC{^|&8fvHI0$k^b=`jmnsPf_4^8sV1O zwhU;HH({L2ZSL1-1ER2qz=#Of);H>}BHy|DHLZuNYsbGzBGTz2xxI1Y1~n*p&B<~% zE(vLM=jrSDYC4j>C^v{06!OM~HW7Fak^{!hdn2%_Hsxt#bZ(?^;qB1x)hT2U<3x3$ z5M2=^4}zvVp@(gr3bpnt>QCS3zGEwYn_B;Nip}@^n$->RIRA2@?v?O;i!@g>*w4u; zXfj$gGIA<1vUoa;1CpLXl^(5=u7zDdS-Io+3TnrGaoc%je*DLcLLtL{`m`ssZNO1&3yIB_+6Mm;i>M(&E)diL<#PXe}^WQxey$OBs^qG2*=UL z%ztlQkYMo#=eA(Va_T!Cr;HowS?Yfv&zGLb_eTHF1}h^xT#=bi#kC{Wb%jycg^>nv z_blJmyu9lQmW1oq*PE`>i%&VlK9O-5yOHR;3vMUM3eI_#_AaA;gQPSx#Vz5Jz-HE+ zLW9a$h`iMYQ;E-`p6)4GmRy=#~>MdZTFig{h=7 zOuan{)Pcak`y>X(TVl6UNnlyP?yG+n_t4*TztW9-TAyX^RUm3ZXsLH!kqh3dV^_{j zz*kPz+;VTjKhs7MrPr+Abmz+kaq8g5 z3QBIHDPKwGGrLOvjCjknhKTDVy}SFmV7)4MGuRUjec%Qq24`Oo5-cr{YJO&R*RkD` zyQ^`}+wWb0a2i-5uiD1e(I3}>*qe?74O55LW(d~0+14Jm=h>T4J=VYtuc|e>m0P8i zDa{buMhQGvT1V+4vE5x?Dz|-S@#h8 zjBTVGuCZ_py_$M0^++^#<_)GC^1|}Ubjlb7&=I^Aiis>p50m@VKwLpB(bVx^2I0!p zg8QT>E`YdoQH%I<>v5bH^=#;YKc(-IU|vkjpXh}&EM!DSgeiM6n+?qe|DCC?bay>5b6jF`9Gv)<1~5V!%~YSqreg!9_{f8uH*6I&~w!`1a4 z!3s=AQGRy59Q4_6FiVa)(^x=E9ygJHc5l=`t-%%^upezO+ptn8an#?RD?1fwSV_?gzLm{qGE#`ZyTfznKwcwtkhm>4Dc-hs19o zZGOw0=TaVI_Yn@QavGt{gfjRJ*(3X1WQoQK*jyfrS_k5SXjn@TZ-01K^o8s2UycfF z_NzOc!4hK6&iDwWl{5%3+uUVmjZEwI%`q zubjc>2L6E}KQqRWcKCPEuzTu(w_yWp9>a`!;v`Na<==cvQt(5ibNxmL`v(TT+#lf& zsnaZX#3+uXd5lpoixeY?m78Hfmt)1*kOm(}$Zn8tN{^n(C=5^R&I2DRTWZUxLYiG1 zIZ7OGqE*R9T=9gr?(iR0i}>y%4!yi+z~(g!0=v5NLm^^PrgjY51f8C*Z>uzr&$0=)8pqF&gL)^8f?2%%7%dK z1K6-2HsA=y*^Wku$+{f&pWb}UTzW%wvvW%JL%D)P+OW4M#ul~LPW2fl>Lz(D3O6%qdJ#u%~XUrc;jMf-k^AkIfNU`kJhr};?ZeO4SqvpP74h3A! z4GS)bFOS{FBY3&?smyJhr1_h>JQ*oCkZg7Shtl+$!NNfp4z>Eid&y6RJ2#V(x%R0SL>I6iePt!18Xz0D5;Di>%h(o; z{j9aKqDS;_HKw@V!*w-@Wv)z++|X|$l?57x{DJuSQ$Sua7LCs*Idg9>+2d8WWrVPs z-x{uJ6s?o656kRl&nOn+m9m4i26uSxcN+UeX#*t->6iBxmko57nn{}nfjyRs50?h! zwg!zhGW;Iubd+WB&+8~{N}?WRAT^9Fm*+^S_EF4x^3Q7^N3V5cnz-r{{~G z{*SZIzNJn)9M8jKOcs_|c2Y0*@b+-fe6zrgO=aa$Mg)nx7B0RH{NVix-}6-)>?ghQ za%l0ffiI$9{oyVj6CuI;>TvnUqv6%u0EnV3ttP5>&3xat6BQf%t%$NV)0`(1ZuZ!D zLBn~0wdHUvZu+owbCqR9h9CZG2Xve4|0C-yz?$sh{_(*E8=a#Yq$CECia0=0K#=ay zC^b+@iBY3d0gDh7Fo1z57$6{>qeEI!Y9R0cD*N9Lych|5wzT=zQ7dWfDf-}nnF)!8EYixs;UqE%_o zv{2JITqM~!I?5{o;K#%jpSr4ZMEBj1#YP#ve*f)YZ7NTLI`lPqXl3C{Cm#&u_cP+s z9;Uy^+$8<{$I3EGaqP8TA2it85qd|@G?j&>{RurM#?3?aw|)QqP}J7Q=euX-`o-oZ zO86lciBt~5(061vTpx;{$9NP`NtOV1i8HgEP5&~T6^5LaKI42 z(7)Q%mL2gVAy`$np^?g@XnOHHS=h-h0J$P^t8|?43ht<677M_V==b#KqQZv%Qd}4J zd~DO_Bk`wE8ke~8 z30e$PYGHdcX?v41v?U`~Jn-y;ddnIs_v1lSMRT-82ui*?6UYY0nMN}E{uMQGi2U3{ z_$kLxzuKcVunVh#aq`BdIiCZe2;=0LzLjt(3trMnxc>;r(;C2QBR#m(L76glr7CmY zV-5}KBv-(t^K_7Rf+&(|1};2+XCirCFv8>s--V;Lu4nu%0EXCXb$kucVC)B0E=El$ z99*9^`VK!fZfk{`gTRPKC&zuY6m~cgiRGtix?Qp|9F;6HS0&6SPg)lVkPlyb!H7w-h|vemSH;_2 zH%j9O7>5Bkh~=#y7aowRuYK$)GbBoCaO9h$4=!?b&AuDy8)Y?OfpcMUB^YlG1H_$A zxy-k|l1{eLcZ54nE(bR&iJ}M8WHHm*pmhsvofySd!uj3N`<4F4@ zlZEQ()QztLee}dN6@Nve8;X{9rH=!r)rjv;{Q4=>j-Cm9!`sm|h6oR5)jgUCPXF3w zdx5QX$$kLOM>#aUyS#*atEXoUOg3_qZ}rQ-n!GU(k^xI2Z~7=PtF@c z&wnc(2?KDBi)Be9#4=WYa@%1^@>6qS#yf6(tG>7H8(yVlA=FX7hmC&^FZ)o*;>pSGcxBXCI zIQY!+>8V=(U^a_1_-(Wi{Wh46`vPK8Q|4fi=%U!{6`mnvhQH{059--l3Qj(;#l%m z9~}|1w{L$Lb&j=Ai9neageBg(m&J1jP?lH_deo^=X zyIo9vs@y-;yMtj2N3)UpZkSgzm&d#l=Jcb%_O|e^nJg`{GD-V-U@$qhTUr7Y>3o_S>YOGClc zH=wx!)P(+xP2OcC!fy@GW9WQW54Rc0GZdjPTdSZ1XTN<#e`s< z(R>c`*700F+O~TCd1)dVH%_}ky!Jg1V{nNeyTBD8aUBOfky&8N{4i(gcfWp>mBiAno3}|3}zw;pYPP>A zSqsNH$UWv)$QeLaPUHEvJHWvI2_hlJ7zAACRaY&m$_`scBzlbSZfl*`u(jT>bwc~9 zhr#(e&dY&sTp~IZf%m0rSUU%w$c^R?qhO$>Qn)@gJo);{e6~Au*yS zX`SRB!f$Pll3i%{#)5HEj#&zn&iV><`kT^-ztJWD%LhyagoqT23sDVVY2i|K$09zHIsJ zif;b~#1os{BI74q_83(Eo1~FmrkaO#hM1lW8nqQ=@v5fZXRxOfDnQ zja^ayf9Wbbyc{wu{WYMsM*-{<-}o0HizygB{G~61v(g5(nR;c?keSqFb}K^4?2OZ{ z3<6FjOW@-h6J96e)_f&5stc&6q!g^r796{{5l+uwp78nY#TVf7Cc8jm5?wuQ-_WT5 zHdT?ulh+T8M(|D*K7K4EAtC0Xp4&85ToXlnl1%pkTr!(U>agAFxbZLX5E$xDq}+W3 z4PACWR3wOU=FV$OHvYcRe#$E|)NnqW!Wt%`lv8v*_)oH><1{Pj|6Rg={1@ak1kluU z{mCjtIg1`lHR_-KJhp5=FTEnBLi~|})KmSYtnvG+B>LsAaBb%LG z-^K?rHZxj043r+x&YT@#9}D0e^EQ#adj3#d6neF5ESz`X@6c=ivc1u2&^TrwFt9G0 z;64BIt5VMSC@(eC&3~z*9I@(J*%L!eby@3VX?AK3I0o+4e+Y|u{+&ke?fq1 zOq#IHpP-<%d8Xut5Y2hafx+G*uwUKKe_jWCc?y)3E8*gvK5-@&N$GYI7I;^JuJ=s%AUVHp0XF|JJfV z--RpZwx5shYQub!CpTt0Y~|#$nnZv>!>&@s%@I5tVMX7+JRk}Rg!lf-Ixm5oKOsX- zKAo|O%A+&_R}tG5+owz~4kao6Lj6g$Iwj9FScAX#uESCoKSZN(Os77#^uHlbnFd^R z-3j^jhknrvbp7Sy0BMr4t9Ut?U3?h$Y07&g{d5yF7=c>#|3~O0u=DW({~F2o45T!a zHPG>*NvCknR@HyWkZa5(LAWaF6_5N6-xl2w&Hn`g>Zj9(lN^Bu!o&*+Kb@_FV*goS zy-;{rJq~@iz8x;k&Z%|@9xiQ6H*C2@6Y_Ej8$R7Zr@!b;RArp!KPe%$UtDXS*lC}? zGAud(|D<8Bl2NIKqp*$pCp?WY>J#rVAI;Hw8ozx$J8se#r`-Q+<}?E;qA8#j>{lRF z_`lj8z8-7p^{epSknue9M*F90}~KAk;KS5C|W;Pbar~$H@9yy{|J8xaC;duax4c;u#A~7)fl9 zq@C_?YNbdE4ex00}>(rF#VGAdsztGP&mNaO3D1o5!x88G&azAVd9?uo5i7 zw8|ny@c&dR1ZuNoKm~F+t};5dsmb)|rgI4aTW(42Oadgf+k#}<1cXy`Yf_Vj{ygRZ z&ggVnDU;AD!RLY1rNAR9K=LE)Wd2K1iV)F@tXfq&CQbeDxi&!e{}a`JViNeg2nS59 zB|z?#+U6BLI^}hoHr0{#X-?c~QM-X;)xXgHBLBgUP?I66?3~*rAGtunSB#^F&4I*0 z#U)K+<^d3>^RPBApaN#PZk91g##>)maPM}%2@L?qeV)HRc>J*~>GKcTc_ecQKY@-D z%!gprl4IrOhabPT2F$C&O9+W&l;j}^Pv8O5U8%j5()RoYEe<&#)#VfoxmAOoLfUncT~V@s{1Ue_nf@ zyG`AJ z;u##Rb8=qc{nP@i4=U*Z$+Zh8|4tUb90_2ejp|R{+1jMYauX)}mIMs$_Zv_FUDMb_s{W5W zCo%xyr<%|K01XAyKfqO;9%Y_Go8jx9DeMGB033Zr&XSC>ka67X$>t2b_ppX|dwyGClRoc%(C{F@6@h~Pt?~LSfCl2^VkSI%JmX@eapkM$$Rnkhh8;RokBI*; z`Fty2LlL`t0T(Yx^f z6}cB9lYOoK2Bs6}^qtMAfFv;ir`Y~|ve6F^sX8WZk%NT@7AJV}=Ko1`lI&(mnV9YL z1Af%Hyve^2P6|$0zCe`OUiTe6TLJZxuGdr<>`1ElM4IwD`N zv(+MLT9p!*-);wz%cz^tr~-3Fzy=w^nr-=rO&a6;&*T3+iRh-0oL~F2Bg#Yr@Dvge zflS1l^<)I-vdjb&I6uQqV@)T5B6_bqsudVu>h7O`NuTzzK)W-ucR2ex46 zJW6mDg!f0gmPuF!6A6^h5mV)$@uwHiJ+rC{{%pi{dR*k6Dvtz`{UzV!EClh@&9*aD;dwf=Z13afkf!|)e{*tV&CbTwI;L3 z+D?^SU%0FtO^AE%(vomN*kO2zGcHlMBoE=*^%^pW?+~@dBPQP8b$sV0HPzXqsy#u? z!b2%;)L!#q=oa5ogM5RxFGpTkL8(m|5ou#d0RnwBaU;TpnL-~kFK1s)>C$z7rLK8r zg`Q1ByZV=))~cDBO&xgxbx@awJoR{iQd)Oi)wdURwO9_80b?#X<>_jl7fh}?SMpz2 zj%q5b6d;q8uz{*dB~Ql$ez$$qexy|SwYE_8+!?42WorsQ4S&H%EUz9D({uN3`*Yp% zJS$w2H}Cp#RF%K+cZ1g{;kIjLlZfn5ckVr=O^jAf>rt2AdHrjlyYTAgi&hfSS)Y{@ zBEoLwNL7tKz?|DJ9gQN3DW1c~%x`iGd0<$X#Gm(2#;J2w7)%5 zOVZ|~Pc#pN>!qG6=+FyP{H@W>H6qxAO;KPLf2uubn$WL5>iaHBSp9@UB#Xt?qBs6- zBi5JPJzR&frRerH3q<4*qSU30jIH|^iMpN!v;@K*WBaYGt5ir?ZBet{ns`m5P z*Hx{eh#2N)@k`6auA3_^9$p(+->qxdR1%G)y5y)b8)@6GhZ#yqeE)E*vmHsLCDO$9 zNHRyiyxzPVHs_7#`yi0YuX?S6KkZiY`khDVc`F4yN>ek{7G25%mSQTb30ysbiMC1R z1Lo3ET}g}S^5=@;bZ^K7ef`#Tv3VILmNhv@le1$OO)Iw{u|AW~ePGXjp8OezspIxx z0+>PUdCdbsj|bmt>J^L=+B)_c@v(#Gtug@-M2JJD$X&e!*qQtmL(i<#otP_vog&>8 zed@$iWBM1W%xHIZe&B>{-}gigy&>D~GM?+A`HS>i=s@HH8KR2J}IstZsF76+}_IvF;5lu;pynoU=*fv_o;-7 zuI53Lxx>u*vX1fb<=e%|{L0nOFUcxL@cKxtK032NSJ8&O2V=?LZ+~N?SdDL1_04Y6 zRFy11FIXcwQp5y(tLMNBtNsjD{rv+M(9J{Vs=IRE4T~e(pPj8xpGxA-CxhO z9)8klvMys_yBDi1t5m1q6iSE{pmp9w+!Oh=8l(AjmbRo_s+YYs8^teHfo) zs+P$z^@N2fVK~L^7a`R}s<^UfpvgkTg+kQcrKP|thGiHDlgL^~=XxW`yC)DlcJxIU zxl?C+s~mn^#FaC;qr>i=duryr%pSH7@R=@C6{Bnn%yBN}rNt)H%9^UHBoV$TH=nU} zKgN;IR7o~inl00uf=St{O=mJY_6_ZVRBK0*eh@k3Rp!PsD~IHREt$~59u4uUt%lN^ zdfM1bIvLx6hAs*Dytn4@l6|2m4uK|lDSOMx()Y#O=zd(J9;cQ&kANUvG~NH9`B2~b z7F18A&6O;cPF!G-NMncA3@t#%tHhdi`^>mJ`U>&X@P4m{bveft&lIiE*Lj(#Xug=E zcQrW>r))BM2HDHQI)1DD!c_$qri7w6skfY|IWnwICWn_bogU&JP!6yyO2t5=^atuT z{9UNL8e!&|!^JMQo}Q88xmd0%p10GjG5sQ5jJ^tX>7F3db8!kvo7?!9w&9Xm9DF zL%^Em<4AmN6{njXmTd6Y60}z%sqtLbf$wHs=m82laYJ;xtL>FFT8Kql`iuOhx%kUc z3piZ8x?I1Q{U~MkOE7+-O>A)>!fh6vA?X-Lb7< z_*u3zv@i9HQ%?yCIrl0CW;qq(h8?8q3DUBdd7=D_GahQgVRnXx{k`_%nwLogKW`@5 zd)ptBnit|J&Uj_=xu~de(_zs+$!*O9+7wtY;}YaCb}kv0b?!d4uexvZ>&e^1FKuBv zG-t~uU`U=&;yX)4`5W~}FxO%e%QYSOpW^nZ{(BENI=p-fzFcsp0yoosnY794)|_RW z+W#!=*L2Df#pMTn6Upmj8;nH=fXYr70G zinY8s&R}7UxD8$Z4i>W=NJ;Nz`C1$odc-t%uR?*^F|#IBNxA)jM{LamK5=mOdksV1 zyLTDk?oHGWM~X`>FN$iWiz8g?-;AH5kox5*&VR&U>vs+J_3i8TGpjSZAK;xL(`k|Z z)e{ff%4!}oQPE_>Lo3*n4N9lh>BW?oUMp66vouj&LVR1`xTGwpCzo=|ET&oc=5G9E z>NR14daAVnGN89Dmd|KJPW2(==1$(>f^{&tHOaJge**9*)XLGbdSdK8s0jUqJ zf2>DoEQGc1NG%CN^WRR%Xj=%&Y^fu_jF_vJ+a?&}n+q=lntEx-v-x{kjm?|c=7n5k zzyW7MsmXX;`gvKBZjLogpZV2&R+|<2J;&I*h)K15)aF*`q&mkp^Z|JOti3Z^qhKI= z0+`1(?V1pejvxce)*?F|j`OaPvsl-WH~&PReNm7)P~4ibbesCa*{P4g882$zUr12C zV$58>6-)GX4wTRI2EQ2M*e8 z1h1ng(4Yv?!caWMlz=IvpqRk1(hr?Wu_WWe$DdVVx&VR*%VFKDu{W4vKQ_{QMp4HJ zKqC;U3-J!4wXtDX>N{cqpOgdGR$Q}DdZD6f9|mEujkIVq^aB+70|{Pi^A4q?5F{$Q zw7SG}2+<0YUWf-vc_b+bU_JD(zdWe}5;R0DZfoRXp68*VY>w&e4onFVRl0WBH?;~0 zTz*!GAtsdlwX`3DEwXXI#j}C)Me!2saG_#D=T&l7B@YRFn8)GufR$TwV+qkYsOPz8 zB-AaigqmgEVQM^WJj5?zNxR78?04NzQ^p`#Hq4wZ{T6$8PLOfQIa*^xh7nFwzJ`1n zlhjSA=O!+L*|Dy-4ymJz?>3Ke59rj|5B2|N_1+!*RXfMVS!H%1HZp;g zg6_&6p~m5Euj^>dRBn{L#Y~SR&vc}Hwea*1@Y{6N3ty5S#l#I#f{{BA!%pt2R0@I; zIV@T^`CeEf1QT%InX3}Tw`!Vt{7nrV7>iXhm6DrsXKvm^nlIHolMZsc^1UD`Rq}I* zcLt!4ACP7DScDlgiY@8K=s9YEj09C?C(R7CtekZMSrhEhQsdN!aVFji7RKaXMMXj*J~TKzm%&n4@XwJXMrU-R z>odOFr5v}#t>>P-T0v7Q70)O!cuio4x@C~0XI#{wvC6EsiIZij2UyP!V#Xfln=D@B z-r(O81B>Hax^-{ro`dUXn-APmSGR(OMVET-hF`_7$G2aXl%!gq2%u4Vo`Sje!z486 z{_|SkNtK$yPnl_OxlB^?slqY#(|(qTVD`RFQXAG#1ab51T)6K)##<0ku{Rz=!yX=) z6fG|e%05Jee29)%y>+|Yb~VUTT#*8}Uvqtueu=VTimUR<%ThENd+@!?--~)v;6)4L zqn04rbnK(r;+)?)3|8PLBa_S+XWKZA!n7N}38EE{FH{TKju-=_bX2*m{) zzMhpm0kORxiiY@j?_+mh_4_}{8I+KlI?hRt-4qWq8FYy5bU)*0g1+PMZ7gzD5bj6O z5!O{-$84Fr=$6N;UcG$zWs*bSD|FtS@^c>OZv45b30Cp8YCA-5;+m6Ztxvu#^gWp4 z!pCxQCfoJOG0$Q+ zqHy?G^3G3%isma7;=Hfl6J^HZH&m?9TUN>b-4W`dwcbrt9^SQxgzKR{W7=B4vR}C2 zqJebh!Z=W-($ zlP=2gZPS4}2M+8iz|(?dxBNnRmmpA%hxv^;-8-vgMLY-ntxs|OL1DKE6fH*cqLI3< zkvg*on(zKejp;-C*I+!kOgwN+vN!0uWZ0Kmm)J8ucAPC8xo!HI8s=<6_wHl4>r2y< zARp@*N-QSrn_XtZ4eI2lG{B)&efXvfw4ACArPqb#-T*8usY=3jwIr*%MZE8e_P^oO};4bwD}US_sD6h zaIg=dMK?YvtC%#m#c`GmDBg3WDFs>7Www04b%pkH8LROETk~Ph-sQ1TjV?i>RnI5# zaAtTV67ta8OUI{UT`2s%#VDM5r?H{3sLNog z*WfjGE*>}!?7Fa&R?;JbkrKBA=Z*wJo_0J!W2u`DB-{84jxPdBnCRZsk(XtAIox&c zO%;}%8nd4aA!^ItIoFu=^UQ)SjD9*nWs&ylMsNA+u6~nC3sQa80`NR(eXzH*w0KXE zGI;TBWjiuSUI2Tq2kKZwamWY{x`mVVN*pFqig34ZKl;?h_zEwZc*{=@_LPF^32Fe| z+tOde&6z)3I^4N?3ue1StumP|68Zv!B5TJ7iPn?llo>kzVswn)65es@#Nwp~#Z$b| zCGM0oxot&3wKtyNX+PDWVyT|sn}X_lb*Ec^Tixbg56^rUHgr%lA=n~CsLZ$}XNpQh zDZe;)=_1ilY(GZIb{L(1zwPn3xue?tSrxyC20x}n8}N3u-7Ag2U(72K;Ikjot)C2) zrhej(VVM6;*5oPq2u+CzM9R>H{)-o1zz73+5IzT@!GqLo$%8M~A0O!RB{$^xbd^kE z^n^bcKN@i9mMz9jj`vQ6rooIr6w^dH;MeR@MEA$Vi+Nm&8u=!WEAlVQzlvD*T3QW! zaPT6N$c+hJB$ud%pb!(kE>1WUizcq;QGMzu`TnH%D@7{P1^ozKfmqmB{&ZMk=+X3plNzFj|N*tb{=;!=v9=ZJJ&rfuSF{Z>Gj z=VPS_6p-TAoE4l~kURmdBhq)5dGp1DJbjAHF&zHei1({&h6$=WXQA$ESIyIIA#t^g zAa|(N8!E;M?(%Z(Vgh>>e%g$v4&H2}x0+eCN{3)F3wn7MK97MmH)l%UfIdf%eTg9B zYg)T64!-7`E(e%f25Z$iMb3eC1PV%cX31gHn zP6=A(M!Ft9{?F3{2K<7R(F>Wag|pm{3+Qirrr$jLmX*?HC5$?+;9u*^K*VB4DaWX$ zXg;Xb?@AR?#tttU^9h>})os}zHs7gh3hw=Q^x=mzx@cPh(@^(_HB5bMi%suc%c9go z@3+hzS~g{XKm7uJEFR}Pu$>dLy__MvQvHJidr&&3vV-qM9lb(P-$k$%Y#!sBPB=Ts zZ)UocHmYkQ+xk$Dc_6O$@>GiNDi(1Jb<9@=?$_M|j?dtL;4c0` zth^i{0;gT097gdh=BOpz=;v8}8|iOcSvI>2D_SaXU}wI=xT`yIGLpKHkkJ6S!r)y- zT?&smto&{1u|R1BAH&qjqn4;e>H>owUGH+EsN?Y4CMHYrDUMvWhz#LG*DEx$hBWZ< zmRvOXo-dh{>ps)6x94Ze$+p8kgM>@|%YPXDQNxeq7y=GD=v@95mh!lcJypw?B; z*D{k2uYNG7kAikR1I}$xx1@er6cXZ>;q;L{pSSWuUS3)w?<>QB8Vpw$uqqNcyGJyd z-OCSVHz79@1Rpvqrpk79{DOIVXn^!Bp8L`Prvd{s$qYwV9NC)GS&-fIDSlQ#O)>g- z^nx?9lO68cc2C3k_NAvSEE+WB_QxMjsIOtjn31#5R}bT_!X?XM`{)|6K?LoU7 zT^vh^43Q2+98^{ubrw32ceBK5QxL*#+vaTH(tOTh9lJ*-+<+-Ft=)nN=3KE?-c2U$ z*fT`;GJAuus^d5Oj`Y|r->_+;Mbaaw?XhqJib%19g;pv(@1@QPOB z6*%2KUwOoxmVl3V0Nh!h>+_(D){xPN)Hki&z~?xTe>s|ev(4WJ@Nk1ho2;|V90nFI ztpke1KOE_6kJ3sihJ^MR27HF8)|AAJDZx(#KZ>J@cX`ELPGUG8!@ere?`%e~%mh z?i3ajq!`cGOt;(;Gu#T0>?}AOi(J7c%njA*lR}I{#FMSDW|`)$XBFBHUg^TvlYG4V zmItVxJ(p)FJ08eAetOV2RXEdnPs8z$3F1VTseB@R*~@shGmG+? z09exGo4ooSa92o+M#i3AopsahrQfa#E7&-j#r#Jv!DCpng5~Q4BvBvU9~^UB=JH=Y zW7$Z3u?Wo&dJB1fKkBA)^Rvh?>|ENi7XTYcYV0Wk&Nqi&mZcr}YUX;3_Z5f!iDguT zbng60_tMJWKZz02V+%so^TwhZA!W}i{s}#W08nJ!P!;UA^vgh~hkeJP1Hd6sR*l8G zHF2Owo=_hPS+FP2W{U$jaAxBkF*O5T(Es+t(42u+wRFIpLZmbMSGE6U$lO152;F_) zZX5Zc7=U}Ph8^zDJ05&Kv_^;rjH)C@0BD!whu+A}Gt1byyd&}}`x)gg00FM2FUKXp zSpH@{@poAC;lyeg5968V9JFr#! z`(+7&DlT&vh&yKv>=+-onRL3~VUuVl_!u8^SeLzFoK7~13N&mZ>V5fAg%6xg`N1t} z%MZatq@Er`2wc3zHo`6WDnbA8n}=|C!r%1^st47(b*#KAARh5c;!cLN){7$qIcErK z^T)X9k&}=AO{@%awC!^X_0p~TJ0B{6o-0TB{Tv-vGGx}V-)?u766yfGq{>l-1X-D1 z-M8`gNhb=HcK_yByeY)<8yMr^srtY?5izN%@P|j%{15yUlVB( -qfnRqi8kkS{LGYO)7g6pH8UgN#4Ovq6A(L?_C00J(bEMn~$H*-w$+>0ar-7AeU zz+5e#IS45C%O#-x_31+F(ILEfT-I{^)-Gp||H_!tR^QDAIQ%1|{;BcBakihqLU<4( za&NWD&w`t5UwYrw>a@)o$Aw0Y^qEx~*~W?r3ieBTxig?1zcstjncVb2Xa4uX#6n1F z7V+rRXykU;=W%2f-JdN|EWJjaN?4NH+U1ah**-ex;Yia+xt9NeC_Ncf z)LIM7qfKq`c7qV$6s<}Jawcz2yPvzrbto?W-T3Es+dWd^0Vv&XpF3*byzu3&3s@Gh zclqibmH*nORC<*m5HBk1A^!(q*&{$I07nd%ZasXoGReihezLejlDx$zO46Z!AK2z) z-`}`F;^grypY~TsUHjs7hrm7(RKi@U;?c7U>|@iPF16XA~6K>Un?mfFrwg%ii{F$;K*tSi!Y#Qi@MMe{~EHjItQkUV1W;W($L^4m=HhhELb{b##uL zA6*T@fc_t{3yu-5+sPyX;?edj884cek{ANWym0?eZI2GPxeMhK&3_o}zt_6(6bQvu zA_w4>?f(19CuDH+THeeIVCtyKLxg$(z=RWl0#NY2+HPC!M-t9E5<`jtBH&bA3`o=x-J89-0%! z6%n-4=<2(zppw4j+=AANl4K<^z?ObmiHpAs@&f_(01<%AkbnrlmKztH*%>(M{-2z2 zbQf&y1itP__8D$|ncsiY!6~|bSuSz{7&0W@Kr1saWZ&z0!zR#0NYn+8hZ;Hc!=4mr z$I=wz{S^0g_W`ky2)JVAGVIa<$xUWhy|kxF`oa|>b-msDUIZJ9)c6yP%)q zNNYczsPGNY#AZ2&4&zeNpw9+mQHOqO4H6bm1!inANgk4a>Dio`iFfSyVH%|yk~0T{ ziFBww5XOLz&-nlc`JVQBha`Y~|Cd|3mcYUHr)25`ww5CWFl?OHfj{j0)yV08r(PB2b6ns(~4xLAghjTF#zht!z(cZy1O-W?sX-Ki$pFbi zQtjz%2e>y7>T#U#qtV?jRSPt)kM$fDdPg8;L@pFshWYT=01+Z?1n zqy9>mF$$zHE6WD(+#LuY z@e+j@cnZoErR%DZ(0s1X8|t-+$b6n+efGx4;VRRW4E{=#&6oB??NZ3uplJ@V)NY*X zK+AgxaeRRscjR}9C?DxmUzy_}Mw|1ok?A^X60!D5xZYN}2*nGY$4mqKQ}RRqST;O9ViT4% zY0)#SC!)ryTXpQ5uG>>2c?LDH+p^en=+5eA@^VaFH+(E+#gpfJYbus?BB2oUdo##^ zOfQE+APCF`X`%{7Eic$6>nYh>v9X_zwN_MJu<>Mf*e%YGl~;Pg<%LLu1Skj8jYLO3 zV=H!?$yYH+F5fqAqSy4`M_a#=hkh@kAF!#5NMERku_?Q{+?8#Nu9QA^|FJs7r$9 z*4wJXzGbR3&S}!6sJjR}%IW!FAoa0kLmu&IgZZW!Wz@BfW|d1)?sfj7-+uHX3s*sm zZ9*=vFr{?1QTy2DN23`g=MpaKeZdaYq;S9NNtSIyPrn^Q^@n$fjOt~c%V(W^aB~tP zXORK6*E_6A)sAFkz8;wNo`*lmfS6^+@L^5EOZzD+Pybk=*a^Mtxo&xCn$Bl851M_f z)bA~+)4XXHHY^|cCyX}RJyCyqaOH{DK6P<`6QxbBv!nA`Q?uoeF#rBZYl^dY~@tHP!ryJMcnAJvCHOXtZZcKndNlV zmfJezCsXIJJRWbXWf`XUeL4mb#LBHJiTjmS-#)7n??7c%=PnYS7=^586)7ydYcPpV zmX>=FEx(0*qSGmR_I!4n1j;$(_fCHh*%Tiut4HG%i@xwR`3`awR4k#9ff+3SFy@v( zHnok3e*S8ln0?b1$4~-0l2#BzjPFP>O+^PXUa+Hv@3J^&qTG6f9Ka0E7_SAzL0RIG zMhx;4{c>DldG_WRzUW*g&bu(5MWDz%-?YRY`otfFHFbnyl+pL%k|PACLm!@tg|Dt~ z+3oed4m@l{q-S|+NeP3#H9?pweA9frpC*?Cq>22ZOEDMjU0!TcJurNwxn)MlB6U+f zYAG`_Uf~(^tyqiir!CHg`w$wD(zc!WtDa&mX^-uH#K_$5qE@0#L9_-!p;_d8mT7TBk5E(-UH=__-&JCsOft0=M=K4#@tbVfbz*PiJ0IrBsgipiY@U;Q2~f_96lk_j#0So#S+5$FX5PAN zdR#ScG4_FslS?q^_U(HKI1_CN6kclLQEHy~AJ z{X}zIf_99$(DEK*9HGqiirh8p%)Ly*>39YQERARxtJ3n*@7|&CPCrRZyiVpC@4JUJ zQZr@N`AHT{Xu)&#Jv|RHBSgi9C$+BI9#pIMY}mUFK$s~zUP6}4!Esgesxs0~%8Y!c z1GN;-19!%rpR`q^NTjhN-rIL7@xe-rCMWZ9U3=3=CxZ@frWT*d@w{@+h?{B-LzOjODs| zwzksD9}TYL4Tgk(WQ?#@z^%fsF`VXOjV-SVf3G$U@VF>-Tnd(r3saka zR#993c6B~;i04`$evH`g?lrwv0ws1xq|M*CNhIaP#w3k|xs9FWw8*XXWLZ1Qb|tL; z!!sMyLJ6FO0uDbeUYTD8H*;!3;5+o+eYj*okB4$^8AlfVoK-(t!$26$mAG?(M(e4~ zV0uAKoM+Zm0ioLiYS_JJHUy6mOx*4rI&QhyJu_lQ+1Z>5jZT3)>+RVUH7Ejbu)Iv<`7$;r{rgNeE*zm43;*7=GyC z<6EfjO+#Fm1bseu)yZ?+cIaWdTF=|JVJgkv9B-3_o<}BQB6x#m+xj?Um2Ptxq)B1o zc-D*Bx)yd&5g(gb9uSe*b+J5z+|RcM1$!Z9n6na6G&4q23KbcI1HcIhiAiheH!E*R zV3ym8)C#e3S$NgNG4;c>xBC9mb}h)8#v7osiTyw5$%R+WT-d# zsOPx_MIMsTA9Sogr?~3|cfouH&-B_)4%SXT+kk_)wZ&`&XRYf-5*Quh_;*dP@`uh$ zR{d}LID5ZGTHV=nE=9^EHesrD$#xY=cH}z>Qr)DU@^Ydu@0H;J$u>EkpBZb=<)a;t zS<&<}?ozUPj&?sDl25)v#`AwdAG?P((PTKqP39E_-y5r&t7VLoU;P+%{E%<2%=$9C zy6MQ}J|Cre;ZGv4n)3|n$2rJJ{O^HjA?)!|BE0Gqw$^okcEz8uIlJSFyjNq?H-6wj zOzbAP3Z^J85F&Oh2^rjB648O9O(+U{LkJpb59>gJZ9u@wOm8i#5c6hDTA>^Kj4|s1 zdGdX&n*l%WzS&At`f9Wz3b-_}NQDOMtBv6=&%1ujMSCx>!Nvqq>J;QtOv~Nu8 z%1kI(5@`?SDAP#?lYy2PI5VWN{6+hLny+Q%keZ9O+WzdIg)~ zVHHJp0^LK4La~sl(8;{=+i{3XGieY!{D2!*c3dhhmqp>N?2W4N=T8E z6^7j7&Fz+s+sALoYuW|SnW@r4G#@RXmE>1dSrLhzX>-fTexb>p*2!I^!AWxz0Wi$8 zbwVX9C3Pj#2V=RZ62Sz@c;Aum+=a!sF0mpn!#In~5GzhCda)iv;|ZhSa-%LU3UViQ zSn9fCxonaH?*|qXMF0i%b0o0sC6?1BNTf4C!3yfXlI2l^=>&m22=|b!v}dRwLwL{< zE?V+M1{iH3b3OB|wy*XBs>_LY?W{a>m%?>yD74;dc|(IQ*-%gD-84$N7ZREvvgVT_ z0K*`qe<0~iGgHuWP}~x1TToa7mEq9&|55f8P*HVnzsxXAjY#JpB7&q+A_yp@edc28vit)B8M{6tT&Sy5VBF;;avG4GA50quHtg<#T-{h#@aM38cKl&IM%6HRNh# z^eQ4Lcr&td01=6{j(o(dD@MJGNRAUorpN$!hEm>)jS4kOkYLhHyJ&J@&>o7kB>0fMsnFera z&712XL1!-pV^A!^Caxf<#|JXVP~hp^!jl|CqKJCN;dT6HX~M(d5Ze5V3m^Os7h*4# zq4F~HFPdu}T~UxM&14_R)ZI&KWlZ-|O1TtEx&Ic-V}-KFPnLf54A|TH{Ix)!N5JLb zC-ey~nH~{n@*@rxJjYlwEudj1T5mGE3j zc}Wp>PaS$&Ebzi&2IW1%Flh;TyD8n)I^xZBwCw8$XJl^nl&FP;x}zSVB46LXm;T}F z_>;IiZdt5x_+6Inry@)F6!)Jb<6eo$J`}OdmB2(J1Rq{r^1K!v61(v1XaQ=04vhDD z{)r7QuO}1OApAZ&>cd?A&#RgodSJ$>w3zTbH?`ZJuY-MB^EQIgw}|&%PUSiO67)ww zovU72eRy0Wnf-*nU{kgr?=G~FxnS^q@wP1tl~B<7`zA;59msun&sC}ZQ%q`tU@ouM zuSUW=CDX^33(W=YzQnx}!WPXhM+H85{tf4|`a0x@8Tw?mXfL9;LAv;hm5(wu$s!iI z|H1aMWcVwlk{}!^l_$@Tq*91|Rl<;HPHo0c=N+X<0iF6l^}{MP#H%dCi?VT$HgCaG zt`hNC9rDYonAf}XY-Fi&N$I&4(D~Q6d)uWH8nIYx80mZDLb#PM4#buuRdBm;$C}rT`XkI8i~8GYMD%@&oll&m#|kE6Zv+fBp8Q`dX&@m*uQa`D7<>PJQ`>2)5C;Nh*MqM_@5No{$qqTFS#;2<7(yJ zN1$`(!JATIf8{rbCZ(n(WVE_S1Dug_`PXYP6_T~q|9M5qzm?r`RcLC-1tcY5<3g!xb0u=O{v#jCR`v~vG-~0=Vt{U zC{FV;H-{6n;B$fiT=G#Zu2&0#c2z!+vgC~JEAb0^;CJe*w+a@qMU;7iLB`v?V{fY5 zxnyRv0N*A#dkI8Viptf-Dpr}NWH#xySo(a)c-HcqqwH$1(=&YJ7gjbY49x>MhDUm6 zkqk&~+!+Hr-Ts!b^i&gPlx=vA2bU7BN=C49hSIz4$I2Ovq)Sh2T_RZ{GHt6{np4`7 zt91hTpVh6>5>7O|6mpS^x9Lk|=LFGkfNJGj8Tr!*4<<0 zsK36Z(A`q@V(U*+?Z22Q8_uIK?0@E{ayqJCER77`C%@yWNX2vN44h&6i254C^g`dgd zdVt5epYAb+MAgktC0|)H@l**lG$X0Q&*cZS zNwATrLWw#dcqB1gw*vJ5Xs#u9yYl-8GZC~w<8s}_gBLrwV>r18_vY^&CEn{7ZH_$d$jrcA5 zS=JtrDK_1uI9-ex&=whp7eXEWx1n%wyNjFhunx&_IR5Zk z6zyDbEGiQRpU|7)uJ12YkrdFM2r;Kh#lifPZE+%|gp-WI6Elv{-JmI&qC((hve5-K zu>EB)&T;nrjoEwytJwgF7elu?un3*%o|Y$cLMw^a^PhxSZ;9PHi(0GNTpdqE^>r@Za?EMk z30OOAo0x`6|1BD+*eIlEF>{&b-MYb}4gpksjn(@4MiE#ELs?1-hLGM)Dq^>#NIABb z&tIW{Y2dd_rx3j-=~A&Jhm{?!F1^#Xo}Ei6>emsi^hxRJp2C!Kbd%$Eiia5|TNNFb zq}*;^`6*}Zr5;KFUD-6ypf>!bHJVq{y<9uvIQd<~7+g-XQd2nQ?zG#Ky6deM7J9V| z+}WG=)+6eH6A^AOz(j>dJxIS>*A^ro*LHKA8in&rrfeS9!2|vMtrB7@cU-}J zdryv5%`@59S{2%xE9YaaTxlf79>Z^>fmxs@vZzmgRIa z5+BhizJ~bL9Ox){r?r{X$UQJ7Ja9i|O+0n&GWs)o0(nXLT^MK83fJTHW3Ihs!oP@W6Ns+%cgmvPV7TvAgShGqe22w%Tc?#_h0#gvl@0k_Pw8E(>^>P> zdnq#zzMFg1MnE_I4b-b*UsC7kW;*Z3^k}Um!f(B>Od^WDj&x{zz(~6k1GFOZJuP+c zrSl|x*Fy#4TmC5`aG_W)T1Alggn_i<%BKA2yTijW+DWb{(6sipZQ8c9({?*|3&g=yqj9t zQ+Y$MFIGLjItUMLxp(UOCG2eO(P6posFc<#9qQ8tQqlg17r0xhs4kcmy7*bI#=_MYYg={h1Whxkw!nk3m%`PBR$& z1lk;OWGpjxFU!$w=hb%GI?YN=F;ui4=qaA`|73wJOm@R5)E%v?s<8tOc^uP{c@kbE ziwsxjY>H~(m{6M(QddtKXV99C6@{`8m-(hf`<6jYMLR6c+d$+4IYsw^rOVDU^-&0G zp=)rF2jEXK)xmGnd-ybAWQ1;2A9%ZXwfEAD_?DUO*jNN&P-8cy8MLT?)^7a~9<{zX zt2U$M4x`UWSG>=hJ*dA+C@XNKo?`%{fxq3a(>iGy`!PA%XyNB1tMp ztnP0B%B^%1&Utii?f0)EpcH{Av!G>zOb;*Ji3`C4Aaz9^00=<9Zl~TAFiEA;(BzNm z*R>V=S}No;ALUw|ddH0jMwkH7q*28=4JTxPnJ`B^J?85J%zpx^u81WDE3+44RCT>g zGSd}WzW-2(A_>C}#SY>FCW97FSY&#J;wrtg*#(>YnkI z#UuJANW(X#lN^wem*=bGcV$UA(*E1h##7_ZT@9R7q)C{-U#Kd33bMzf>H~Z-ggmiT zW-A11zPfh1WQgO^?U2qz`}ER8N-I1fL2T`Sw3j4|dJr=TY#jIryW%QJ=_^i8_FJrL z#?A@7R~4~sFtU0vaDiT?0+991Rl+oDnj#;(4$_d2W_tU~d4U8|u^x1o*qRCFuc!XQ zSrpr|mq*{#bW@LaKQ-@Sg|^4Gm68$YNN&4FB68)6D{<4vTarD!y(=fG<<;i-)%<)9 znnZtnh@F0`_1p1iezL2u_goDfM+M#f3b*w=Ar08JfdW~bxKnf;9e--#-d(yq%bLTxWp2A=kx!r(i$f zD=#fFBQjZ*t(Hn*bmQbi!x{^ljc(PZ>1CX$>9t!bS|3e7|GKNR1;|s~FszF!hdI~hu@Wn z+16%*K+kVgQ7p+#c9UV{j{-sa!A6UNrK^q^u29l(JhQ?{8=}m0ogL6Kd;av{`R?la zx&NVn-sW$*)e~xhP#h5CxPyR_w9WP9qKVNUDASzN^#t?l?0HbyqL$z4@UnIokRSk{ zI`ba6CMn1{x{SG%?R!f%?_}FTG=BVti0BFh{i81?NOurSW^%NErzWWJAlA1!FvSG` z3Gjz`blX4^(0|ICM}R#ag0w*bw(Nt;6)??cEdB+Bu5f9~OOdh{-54zbw#fsCixUWz zp!Z|eKBqrj>RJcnNp!I-X*I((vvnL-N9!i<<6dAUg8nU0Cnh+osC?ReJ$MZDye6`P@AzdBQsI z&Ye}6=6_)VBC=O3Y!HugZ@YwU9|$z}jVYV)_ikcc>v^uw5SJ{T*$A-CKWKp`;QHkj zFq>zyLbZ$e$FkwJ01%h`cXc%Tz^oKBR~RclVvdDxn(L@1x)A;PD9)&zzNz*P!e1xa zOnE$TCv@QsFNuq;@n0hS(U%1Lp|JhJM3!%4bF@yLrKD~wSWAobeWe@rWMGsbV7YWv z)+}*b3QIk7r@8`KsQ;f9{Kq+TRHh}|6&!aL)t>6$(_TE` zU>;)Bx(;{3W$v1o{`f~+k2n`rwUax2V_bC>(>ed)3;^n(Y#!Ny#vb>kKA=>qfQ^!X z>63zPQ{v?`kPBpxNd{K_M%W{N3yrq&rd~34B6R#TC*-|L?v+Ip6Ea=XOPT1xejE#| z9#-Ta1&EaB!nUi|aVQ#LqqCOxpIm|9v_p@e8Hlv|Kq~fLqUWe^dCy_3%!j7<@h;9UXFSqreERcoi`D+0o z*T3Q@1Iqr~&=lvSt9>_b6T*A#@g3NHN%7djh%@Ym?+l2e)oWm+(o#Lwx4pP9otIu{ zX9Mgj+OwD%Akli+D-_OM{|CoPX!G~L`BE&RuY!(&v!Gm|1|KE&wKbGGq9e_8g`-|U>*LnoUh1B=k^S8)OVTW3kBqo$DF!BoMaLg3hSUe?fhLu$@fer zMf`CYtLyY5`{Y~=FbVy?mC4A3K66Yyhk5)7S2M7GsF3PARBh#m0?^A@|rWc9)N4jW@)PK)d%C&J+!P!gt7$ z%z3v~{(|}&`7d4oGHK<6Lw^+qZsu<(R}KuVg8tYT5H!`)PAi@MPg6A9%oidJfcP2w z-zFf#Ik&=lh?+OjFTQvOKi`V2Hhisi4!0)nf4)TLq6PGsdzsQ>FIrbq8Q zC}y<%@35M$fz8WX=}%jn2HIi*F1M>mJq6}>A7vt8Xbyn5%G+Px`3@8 zJ-Y+?^l!c3$mjqr21I4JqL?~nZt{zaE`|Y)fI|`(Y;7;^i-9=pv}~gZ?{ZPDTBmoN z99jM-5Bx6Y?iA71$n?ygnBr99#;yPOO2HRB==o&OOoaL&-G;WhH!zJYfywIvplZ6m zn|D}0Lw3mv{&LRwxf0_!(&%4kxxgmf+kfKd!RcN4O-mpOK8fvq!p>|X`}y3rZzQ+` zaHoW&ZqL%KI2w^v&6U;jG@Qu}ZkRK+A}8st4WQ{oy5kHb9VeFp7{y>uMmdt6MTRMFRPbq^x$^8*z8YbKdD6qIN4=k0DFZxt;7<4L)fkp0o z9mG2Gc=ZM>;L^7D#cdza1Owj!b@;qH_h%R2Ut8qWeVcBEs6K5FdTI!?a_O0IA57whhD%P^A6}5HY=n3Tg_9OZ9%OaHS;zNrX*D_PdD@ zgAPk@E(){{?SHsz4yoTJ8yf~AKcZ3Cm&loar+pOwDs?;t64U!c0WPVXq*q=dq>Uk6 zz99aWqOGs8RPSi26Ja{*_kDm0^zKPV5n#B((Yhy0#}9v|AnUiYbSQ_#(V zVj$_x`G)|k*3zFE+50AwA_n&SI}u2S2NK^s*V4%MUHFb~3VA8O!XeQW_#A+OL=Q>R zz0`R=Icu~s*fk0auh(J+N>UwHqlWTQR@}A#4m=BloBVFR!4VE~9U{U;PBCD=cao9m z&uG6JzGDQg)f>mtp6AU)U@@;<^0me%fqsb_L zfPnZ1W*0}UJPrmRBi@Q0Z^iAmtpwBs6H`dqvHvM$08BtQ0xeTsK^|}dT&YX6S)X@w z1KbPX08=B^D*1#?h8!=)*8^er{8SBlbl0Ez=zq`ZKj#2Qi4$6N+0iEBsq`c>S!^n% zhGr4e){0I$gPL>eonYBNA8H;ybOT_?GX*d~04e1>fM4rh{OZRxzq% zf$BSdc8UYf>drTJh-j;l*L?pa1Uab|9M@q?f0={Mlum;WP;Xv|J)Gt*O$f*Qtp6+o z25tZ%N^|#1PO1__YW|@4jF3g=$`lZ-?|(<)Sl#4kmOs9;{v+YvM*#xtpFOyn|LaXw zwBlcHveGj&m*7JsUQp}x2IXfpM#fM#BKsiewA`zklHnJ^PMnHhxq0P7S*Zn|ivObP z7NQq^Qrxh=0NL;^Py5m(!LuCdWtln@Jq$S~oy(RKv#=+m>?us?S_yaGmHOnzWviW5 zeg5s6*`iL{4eP!vx2pH2vXsu(&rFGDH=*BN+Fj&p<9`x~)S^^)qFz}tok_zVHDvSj zgnqc~d&~YX_zkreye(SFNWt@WB3WlUS>#8G5+vEzhNiE8!8hvzk-VulKJHA9B2Pvl zB0aS4zk4CC&0)J!_&izq^Pb~=)vs@t^rB*m9(hS3#zJh&p5?iEd#qp2v?UpfrJ4Mq zTg|n@C@boeV0 zWdg6Ed;lx^>5Bt7@qCs7u*+`ajlq`AMT{IQU{@RLO(@z+?Hh{(^2_fKUt$XHR( z@~Xm9pQ}TJG6Hg6tfn)*eq;L)dAcMG_<@?LMNx1~j%e{&qsT_4net{~>objz^^?TM zmG_a9604h^(dkshA6K3WGRh+HM1AJ_uCLTwhM>d6=LOE1-DD3y6r8WOdHv{o{K)|H zR{PR`kofDF6JCq-c=y6^XI57GcHkV*aH81YltqZggfQxwDiii}`mjKIUeRy8Up)qRPYo4K z>u>O{*@ru~3dIl9;TEhGY7Z9zZTQ+9+Hz{2$@Hpymm$Xb@H|WE_4)dSt~U8pWSdCM zPll_g=#s=5n0*GkT4TzbE%4Oy_9sFS7^6Es`m0gryZqjUsmTddKGlJU$VBX=Bbv&2 z>1VVYMn@I#wYyc2h!`hmPfAJ77kVu*QKpa0nY12BSB<`jF>oDZOptI3b*EsAMXpQp-^=Qtw7xe#^N4-9_T~IMn&tA3X~6+c)HT<~ z7sH%81`nE)!B;3Cq8U9@C~(PK$$CWf=jV47P0z=9zNL5ik-^f@-0UIqowE*W#(!EI zDZNZ}G9-4E!@}d!cjY3AF1DNiRbP4r+RS&q6mXm70EP)PXPjwgl_<}ES%s(GqXeo{W;+Y3RDnrUTSw3c#}23h2h#YE{2BE z)GsIAT^S0bK)QbF4mn?TbuEXAF3laTD7Z=YB#Dtn?nI=~>UQ=K_0pvo@$g+fIvDXZ zziE_BCp&Z*Lb~!q(`p%OeBCu`^B_qjKB4W3#3zQ5l18;q!CpVdZgj9Um{!;8f_6EB z^fF7x%XP)Cul0Vu?#Edv^P#i_1p)u|Tb#ywQN_?ovZydF36H9UoJtVH_j%j8Lv%s; z(cfNsz7)LjrT%Sg@~XM91NXg^yAe7NMmDP(Z?5Uw4Zq_2ApF7HQ&aVjXj65=s9}a774sQhJS+xqjOe4LK2A3Z zI9+JNy_om`lc7k!G>lB>zMA>;UQy`U5>=G3=TJf+E{$hrwBN!vJe&&np*#^C)IBE- zg&M&<^OF18?nu77-|_aj9&-9@5(wRHt$gNe9Fj_Ox8UGM@Kc3Vlb8`x#-J6LKkI{T z-4kemrn4ZH-YHrBu{qvs@qnbJgU8P#_u6TLKNo~in6RNUNwmTD8cs#ona`hp^vc7s z^jY?38>8lZ%#g(?1(C8jk&4h%=&Acu&8rd;vqNyX+%xQ8J;*8i!|X4@rE%M1=JI(1 zecDWR%pV3A%&r$iGsS|KE9FA=EEdDmyLK1rsT^VDr_yTW~@K;zjJQ0K$WvfK;p zOJ}am4mGPflsXB(&sr-()Q}S5H*fUWc9j)#2W+9N57Vyq1o*M_V?^%MBNYjm)XrR` zCDMlWbdxjVo6*v?X4B!jYtK0kFGPfcgdIdpG6(~-doo`t?mwM&=ajIXbGpc*%5`P% zdB@pCm#;Uz$?~%IHzjyf$904o&NRTetnsz`hb@$-gKy7ChA+=I$aP$Hef)W2qEXls z6lsa|8ETk!{c@ooV(-(X;oR5;?h?h5x;K-*4N=u2Aq5Zuyt-Ka&cnmbFmto?J2T6* zVm_kl-%{-k7P^Uz&oo*kPG2*DC@Xi>szv{x#8E&HcS2Ha)puRpg$8~1Y|g!!aE$ph z%6PBoVrhJ}c^dn~fj&fThkgpxNtS2{~HMPioJM*NxhpcEPx(124tRtuZ@N)c{%)0^tRqZX0Yv+B=mTkBR)6EHPu<|W!aW)p9CgkM zHhJ!|e3Od|f%l7NkIrECocPsAM=}ZK(DuRYfs3*VpOjhtnK0f<<%Fiy5fsW#)fwQ$5y@Hst z^9n}c3EELM>}n;({hO3ao|_9U)T<`e%aGYSTr8lWBuFEP+EP(32a9@w31GNJ&7es6 zLJe*kVy9B-y;T2L_}<+c3$`s1fm?yj=G`cpZ`Vwjg9@atGcCAD=Hc@z@F;69_9XZ) zG3Z7mbvxc5XA0#PORahKu}+4@WAw?g(o>2`wgIGaL7JzWD{r+3Np}4b$U|kcBa8d{ z65nP?Z^gTzS+Cq^S&Rd(fhIR;7?Y^|h&tK>D10pS?Q0;RDfqJ>oy1Z*FBkX~49%(C zu*z%^+6-|w4-Q)lym|3a-qcmuGJDQBlQbE>Zm|fCp@3{e1OaH#b&c{7?nZ$c>L%jx zF!6~=e5BL6NUOZ-sb#$PErlY)A&uA0HQz(zVs6EL3mJk_t>>bW711*M5uBb6uO|4u z?nd}cK^Il8^Dvnsd$3Dc!cR0tr?|UwjNY@m=Oi8T;C_!>Q}%*cp90 zk_Jb(yflg@KeEJAu#jNTgm5i`S zPPi&%btPXzA|q%GZLTj9XKM-d2o;_pT1XK=V`x!Zcu1*5>Gg;{j67NiTyP0AQo2Y*+UKXak*{^wb zD)PoJ!U~HNk&8Ihj=$xOBxPJW0< z?Yj?GJY(MOOzC}%dKe2+$$wt4Bg#SIgfRR*ublz&6IDW=;6`LZxQp=5dXU?=_{JoYFFxzC!>+wwF$IXV4q_Q!+_U+3)h zZht&6SlaR&BU{e=aAHwh#EOk!L_L>Y?8#^NtJ(=jKMJUdC5q|J%YaZX6{(EGrF6t~ zq(s#-K|QGca zpY8*_e#~z#XN4=e1V7Ib)Jq5<{Z3E1{wzW^*H6rfa#+sm!aXkOn0SK9N!h$Bs24o= zIDD1RP<$R6){;j6@w1XDfbHeO5I5W5r%4xMt@2-jy$X8if?vVG-UHg)cWRSIP$CSQEs4zh+0g?7yDcZS!X1^&7L{DG*Iv2V|}ycNBe@%4H}4O^}V zGGkj7o;{4rb}oH`FBW>C@R^Yrv0d7to^~Few!WZ1n*loQj8QwE7I7bca^G%>Aa|>~ z=vm8?!lb7h=iU%nlQ(2j&pl6JS+QJXGS~eWYp-08Geys8VdUBJ9x_^h7k?N1QQm~! z`b!Ro9a~jp!5=YfE*0vXq5%~{XBbVv<)!iIkIHHUi(b9>@cqLFg^P5^`^Ash3z`_c zD*F*HLMto1p{@ZkdKYqPn?+)&s^Cy5{KY7Z1uzEa;Q0}}M}$@PzpJx+?C4GTeK|E- z19`qRT}Ls)K(I&$3oRhEeXw_Tv=n>(Q_s5yud)0>dgb`ISJh$8JK-@Y@Iqk&Oi~Z*vCA{@L5u=q4ylElO{B>B=#v@OdHqq z(%#R718RGp;J#|6l9K4*K`>?XvL1P+x6f7O(Hwur|6MNa@HGFoEzYeOil;uf^Vl@~ z0cKXP^kck%icBk3j1uBfPO!8o9P&ylX@kg{PR_sxqIrCS8+V{-J zMT6$~v5xhR+0TAlo)JpZ3uoC~j4SoAvA!?@u5X??- zjInP_rGZ7$;O@h) z`QBe|8arGE>XNVK#@;%b8Big1FRdV1B?m)RiLSBNC_cXT%(i#x=?uki9^xWYp~C!M>@+w$Jb3r;-c6NQgtjhF13Kvl<) z4@qGouN^vNRY#}HuNF*QK6=W=&NDh%*t1vG;D#T)OJkN;Gs=hs#idO42};pEppHA7 z6y$7=@onGa03V&B{`GN`Q;Y_7Muox<{U!hsU1H^%@y@v0b|ze#w>3t7BtKPsVsaM| z_4QmKOfL(EtT{ibo!YrG3s+YB6mHBS-x@vk7raj zG52-IFFcG^ZZaKH&>CYF8-~24yfjtE>s5^p>No(P<(aO;c zh6ayzYl8km}c5_fyuszoq0}d05y@~R|lv{1syI7-l3h^HDsa8-Bv28G#c1$ z%jss%-mHsN()9V^f>oeV+me4BIkEGjb(g20gzB>E&#Ks;`hLG+u?RCUZ2!SIj`KTO zOy8~OEKSZ>w!Wa*rvN$7UGma|k+Sh?sMzQY(fkd`+1o(*_p+lucP!|e zaSr9w&gQxy^}3-OX{hr?6&+^bW5<{v1upUK;>UDSj=4Km7J`kmPr15zjn(gBXejG# z)(B5R{M!R9(V60swb7!b7oA%iBOO%yg#=cR7>(Nd;Yymt9pI>><}My+`C zkapp1-Ntv(1+OCTvx5_r;s@E?fg5)ohHfr;>L4EPI=(DHD7q8W9ue;693*0wMr+sZ zcWrTWZKVJ^!{dIO;#s$04^rPjW@WZXh=8ju9&HqTt)l^bQ&@m;?JJ6qKHAMeuHy1g*Ub&sMx@eoNU%96Q!xwC#08s(bCutw@M^9@yAHFSwFB|9;O?BrM zwb}Up{-(VR?f%})xdHP7$r=>`vQk)1;b|B3`nE@Eax|6^Yz$sQ@Ry5@?mmhL0-I+_ z{y}R@ltM!GQ|vwYvsA;iYa@Umj)l(0B8`a?N2UUoU)nrXM0nUQf3SBxZ@jS^r7X|Y z@=#>MuZnX^VZp>ZiZ}BD<0=rst%h>3Yvo73Wq1fqBz}y z)N<|jDh-;X9G{_4f5iR!xCB`I;-xfIT{swOe@~hSeo472p`P8)CS>({him_W|HhU- zh;MU69JkRa4BC$dK_FhN5Kp0&CT?CT!$CJgHQ&>EFW-BhqA8GnV;Nv z5`UG})ZdA4qrDFAp*Fd2qzG(t&QA*yM88hCk=Cg`c4+^@ID@j&YjU4NI{>fWg(@(x zpCF{4b&;jcoH#R6v}ps|8$WRuWg}>gwkk0A+mpD?trQVdR&4*O2C>+Fo-*Nd^AF^Tk@;yaD^yS$Mfn7b)!%x^hn`2&Bw)`H}&Y7 zl4Fk4W3Y%4v8_BP70($Lz;G=|QI5+uFGG=8n?UKBGX@v|LL14<57Tp*D`*PUw3yAa z{_rTlchssIO5!6`W?pUU**yFw5Nf;`CM;InYGghwT);)#2*18az>~l`wy&kL_ zHc^+U{_R|{$YDMnp|mwidIRQA7d4=UC{p|fT`C?Q8812HMuGRnL#N=D?Pug0pTB_j zoU++d%NO(7W)dp5FjDO>AQ~C5nR0muTSR3n>%EkOQ}K@mvj3px$^#y9ppt9X#yaQ1 z@a{v{LSgxhBn_re7wgajtr)TQd%+_j&kuMXd0cxyP`h}J_t)NX;RLhaG_zw`FjJ1F z((?^pgJiESYNn|Sc^Z-VN{=Ha2G7Ipi=YS_TR@J)ic!029SJ);`mDH!{=wu=Isu;l z73yxyrzM$2ip@pZriMQv@Uq7I!W?L)v6;uQ(P)IUMzyGN!!Jt`GpL(G@lhA`-Fx)E zw6K`-X?%PfAI5SS7KZs(R3~&N?sU?89qENhQNyp4NOB_lohWM?SJC}9;jK-dCb6D) z_%U7Fx)yR;iJmW$?X`*Mj;Ux;ik1sL+w2jdOpbVQg$wV{1Wh?WMo0!LvI5fgYabG{ zslrND0PqI61!w6#pDt5W4d$bDk7dbche-IfaKbU20xG3i{sdr@)&e#FHsog9%9;a` zE%7$m@0Bm2RpA<*X2`lAvbFtGmh-PN;#^P6&m<8PE(2UbikXZ{0c{(D!zm&Db(*0j zQOze4&s6Wua@sH?#9pf{}Y?cjY?my-8dCS&9h>E`me~NwiF$f-S66KM&UeKUI z`E`#iK$4#a1vzneuWl`i0`|jq*3}X1EWPMY+6{GKbxEdv_K1?T!0v$}%O4#8%-4WX zGTB^kqM#0D^DyW%bt{_L>sl~jFvLMej?*LtilyWOF!d+461nDEY0PBOX0`iQ0%`vh zi4{Cd(!_O|R-eD^Lbztb@&^_;y2tVX)>-C+frB&nG}=A}Jy_uDy-E7cw{hdX~5ndmIe%~|wtD9CK~ zZM`}fdTeC?ZKt=<%Gp5^_c?9h=1$*DwIx>we3b(X;}4kOH$jrcPG3quLn_k2g0Wyh z^a4y|fw6lVVX_Hz^5FlP@mB6>g-c7sE3(gAGT4A4jhkE#wN{3QQpnT~wd6;kB&Joq z%clh{oB)CiaFig$wiw+uXmT5wNyE|6qdKz`CxumGjVU+1uf^>Ax~I|n)kK9HRwr5` z9X-Nz_hx?PI8fCn97F}S=ZufGvZj~;Q7Sfo%`o?$sp0(mnH9QvW`BtadL+>@-UrxU zc*(YWL*Qn3lo#CMsTfgfa!=pcI`qq`P`ibg8M1714nqg41Q19IkoB&rbhLa|4@ZZz z;Dp%}LyQ)`Guj`$%n5(3M1OvI;O5H-w6Q?iUF5;@{sNmX*dDHtl1j0Mzw(K)xXp#Y zqXmC07Qe}D4*7X$oQ*R2rke-L*ZGpK?k#Voac(oN72jWs8&6A+qBy6ja@%F#w&ehtD1v=p?#k1xS6K8eXAa+Qw7WfYgcZ6Jq~%XQdheRc!f;z{+~pE z=Wq3{)Y~DSUu%IEw!8H z7w?|;CB?7ue<3aA2Cy53PHk$~3UW-_j%3jIbnU|Y(SNbwT-EqJkXCK^{Q{KiD0l0t zJy>xW|7>M-)jC*Z9D%M8wsa@PPLc?G1rT|LYdZmGDDFAU(pdoT1{AyG6a|itl0-BD z7w9>&43_68p|lNk9d5JE74qXL+aHlXCn^I>N@bOZdh(qHIGLCIYLKH*+S1`lCx z@5G+Ha@%m#b?{DnYgpg+mgjM^5Eu}E4nI`61IYu|b|JuBa-a2NZdefdq*&|=i7ykO z=#Y2_SuB#!y z_E&}vEMfI0+A4CMSLnzO1ztY;_12>t1v-c#@godu_DPLCsU30#d$fXCNA%>G57{=j zl5KJRRTQwQHCJ}@-CS%dBC~`Q)BIsvG~e}K^+j=WH`^R@8b1|$-!iObxgiC#f`9k+ z1_p9Pk-y2JvWKTLa&T1CS8~BlP1gvpueU$@k(_#V8EN6?`zIfN$Bpg4rgp~hMuO3- z9FHN=Gp^?MTAH0L&o7GpczC13T4T7yOp;TWT|y1c>G33MYl(g5W(K46NN$QL7ZZrm6NynGK4H1r*v0rD){ZExN6aY_TeI(K{l za3Y$k=9Qy%x@2b}Ad&6Z4QSe&18_f|kH_$3g%} zA*YarcKailb-Pyh`df#!qxCmMv~a31w~5&oYv8%-ilXyfqOfh)7emAZFWl~hchR`U z?_2G*X>%{fht7cQ=~{p&Xw+W-t{1eYtn6vrzPtgDnqzyXSIH;)3s2=YRsF5wKKF1q zph5fjP=9Nfg8vpts4F`1uP%=AN6O!iR)X(Xlj+MR4>9ui$F&Yg4!EhG>uyDvr!sck zACMJpFyDj$r9~TvPw=4`1q?^=J?igPkQrSSkG_3~<`h!^hCfns{MMH-+t?=av|#tx z@W)D8{!j&qrLyLaHt)9<)D;)|V6~tA;yVC?ZILbRl{2mPQ_1`d+D;yJXAZr5qA5AR*=&h`}()mQD4Ac4h*81)&EvaKI z9esdq@b$`Hg_8~TRbT~bS-L%Kt#Ba20X@%KZvvaK?-i2*jJ}OysK2+TjlLZ2)CJxX zfK`ga@Cv})PG6zxH`Vnzz0}EHoGrVlv%vDspKh<=)}|r-=Aa1+49|ru`a0UU3j|Kc zv}v{k+h^k698;$@N$xeYJO13V1Wy8U*NM;pU6DIeM=O>8ZH1tz7$NF&?Yln4*1_c# zK}xgRe&2o;euc&6HEr&6-Dr0vNmB!BGJFi3_s?%!S2X>#f4AP)1#%BXq#$R;h4v?J z=qhZ|lugo5_0VkKE{!nOBERv&5LbOz8B5&~tC_^Nx$E!5jNCfM-Qxr#u!xj8MC$0b zZwc9y$J7|f<)K^xtKap0ZyOAQkwM6Jdwqx}-OwG-lXK z5Nz(sJpsSz>_rrPjiG9(U}FfGG-r2yG_=LZg0rgXxoDv|L2?kn$kHA zcSV40R5rkMKzlC{-0uw_Ow{*_N!&^-ZOWRf!c5YidN>X(g0@ynj+OtDV&ctEf4W70 z$d5Bf4_W?IbpflFY@c2b1tu83(rswhE)ea820%GzX+{T<)u`PkGXSI^?fx?gSS&qm zk*@bU7E9j$l2aP;L{4xy2DqN=A_?{HROBT(Pp#e>0T8B>ff{Uqk^1DZ1qo;z1$iv~GI>V) zGpf>L6IgvVd|m7Y2SNtio0qiA1F6qjbwrf&TrCd|6mJc{e8 zJ?VjK6e6dmE$M>Yoica_BR5-|Oq%zV2S%O>RBz6V#wGL8@#EQ0Z>pYkXxCc7Ye2uVCVo zRMHKovw~D^w>F3=8@YRSPdK5X#uzvlTV4_j{m6;&6u4KqVbP(yc0N)0I?4bn&$gy_%+2!o_jLkUPr zcSz?T-65TWAkr-*BB2N(%s)KO^S}%h3?tRXjeXd)ypPz5uezmU@0K8DW}UuW_9z)VHk z$Af>$WjG_D6z|DQO}EP4X^)>gf9}H|$`S5KrNb=RFWp8sO|OE&@C|W9d9vv_rc0Vj z@w}QT%!jIeW{@jDHatkiF0WgSgmU_#-JZ}nZuKVZ3as#BS?#-y> z<&k`z)wP-*m${Qn%4ykx|Uu7$@%aiu2K%Iw76_qcPc z9Lp>{G?DokNFr(z_|q(GVlP75C!&Y`Y{5L)SpT@=2(XC)&#;IfMc=AWuM-)Rn*HG^ z1#b!c2v&*8oszbxX3xr3VSo3SWcLe)Y!;BNSu+p%_&j#mbK`+g)Y|r0pF+1}sR*N* zd2C}rb)BZh)44W_Lu{~eALj>HkWk<9ZDzOfGQAf9LeEiv=y2Jtt$1FumdL;ZUc%vc zn}@Z#{US)-0ZvX^x=QK(>kQ3g_sE`L%QjAryPN4xEjT0s*9`&V4k?7e)s%|$Q0T^7 zBFPAa5KOwK_;qi^aT2k}u66(KXfR3LxeDzEAG&NrF#c`MIQdIin|ns=$wt~?3G{WV zWYb?+8uKPyc0<%~T~4FKj85q6pRBbZWGGE6k z5;vRQ++dgJ#meZ%_tK!zgo3eU`r3_0c}YJv`4sYpHQEtu59=f46AIqHFiXnxC?v8d z9Kff?{D3+;gx+H0Flqx()8dml$i_usf>Ko&3>Zuu}t2opi<<&c+aXIy#j%8Ax$E?mV%g;Gn1Q0ei= z9A|-ec9%~jKbPU0O1lvQhM>sq&ZsF7X)*8Idk|EYJ(xDhK0JU>fa%Yv8n0as$xFOG zPMA()ANJFS+Jtc-39mNu=%LTlQ9c{xyP?xgk+X0?dJ@}v0RF`~iddKt!hn(V=zNwWd`Z6TV=TC4Xer5Z!g)h{N? z7O&qP)7IgkQG^E;_lMSB+=11Q--he8?^1X0^_0>w%7oC?H{lv|z)sFhDC__#9 zoSEF_7VK1Nmp&h&9*=FbNU6Y_|FVT*3xLaMM8V8Wm1#OJq>?s-?Ws5rtqA%g7676x|Fjv zD?ZeJ9ocboW`EZ*$i2`%nCrzH>h61sK@eQ1>b~6NG+ja;U$6AG^U+xr-?&t&amIJ^ z9ZLp21c0<0ZK+(bF#0M_SRAxd)1Zz96#ge!+1`pcdm~Z7_f1?4{7>u?e5Y$OTmbhOIC7} zA$TjC97TMfB*ugc+RlvHf$K`ogzdtG8}Is?xBuBos8Sa)3Up~G&p0f3MuhFVg+7$^ zD4-$Cdd@Y1jy}WhbxAzOXZ|ouX?J%xhYJt?5IqQGaJxEQr5Q;PH0v0(M(7anhVzk?^W2-HcrYjJ3nxCS za17Wp&Bk`ktxpMHjCQ&;=+uR8KH*8lf(Kxv#v|_rxFs->v6G}?iS&)(kMd`ORiz=f zJ&A)FA8m(1U#$^Ju)9dWT}DxFUMYnuN||$RgUXxVR`QuQe8#od@t{m4nf@Hiv-6~R z*XA)=0K`ei4)f#Iln$GriyeBJY6q0glkqGtlm222pdluSfL7jvWS>VC(7zq-1{RvU zEe40bLceuCia|?Scxqb3ph>91NxsL2Hbz7pmKxTb+Wn-B{u#k61MqraWjTx{Q)hos zYyfsu1*Mq0k(mpTPJ`I*M&|DlW;c`M^0^c?gI9-QD5Mi;_duQ|vD$MWTbPOI<0x*+ zmx8>yilx_M52`h@S|O?Sg5QZxP6z;PGE_=MrSvoUqas0QwYjOTB&(?Bk}F?6p& zer(+@T+{tQElSKCSlOaEIT+QJ7A$2DahinJdrwaZy9p4Df3+P+l=(Z@?W^qrIH-Xp z2)E&_{Orw2bByAfc$tK;Ic8sA=IyDP1C!(j9HHE?eG|BHxfPyd{2~dVFE+A0Chg z%X|JHPtpuR+WHPq?FD7<)u!E2A<=kw4@hS07JyU-c@`BT(9HrKr&WKb4N^b zk&x8)bGdaiPK1Aoo-yVfe|c{+^1j{2x!)M}ytbH_Qc+5cxe=m&eeApsNq=`F=b88R z;adDdg95^Iu&8X&#j6BninpUM!c~)?+D7OdY^woYtHBh1;C+MQzZ9-Ay=>$Q*^kR) z-~8lrHB0*uX0|sE5p9MRf3mSrA~eWLj6&)*@uZ)bnw!d2TfE45nI z^Ke&pa3S1yCZbfoFwq!IVhelVE9+vc^WppB8oJv0&Jphm?Z;X0&|b%~lvZ^Jt(liH z`teWp`6E*CpyZe#00%q13X~MRJEJHWZn}3Bge`{bmC16EMf{Ccm$@O|T8?QY zV?*U3cEI8=W9L7WOP8?X_sr5*QCSZ;U`be$7n)Kep%Wukc5jhb<4*O-Mw>rgWA+-T zC#wB76Jg(_S$`jih(IJ>mYAj%$kaaDyEN#NZ=-pA_i8<`h?xHOF&?D>09}9wGl))Z ze2B3Y-CgXlur!_AmHKk3WUsDMg-Efd>88u<8iP5t5w+OZ5&)iPj1^^R@$}+3RrYB| z1l)>?32t>+q+o)R_A2$zKY5;P*Tg^9qkBNv4k7Nmcqb~+AB7CsqLS1r?VS-2f_V^T zta(48>$cLOd-S3G6$WhOL`2fw-QPNpPmIq71CYW8KMa@sE@k$~8YIRwpG5-5Q9R6| zohfG#m|I?YS;BvVMCtxhJ=p-tm zGo@2T!r1a#0G#pHc|wSsdKQbb#@seEtqnGEZzAkcPN93oAXZ zT|)0;BFfFHr0@v-{BHGFud?E*F8!mH9b&^d_I{{x%uv;*1P|hUG?qKoMM(Fg(3#Og zckt*v>$jc}+PsMU+7U`;KQYuqZRL1HRMj+Wv}&~Hd7i7J0l~^`GgAf!Z zfzSfeP8pd}bk7+(J1n(4jBaS_Df+0YPMbPANDl{WMAumX1&9r%Xpcs={AT=^fl0Ge znpu6`#AHTR6DAb?l*CW6+X!DOftY9AJ6b3V>YdEee@Md;* z`@31ZU$e(4QgTzIZF+#(`G|$LQ_OXBltKVfJUlAh9?cj)@b{TZ3);8Kn+nw{ty<-W z-)s*e+=r5o-Rj-WaLl9_#_+lJ8$4(YJMkoHol&2dA%TfaxI^Z}%F)?ZW{C#{z7!)V zfPIXcu}6=p-=c(lGz+{>nRICoNx_5}k*)rsBf5q^0q6LfDZjm>9U0L2%fcUNxG0gl zfc=RhKwD-E_-c|vy4o@8#h&u4dZCSfc*kPzh0Vr1Z2LnMU^8`FU}a+?5*Wz%J#Ir<_uRo#dJ4C4!F>12ZABK~!rw0yo%`Ry zDCkJna6HjJ^|{T`R7Nu zJIA!8i}i~{Sg;M;%Qze;@U=Y52HftPpgq8IoLKaJTGz9D`27&@=eyo7mml!1A7a=^ zdMm`%`}oL@5JZoD456!G3TBy!^(Th)rxKO~_Jfwy=lhqZB~-r9;tewwl0({JXAk|I zM!^}_8eU|?W?C_j8A;B%epsb2M_u&8&h^ak=(9KtG2Ypa-EwG13bI%KfHn*iHbE3t zy-Qp}%-nMjfc-s*()w_uK`S8s>5cw}Znb5yZRSbWhN{JrqXR#$4tmYL$ElJ9UEU^xHa9|N4k+nx!~iTjo~oKH=N@<;FUfna{gA8D1wb-8)}I#2|fe+0fb_*s)&a^aai ze)Kbn9LpR^@CJ5Fb4ap8dYqz!U5_~#cMUtO9w#-JnupHZJ-)~&F4UHlN%y&Oe^$gP zP~ekM5*B7Mjv%%gfQ^QkH9ZC^(uDsf@K7*rlQo|-uj`3;O}-SHLr{uE z0*&1+*D~qgStCY2|L7oA|GFs`S^$$NS?j#`y7c6Bddl9CcGo~M8T&^SA&AH&voKVr z8*q>GVyg{bv;??6@k{CZ%XrfH(!#=!4dG%$y3^jXlGzt?fkwr!uUq%8Q6k^h5+?7? zTHhXlNUydWq6ak0Y*lN;6qvq_3SW}5?TNxJltt@tY=0fnE7$k8_l`JEp{{>o7PdmYU4a{+_@0xY(!`@E8)f1#foiOhNDB_C~L> z@ro(+aRnY)u;IU=a2Ex+@9cd`Sx$)cOSwMZ$-b1D*8>$7ZWU2~#i32Wju#S`I!a&R zZkHms(|Kn}?08I@(8M3QIe>azSyLlevOEWNvWPkj*XZkM*SDM_Sdw{$mD0@*6ZkIrX z$uwl6&Oh4tv7EAol@{I{PNqXH4}*9L9(Dsa8iC=mvDK21+5x|b$WcT;2;AbESV)M- zq3-1S1V*BQ6051Gk!Je&^f_{y2_L5kIm(3|$rpw{RaXy!)>i)t)t`T-SU?lJ?q^!v zqPUZtjmtj4c#`=cpa7n-#S86=cyiZxaw04dUW9!y7Y#Y1yFQ}x^<|wA2iPd6JdCh( zfv;d?H)e%C$bUZ7e^_Ri6S}|w)lWDYXZ@LiN3HXy}#8H&Hrw^YfwCteDz=g*W(`c`9cU? zr|_*Vmj8}_j-HgrcMKVp7P&NoYY9z*(-v)yqW&TK!t zTSaQeMyiA>ScmwQN3|X>Q1G5#602)lG8zv zIntz4IbMAU%=~hroQ0)!F}3_%3eamO?P4_|3#aA>YcWr~PFeT@iwX-{UVXEV7k)xT z_yWAg&wS(-<=I-k{8}BehLs>P-d|j$jGhD zY$t8pgBF*Z_P6nI$4AF3xgBrfE67=y63}r-7R=BTZIMZ%D8^~majI)iw7=W>X&O!^ z3gW}uB2YQnl%JTxjXJr$$PN6K7JNHfqosICQ_~VucZ-14QX8|8_9&~~#3KinBn+`;_xH?4Vt`MMky!guV z1>=)$f#A@NSzRVU3Xp{|sQ3Z+=eO{e@vKv-bD|}ruRHO@MNVHmE#qQV#dD?=kX|`` z=ltH6?E=oCkvy45xLaaGJKE%j15|;Zir4UG6#S1^eajs%>rCM{SD3`Pm6FHO&_VEr zp!-xHZ~h|_?69?EJK@b%%T~WpI(N~gs0WYi{ggo0x+~P51FyXG#4|!1!K|jLP7p3+$kC` z@exhr!5P>TB_A#7oLHNW2_G2hQ))}~OtZ>4OmM};yiS2t2xX~kkW@D!HgjHH>?N&EkK~7qL z`#TAdNs0Rdxp6Bup=hC|Z1l7JG8~2os@EWBYN9xQQ?4A^4R9Hu$h0KmhZxEuYjo%JsaFfCQ*7jDE;~zm_ht zA5eF9|LE!94(k*?=fW1nPT6&sq)e+6p+G#qS=Mk3JJS^8+(YZ!L$r2>XMT#cmwn*% zH~Ct>8)HhMq*0b%7O1=`g#3y11t34ZCR`L8-WmJ2!Hb^55o2~Ke-qEmCjXPi-+XgC zTjwI@&Dz^Rj6aXd{3r2C{%!9J!I@62Wwn$78s8)0uIO<7O8S#$pZnt`V;S9XJGoYe z$3O6QmVCYI?-U(Cd~-=9Iv&Cw(B@HBW>J~WWT#rYHh!TnZPE2sQAhL!RN)yKiN2^;G}{H z_zG8AV;013a{FfGdz~!G#eV+|H8qw6_#1aGJGxyIU@6uqdxv92b!q>rp`MNIsc7n} zg}fiQu2^)9WwjqVoMhFX$Byn)QgqBkb(8fC^n^tVXN+m+ryFTH|* z?6eWvN&Uv6@9;S9Ml&CFhD1?@X^Id(OGWM+F=Vy83 z`>n^(6jn{tYkk`Td?(A%$q3b|h^yp0n&ccw%u?S zkSUw5eB9dZAiyv^S9|bfN$F&%d!kLR^TweH-(CfLvoZ9-Rc^Dwm2F+K)1D5DyKa^K z)r2ydLWfhdbWY z36@~$2;35ai+kpz;Le{VPH`usJqN)6_f7PMBn^?IUrOaqFI^;;D8o$unliGA|fCP!j55O>jW z)#SG=L*OUOifPA_>2#$~8Fd4rfwb}x8 zRo`6?ncyFwP9Ez6l2)5quHi%;0eP`dQC%u71?2A06t`|x=Ib+pg<)}n9tmD{KDcIm z>C}78#M|ma^<~pAUkTH9+7HW>bOrF2{pOF~(`LU#zh#LsDw@AAoGG>fpSe zC0BYlA;GyufgEXaH7-IC%QBPH!Y#YN&*(GEJOxXWgj&3+WcVsKN7HI=zZI;jOUQ7X z-6|ZlhlB%5i3t?=5Df@CwDo9?-XiY3wShMhUU!lE59>2nKF1KB-pU@Kz9T=8B~zip zDxRd3%luLp=2>0mq$ulyp6Vo(`iot|KTEjS>Yf(AGnrnTrWj#R?W*usgLF^C&yTFE zh-jm0kwa1m1@zKL!{?r1pZAr^4*zVJ2KhZ`h8(tycok<`n#JA4u*IzLyB`xmrCQic z7o>CbJ3dITv6K_E*AfY_K7AoC4=b~x!b(5aGm0j0~ z?;bz5val4FGMOJ*BI};x*ep3*hq+{Ad5NeDbbHhshPY)`?R*K=za$Zr zf!T9_LWOw2L0P@*^rD3K&i8HeIGaf#PNC#hZlu+YZ?+6dMs`FD0D%zdT zZoGOlnqc3z2OfrD493a;nAFXw-X<`=q_%=iP--rI9q5#t7ykY zotgY>ag(4QO7x$qSeX8HfE99;2N&|F(7i@l3deM9Qy*mQ$)610z6-KG-AdANX&JAy zA$y`sG3n0+(}3@xRti%Of0sTaLRK1orAFG`pX>El&0iC&7JD5xXmoLy`dBzhFx^;g zyVXqQxMk4blvK>&U;;Hzf+d`vm*{Uy(t@8{dkaAPa@ZmV!ql-|~fWnYl$#S5L)P zdTJBucQ<7kGZudOb`Ckp=hwoG;rkWQpX|BKP7DiZ zKbP`$gqVF9nQb&u&A)fPWM8cmBWF@flL<=|cHEQSzr>P{AS%;z~H!lQ)7r9|+CGmo&h(6a7swDrBDtctFLnFlz^|(Elt{%xWpW?J&j{Ma!9(L&XIA|a! zAJRD2PoQvbr?bw;C33!%wY zM#Griak6E;<$e7vi`n?w?O>^(;6bOXQ>kRqKm_4}5#K7*e6IK0-$iKX?8#%?`-2|K zx}Q>}L!rBoO0oV6GcVVIsge)`5Eo_QP~WF7dO4hz-@^q{d@WgjH+LQviAYe-zEx9O zAA(64S)XHq6e0E9G&5DyN!=TlB%32bN=MOgw5iQYX$-}8Ux>IEzGcCm?^S3-B6b$X zI3|Hum>P^DBKdE3`!4B7QnaA4=%|svd!-(5aV=vdBtl=Qx}}IuJp8!L@^PU|7rv!< zJQGD26Ej05?0U;?!p-U~xd|Kb5sG4_$=;)&PRn%mrHA88xXcU(rFef0Kc&zX>EfT+ zim%5?Msma&u0BK1)4rHEzmSK^DCDQD;V= z2{z-9p%L}-kLu=aP_}8=sVEaQhEgTB+s?jA^p6So%|;4mqi=!f+%-S~oD=r_;dezOGSgZqlQ@AF0_oZ#|;?V8Mv#S@jA$P<>i6VPngc2Xf;msK?Ig@GL zO3XX}Q1U2VXlt6FqmFvTQu1GkjB#v4Dfwc;Ch&+1x>?;tytl(y|9qS5p$hyhg}seq zT~q1~qFT{MST=0Ei80B)CxaLCg{I3lM0>NJb9VqF%l=gP{!>`F3RG?rqSxe?(d0LF z$J-;-PlDY;<1rEI7njPfgn~*Q_jU-U!VNc5K^b&}qunH6ahpPR*B`$hd z!d5v*Eq2c(TF4kILbWtp$HzuOiEK39-(--;_1B{!Y_WmOhbfSlG*RKXuT}nG5I}aUWC=JRO(J@prR%6oLwbr4sh87 z{CUJ3%Pt&)4#oART<43e-u0tuiVCJDe4*iiV{__hj#BFew(UChH2ZZnqk5VjeVj7) zW{1gizx*?+(@_ZYo}pGTq$b+oo&q?ar0|hzp*eW5o8TxEI%J1FTxSl1RKlm##7CUI zJ<=ra8VW@k5JZ>|Dbt7DDSm`E_l`=8(UTIWl24w;6E85NBZtM@{w^OaY2AYIzatK=hDas%P%L9n#wHd4St?lws++R+Gm< zGBEFaDkJv9ukjjC4nhQqSA`+bsm-FW1+cL8}oSAK3W1Eh7lP|hBu#GPBT?g6(<5~A3J_4yNu zFH$YjqulWbD>Rcs(oI;Jz#iy#ral=t>?x)`rX!k+&)M-AF|a!*c#`q*7?OQbY_p_`@8yK?UlA4f9khO^DV6ojau6Nr^@h^2X1H z@i(i}D#a567g>xlloc3=PP1{HL0S-BayMTZ@FV0%jS|<`iR-sivr)qS zFwuj@X)ocRoq1cwuK_!1j*b_1N9yo?nkt{5v%b(iJbm{9zQUDmsOw~ zWH}vE5id|8LtGUv;BG)z)AH6LF@C_aJ~Q~Sc7?I+2FLvb|0Q0`O+ zL*P?h*sc0}n6ArGN%pA(_$ zt6eS|U5GRNG1c-khA;7&#!!t}FgH2wT6Wq7%hCMnav)ENGW<8^$2|P^^mP+j4I^-C zKQ-ucC+O->qdKf<*HJXJF}Yil3-P|pXA#L1?v=#TP`sE!V^t_fCtX$>TpB|EBooNl z+sxSd;P3te@j0Nwk+gYh6Y^eC!FhmzTsuu&vg$&FYNTH0F8DQZKt;Eq8GXkbe$}hj z4Gcf;Rxg_T-t(Ow(we)KB!Jyd=PuCV=_Y6dI<@$;NF!SUFA4fCJ3mIXmk<;BqXb9> zA#8T7b2Iil&H8!xxnD+GZ+Sjq|5eDZ6tdp071P!&#nGJO2CYTbR~5G$nfC zpnBx}ddv~lZKXX4-BG})9yXF*jx2n)hrK!@vc;#o_xDrwRc*!2BlD#3FD*^!+VREG zkgzd$l~m!OK%K%;KYYDYYo{HzcVq^}^(nLOe2T`FCfBbHuP?n9#tyK^tn$iJK5o<>`D6W)#0AMy2VBJy=v`}La=2U*8S!HCdowl zar84G0|Uwxwm2v&{2b#h?ag_ToJCbyGW)GIhme|tCznlE+QWvUMs`Y`?=Ex0k$RVH z!><;G*(+njrAYfP##X=b;u=HKbT|Coi8DfvEL4tP;88^_1r9OmN)qE|NP3cnSGae7 zERh?wav~gUb3ZCFjzNw6%o@`rDS{(#B$Vkh8OlW6zCO&DP{VOr^xzr|P=u#Vth)~p zPazMGb2<{K8ADjq>Tld7j6uLFk~{auCM^6+mj-lq4u+VYOkRJZtuCJonw|ti!hlsU zBWD0nZwEaV0r;GSk?z2dc8rjdPH|9&d{``JDQbU-aEKLzcp`dO^@c6Qjb*<=9qQpm z%^&YUiyl=q*KYMPtl>Qo(s~s3x5;XHJC-JM_sPM3;EnNlR2Qv&J~8x zK6o<&ubW|w5#9xnqA_lzh?!d^qK_@+!dOE7lmNsTw1CUbINGcZZ@{}{793G7kv>?=&5;LInM!LLO{4)05~sum9XK(EZD zy0HdOg0}&4EcS!ei!J^uJ9;7e-JeO(b4994z5akB77U@#JUPY+oV|MKJz|&LofRYI zhez~qHf!2q?d!uY#TaN;w|J5{|APGRugrT?M8rucl`_elHE&mhv)I`=M2%4^@H5}B z@s-2nR$>fqFX{Zs+T1%KSaQrP_`8+x8BmC4Q~Y`rtG&6x^ks&r+T&u<`8(kI-`4 z_9;xH8UMlp2)*h;lHI(q`^OSrxO0=R`oZg`U&LsH@6N7~vF@H+uB|c1lyW=`C; z!1XlczlsKl)Eto%!1odZpy!Xq1=x2$?SW(C4U*r(RP&dPh2~jdo5~1$1Tv7n74y-f zu=;u*U-&UmXS4M2yQ8TciV6qH%w;`;vCFcBaQ2mn1z>6ASc>#;UEwg}R^U$<7V3+MZi^`ZMPs^lj!kNgIYdq>$#&44+t;I;?>pWk7CrFP1Lx%C zMWr~TqrrMgr?Qq1s+ymZ@x*2Dz07;VOUu;_TEVSQ5JL-jC z=Q-6&Bo#QIlR{dGImIDL?D#+A(hw|nvS zzb~)E$Nfzo|Gc6PGyUPa`447wZB>0NU#&_@F4h$)>S`zF1@%paeu&3zid@%V_`41= ziQ}$OC6+}YLiR8=4;XjAjhmQ$NlQ!oljUj{NBkz zto!XvH~c*uQj_GNMjr%Wg-&+EuN|puP)|3>*zL+s>&x`621>91evsHl=%oI6 z753@|neABjWYmz@PS^Ww6@#GJOP~{5?eSw4)G$`!&Xbqrg@(&PrRv;XQ}UHM*htV|jb6Zos^w=b*GzV-bM&8g<# zm1d+U$CVnHAk35ccZ*)yS|S<$f4+EjPQ|uX%+s*&I)~A;*jb0rS~kx5Pw_~h4P`FW zSoHX>;&nazFSvb?%Vm5^!S*RL(C9vfo*l-FqMl-`!ih#tcZ`$X7RuW&^@~XhUm`1X z0{uUZc71}|N;sYo&G@|C2GKs?)ILBQ=Unld@z(K6HrfmF<9pJ9shfdYCf#b_q^)>n4qf8!N}V zD|>Gr1V(s8;?N-ulEd0H0=6{tiBy=!>dNk?9Eqdi{=lA{m*GLp zj)S*^+gey~e5iW|;|+ZKB@0UZ5C2vQv&U3WRB0$tlQ1XE5=iBYUVnSNrNJt7ivl{S zaJ|8HOeF$+i5(>K8anXX(s0Sq#IPG5FHH)qo$DPsVV`d5=N>bnKl@hBXL5169xsvW zQKynu@#mi8J=dG{(31$;A5# zB{^V)f^PX3RU@e^E^OkdC(#aiFD`j-#w%TKno>f`{>=-;V=7!`)sFuU?Em7Etzq%V zk|i6i3B>X1l2Sie3C;d1Un>-LK+&^^mA&pAt31{Iz)I?=g-wLON3a0M4Yh?<>zd^P zy^h6owSXp)9m8Y5$*_$l#Df zxT&=7EcbPio?A2F10^!(^8XkTyCmhZDNF?9ZeJSppRORgN>#k7g!Wxk3ot?&USq3q z+=W#f`P`-V_fptJ|6c|q;?NlkP5X&;Y;+0luioI|B9P&-iQA?DI{1p{T=F9U;lD*hvXr5y~u-M2x4i`ejMLv2k`nulU+hnBx8 zEq|3}0e*sQ6O04kUbZ}nSD1_w>D;6w&fVA5JK7IfrpCE+Hx3^}gZ>u^J{)I**MRzf#@#4;1zv zL@_1mO5q(I*OMg0D|yz`0z*2WssvyoD^UZ+5Tu{e-k&rWC&>YNq2%`hov-qwMdF`g zmd!teTl4>wM7A?rV^&_af6yI=l7j?RcZsUkEBkOyb(Rl91)n+-Y%6f^X)_mutmytmNl;fxSU+$h9l zL(TPHOyK0m((sK3kteCEn^S)p)E+=wN?$Cjk9<)0XLHX#8&V4IIreGz;d^J=us7j< zG@OLq%=_%}*9`)>?6l&QHCFMgicufu`o4%3)OsG&q~Doqnv#LVJrQA#^OLwBtxhtrfKDu zs}854#7Rn!q#O5_9~w*9PX76Iqe0vS-TO<{o#NK9?yTYT8K2_{VNO<2I$sz!s&Ztz zKf?TZbS(QWKl#nr8!Py z1|t+!!H@|e2h8c#X?&A@*@ZvsM`WM<(0?4R7Z zNupJP{i3NevW`!qn}3GWv*yz)l-(sXZiM`-g>ZA|C7Nabx^j}S3OBXjy~zhsXWQ~2 zZ0w+PYxs`S*r!YuoSvG>?*AHcw8E_so4o$v8N~JU|DG2&-M)hDJ#3Fvit7b$;HQk7 z<1v5yF=AoGFmfV5;PhlUZVAK%B>O+Fzkn7coJiQQ&ffoD6fPAQ?(dqz6kITkx(^38 zfnQ%NKH?!AeL*t67T+r?d{vmcsJ&d6eWDy0kJJ8Ng%HG2F?naDHgHH+*Z)FI{rNSe z-5*4fq!j6UQzmf5!t1Um{n=T<@s+d3Fgk{Dib0X2afbBlQwQU}zPLdfzTKk$UEQ|4 zs3gIssM1DK?~^4drBgrtcNM$0Q^$0M7uA5l2dMG_mVN`w+MBK9uI{p?niC``L&QTd zB(~UDxIuRZ-&)Cks{Hwt3cd-cB16`{AZ7O{ zT6z_JAVVHNlaA{FCekHU*>|Zy?C95x4!1@AUAlzfJEBTJlW&vP?ce=48TJA$(rT(Y zWo&PZ2PL^_0WSrq8R7w#x*i=b{>qXjJ%Ncy1nfu(hnPrJbu2GFr53X$4_x(?zm~QA z*Y8T{@e4}ilm`B;zr6rUi;F9RIFBQ+ctq)YjQ^Qhy(#OmDRt9a`3%>AUaSA6YE=G%Q@ttX zu(@@K`WBjv!*3E?(SnlePwd5nJswvs4X;;|i3ILAF1ygs^9JL zxPPgh`K33<#mA2lks=NHgQ`c)0075V!o9X$ibAKD9)7l))sl`?uwZoX?!3XfOqE(J zGy4Yn`?<-Vtyjs+D1>s62I_1&5-Bcu#M7FNzw*0@sYC z{>uz_lAvIOC z0#o@ll74j2ck@&G?9ZQ~ebwtU>enwHJej?|sNB9@u>8=LU-qDA4MmtWSM? zg7X~(OaRC!zO8|N)}MA=exU^wnhH2Z!VXb z_c)J|hNNu)$A^y625_eMa`I=LJAl<~O?JQYqg%||LifRa?5;< z>zw;Eu-+QU0mP@X1%C+qpp|EWQah`Ms$}xey$YlOVkAsOW=>&CQPr6h0 zj&|JR(l>Y6F1y-3b~|-fRCVHY#I7H{|ADGM^}@3oscf7a)NmfHCx2_z?2;58j+CQc ziJx`DubIWrFq?p4n1yv7aKCQ*DdtyNY~(g#E!;4Se^)1eN0Ii8d|E;Nnb5L2fiLq@ zFL6+0ne`P1i%R5(FUR77=~hEZNe{LR@^8@6Q2lJ- zl~VtRE}kK;lfC&nrF555qty$IZH<@fS6{@O;0?PSc`BzT>$5`f{=w!G*o2)I6`K|R z1$go4Xt;r!nYC+LSI(>uSDiffrJEeg^P=2At3^IOlfitNCWk^04G8t&r>oF2&jm47 z!pa@U#h;4M#N6l-M?dDE&j|vN`qZ#A&o6b0etcmSAA}v$La1)3Psqhk-Qn3;xYyO2 zZKJ*Lh-2uYMq;3&@3w)efms<#;1FL(Z}e-t4oftQ=e|ImkiWVYxQkva&_x}tXyGMeht>M?ZR$J9|3Mtcch7-P{U2_tag0&EKG9QKu9;Wk~GW+8sE(&F$g&v{Y(( zs6uaMw5ndORE3Pos=7Pt~8+bhP zJD^t0`*@`5Df9N+TGHr+1)uGr=uVB;oS?}Y7c`WsP{&uM^p3PA9{4=ya(=hgd+MB$ zWcAEip3$J%P}i5|-?^L3o}Y^k-I@|z)uPj-9vn;}gh- za(Yf?k*5k&1mX0%I41*oI|i&_r^j`Up((}=I4U-K|?ahx0o@GgO@5k zgqcU^YX&}ci1rA~uX+;(4VJsF^WjQe3NZ!c0_x&}8od23?7^CkhpH`gsb&SpNfTDV zn@?A|L>ekGqhp+5E{vK@fxEWn{4Sp2DiXK(R-6^B$TRB{ZFv5JcDi5Xs8Hsf;m!HE z4DY_>D*>D_>_4?=J>)WFqY_E_`c5pD)I}6zCp2AKI#~)5F1jqRh{{{VT4wEng}xt= zMYnRjq~X^RpjtaIK%1hd#W|?ZZGDpz#x(5OPaQd-`z#19otqr_719>+$-$j_=K2>P zELe1w=FDYRRnma6I6LX8jt;JwyW{R{elGTqJz$Ka%LRD_M!sP?V{p2jyA?M`iTYL8R-i7x*9`FDt+hBF6s9+94U z^EVq)TotkL@0^V_3F9xqf>IIqwb)Jr>%u2SrAn$5Oc?6MJICMHp5v-LosDdI$qmoh z4En1jFv(A6*@oGllCrANa^NWXrDvHRQqk=_YH4cUo4xt@T2uHf>bUguY64+iHzaM` zLcX`o!D_vOf7lgQKI4i<&HS=ejboVG)tP~Qu!v`ZeqWt$KkSzcpz&y5A1-BBi2yqM zrd(-_|4wR1sP=BHviQX2cR3DfQ;0X3w;j&8I0!>=Rrp%v5~Fi9dA37nQs%a2ojTf5 zJ!iu_l8i>NC+;yqsl?hYS=zlh*))XE_9AI5W?3*8O%m~HKcDJG2zD**QzbP|BTuYk zlRl3+3fRnW(sRaySqaY@Ik29B!7p$LXm!w{49kAqzh>#S6?-aT-Q-Hs5xL)IY)k5< z&6P>byvF(cc=WYC+WIy>E=#Wx3)+1NBg0cLQ4TO|mlQ-^68g$DO|eI$PTaDuit`bA zH(@0O1M_d`qO*5RHjwYH*NTSB7JapUZXR=1Ja&kvtc~F#de!aB zZ__}+e5TQeE8V(yh`=8vDBAQ8UFMZ;Sf4m`~CrDp8t6&Txg4{s@bTpenm@Q1>k7~pHiz3Gbce*ckFjQK(3P>{1Fewr~Puk*OhJ=Z{oQCJM7Qx7R_$2%;l zq|YK*{p~8X2g}p<&ua7@OjqxeTxVL?M&+u~0rBBdbLR>F1XZ#El_~U8@>bWgUPa-y zxqx!nSI8aHGZMM<@Lh$=%!GNZ;-EW6hTirxegfD5nlPRN$IcJIejwOIJZzB~bKlQB z3r+nFk78*;@s)X$?zm>n(U|1Wu~_=D=FoUI!0q{C9_^SEXu*qAP$w|JJ^`tb(i!LB<@%KUUcSK=ecFv$3Ax9KtPMuZgt#v^e4BG)wD>RGQFs{20 zRy-?f5E#gvcj6hfOIXGZZX)zj^nR%Dn`L$}raYL)b%7qEKG;*31UU$Jsucr;-h2{N0eAv?i1is`;kE zYhy6waL(Ut*_LCRHV#c)y-K6a5ohBZDRY3!Ify);o6|;e2;Co=cwzIq+|v1q!)TxNGXKLYC(v!B9ttd13s z_y&URcllR0raer22>ibPOz*??VU59N{N;(H+TQTW=D56J@BHF+WHn|+CS{yS8|kMmmD6QWh)Ca)n5 zn32f@`9(Q@8U9?RXTr9-66{3ib45liLx=zg+y{TS=~px-@=zm3NrR|&vjL%TjV7%p z&ors9omuv~E43ve37&_aBg3OwMWd4MAO_L;nM4`0;`F*uv4qUfZz24vcx9vlYP=z( zM6W!rNhttV-Ux}rYPsvLglxjIY%dh&4h!75nCk8J=+gKt*71rx+@nA>g5U|{y_=b) zoz8jI^sL2eneo8RKJIO1Gi3z&R1PFlYWOdH%A zgqT~Uwp-^zT0$-)m{gN!Y2BW*u0m{cBl=rve}sYS93Mm~i7geW{Rp9daa8b@1Ao!4 z`lM@Sd2aN{gqn|B-UjUV$5ddO*68-iI?Kx7`le{?p`P9-jj$TqA=ka*x3vg_ zBOz3VIF{4mkqDde_hk0M3uW@5Gh9Ti6yhBn~rYfYhPTZ$` z97@DRl3cYRhL@iwh)pL zGH?;$gem$qCdD>}sl!as-u1aLX05oDi%*0$h+&X>w}<>bKDD*0g5rwex0;JiwpgpI z^3%UlS{JR;QZ;tF))@YyIqZj9#73imQY!BO4gZBl1gA{%If%IXgZas*vD0XW2P_-z z{(_mUn)rsB9+`d^_)b^#EybGRCRAuxTknIm9`zRADtDm}&B&Vw4Y#Ihb@d;j{N76} zHv?E+@v~q@N;#*?UI(Um3O21BgoH>!@u zKja_ol>6wzzJ_=87|}6s(w62W9A=dJPSRqTEgrt^wD3GRsSe^Ayd<&%=8`MF-c3Zd zVSirk-u%jZIXQ$w&)a-7O+Tdz3!>-Gjv+Xua5%XN5LrU zYs-`}$yQTF9607W&FoRyBsCso+3chaJ;TnGVb$JlWW2|0`lYu!I{M8UNqA9-UBJ&b z!4EvXoTjxx+quV<;W97!NLcC0`#F%o&AKg zJ3U|^WylRf4h{lCg&TR;U;)euTHl{ZkwKFH}BH~t4HydH};H{CT*Wxs^E)Hg&U)xa0o zQ;G|$`%Jrk6ZZC}f?bxB#@g_2?vZ<^N17d3SkYjr$diiPt_fo!!n-3O+B}bsxhD?X z5xvs>uMBRy8D7?SN@{SRr)re?O@!Lb+l!3 zAQS=5C)h22MhNsZ{(cQTY;zTVMXf@lU&q~ydXi}g_V2;6uwhRo(7I0akNGBjr1GE% zA^WmeEDh@Lu-AD#`(gk$ONlYe5jU|zXoyX;ZHDtTdhem&Cblz?>d*HTXwh2q_78Ql zc*Js~KMsGK9NVM=OW#f|`#2prHZu6anQL6#jLD}?E7`W&)M@sS<4_6b8>74Kt@nmf ziPJ)}1KJ+mqHvozOFOCG?NM!R zO{$k!of4RLM$a1GN+FfZKdMt?c@o#sQ=Eq%N?s9(>6o6KD%D?|eb}qltUh3VQfl_~ zT?e&9rCE??+G4}n;t0=2s)5DxypSO86%N9PpG2tw`}k->`O?QFWA9f?Z63>tnOJgf zac^7Nt1kohpXe~V-)G|%RhjG0v_Wfezb7)%n&PmD$`B6B#T(KnD-nhX%zD}EV!_!t z1}souwnDtMf=qL(x8G16T)|*cQX;yEUgbHeO?ycJUb*&gjf%|Qhwp*+Ie(^^7 zG3Cumn2&7{1}MsQ1Z**D(6&v(gqAXc~8XVXx?}Af@S7RhO2{e9(mU*iH1g z(ET{I^y$m%umW(j?$(VLi#1zd-8!mKU<^k8h?(G7wVf9^TuU-9H#m9s@Z{`m#V9Uy zCzICfWHcd9%LwTM;LQ`8ybL#B}t#fbd45@vY)7V2}^0G}Tt~~c7 zvWe!GzZJg`D1;6OY1Gl%)h2-pRvudq~sr%dmT1cSZ zj&>KKR!-`Hpj4bz^duhq5xr6J>lXtE3`_yTkk@%hTMM-Z<+U3t>Ej`(k}d+cW3xT) z$FZ;CJZM$3#z0cIQqSAuax7?cOXFwg8SjWUirhK~t~&GpFoKat_ZOOXfL3W|`~neI zaHxwpV4I(Fh}pT0iFNyQ;9KLPHIoDBsNWR)n@dSQQ_73@Je^d}sTqgYPIML{cVqq5 z0ui)l#wVsa&KNbmGxA<+fcNRTe|bhX&3~?ifNUWHeAVZ6u5I2C?t zrHCG!m%4AY4d$H#7k=7ZiTbS|yQh%e-e$iSG=JYKA|qj`_j|1DAw;#DU#bcH11mQk zYL!Av=J`+q!r(8?G{*+ z4{9U+Ge%~0*@kO8rE-igL-$y*`H+U`qSE0m%B|D5Z1ANpa#YxRVRj1lJrT~dfT{%) z@J9#rz#|6k%ZNzhXS+vojR(O#f<}}Fj?{U|AExj7t%HHGQeMmoA?mEt@J3FrNW2!c zX`|sMYoKQpq88{t2VenE6cZ067P-%sRSIizj_Nj6y=yxi$9;eBCmxtfhDT67O5_Gq z9U9>ma*7s>r{mNDE8DZs53YZV%XCcL=SH*e&aKzpT2aP8|Ai$7&6LSiu6CV)i_usc zcsW0^1;7Jf(?Z^rMT{~d@QmD_NBl3iw(@X~a(g!AKl@1`1OV`XTFS0~@>yU~YxiZ@ z;de70CWAUdAO@_P_V4}08Ze;$m0K&)pLQkF$7kQY%9dnv0;b+mK!oOr4iD7udMM&4 z0oew$+53yo6bTG~EXK;!rB_cR#kM6^zZvM@CNKLB3Tii#kbto@6OaG^N&`&p)h?n_ z(6V0({w@`zbZea|m9B?z>gqPQNOP+IFuX1BVe-q6R0?57tZ;^4Rgk{>Qw;rKCbAij zrrc4p+|m0T1kLIBR6#q|)XM;|i6j6x4YyIXIN84v2iU6z2nixOoseDTU(thfXQbEF z5T!-=km1v)VFDQNqdYJ0#K%d%1_4^Op+y1Fi8Qv^2~u;iakaSE`lS&B*4E zqJl{_kZWn$M}UU>`}En?2Rk2S3PLk@{Si+{e-r|26py$I$PXBoh=aT12G2O1h$poI z#JH(PA+IQ8{^||b4WQWgsfNTsnk(dV%lBX1UyOk&tlVX9fBJnrKR;Ka@0I+9t`mRN z)nt$IKbBPtqSzO(OUg!f0Hc5x(AY)2X>EJg+V%rZ0LEQvApucRcmOtlR=S6On1!y5 zB>bA*26JH+0dI{qj?Hfrl>n6o|Gs{>@#1H1Isn7Z1XIL;ab0=y4LV9)=d<|{e+`*3 z7?~1K5D9qdFah^Wa<@FdhUNhr@U(w;AXA0|hyD~#B<{_vir6>LS-w2-EC4&Sxycg_ z@@cS8b}IAXn<1$$|5Ez7x{)hJZT&$${zofQ7J?#zKk%3z5wa9IaE~PuAdyV15XxQn zUmiI{CGUQ%apT2}sl6CWW`h=g$~+^e`EOj< zA9w{Ag0RU#$>?wYekDL^fAvqH^&eX(#_5e_ILI>F>2i(EE2=chK%EZ?!ULeGQ{4>% zn=`-HW^3pP{VAT($I@#bm7KeQ>O>6<_G!mgz8KZ98v-wX!2ej~f8<3*ya!mo>D2)& zWd0s}^x%c~iC_B1)8sUwlT01LYU8>6MhQ>3TmLfs?>QN{?fgde>wV5fOnU&*sG zM4byBbcN@stN-0Auu+O=P=7@emO%~Zq4uf6$>m&7Z?8-`(e>oj?b@Pg`;F)HzX-o4 zPso8!%*_eSLH246%n7||M!(_l$1T+br#|`fILC3081@zZLCB976$C`7Me~dRD*rEW z7drqQmj^y$osqyO*JUS}t4;uB3i5K^oqc8ixf~eNJGP(p5(rERe0voR3qL2A&V-xh zb>>`BgC{X+|109Fz_3YRzAIKPdM>np{C_kk1deqy>Bk?)+#NqziBp-o?XRRKqOr8aeX8HOuTT@nC0T9imRekGHw6O)=zk588Ga4c&T->j zhWiNv{-)8VcC#rq-lO%==g?*~e=R$nQLu|7Ap8B$82ij7KInqfz=H8{sp)a)`+u+~ zvn~N5{|gGTs~Wba%Ibbc8c@@*V+%xa2e1#LMGnVT0V8sNu40Yp4GAvK6R!W?8TqeM z{CzUc1}!bzQoeUu;r&v6F!y2T9YPNaL=0DJYCX!tW~#y2|2?Os*5Np?Xw&IA;UYD) zPAw)Sr6Ri05Z9;jO@R28@6 zZ0$6khTjrtta>11x{FDE`AzfS(CEB8L&L%6%Dk&j?RJ{ZZ(e$E!5UZs0HD?HN;s&# zzZ2Lnf0E{Ju(XK&M-z|$`n&VJV752@NJF}EKBZuylgPH*bm$`fG(c;nO-G^$X4Uyh zh-|tm^!^oa@`aqGnikkQqH`+Qk&j0LS}ISTOrNnwdjrMlz5O;_Io4^yK+pojAr!E^ z=4En%7T}yGReV5Msnk}>v9NKT;Y|+dWkF1T`tYf`0oZzjc#4sSzr@KeBo+# zCvx6uRWs)q?VwpBhh`4NhO1@}>I;$|TO~cRavSk0`SAl z_c?-n6vg}np_jSIYS>W=uTf=e$;)GowDFLBs$4S8@6<=sowK94Up5|nWvA&JCT8`orE{3%IP=EM>jtJz2p4VDS)OT1eqv&~;|q2x<-##2%v7f7~j) zr||xGrb>xX@e%}>H>gaW=}w6}8FHc6Xr3~!}>`Um6VT|Vqv zYBWbVcX)7)n4;7%1>>ho3NZsO7YT}_C=h}D2=M83(Q9_uYhamwP8YCSJ!~sQE^QP% zfK8efM=c75FDl4*rHx=hAZ69Lwm4zR+Mm0?W8m+7Rl2FdkIMiCNG%H%{kjD`TN5 z*ip6yz>7OSy{b6?OHl8N>66~18bokI2Is>k@Z0rYSJB#FB7WwwVW5# z=n}gtVArnBCMo?vWZ`v6YEQwZyTqEq{jM0STJ5;PYEhQs^^MC5GgAv~o2o0XpQ*^G z{+a}2uj*B%_QF{%ywzV|qOqy~T5bhpZ!kHJRdC?!l^BpE#sB4M^sZQu#4*59!AfYV z>>p8bZ%_M_EiQmcG}j4d!LG+;r99AR-o2PvN`m-TE&w)1Bg%kQg>&sIvI8@>Sf0|5 z0E7T!2Y_JGzX60mS~)E+pi|`b5ugQ8{F{&Hkkfd&F~C6ELFKF4YoSFHIaOH!5dw&a zCIu|x%R&77D77;(PgP_5`89lCaB(G=W>zVlne$6h&!f^z3S6BHT31e zS-L{$El`^+pjZ%hY?8%66~pKDTSb3kinBF<(~5Ep&R3l|LFYzC0!#p4534A1V&}E< zG9-9w1Ta7g-`_RT12jEuz_z_L2UX~ApLV01K~*p1m9{s&sNuL5Lv48X#+P@o){6iJ z5E(_vzW6FZgl?ssvYWr)&i@mT;;aS)uwj*3Ws8|&iJ4-an&6_du>daMPQ#OJ;6gfg zU?r5;mTS#V@w#8920s3tRQ;h0 zPAL7MWskG52j1Jfbu1y98^D=b&?EnOuL-#N@;rwMFZ9toX z<|Ow3L(o78|2mP#k6r{q6ksWU`N(MP{yBku*9Z)x%#7^tLKpfr3pHH_xBn*w39*P* ze4>I@1T}8(M|GqF60aHCbV%m`p%gv0<{Zlo03?7=C|1oskmC9O&VT*}wQ&(ZWW4}) z*HNG3Wmiw0!a;H$01i0(Dji_(7x~rZOvCaC(3HZ&A2F-_PRqS&%*z1@X|*P@0aE<+ z?A^zKEe#;R{Kq=T9q04}D4v;;@+a9qQd!0Tx3|U>3g>Hl6C1;Ye>wkWLvq`v$n43J znTw{!%5vK)K3D_C|GWjHMmvHbUVm;Y0ah)$XDWF2#jRFr;GaM;k~%)T7z%`dg7K1C zKd*l>sN_FXWcT#6oC8}5-uI>}L_MJd)V^1g;75bCPZ+1XKVr~eG00#rf)c!R@WCIxl`m0kYpc1^9|pJk^18TJf>6WKi@0pNhtXb4XPWCk2m zqYV=OeOQdM@uaN|QHW9Q@QweWy4t?Q4`>GPM(N2C<08I)3oobsx9}3`c2XZ0eHl#| zeW|L|N#r=!^_4W?&E@he2pgiwegsgG?b`G=eUqs!*j6Vm z7RhJAEpj7B72miSZj|E->{_EX%<>ziz}&sc4>(w_DdvXkbf^?^!8Ns+!xJK$=HoeB zd##Lsp9V}uYFPzBqJI4f=26}y=;tR^(OOK$@g(yhsV?tH7K@C@ za!On4=G0^wl}n+Pe5#63L@Tc?X(8cd`c9o*V^o>zlT@~@Dlx-z2Kc%Rn2m*tZx7$? zqd+Tu-gOL=hAK-{7&G$G-~$+$fWK|1Q=mBLW+SuW9G{~UG%b{-7{<$qX7OFV@BEhL zO+@IV+V#LN%{NzQqjQBTl$Seld9S;uHE^UAVigQTQ|QT-%XzAd8L*Sjr6p!6lP03U z7_D zQ-9RLWr6UB3dF{XL+gai_#Y<2`o;yJoH8O#Wh_0lortS4xXyJ0{;SI1 z#}zfNLtoDnalVj9tSSpg*%arG{pkz11(?__)SApuQqkg7qm-njc>(;XPt7N+@%~& zx60X=mS<9VKg!lbJRT}&aze@kY&(7b*fjAp;KNUQ@|oT=NC5bu`O9Y}V96b>AQ&F1l3VZEsm@=W4s| zv&#zV^sCM-Ix?A4%+FH2J`&g++SW)vV^k!cU_ua8*Vi#rjPir_KlW+)PU&2u(!M2> zqf}je=60TZe~#?C)3VFQU)a9{n~LM4U!up!de7vdl3JuxgCiK){nI!K<8yDcLAZ88 zUdqwP*w3e+amL0p*RDF<0)f~2-iJ+iASRhb=+xyl!~(#!q%91GF5M1JOp$*#WJm+` zyf#wWA56Uw{KRLjG}hLA>;c#37w1QNcp8r{xRR|LlV7sn*-Db{tlRf8UtGf7QgpGx z700m9dxE(gh6|k@`aS2YU!+F6b%{STYixhQ$N`MkktlObIR7y2Do&ywR>YxmXYB%y zXm2!QDgK<sikK~ylxSD?7aUKKwGh{K7VwqYpVnL)lMJvM(ivS$!mRu+jTT&znpoiGno4Ps#-`YPvl!NH z?N08PU8WSjMKSDr77K5>cX;g8(SdJl)Y=d}=3HlKueBUok$0l~YWEnr6ZxcgPouv( z!DO;}1~By}M8)D<6`$|ddg~x$Sgl{ZQ+!Rn#1`r-E~a%dZV+21#MlLo8FBXSqczmc zk4e}FD8DGWZoF7j!&-vXY3ES7q`0ZiQMOjDQq);|;@dWz=vi^?$hJm*QNq3Q_;Wy4kCWr&Ckw2RUzXNQJiw`ME!a|nE-#34 zgX2*g1W?7LYHB7VKTQHo!g8(9gAp+X$g!~OufFWv`iAbPoAuNE6OP)OU7bgj>OkKRX@&ZAf=Mmnud zK5>pCQTv^Vrd959Jkd7So)!po9j*cYvfRAQgLNFAZp(97PI-5gIH;jK}PIG)`TDh4eWZ-m43HKa(mD6iPyI=4# zsXM6LF%ZVvD_XPDP1gh5e<4-o!Dg}xlV~#|U+c4i?>9Fy9a7K+ObO+igZicX`P~d%njZ;{C;q0z&Nv%dqW3~V8bA3hvxkSKCJabGJ zBhf8#7GB`Qnow!;E{rejdl%*#)0VDuAfb+Dh%c?-9Aas+1Nrq2qKJNHP8NI~ea^s5 zGKqF#x$s2__ey|GJJdBxfYT|sZNibiyXi#h%$J%Uf|Xjw!=i%kPhJk{(FDdJKir>$ zuHLAicWwK-uBuC8pCl9lUAdKQ-v<)J&zE=-5%Jfv=p#S9y&QiJ8 zf>t<`i`XaLNQ@IX&^K5w@{Lxcq88L%D=d`g|3x`8RGIc7qhrGo9XkP{K;W4XfNBO& zUEmj8z5!VqcNM}z)QMDg*iCpdVmv_tJlFj_8~u;QEfdi&dnZ;QQ9n((7WYoFPCWpSNtpSwAZyFCvvb#R&j}#xT5kq zcR>-fSnIAGx=X6&mgK_(yj!%32#m|k-2O0r^g!U|n4_>NRO&GCCh4}9Dox-VjhPlb z?JA8%4sGAg?NlthCIo(K5Em94VUG<9=SWDz1?jFL+;V8=pCil&5$lX#wPn6pMhFI% zB2055x0gFFgmwR`&jBncz(NtKoit@dqezT+gQmWJDtX$C`k58=bxd4H#U0HGTvGxf zi^h9x)g_WYNCmAVMNF_~OFV8$mmtIgv#dpPscm-LsIK9u6VZ+dkj6WZ@7G0cgqZ7G z2>q;|w26;M9jDhF(O=R}Gb5%>mPhJ0;@;tDkTl3G)dW(nH{FW-0Um`zTgEpeEN7+| z$(^iW0x^)${PnJQjZnO;sC(0Q>DwzzI*Ye!b5ns{e4B%rZ?vd%)RJ6@8T7r_h6J2Y zv-eg=@bvd&f{03|K2@gHwHgdH3YQMzS7ry@s00gNb%GMReXyK4dAY7KD}J&{*gGpp zA%|I~MMF8SW$F0aT-tMraEop1#e%Z$)%PZgAKi!)ri~vAP`*d2B68PlGChKreb4|F z-f{Fh%KOscSMJ0&)$LF=d0SnSHtWXy0R9{JQZ=GD?dhhgNk?g-oC#_)Dg4d%OuE&o zh4Nm2keh?oe^@=VoJa{Gq^IN>JrJjh>9HtmX1Ad+o*E0Mx-O#2N&5tzt8*EfIw;nv zi>M>>BPCoT&a2)rSb-@LQ9eCb{zF zTGGT3lf@5^nWVVX+(K}S`YhV-U6Xdo2#0da>BrfL}$$_PU?C0}t5-E79D=Fw~%-M&Q%AYyzaG1;9lM)D;oAB9-B zFn)ODR45orTx7p(iATKUj+>Ks>XtoJdiA74~4Siyhhk;PPng<+ULOJvg2qh)=#VtG<#GyDzVvGDgonjsK3UQgqin7c^1 zUW1o-Z)IJ#xzzO_E@!1%*WgfrYaI8ZQn9e|CKPQ`!DZ{Pv6Z5&se)&uq`L?jpz>Kg z$0>sZsaL$P69~RaQ%%cEWR+)RX1X2trUZKD#Kc>@bFN-kbi}=z)LF;*3vcC9E?TUG zRdD`@-4K72T3N+okd%imcqXQQZLmV@CW44TT*HfZA3eR=B#KTD9N?;ikprKpZung2 zE?FQFk&?#kLd-7w*D^6lW{IWuaIy~xkxfZS$_Yv3hjmNXBu*n}>diDmy{BG!m!3OO z7od@KaedHX0+2)2}YmRvf$|y03=RxIu zSW<;5LtL`I=Xl1Q!OI2)m&~xx4JhWf!d`twDWGjPlU7%#UO)_a}s^YUpM=Ig@D-W31 zAc&Db|4_8x$qtREl%rf_;lc_?&7D=9;L68XE=zzaO5L|%Rz*ymJWqI~7W+&{2$#wz z9)N;5s8mfmQJ?st(-70;ex6SHb(Mu&`=uuxoj=S4FwZ8Z)_Ktt9sdR^vk z#Qjk3?<l(d1bi6%7sh?l%e zyv!wD_oU6`E@M%cMu(RQ^V2UqA}4zTNd6M8NgA#1l6rgdgI{+N6KtgXOgUKW+rSn* z(MoSm^l_hJ(thD4RV^R}aq%R)D5_R9qV8kLuHvU^ty`yZ7@u z>XRi-$&4^fW^7$9of@FT*OJww0@o8v#18YyIUkF?uv%1Uq_@8 z0(>X>b%+xw`J*F~Yz1{gmeQpQn4o
vwi^PRpT0suR-3BT7IPaavJK_}6kbeGamX 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 z%0D9q@PLkhrjp1P`I{hRH$Bxe@vPNvgS=xzOKo7y?(^y$**sXDa_KF$X+s|vLlP8V zzzGMoeuDgY1mKS0iiz7iYPjKcr-3s};k|6Xr4tKw*)6N2bRfWMCyIe1msX8|=>XUu zsU&Vxm@o+3)Uh^KtBjySS6%ZX*TFqLjXEcf>Q;~Gf1JgY0A&BkYIktn8X%CfZsy*Q zC|>glT+5h#1xgU<-&H{U_lIM^5J>3?DvI`bioIb4$kZ>!j)>p~u!~y?BI6%&$;VOJ zAL=Ip#i11VQ&!J*D`}B|4CQc+^GJPFcH+DxXQc~@e>$_~4-=2h7gFW;L(YI?dlqU? zn08o809|c;BGD8T{+#Qt6}{0(HwA$O^oMK13thnwt>OcR!-8PEQ`c{p|~ zR%w-R5;`7h;U7xTHE<==k#nnVu%r6kg00$C=L3)xA9FdKm&}G^LMyem|L4YkR-n>D z(er=6ohnH+6B#WS1_xJKhEOpT3vGZ#^Pga?BDq6RFn4g{;Gr-9{XRbEE8lVpPu~k< z@h9>i8!I36w*z|0KjXBPNFbN6W**j{+35I35Lu4dhQ&8AJ!B9j|EeA*YA#Z^rbkPJw>{#DL}kFmY!Ayn2GF zx>*$YuI4_z{@5t?S#Z1=_}3N_C?%^rMr=uVaXA!43esQd)7SZ-wD{mb$HyTXopgZm z@SOPY_gydLcISvy2HEm&LPfy^pcB}L*e$#aC{(ov z*ko5XzfyakT`INXLCR;a=dzgfzLE5^ygTG$Zdb^Hc%6&P1@%={N-)X)H3O)M0ehsi zx7&Xi%Pc$|H6EJ&@HR;Mi^M)-D#{r;4-l)q9xW~uD}LJxdAvi)b@qVe_}7<0!o3I^ zm~Y#rlY!LGp(m+eibXq(*12fXL{}#xNFrbe_^`^Yxs!=JN@4%6A=}w^J^UK5zD+c& zFe;CqxlF~Qx9r!m7Kt@?VDDc%sYz^8#N9150>xOpH^(rm06tTLh@xsenHap3YcTX) zxWIkfgLj3~d26?O5M&Rke?&pRv-w^W9g{aNwN_nxJyt{p2x6ze8~tRGrmg>g`4QTn zvzxj52uLb(9WL1ys`d$Du^ZChtbIf47;r-pD(KX^<&I^nXzZr*UBD|_qF(W8v4E7n z6FtgEmGbK%^G=%jD@=~FG+6wXh)?@BqDo!a`!!b1-4Wt2AaT4cWMR1sly4iePgiBa zO2&kn3@9Ywjpcq-cXmru&#%P-=+Ak_zrRRS{2nq(4+6u!!+n(me=lyhE)Bj7hP1aJ zf!kB@2rH1G;Gby7I;{VUul4 z6TupS2Hc0hu(>9*y=A%TEf*A#+0}B*G#p=p4w=}nA~_-jmtg?mFM^BJz(**21_4(7 zmzK>1#MX(7D-#jx(-^MnkC+SxWT-OtZee0{ai@(3fi|htk^w%H`f!z7Y+(SB48z4_ zA^H_fynuTy)oR5UQN0TefAOeTiTQmCGrweO{yV%8Y1u7#5$fJN!Q=rzDT}35d~Xz( zYalSo_9^`NP^coTeyuBC59>{tfQ#2WG~UL{7iGX_@ZSUbJmWh=W!hpuj8Ye&DdRe; zM1`AFI)?2OoBnFGsDyZVl`G!6p+5j2tHGnF;Xr)T*RPr{*=n*4cV%?RyJ~3-L~Uda z(7^U%7eyc>h|Ecf@S4CA4CO-*W5?K+53&Ime*q7p4+Q$MX;M0ag<}ehw8JX50)Hmy zunlK(rmk_C;}!u7Fi0NKE9_>ZqH3Ea9x)cP2XZQ(ar-eGe7){px4gX3Vw^$21Xdf zsB)`GB~5fwQ}2n{+212KimcWmby~HyHzR!D+|WP;G%S!PcDf|BU%kCVwrg_NZ=;7H z6viGw8i0hS0=U2P8PVP0DzNb=TXmiHvhiYIaatlB?@+L}xa^JKKi=Lm{AeAlX3azB zif5S2K0Vkp1fJw3^v4M<<@l8FHVqy|rW54C)IfmHNaF3sox=rqf_xmb5~VKI8jdRx z%EiS(+lWALE>)|*Ko;Mk;dy0_LLUCS)o6*&Psxn5uYr4mfD}abp`HC*@wTLPw7) zF?z48j$ZS-k*c@+q0x&93Tl8v5v%D$0*&(|~8ZIVpOCeR=6(@m!tU2s^H^7hL7$5ZVj{Pf=;M>r&CmP?69H zMN@8MA);ausxfd~u}KA78@|(ISWo8w`^DQ4kohz_F4Qr?oGdJ_ZM+0kzTZQjuc&aX z<>THbc-J;oI~34cwDC;FdKN7-%4)mm{DkfN z!kE4D+O!RaiPpfyL-036h-^uh_y<<*#MRdWY~5J*Ihd59HFWW4TS_}4qI@6!Q2 zCwgzbB}`aG(s-`iQ)b*?@YRg%c+(7r&n(`!11F@i*0HH?EEeO=Ox}tqEF! z(3o2cN*M)}(M%QX5@8(QGp9<~$3vRO8S& z>_35NYH(-dLFNAjwFfc>;rZq=zK#qn3P32^H~>;P;tzL#9^Qy5^zX=lr%KXfu%7W~ zU^%oTt%ehLJ_;3QU?%P=e&mI!c%-`ZRiM{Rn3R4jsxhm1`E2{E^=b_;2(kc} zyWu*H$upjxcs#P!$MMF**EVQKb+lg;3DweyR3P_kES`QN{4Z9+aeFib4kQB54mDV9 zZ?p(~I0j&)m~(oeo3{VNLpm0eBC>of$HoHOmW11`rlJt%X*Se-<~Pkkox`bIRpkuL NSg_jLO5tI8{{wE!EX@D_ diff --git a/sdk/tests/web-app/tailwind.config.ts b/sdk/tests/web-app/tailwind.config.ts deleted file mode 100644 index 4dcc94ff8..000000000 --- a/sdk/tests/web-app/tailwind.config.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { Config } from 'tailwindcss'; - -const config: Config = { - content: [ - './src/pages/**/*.{js,ts,jsx,tsx,mdx}', - './src/components/**/*.{js,ts,jsx,tsx,mdx}', - './src/app/**/*.{js,ts,jsx,tsx,mdx}', - ], - theme: { - extend: { - colors: { - background: 'var(--background)', - foreground: 'var(--foreground)', - }, - }, - }, - plugins: [], -}; -export default config; diff --git a/sdk/tests/web-app/tsconfig.json b/sdk/tests/web-app/tsconfig.json deleted file mode 100644 index 3309399f7..000000000 --- a/sdk/tests/web-app/tsconfig.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "preserve", - "incremental": true, - "plugins": [ - { - "name": "next" - } - ], - "paths": { - "@/*": ["./src/*"] - } - }, - "include": ["next-env.d.ts", "./src/**/*.ts", "./src/**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] -} diff --git a/yarn.lock b/yarn.lock index bde8831a6..c5ce9db42 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,20 +12,6 @@ __metadata: languageName: node linkType: hard -"@adraffy/ens-normalize@npm:^1.10.1": - version: 1.11.0 - resolution: "@adraffy/ens-normalize@npm:1.11.0" - checksum: 10c0/5111d0f1a273468cb5661ed3cf46ee58de8f32f84e2ebc2365652e66c1ead82649df94c736804e2b9cfa831d30ef24e1cc3575d970dbda583416d3a98d8870a6 - languageName: node - linkType: hard - -"@alloc/quick-lru@npm:^5.2.0": - version: 5.2.0 - resolution: "@alloc/quick-lru@npm:5.2.0" - checksum: 10c0/7b878c48b9d25277d0e1a9b8b2f2312a314af806b4129dc902f2bc29ab09b58236e53964689feec187b28c80d2203aff03829754773a707a8a5987f1b7682d92 - languageName: node - linkType: hard - "@ampproject/remapping@npm:^2.2.0": version: 2.3.0 resolution: "@ampproject/remapping@npm:2.3.0" @@ -197,7 +183,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.27.1": +"@babel/helper-module-imports@npm:^7.27.1": version: 7.27.1 resolution: "@babel/helper-module-imports@npm:7.27.1" dependencies: @@ -1070,13 +1056,6 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.26.0, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.7": - version: 7.27.3 - resolution: "@babel/runtime@npm:7.27.3" - checksum: 10c0/b860fe374a36fddbeeb238e52e59443abcacc046eebda1bf278bffbc67b5c8f713b939e09c126b086ca5f97cba1987ea17fd1737568bc50fedb1f6ef1cf46f69 - languageName: node - linkType: hard - "@babel/runtime@npm:^7.25.0": version: 7.26.9 resolution: "@babel/runtime@npm:7.26.9" @@ -1188,87 +1167,6 @@ __metadata: languageName: node linkType: hard -"@elysiajs/swagger@npm:^1.2.0": - version: 1.3.0 - resolution: "@elysiajs/swagger@npm:1.3.0" - dependencies: - "@scalar/themes": "npm:^0.9.52" - "@scalar/types": "npm:^0.0.12" - openapi-types: "npm:^12.1.3" - pathe: "npm:^1.1.2" - peerDependencies: - elysia: ">= 1.3.0" - checksum: 10c0/251b50d438175aadcaa19325ddfd30eb109cdc24fc7b9a4394d4da81dba02128248e30d8d1899e9fb4e023afcaf13a9edf1002285dfc540bd955f8cf9cf42733 - languageName: node - linkType: hard - -"@emnapi/core@npm:^1.4.3": - version: 1.4.3 - resolution: "@emnapi/core@npm:1.4.3" - dependencies: - "@emnapi/wasi-threads": "npm:1.0.2" - tslib: "npm:^2.4.0" - checksum: 10c0/e30101d16d37ef3283538a35cad60e22095aff2403fb9226a35330b932eb6740b81364d525537a94eb4fb51355e48ae9b10d779c0dd1cdcd55d71461fe4b45c7 - languageName: node - linkType: hard - -"@emnapi/runtime@npm:^1.4.3": - version: 1.4.3 - resolution: "@emnapi/runtime@npm:1.4.3" - dependencies: - tslib: "npm:^2.4.0" - checksum: 10c0/3b7ab72d21cb4e034f07df80165265f85f445ef3f581d1bc87b67e5239428baa00200b68a7d5e37a0425c3a78320b541b07f76c5530f6f6f95336a6294ebf30b - languageName: node - linkType: hard - -"@emnapi/wasi-threads@npm:1.0.2": - version: 1.0.2 - resolution: "@emnapi/wasi-threads@npm:1.0.2" - dependencies: - tslib: "npm:^2.4.0" - checksum: 10c0/f0621b1fc715221bd2d8332c0ca922617bcd77cdb3050eae50a124eb8923c54fa425d23982dc8f29d505c8798a62d1049bace8b0686098ff9dd82270e06d772e - languageName: node - linkType: hard - -"@emotion/babel-plugin@npm:^11.13.5": - version: 11.13.5 - resolution: "@emotion/babel-plugin@npm:11.13.5" - dependencies: - "@babel/helper-module-imports": "npm:^7.16.7" - "@babel/runtime": "npm:^7.18.3" - "@emotion/hash": "npm:^0.9.2" - "@emotion/memoize": "npm:^0.9.0" - "@emotion/serialize": "npm:^1.3.3" - babel-plugin-macros: "npm:^3.1.0" - convert-source-map: "npm:^1.5.0" - escape-string-regexp: "npm:^4.0.0" - find-root: "npm:^1.1.0" - source-map: "npm:^0.5.7" - stylis: "npm:4.2.0" - checksum: 10c0/8ccbfec7defd0e513cb8a1568fa179eac1e20c35fda18aed767f6c59ea7314363ebf2de3e9d2df66c8ad78928dc3dceeded84e6fa8059087cae5c280090aeeeb - languageName: node - linkType: hard - -"@emotion/cache@npm:^11.13.5, @emotion/cache@npm:^11.14.0": - version: 11.14.0 - resolution: "@emotion/cache@npm:11.14.0" - dependencies: - "@emotion/memoize": "npm:^0.9.0" - "@emotion/sheet": "npm:^1.4.0" - "@emotion/utils": "npm:^1.4.2" - "@emotion/weak-memoize": "npm:^0.4.0" - stylis: "npm:4.2.0" - checksum: 10c0/3fa3e7a431ab6f8a47c67132a00ac8358f428c1b6c8421d4b20de9df7c18e95eec04a5a6ff5a68908f98d3280044f247b4965ac63df8302d2c94dba718769724 - languageName: node - linkType: hard - -"@emotion/hash@npm:^0.9.2": - version: 0.9.2 - resolution: "@emotion/hash@npm:0.9.2" - checksum: 10c0/0dc254561a3cc0a06a10bbce7f6a997883fd240c8c1928b93713f803a2e9153a257a488537012efe89dbe1246f2abfe2add62cdb3471a13d67137fcb808e81c2 - languageName: node - linkType: hard - "@emotion/is-prop-valid@npm:^0.8.2": version: 0.8.8 resolution: "@emotion/is-prop-valid@npm:0.8.8" @@ -1278,15 +1176,6 @@ __metadata: languageName: node linkType: hard -"@emotion/is-prop-valid@npm:^1.3.0": - version: 1.3.1 - resolution: "@emotion/is-prop-valid@npm:1.3.1" - dependencies: - "@emotion/memoize": "npm:^0.9.0" - checksum: 10c0/123215540c816ff510737ec68dcc499c53ea4deb0bb6c2c27c03ed21046e2e69f6ad07a7a174d271c6cfcbcc9ea44e1763e0cf3875c92192f7689216174803cd - languageName: node - linkType: hard - "@emotion/memoize@npm:0.7.4": version: 0.7.4 resolution: "@emotion/memoize@npm:0.7.4" @@ -1294,104 +1183,6 @@ __metadata: languageName: node linkType: hard -"@emotion/memoize@npm:^0.9.0": - version: 0.9.0 - resolution: "@emotion/memoize@npm:0.9.0" - checksum: 10c0/13f474a9201c7f88b543e6ea42f55c04fb2fdc05e6c5a3108aced2f7e7aa7eda7794c56bba02985a46d8aaa914fcdde238727a98341a96e2aec750d372dadd15 - languageName: node - linkType: hard - -"@emotion/react@npm:^11.13.3": - version: 11.14.0 - resolution: "@emotion/react@npm:11.14.0" - dependencies: - "@babel/runtime": "npm:^7.18.3" - "@emotion/babel-plugin": "npm:^11.13.5" - "@emotion/cache": "npm:^11.14.0" - "@emotion/serialize": "npm:^1.3.3" - "@emotion/use-insertion-effect-with-fallbacks": "npm:^1.2.0" - "@emotion/utils": "npm:^1.4.2" - "@emotion/weak-memoize": "npm:^0.4.0" - hoist-non-react-statics: "npm:^3.3.1" - peerDependencies: - react: ">=16.8.0" - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/d0864f571a9f99ec643420ef31fde09e2006d3943a6aba079980e4d5f6e9f9fecbcc54b8f617fe003c00092ff9d5241179149ffff2810cb05cf72b4620cfc031 - languageName: node - linkType: hard - -"@emotion/serialize@npm:^1.3.3": - version: 1.3.3 - resolution: "@emotion/serialize@npm:1.3.3" - dependencies: - "@emotion/hash": "npm:^0.9.2" - "@emotion/memoize": "npm:^0.9.0" - "@emotion/unitless": "npm:^0.10.0" - "@emotion/utils": "npm:^1.4.2" - csstype: "npm:^3.0.2" - checksum: 10c0/b28cb7de59de382021de2b26c0c94ebbfb16967a1b969a56fdb6408465a8993df243bfbd66430badaa6800e1834724e84895f5a6a9d97d0d224de3d77852acb4 - languageName: node - linkType: hard - -"@emotion/sheet@npm:^1.4.0": - version: 1.4.0 - resolution: "@emotion/sheet@npm:1.4.0" - checksum: 10c0/3ca72d1650a07d2fbb7e382761b130b4a887dcd04e6574b2d51ce578791240150d7072a9bcb4161933abbcd1e38b243a6fb4464a7fe991d700c17aa66bb5acc7 - languageName: node - linkType: hard - -"@emotion/styled@npm:^11.13.0": - version: 11.14.0 - resolution: "@emotion/styled@npm:11.14.0" - dependencies: - "@babel/runtime": "npm:^7.18.3" - "@emotion/babel-plugin": "npm:^11.13.5" - "@emotion/is-prop-valid": "npm:^1.3.0" - "@emotion/serialize": "npm:^1.3.3" - "@emotion/use-insertion-effect-with-fallbacks": "npm:^1.2.0" - "@emotion/utils": "npm:^1.4.2" - peerDependencies: - "@emotion/react": ^11.0.0-rc.0 - react: ">=16.8.0" - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/20aa5c488e4edecf63659212fc5ba1ccff2d3a66593fc8461de7cd5fe9192a741db357ffcd270a455bd61898d7f37cd5c84b4fd2b7974dade712badf7860ca9c - languageName: node - linkType: hard - -"@emotion/unitless@npm:^0.10.0": - version: 0.10.0 - resolution: "@emotion/unitless@npm:0.10.0" - checksum: 10c0/150943192727b7650eb9a6851a98034ddb58a8b6958b37546080f794696141c3760966ac695ab9af97efe10178690987aee4791f9f0ad1ff76783cdca83c1d49 - languageName: node - linkType: hard - -"@emotion/use-insertion-effect-with-fallbacks@npm:^1.2.0": - version: 1.2.0 - resolution: "@emotion/use-insertion-effect-with-fallbacks@npm:1.2.0" - peerDependencies: - react: ">=16.8.0" - checksum: 10c0/074dbc92b96bdc09209871070076e3b0351b6b47efefa849a7d9c37ab142130767609ca1831da0055988974e3b895c1de7606e4c421fecaa27c3e56a2afd3b08 - languageName: node - linkType: hard - -"@emotion/utils@npm:^1.4.2": - version: 1.4.2 - resolution: "@emotion/utils@npm:1.4.2" - checksum: 10c0/7d0010bf60a2a8c1a033b6431469de4c80e47aeb8fd856a17c1d1f76bbc3a03161a34aeaa78803566e29681ca551e7bf9994b68e9c5f5c796159923e44f78d9a - languageName: node - linkType: hard - -"@emotion/weak-memoize@npm:^0.4.0": - version: 0.4.0 - resolution: "@emotion/weak-memoize@npm:0.4.0" - checksum: 10c0/64376af11f1266042d03b3305c30b7502e6084868e33327e944b539091a472f089db307af69240f7188f8bc6b319276fd7b141a36613f1160d73d12a60f6ca1a - languageName: node - linkType: hard - "@esbuild/aix-ppc64@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/aix-ppc64@npm:0.25.5" @@ -1578,7 +1369,7 @@ __metadata: languageName: node linkType: hard -"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.5.1, @eslint-community/regexpp@npm:^4.6.1": +"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.6.1": version: 4.12.1 resolution: "@eslint-community/regexpp@npm:4.12.1" checksum: 10c0/a03d98c246bcb9109aec2c08e4d10c8d010256538dcb3f56610191607214523d4fb1b00aa81df830b6dffb74c5fa0be03642513a289c567949d3e550ca11cdf6 @@ -2535,7 +2326,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/gen-mapping@npm:^0.3.2, @jridgewell/gen-mapping@npm:^0.3.5": +"@jridgewell/gen-mapping@npm:^0.3.5": version: 0.3.8 resolution: "@jridgewell/gen-mapping@npm:0.3.8" dependencies: @@ -2662,309 +2453,6 @@ __metadata: languageName: node linkType: hard -"@mui/core-downloads-tracker@npm:^6.4.11": - version: 6.4.11 - resolution: "@mui/core-downloads-tracker@npm:6.4.11" - checksum: 10c0/6875a06188119320083566bbe000369a838ea4badbae81fb36fcc750103f3c9ec15fac3407c1efd7f3596889f30732780c58842434d0d48f997219192f7fc3d1 - languageName: node - linkType: hard - -"@mui/material@npm:^6.0.2": - version: 6.4.11 - resolution: "@mui/material@npm:6.4.11" - dependencies: - "@babel/runtime": "npm:^7.26.0" - "@mui/core-downloads-tracker": "npm:^6.4.11" - "@mui/system": "npm:^6.4.11" - "@mui/types": "npm:~7.2.24" - "@mui/utils": "npm:^6.4.9" - "@popperjs/core": "npm:^2.11.8" - "@types/react-transition-group": "npm:^4.4.12" - clsx: "npm:^2.1.1" - csstype: "npm:^3.1.3" - prop-types: "npm:^15.8.1" - react-is: "npm:^19.0.0" - react-transition-group: "npm:^4.4.5" - peerDependencies: - "@emotion/react": ^11.5.0 - "@emotion/styled": ^11.3.0 - "@mui/material-pigment-css": ^6.4.11 - "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 - react: ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - "@emotion/react": - optional: true - "@emotion/styled": - optional: true - "@mui/material-pigment-css": - optional: true - "@types/react": - optional: true - checksum: 10c0/49640579e299ef650e6efe25ceb479fe2df8636ebebd00a9d1e7dd32d2cd3c81a99f093f4fb6de58a6463f2be4f5c93fb6331ded6085f0ebeea3a30629fe8ecb - languageName: node - linkType: hard - -"@mui/private-theming@npm:^6.4.9": - version: 6.4.9 - resolution: "@mui/private-theming@npm:6.4.9" - dependencies: - "@babel/runtime": "npm:^7.26.0" - "@mui/utils": "npm:^6.4.9" - prop-types: "npm:^15.8.1" - peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 - react: ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/3b198fad085b9ce5092cb2ad2aceee5f6a643f68f4fb1469d0748615490b8b9228179a6564be9c6784aa6f1f42a9afe61f1ad5ce0af56858e9bb58d36472e339 - languageName: node - linkType: hard - -"@mui/styled-engine@npm:^6.4.11": - version: 6.4.11 - resolution: "@mui/styled-engine@npm:6.4.11" - dependencies: - "@babel/runtime": "npm:^7.26.0" - "@emotion/cache": "npm:^11.13.5" - "@emotion/serialize": "npm:^1.3.3" - "@emotion/sheet": "npm:^1.4.0" - csstype: "npm:^3.1.3" - prop-types: "npm:^15.8.1" - peerDependencies: - "@emotion/react": ^11.4.1 - "@emotion/styled": ^11.3.0 - react: ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - "@emotion/react": - optional: true - "@emotion/styled": - optional: true - checksum: 10c0/332ff6c32e7bfb34e9cd8a3d8d4abb13deaeea3216fb6d1441d8d154c615a76d594595cc34076bc0911f7f4784042a7fe0a83bf1924e78040935fa7242ee5a70 - languageName: node - linkType: hard - -"@mui/system@npm:^6.4.11": - version: 6.4.11 - resolution: "@mui/system@npm:6.4.11" - dependencies: - "@babel/runtime": "npm:^7.26.0" - "@mui/private-theming": "npm:^6.4.9" - "@mui/styled-engine": "npm:^6.4.11" - "@mui/types": "npm:~7.2.24" - "@mui/utils": "npm:^6.4.9" - clsx: "npm:^2.1.1" - csstype: "npm:^3.1.3" - prop-types: "npm:^15.8.1" - peerDependencies: - "@emotion/react": ^11.5.0 - "@emotion/styled": ^11.3.0 - "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 - react: ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - "@emotion/react": - optional: true - "@emotion/styled": - optional: true - "@types/react": - optional: true - checksum: 10c0/6d1875232d8836c84b6f94bf32215f8b46370c98c4948a68ba934ef2baa652a5eb08e3048fa77ad16c464167a4d8d0548809d62d5f221829cfa744a5cdd90be5 - languageName: node - linkType: hard - -"@mui/types@npm:~7.2.24": - version: 7.2.24 - resolution: "@mui/types@npm:7.2.24" - peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/7756339cae70e9b684c4311924e4e3882f908552b69c434b4d13faf2f5908ce72fe889a31890257c5ad42a085207be7c1661981dfc683293e90ac6dfac3759d0 - languageName: node - linkType: hard - -"@mui/utils@npm:^6.4.9": - version: 6.4.9 - resolution: "@mui/utils@npm:6.4.9" - dependencies: - "@babel/runtime": "npm:^7.26.0" - "@mui/types": "npm:~7.2.24" - "@types/prop-types": "npm:^15.7.14" - clsx: "npm:^2.1.1" - prop-types: "npm:^15.8.1" - react-is: "npm:^19.0.0" - peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 - react: ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/27122262bc24d31e8906e3133f3f6e6c858733802019e0e9ec6dedf632ca46287ab3735c9da6be7a7e0b4f043ced9b8f36b5b21bfef1d96ecfa5d150ea458508 - languageName: node - linkType: hard - -"@napi-rs/wasm-runtime@npm:^0.2.10": - version: 0.2.10 - resolution: "@napi-rs/wasm-runtime@npm:0.2.10" - dependencies: - "@emnapi/core": "npm:^1.4.3" - "@emnapi/runtime": "npm:^1.4.3" - "@tybys/wasm-util": "npm:^0.9.0" - checksum: 10c0/4dce9bbb94a8969805574e1b55fdbeb7623348190265d77f6507ba32e535610deeb53a33ba0bb8b05a6520f379d418b92e8a01c5cd7b9486b136d2c0c26be0bd - languageName: node - linkType: hard - -"@next/env@npm:14.2.29": - version: 14.2.29 - resolution: "@next/env@npm:14.2.29" - checksum: 10c0/f4579139610a3a6eab5dfc92a982ed3530350e2b7d29993ca4b76aee3f23e9c4244fcee9f24e85bc7840e84a375fbfa819deced9f0c2aeb3bdd86b5d57abd23e - languageName: node - linkType: hard - -"@next/env@npm:14.2.8": - version: 14.2.8 - resolution: "@next/env@npm:14.2.8" - checksum: 10c0/8fd09c932ff472c9fd6c58c532f85972b7b0c72ef40bd937034ae34f3ff2692d6c829ef31b30eda761d467b1cd2c7ab7ad31aed829547546483e8beaf6d753f9 - languageName: node - linkType: hard - -"@next/eslint-plugin-next@npm:14.2.8": - version: 14.2.8 - resolution: "@next/eslint-plugin-next@npm:14.2.8" - dependencies: - glob: "npm:10.3.10" - checksum: 10c0/577b336feae3cd915af5befd6fd0e733e396b98dcdce792e406a7ebf020cc4a206e44f16d8cfb21416000086951c1f0eef37a6492551eae64c3e756c81356c95 - languageName: node - linkType: hard - -"@next/swc-darwin-arm64@npm:14.2.29": - version: 14.2.29 - resolution: "@next/swc-darwin-arm64@npm:14.2.29" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@next/swc-darwin-arm64@npm:14.2.8": - version: 14.2.8 - resolution: "@next/swc-darwin-arm64@npm:14.2.8" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@next/swc-darwin-x64@npm:14.2.29": - version: 14.2.29 - resolution: "@next/swc-darwin-x64@npm:14.2.29" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@next/swc-darwin-x64@npm:14.2.8": - version: 14.2.8 - resolution: "@next/swc-darwin-x64@npm:14.2.8" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@next/swc-linux-arm64-gnu@npm:14.2.29": - version: 14.2.29 - resolution: "@next/swc-linux-arm64-gnu@npm:14.2.29" - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - -"@next/swc-linux-arm64-gnu@npm:14.2.8": - version: 14.2.8 - resolution: "@next/swc-linux-arm64-gnu@npm:14.2.8" - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - -"@next/swc-linux-arm64-musl@npm:14.2.29": - version: 14.2.29 - resolution: "@next/swc-linux-arm64-musl@npm:14.2.29" - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - -"@next/swc-linux-arm64-musl@npm:14.2.8": - version: 14.2.8 - resolution: "@next/swc-linux-arm64-musl@npm:14.2.8" - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - -"@next/swc-linux-x64-gnu@npm:14.2.29": - version: 14.2.29 - resolution: "@next/swc-linux-x64-gnu@npm:14.2.29" - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - -"@next/swc-linux-x64-gnu@npm:14.2.8": - version: 14.2.8 - resolution: "@next/swc-linux-x64-gnu@npm:14.2.8" - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - -"@next/swc-linux-x64-musl@npm:14.2.29": - version: 14.2.29 - resolution: "@next/swc-linux-x64-musl@npm:14.2.29" - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - -"@next/swc-linux-x64-musl@npm:14.2.8": - version: 14.2.8 - resolution: "@next/swc-linux-x64-musl@npm:14.2.8" - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - -"@next/swc-win32-arm64-msvc@npm:14.2.29": - version: 14.2.29 - resolution: "@next/swc-win32-arm64-msvc@npm:14.2.29" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - -"@next/swc-win32-arm64-msvc@npm:14.2.8": - version: 14.2.8 - resolution: "@next/swc-win32-arm64-msvc@npm:14.2.8" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - -"@next/swc-win32-ia32-msvc@npm:14.2.29": - version: 14.2.29 - resolution: "@next/swc-win32-ia32-msvc@npm:14.2.29" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - -"@next/swc-win32-ia32-msvc@npm:14.2.8": - version: 14.2.8 - resolution: "@next/swc-win32-ia32-msvc@npm:14.2.8" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - -"@next/swc-win32-x64-msvc@npm:14.2.29": - version: 14.2.29 - resolution: "@next/swc-win32-x64-msvc@npm:14.2.29" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"@next/swc-win32-x64-msvc@npm:14.2.8": - version: 14.2.8 - resolution: "@next/swc-win32-x64-msvc@npm:14.2.8" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - "@nicolo-ribaudo/eslint-scope-5-internals@npm:5.1.1-v1": version: 5.1.1-v1 resolution: "@nicolo-ribaudo/eslint-scope-5-internals@npm:5.1.1-v1" @@ -2974,13 +2462,6 @@ __metadata: languageName: node linkType: hard -"@noble/ciphers@npm:^1.3.0": - version: 1.3.0 - resolution: "@noble/ciphers@npm:1.3.0" - checksum: 10c0/3ba6da645ce45e2f35e3b2e5c87ceba86b21dfa62b9466ede9edfb397f8116dae284f06652c0cd81d99445a2262b606632e868103d54ecc99fd946ae1af8cd37 - languageName: node - linkType: hard - "@noble/curves@npm:1.2.0": version: 1.2.0 resolution: "@noble/curves@npm:1.2.0" @@ -2999,7 +2480,7 @@ __metadata: languageName: node linkType: hard -"@noble/curves@npm:1.9.1, @noble/curves@npm:^1.4.2, @noble/curves@npm:^1.6.0, @noble/curves@npm:~1.9.0": +"@noble/curves@npm:^1.4.2": version: 1.9.1 resolution: "@noble/curves@npm:1.9.1" dependencies: @@ -3045,7 +2526,7 @@ __metadata: languageName: node linkType: hard -"@noble/hashes@npm:1.8.0, @noble/hashes@npm:^1.1.5, @noble/hashes@npm:^1.4.0, @noble/hashes@npm:^1.5.0, @noble/hashes@npm:~1.8.0": +"@noble/hashes@npm:1.8.0, @noble/hashes@npm:^1.4.0": version: 1.8.0 resolution: "@noble/hashes@npm:1.8.0" checksum: 10c0/06a0b52c81a6fa7f04d67762e08b2c476a00285858150caeaaff4037356dd5e119f45b2a530f638b77a5eeca013168ec1b655db41bae3236cb2e9d511484fc77 @@ -3093,13 +2574,6 @@ __metadata: languageName: node linkType: hard -"@nolyfill/is-core-module@npm:1.0.39": - version: 1.0.39 - resolution: "@nolyfill/is-core-module@npm:1.0.39" - checksum: 10c0/34ab85fdc2e0250879518841f74a30c276bca4f6c3e13526d2d1fe515e1adf6d46c25fcd5989d22ea056d76f7c39210945180b4859fc83b050e2da411aa86289 - languageName: node - linkType: hard - "@nomicfoundation/edr-darwin-arm64@npm:0.11.0": version: 0.11.0 resolution: "@nomicfoundation/edr-darwin-arm64@npm:0.11.0" @@ -3502,15 +2976,6 @@ __metadata: languageName: node linkType: hard -"@paralleldrive/cuid2@npm:^2.2.2": - version: 2.2.2 - resolution: "@paralleldrive/cuid2@npm:2.2.2" - dependencies: - "@noble/hashes": "npm:^1.1.5" - checksum: 10c0/af5826df93de437121308f4f4ce0b2eeb89b60bb57a1a6592fb89c0d40d311ad1d9f3f6a4db2cce6f2bcf572de1aa3f85704254e89b18ce61c41ebb06564c4ee - languageName: node - linkType: hard - "@peculiar/asn1-cms@npm:^2.3.13, @peculiar/asn1-cms@npm:^2.3.15": version: 2.3.15 resolution: "@peculiar/asn1-cms@npm:2.3.15" @@ -3670,13 +3135,6 @@ __metadata: languageName: node linkType: hard -"@popperjs/core@npm:^2.11.8": - version: 2.11.8 - resolution: "@popperjs/core@npm:2.11.8" - checksum: 10c0/4681e682abc006d25eb380d0cf3efc7557043f53b6aea7a5057d0d1e7df849a00e281cd8ea79c902a35a414d7919621fc2ba293ecec05f413598e0b23d5a1e63 - languageName: node - linkType: hard - "@puppeteer/browsers@npm:2.2.2": version: 2.2.2 resolution: "@puppeteer/browsers@npm:2.2.2" @@ -4547,68 +4005,6 @@ __metadata: languageName: node linkType: hard -"@rtsao/scc@npm:^1.1.0": - version: 1.1.0 - resolution: "@rtsao/scc@npm:1.1.0" - checksum: 10c0/b5bcfb0d87f7d1c1c7c0f7693f53b07866ed9fec4c34a97a8c948fb9a7c0082e416ce4d3b60beb4f5e167cbe04cdeefbf6771320f3ede059b9ce91188c409a5b - languageName: node - linkType: hard - -"@rushstack/eslint-patch@npm:^1.3.3": - version: 1.11.0 - resolution: "@rushstack/eslint-patch@npm:1.11.0" - checksum: 10c0/abea8d8cf2f4f50343f74abd6a8173c521ddd09b102021f5aa379ef373c40af5948b23db0e87eca1682e559e09d97d3f0c48ea71edad682c6bf72b840c8675b3 - languageName: node - linkType: hard - -"@scalar/openapi-types@npm:0.1.1": - version: 0.1.1 - resolution: "@scalar/openapi-types@npm:0.1.1" - checksum: 10c0/ef7108a7621b936694a153875ab85bf720fbf8369d4125778653dfb88a41da3308cdf55167da39052c382035766eae95c89fc2ab50f7346b87309f6fb65bd5bf - languageName: node - linkType: hard - -"@scalar/openapi-types@npm:0.2.0": - version: 0.2.0 - resolution: "@scalar/openapi-types@npm:0.2.0" - dependencies: - zod: "npm:^3.23.8" - checksum: 10c0/d96c826c4d595a712fa1e27739e635fe2cfa680183b97aec6e93b0cbdcd1ecf7ebb057506b3769b8e07eb569e1d73e01e66567e12d42cabd900486577355174a - languageName: node - linkType: hard - -"@scalar/themes@npm:^0.9.52": - version: 0.9.86 - resolution: "@scalar/themes@npm:0.9.86" - dependencies: - "@scalar/types": "npm:0.1.7" - checksum: 10c0/e9293c72cc3966919152c61d4904844c7428a33d123d06c324e363d22a0b9aaeaacd760c4c0d03f96234bab47f133f2b49ff9951aa102e1587a5160457506d77 - languageName: node - linkType: hard - -"@scalar/types@npm:0.1.7": - version: 0.1.7 - resolution: "@scalar/types@npm:0.1.7" - dependencies: - "@scalar/openapi-types": "npm:0.2.0" - "@unhead/schema": "npm:^1.11.11" - nanoid: "npm:^5.1.5" - type-fest: "npm:^4.20.0" - zod: "npm:^3.23.8" - checksum: 10c0/6d3ed7e358f9062901b3789da546a40feb8cecaaed40580e0d9e672ef4909781015eb9b8f3f905faeae0f73836989e23a97a6361010b32f47809574806183b27 - languageName: node - linkType: hard - -"@scalar/types@npm:^0.0.12": - version: 0.0.12 - resolution: "@scalar/types@npm:0.0.12" - dependencies: - "@scalar/openapi-types": "npm:0.1.1" - "@unhead/schema": "npm:^1.9.5" - checksum: 10c0/5776818cc732b4784b2406c1e81ce9916de6149c0f3452907372a6fd97fdcc2e7982acf7aee2832e1a7e08c47d3fff3e965009d612194870929747a0c21b4b5c - languageName: node - linkType: hard - "@scure/base@npm:~1.1.0, @scure/base@npm:~1.1.6": version: 1.1.9 resolution: "@scure/base@npm:1.1.9" @@ -4645,17 +4041,6 @@ __metadata: languageName: node linkType: hard -"@scure/bip32@npm:1.7.0, @scure/bip32@npm:^1.5.0": - version: 1.7.0 - resolution: "@scure/bip32@npm:1.7.0" - dependencies: - "@noble/curves": "npm:~1.9.0" - "@noble/hashes": "npm:~1.8.0" - "@scure/base": "npm:~1.2.5" - checksum: 10c0/e3d4c1f207df16abcd79babcdb74d36f89bdafc90bf02218a5140cc5cba25821d80d42957c6705f35210cc5769714ea9501d4ae34732cdd1c26c9ff182a219f7 - languageName: node - linkType: hard - "@scure/bip39@npm:1.1.1": version: 1.1.1 resolution: "@scure/bip39@npm:1.1.1" @@ -4676,16 +4061,6 @@ __metadata: languageName: node linkType: hard -"@scure/bip39@npm:1.6.0, @scure/bip39@npm:^1.4.0": - version: 1.6.0 - resolution: "@scure/bip39@npm:1.6.0" - dependencies: - "@noble/hashes": "npm:~1.8.0" - "@scure/base": "npm:~1.2.5" - checksum: 10c0/73a54b5566a50a3f8348a5cfd74d2092efeefc485efbed83d7a7374ffd9a75defddf446e8e5ea0385e4adb49a94b8ae83c5bad3e16333af400e932f7da3aaff8 - languageName: node - linkType: hard - "@segment/analytics-react-native@npm:^2.21.0": version: 2.21.0 resolution: "@segment/analytics-react-native@npm:2.21.0" @@ -4884,23 +4259,6 @@ __metadata: languageName: unknown linkType: soft -"@selfxyz/core@npm:^0.0.3": - version: 0.0.3 - resolution: "@selfxyz/core@npm:0.0.3" - dependencies: - "@types/react": "npm:^18.3.4" - "@types/react-dom": "npm:^18.3.0" - "@types/uuid": "npm:^10.0.0" - ethers: "npm:^6.13.5" - next: "npm:^14.2.8" - snarkjs: "npm:^0.7.4" - peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 - checksum: 10c0/5d1e5b4a8627126f727dfad34078f747cbf08a629d74bc83a24dbceb13ca365e35d0ed82a09b1cafeba5e3c1cc0ea76c0a47d8afb4695b63c0941fb200902500 - languageName: node - linkType: hard - "@selfxyz/core@workspace:sdk/core": version: 0.0.0-use.local resolution: "@selfxyz/core@workspace:sdk/core" @@ -5033,7 +4391,7 @@ __metadata: languageName: unknown linkType: soft -"@selfxyz/qrcode@workspace:^, @selfxyz/qrcode@workspace:sdk/qrcode": +"@selfxyz/qrcode@workspace:sdk/qrcode": version: 0.0.0-use.local resolution: "@selfxyz/qrcode@workspace:sdk/qrcode" dependencies: @@ -5388,13 +4746,6 @@ __metadata: languageName: node linkType: hard -"@sinclair/typebox@npm:^0.34.33": - version: 0.34.33 - resolution: "@sinclair/typebox@npm:0.34.33" - checksum: 10c0/88ab4f7afc7514d576602dce5c892462a89f9082d77dde0e8e21342b3a5c8891ddfc51a65e7dbd5b3f5cbd8f5cb76aded0c0edcfcfb5730f189c2819de9583a7 - languageName: node - linkType: hard - "@sindresorhus/is@npm:^4.0.0": version: 4.6.0 resolution: "@sindresorhus/is@npm:4.6.0" @@ -6908,23 +6259,6 @@ __metadata: languageName: node linkType: hard -"@swc/counter@npm:^0.1.3": - version: 0.1.3 - resolution: "@swc/counter@npm:0.1.3" - checksum: 10c0/8424f60f6bf8694cfd2a9bca45845bce29f26105cda8cf19cdb9fd3e78dc6338699e4db77a89ae449260bafa1cc6bec307e81e7fb96dbf7dcfce0eea55151356 - languageName: node - linkType: hard - -"@swc/helpers@npm:0.5.5": - version: 0.5.5 - resolution: "@swc/helpers@npm:0.5.5" - dependencies: - "@swc/counter": "npm:^0.1.3" - tslib: "npm:^2.4.0" - checksum: 10c0/21a9b9cfe7e00865f9c9f3eb4c1cc5b397143464f7abee76a2c5366e591e06b0155b5aac93fe8269ef8d548df253f6fd931e9ddfc0fd12efd405f90f45506e7d - languageName: node - linkType: hard - "@szmarczak/http-timer@npm:^4.0.5": version: 4.0.6 resolution: "@szmarczak/http-timer@npm:4.0.6" @@ -8338,15 +7672,6 @@ __metadata: languageName: node linkType: hard -"@tybys/wasm-util@npm:^0.9.0": - version: 0.9.0 - resolution: "@tybys/wasm-util@npm:0.9.0" - dependencies: - tslib: "npm:^2.4.0" - checksum: 10c0/f9fde5c554455019f33af6c8215f1a1435028803dc2a2825b077d812bed4209a1a64444a4ca0ce2ea7e1175c8d88e2f9173a36a33c199e8a5c671aa31de8242d - languageName: node - linkType: hard - "@typechain/ethers-v6@npm:^0.4.3": version: 0.4.3 resolution: "@typechain/ethers-v6@npm:0.4.3" @@ -8628,7 +7953,7 @@ __metadata: languageName: node linkType: hard -"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.12, @types/json-schema@npm:^7.0.15, @types/json-schema@npm:^7.0.9": +"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.15, @types/json-schema@npm:^7.0.9": version: 7.0.15 resolution: "@types/json-schema@npm:7.0.15" checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db @@ -8642,7 +7967,7 @@ __metadata: languageName: node linkType: hard -"@types/keyv@npm:^3.1.1, @types/keyv@npm:^3.1.4": +"@types/keyv@npm:^3.1.4": version: 3.1.4 resolution: "@types/keyv@npm:3.1.4" dependencies: @@ -8715,7 +8040,7 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^20, @types/node@npm:^20.11.19": +"@types/node@npm:^20.11.19": version: 20.17.51 resolution: "@types/node@npm:20.17.51" dependencies: @@ -8738,13 +8063,6 @@ __metadata: languageName: node linkType: hard -"@types/parse-json@npm:^4.0.0": - version: 4.0.2 - resolution: "@types/parse-json@npm:4.0.2" - checksum: 10c0/b1b863ac34a2c2172fbe0807a1ec4d5cb684e48d422d15ec95980b81475fac4fdb3768a8b13eef39130203a7c04340fc167bae057c7ebcafd7dec9fe6c36aeb1 - languageName: node - linkType: hard - "@types/pbkdf2@npm:^3.0.0": version: 3.1.2 resolution: "@types/pbkdf2@npm:3.1.2" @@ -8754,17 +8072,6 @@ __metadata: languageName: node linkType: hard -"@types/pg@npm:^8.11.11": - version: 8.15.2 - resolution: "@types/pg@npm:8.15.2" - dependencies: - "@types/node": "npm:*" - pg-protocol: "npm:*" - pg-types: "npm:^4.0.1" - checksum: 10c0/e3bc75f02af897ed960e83d1af9bd0cba1ff41cd0cbae0eaee323eae84f55e6d433f620aa1c72f7bd5107c80b018185c0e47de553cfc5439514c3da98768ef6c - languageName: node - linkType: hard - "@types/prettier@npm:^2.1.1": version: 2.7.3 resolution: "@types/prettier@npm:2.7.3" @@ -8772,7 +8079,7 @@ __metadata: languageName: node linkType: hard -"@types/prop-types@npm:*, @types/prop-types@npm:^15.7.14": +"@types/prop-types@npm:*": version: 15.7.14 resolution: "@types/prop-types@npm:15.7.14" checksum: 10c0/1ec775160bfab90b67a782d735952158c7e702ca4502968aa82565bd8e452c2de8601c8dfe349733073c31179116cf7340710160d3836aa8a1ef76d1532893b1 @@ -8786,7 +8093,7 @@ __metadata: languageName: node linkType: hard -"@types/react-dom@npm:^18, @types/react-dom@npm:^18.3.0": +"@types/react-dom@npm:^18.3.0": version: 18.3.7 resolution: "@types/react-dom@npm:18.3.7" peerDependencies: @@ -8827,15 +8134,6 @@ __metadata: languageName: node linkType: hard -"@types/react-transition-group@npm:^4.4.12": - version: 4.4.12 - resolution: "@types/react-transition-group@npm:4.4.12" - peerDependencies: - "@types/react": "*" - checksum: 10c0/0441b8b47c69312c89ec0760ba477ba1a0808a10ceef8dc1c64b1013ed78517332c30f18681b0ec0b53542731f1ed015169fed1d127cc91222638ed955478ec7 - languageName: node - linkType: hard - "@types/react@npm:^18, @types/react@npm:^18.2.6, @types/react@npm:^18.3.4": version: 18.3.23 resolution: "@types/react@npm:18.3.23" @@ -8864,7 +8162,7 @@ __metadata: languageName: node linkType: hard -"@types/semver@npm:^7.1.0, @types/semver@npm:^7.3.12, @types/semver@npm:^7.5.0": +"@types/semver@npm:^7.1.0, @types/semver@npm:^7.3.12": version: 7.7.0 resolution: "@types/semver@npm:7.7.0" checksum: 10c0/6b5f65f647474338abbd6ee91a6bbab434662ddb8fe39464edcbcfc96484d388baad9eb506dff217b6fc1727a88894930eb1f308617161ac0f376fe06be4e1ee @@ -8933,31 +8231,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^5.4.2 || ^6.0.0 || 7.0.0 - 7.2.0": - version: 7.2.0 - resolution: "@typescript-eslint/eslint-plugin@npm:7.2.0" - dependencies: - "@eslint-community/regexpp": "npm:^4.5.1" - "@typescript-eslint/scope-manager": "npm:7.2.0" - "@typescript-eslint/type-utils": "npm:7.2.0" - "@typescript-eslint/utils": "npm:7.2.0" - "@typescript-eslint/visitor-keys": "npm:7.2.0" - debug: "npm:^4.3.4" - graphemer: "npm:^1.4.0" - ignore: "npm:^5.2.4" - natural-compare: "npm:^1.4.0" - semver: "npm:^7.5.4" - ts-api-utils: "npm:^1.0.1" - peerDependencies: - "@typescript-eslint/parser": ^7.0.0 - eslint: ^8.56.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/8725c2193a16cc103a697d6e408c515a7618df3902dc504cf69999f60634dac79ce14a5bd942f0388ba7547caba44ac40e01097cda1106aa3912e2303dada8ab - languageName: node - linkType: hard - "@typescript-eslint/eslint-plugin@npm:^7.1.1": version: 7.18.0 resolution: "@typescript-eslint/eslint-plugin@npm:7.18.0" @@ -8981,24 +8254,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/parser@npm:^5.4.2 || ^6.0.0 || 7.0.0 - 7.2.0": - version: 7.2.0 - resolution: "@typescript-eslint/parser@npm:7.2.0" - dependencies: - "@typescript-eslint/scope-manager": "npm:7.2.0" - "@typescript-eslint/types": "npm:7.2.0" - "@typescript-eslint/typescript-estree": "npm:7.2.0" - "@typescript-eslint/visitor-keys": "npm:7.2.0" - debug: "npm:^4.3.4" - peerDependencies: - eslint: ^8.56.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/11ce36c68212fdbf98fc6fd32ba0977d46b645fd669a3f4fdb8be2036225f86ad005b31a66f97097e90517c44c92cf9cc5fb1d6e9647ee2fa125c4af21cdb477 - languageName: node - linkType: hard - "@typescript-eslint/parser@npm:^7.1.1": version: 7.18.0 resolution: "@typescript-eslint/parser@npm:7.18.0" @@ -9048,16 +8303,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:7.2.0": - version: 7.2.0 - resolution: "@typescript-eslint/scope-manager@npm:7.2.0" - dependencies: - "@typescript-eslint/types": "npm:7.2.0" - "@typescript-eslint/visitor-keys": "npm:7.2.0" - checksum: 10c0/4d088c127e6ba1a7de8567f70684779083be24b48746c3b4a86a0ec7062bca58693ee08482349ad6572a17ada8aa6f26b74d1c7139c8fcf7101fa09a572e0ea6 - languageName: node - linkType: hard - "@typescript-eslint/scope-manager@npm:8.33.0": version: 8.33.0 resolution: "@typescript-eslint/scope-manager@npm:8.33.0" @@ -9094,23 +8339,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:7.2.0": - version: 7.2.0 - resolution: "@typescript-eslint/type-utils@npm:7.2.0" - dependencies: - "@typescript-eslint/typescript-estree": "npm:7.2.0" - "@typescript-eslint/utils": "npm:7.2.0" - debug: "npm:^4.3.4" - ts-api-utils: "npm:^1.0.1" - peerDependencies: - eslint: ^8.56.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/069b65ef327e1bfa1e59009504c8307f88f3673ebcc23d17ad370452ece107013c9dc321876092673d2c02ddd35104f67231b31b0e4f7d5ca6fbf95b43f828b2 - languageName: node - linkType: hard - "@typescript-eslint/types@npm:5.62.0": version: 5.62.0 resolution: "@typescript-eslint/types@npm:5.62.0" @@ -9125,13 +8353,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:7.2.0": - version: 7.2.0 - resolution: "@typescript-eslint/types@npm:7.2.0" - checksum: 10c0/135aae061720185855bea61ea6cfd33f4801d2de57f65e50079bbdb505100f844632aa4e4bdeec9e9e79d29aaddad949178d0e918e41867da6ab4b1390820e33 - languageName: node - linkType: hard - "@typescript-eslint/types@npm:8.33.0, @typescript-eslint/types@npm:^8.33.0": version: 8.33.0 resolution: "@typescript-eslint/types@npm:8.33.0" @@ -9176,25 +8397,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:7.2.0": - version: 7.2.0 - resolution: "@typescript-eslint/typescript-estree@npm:7.2.0" - dependencies: - "@typescript-eslint/types": "npm:7.2.0" - "@typescript-eslint/visitor-keys": "npm:7.2.0" - debug: "npm:^4.3.4" - globby: "npm:^11.1.0" - is-glob: "npm:^4.0.3" - minimatch: "npm:9.0.3" - semver: "npm:^7.5.4" - ts-api-utils: "npm:^1.0.1" - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/2730bb17730e6f3ca4061f00688a70386a808f5d174fdeb757c3cfa92c455373f69080df33237c1a8970e818af0cea0ae5a083970ed8ba493f3b04458c6f9271 - languageName: node - linkType: hard - "@typescript-eslint/typescript-estree@npm:8.33.0": version: 8.33.0 resolution: "@typescript-eslint/typescript-estree@npm:8.33.0" @@ -9229,23 +8431,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:7.2.0": - version: 7.2.0 - resolution: "@typescript-eslint/utils@npm:7.2.0" - dependencies: - "@eslint-community/eslint-utils": "npm:^4.4.0" - "@types/json-schema": "npm:^7.0.12" - "@types/semver": "npm:^7.5.0" - "@typescript-eslint/scope-manager": "npm:7.2.0" - "@typescript-eslint/types": "npm:7.2.0" - "@typescript-eslint/typescript-estree": "npm:7.2.0" - semver: "npm:^7.5.4" - peerDependencies: - eslint: ^8.56.0 - checksum: 10c0/37944e1a4038820da82b51ac4756e09cff31851d9d957d3fd67a3b6fd2cf6c0e87767161eaeb8b6e63de418e513bb2570a6ee3fa986ba77f6d451d66a538f753 - languageName: node - linkType: hard - "@typescript-eslint/utils@npm:^5.10.0": version: 5.62.0 resolution: "@typescript-eslint/utils@npm:5.62.0" @@ -9299,16 +8484,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:7.2.0": - version: 7.2.0 - resolution: "@typescript-eslint/visitor-keys@npm:7.2.0" - dependencies: - "@typescript-eslint/types": "npm:7.2.0" - eslint-visitor-keys: "npm:^3.4.1" - checksum: 10c0/2d7467495b2b76f3edb1b3047e97076c2242e7eca6d50bbbdd88219f9ff754dbcb9334a0568fe0ceb4c562823980938bd278aa2ba53da6343e7d99a167924f24 - languageName: node - linkType: hard - "@typescript-eslint/visitor-keys@npm:8.33.0": version: 8.33.0 resolution: "@typescript-eslint/visitor-keys@npm:8.33.0" @@ -9326,137 +8501,6 @@ __metadata: languageName: node linkType: hard -"@unhead/schema@npm:^1.11.11, @unhead/schema@npm:^1.9.5": - version: 1.11.20 - resolution: "@unhead/schema@npm:1.11.20" - dependencies: - hookable: "npm:^5.5.3" - zhead: "npm:^2.2.4" - checksum: 10c0/f2f968639bbd18f90ddfb83b77c9256bc4c0379ab75efa24dc759f3f597aae707d4dde97df690823f8902eab31d73a5faa8bdd8daf18c6ac8e4503a78b42be74 - languageName: node - linkType: hard - -"@unrs/resolver-binding-darwin-arm64@npm:1.7.5": - version: 1.7.5 - resolution: "@unrs/resolver-binding-darwin-arm64@npm:1.7.5" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@unrs/resolver-binding-darwin-x64@npm:1.7.5": - version: 1.7.5 - resolution: "@unrs/resolver-binding-darwin-x64@npm:1.7.5" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@unrs/resolver-binding-freebsd-x64@npm:1.7.5": - version: 1.7.5 - resolution: "@unrs/resolver-binding-freebsd-x64@npm:1.7.5" - conditions: os=freebsd & cpu=x64 - languageName: node - linkType: hard - -"@unrs/resolver-binding-linux-arm-gnueabihf@npm:1.7.5": - version: 1.7.5 - resolution: "@unrs/resolver-binding-linux-arm-gnueabihf@npm:1.7.5" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - -"@unrs/resolver-binding-linux-arm-musleabihf@npm:1.7.5": - version: 1.7.5 - resolution: "@unrs/resolver-binding-linux-arm-musleabihf@npm:1.7.5" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - -"@unrs/resolver-binding-linux-arm64-gnu@npm:1.7.5": - version: 1.7.5 - resolution: "@unrs/resolver-binding-linux-arm64-gnu@npm:1.7.5" - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - -"@unrs/resolver-binding-linux-arm64-musl@npm:1.7.5": - version: 1.7.5 - resolution: "@unrs/resolver-binding-linux-arm64-musl@npm:1.7.5" - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - -"@unrs/resolver-binding-linux-ppc64-gnu@npm:1.7.5": - version: 1.7.5 - resolution: "@unrs/resolver-binding-linux-ppc64-gnu@npm:1.7.5" - conditions: os=linux & cpu=ppc64 & libc=glibc - languageName: node - linkType: hard - -"@unrs/resolver-binding-linux-riscv64-gnu@npm:1.7.5": - version: 1.7.5 - resolution: "@unrs/resolver-binding-linux-riscv64-gnu@npm:1.7.5" - conditions: os=linux & cpu=riscv64 & libc=glibc - languageName: node - linkType: hard - -"@unrs/resolver-binding-linux-riscv64-musl@npm:1.7.5": - version: 1.7.5 - resolution: "@unrs/resolver-binding-linux-riscv64-musl@npm:1.7.5" - conditions: os=linux & cpu=riscv64 & libc=musl - languageName: node - linkType: hard - -"@unrs/resolver-binding-linux-s390x-gnu@npm:1.7.5": - version: 1.7.5 - resolution: "@unrs/resolver-binding-linux-s390x-gnu@npm:1.7.5" - conditions: os=linux & cpu=s390x & libc=glibc - languageName: node - linkType: hard - -"@unrs/resolver-binding-linux-x64-gnu@npm:1.7.5": - version: 1.7.5 - resolution: "@unrs/resolver-binding-linux-x64-gnu@npm:1.7.5" - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - -"@unrs/resolver-binding-linux-x64-musl@npm:1.7.5": - version: 1.7.5 - resolution: "@unrs/resolver-binding-linux-x64-musl@npm:1.7.5" - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - -"@unrs/resolver-binding-wasm32-wasi@npm:1.7.5": - version: 1.7.5 - resolution: "@unrs/resolver-binding-wasm32-wasi@npm:1.7.5" - dependencies: - "@napi-rs/wasm-runtime": "npm:^0.2.10" - conditions: cpu=wasm32 - languageName: node - linkType: hard - -"@unrs/resolver-binding-win32-arm64-msvc@npm:1.7.5": - version: 1.7.5 - resolution: "@unrs/resolver-binding-win32-arm64-msvc@npm:1.7.5" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - -"@unrs/resolver-binding-win32-ia32-msvc@npm:1.7.5": - version: 1.7.5 - resolution: "@unrs/resolver-binding-win32-ia32-msvc@npm:1.7.5" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - -"@unrs/resolver-binding-win32-x64-msvc@npm:1.7.5": - version: 1.7.5 - resolution: "@unrs/resolver-binding-win32-x64-msvc@npm:1.7.5" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - "@webassemblyjs/ast@npm:1.14.1, @webassemblyjs/ast@npm:^1.14.1": version: 1.14.1 resolution: "@webassemblyjs/ast@npm:1.14.1" @@ -9848,13 +8892,6 @@ __metadata: languageName: node linkType: hard -"URIjs@npm:^1.16.0": - version: 1.16.1 - resolution: "URIjs@npm:1.16.1" - checksum: 10c0/4709474a384394d4b28987b845989ca56297f07afed3ad58204ba309727530a3aa0106cc5a90b0d784cda390b0ca500575981951f1fa065e8e766a4ffec26f08 - languageName: node - linkType: hard - "abbrev@npm:1": version: 1.1.1 resolution: "abbrev@npm:1.1.1" @@ -9876,21 +8913,6 @@ __metadata: languageName: node linkType: hard -"abitype@npm:1.0.8, abitype@npm:^1.0.6": - version: 1.0.8 - resolution: "abitype@npm:1.0.8" - peerDependencies: - typescript: ">=5.0.4" - zod: ^3 >=3.22.0 - peerDependenciesMeta: - typescript: - optional: true - zod: - optional: true - checksum: 10c0/d3393f32898c1f0f6da4eed2561da6830dcd0d5129a160fae9517214236ee6a6c8e5a0380b8b960c5bc1b949320bcbd015ec7f38b5d7444f8f2b854a1b5dd754 - languageName: node - linkType: hard - "abort-controller@npm:^3.0.0": version: 3.0.0 resolution: "abort-controller@npm:3.0.0" @@ -10061,15 +9083,6 @@ __metadata: languageName: node linkType: hard -"ansi-align@npm:^2.0.0": - version: 2.0.0 - resolution: "ansi-align@npm:2.0.0" - dependencies: - string-width: "npm:^2.0.0" - checksum: 10c0/a3e3e5e58146ca7da775b919a480b8588ea76d0c91aa03c055535de25f327a09b72f7c10be2de6c84a6e1d8387b89bd9b4c98321b1759fdf4c2767c6f10ecd29 - languageName: node - linkType: hard - "ansi-align@npm:^3.0.0": version: 3.0.1 resolution: "ansi-align@npm:3.0.1" @@ -10086,13 +9099,6 @@ __metadata: languageName: node linkType: hard -"ansi-escapes@npm:^1.1.0": - version: 1.4.0 - resolution: "ansi-escapes@npm:1.4.0" - checksum: 10c0/11ee31a0827d2c95129ea7c3df13d4d9d15b487517209d1d16027a876e6029e1c464ba626771af525a5aee12b26a740fc0378142b3193f3a62aaa2f03b7a5e9c - languageName: node - linkType: hard - "ansi-escapes@npm:^4.2.1, ansi-escapes@npm:^4.3.0": version: 4.3.2 resolution: "ansi-escapes@npm:4.3.2" @@ -10120,13 +9126,6 @@ __metadata: languageName: node linkType: hard -"ansi-regex@npm:^2.0.0": - version: 2.1.1 - resolution: "ansi-regex@npm:2.1.1" - checksum: 10c0/78cebaf50bce2cb96341a7230adf28d804611da3ce6bf338efa7b72f06cc6ff648e29f80cd95e582617ba58d5fdbec38abfeed3500a98bce8381a9daec7c548b - languageName: node - linkType: hard - "ansi-regex@npm:^3.0.0": version: 3.0.1 resolution: "ansi-regex@npm:3.0.1" @@ -10148,13 +9147,6 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^2.2.1": - version: 2.2.1 - resolution: "ansi-styles@npm:2.2.1" - checksum: 10c0/7c68aed4f1857389e7a12f85537ea5b40d832656babbf511cc7ecd9efc52889b9c3e5653a71a6aade783c3c5e0aa223ad4ff8e83c27ac8a666514e6c79068cab - languageName: node - linkType: hard - "ansi-styles@npm:^3.2.0, ansi-styles@npm:^3.2.1": version: 3.2.1 resolution: "ansi-styles@npm:3.2.1" @@ -10196,23 +9188,6 @@ __metadata: languageName: node linkType: hard -"any-promise@npm:^1.0.0": - version: 1.3.0 - resolution: "any-promise@npm:1.3.0" - checksum: 10c0/60f0298ed34c74fef50daab88e8dab786036ed5a7fad02e012ab57e376e0a0b4b29e83b95ea9b5e7d89df762f5f25119b83e00706ecaccb22cfbacee98d74889 - languageName: node - linkType: hard - -"anymatch@npm:^2.0.0": - version: 2.0.0 - resolution: "anymatch@npm:2.0.0" - dependencies: - micromatch: "npm:^3.1.4" - normalize-path: "npm:^2.1.1" - checksum: 10c0/a0d745e52f0233048724b9c9d7b1d8a650f7a50151a0f1d2cce1857b09fd096052d334f8c570cc88596edef8249ae778f767db94025cd00f81e154a37bb7e34e - languageName: node - linkType: hard - "anymatch@npm:^3.0.3, anymatch@npm:~3.1.2": version: 3.1.3 resolution: "anymatch@npm:3.1.3" @@ -10230,13 +9205,6 @@ __metadata: languageName: node linkType: hard -"append-field@npm:^1.0.0": - version: 1.0.0 - resolution: "append-field@npm:1.0.0" - checksum: 10c0/1b5abcc227e5179936a9e4f7e2af4769fa1f00eda85bbaed907f7964b0fd1f7d61f0f332b35337f391389ff13dd5310c2546ba670f8e5a743b23ec85185c73ef - languageName: node - linkType: hard - "arg@npm:^4.1.0": version: 4.1.3 resolution: "arg@npm:4.1.3" @@ -10244,13 +9212,6 @@ __metadata: languageName: node linkType: hard -"arg@npm:^5.0.2": - version: 5.0.2 - resolution: "arg@npm:5.0.2" - checksum: 10c0/ccaf86f4e05d342af6666c569f844bec426595c567d32a8289715087825c2ca7edd8a3d204e4d2fb2aa4602e09a57d0c13ea8c9eea75aac3dbb4af5514e6800e - languageName: node - linkType: hard - "argparse@npm:^1.0.7": version: 1.0.10 resolution: "argparse@npm:1.0.10" @@ -10276,34 +9237,6 @@ __metadata: languageName: node linkType: hard -"aria-query@npm:^5.3.2": - version: 5.3.2 - resolution: "aria-query@npm:5.3.2" - checksum: 10c0/003c7e3e2cff5540bf7a7893775fc614de82b0c5dde8ae823d47b7a28a9d4da1f7ed85f340bdb93d5649caa927755f0e31ecc7ab63edfdfc00c8ef07e505e03e - languageName: node - linkType: hard - -"arr-diff@npm:^4.0.0": - version: 4.0.0 - resolution: "arr-diff@npm:4.0.0" - checksum: 10c0/67b80067137f70c89953b95f5c6279ad379c3ee39f7143578e13bd51580a40066ee2a55da066e22d498dce10f68c2d70056d7823f972fab99dfbf4c78d0bc0f7 - languageName: node - linkType: hard - -"arr-flatten@npm:^1.1.0": - version: 1.1.0 - resolution: "arr-flatten@npm:1.1.0" - checksum: 10c0/bef53be02ed3bc58f202b3861a5b1eb6e1ae4fecf39c3ad4d15b1e0433f941077d16e019a33312d820844b0661777322acbb7d0c447b04d9bdf7d6f9c532548a - languageName: node - linkType: hard - -"arr-union@npm:^3.1.0": - version: 3.1.0 - resolution: "arr-union@npm:3.1.0" - checksum: 10c0/7d5aa05894e54aa93c77c5726c1dd5d8e8d3afe4f77983c0aa8a14a8a5cbe8b18f0cf4ecaa4ac8c908ef5f744d2cbbdaa83fd6e96724d15fea56cfa7f5efdd51 - languageName: node - linkType: hard - "array-back@npm:^3.0.1, array-back@npm:^3.1.0": version: 3.1.0 resolution: "array-back@npm:3.1.0" @@ -10356,13 +9289,6 @@ __metadata: languageName: node linkType: hard -"array-unique@npm:^0.3.2": - version: 0.3.2 - resolution: "array-unique@npm:0.3.2" - checksum: 10c0/dbf4462cdba8a4b85577be07705210b3d35be4b765822a3f52962d907186617638ce15e0603a4fefdcf82f4cbbc9d433f8cbbd6855148a68872fa041b6474121 - languageName: node - linkType: hard - "array.prototype.findlast@npm:^1.2.5": version: 1.2.5 resolution: "array.prototype.findlast@npm:1.2.5" @@ -10377,22 +9303,7 @@ __metadata: languageName: node linkType: hard -"array.prototype.findlastindex@npm:^1.2.5": - version: 1.2.6 - resolution: "array.prototype.findlastindex@npm:1.2.6" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.4" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.9" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.1.1" - es-shim-unscopables: "npm:^1.1.0" - checksum: 10c0/82559310d2e57ec5f8fc53d7df420e3abf0ba497935de0a5570586035478ba7d07618cb18e2d4ada2da514c8fb98a034aaf5c06caa0a57e2f7f4c4adedef5956 - languageName: node - linkType: hard - -"array.prototype.flat@npm:^1.3.1, array.prototype.flat@npm:^1.3.2": +"array.prototype.flat@npm:^1.3.1": version: 1.3.3 resolution: "array.prototype.flat@npm:1.3.3" dependencies: @@ -10404,7 +9315,7 @@ __metadata: languageName: node linkType: hard -"array.prototype.flatmap@npm:^1.3.2, array.prototype.flatmap@npm:^1.3.3": +"array.prototype.flatmap@npm:^1.3.3": version: 1.3.3 resolution: "array.prototype.flatmap@npm:1.3.3" dependencies: @@ -10467,7 +9378,7 @@ __metadata: languageName: node linkType: hard -"asap@npm:^2.0.0, asap@npm:~2.0.6": +"asap@npm:~2.0.6": version: 2.0.6 resolution: "asap@npm:2.0.6" checksum: 10c0/c6d5e39fe1f15e4b87677460bd66b66050cd14c772269cee6688824c1410a08ab20254bb6784f9afb75af9144a9f9a7692d49547f4d19d715aeb7c0318f3136d @@ -10520,20 +9431,6 @@ __metadata: languageName: node linkType: hard -"assign-symbols@npm:^1.0.0": - version: 1.0.0 - resolution: "assign-symbols@npm:1.0.0" - checksum: 10c0/29a654b8a6da6889a190d0d0efef4b1bfb5948fa06cbc245054aef05139f889f2f7c75b989917e3fde853fc4093b88048e4de8578a73a76f113d41bfd66e5775 - languageName: node - linkType: hard - -"ast-types-flow@npm:^0.0.8": - version: 0.0.8 - resolution: "ast-types-flow@npm:0.0.8" - checksum: 10c0/f2a0ba8055353b743c41431974521e5e852a9824870cd6fce2db0e538ac7bf4da406bbd018d109af29ff3f8f0993f6a730c9eddbd0abd031fbcb29ca75c1014e - languageName: node - linkType: hard - "ast-types@npm:0.15.2": version: 0.15.2 resolution: "ast-types@npm:0.15.2" @@ -10566,13 +9463,6 @@ __metadata: languageName: node linkType: hard -"async-each@npm:^1.0.1": - version: 1.0.6 - resolution: "async-each@npm:1.0.6" - checksum: 10c0/d4e45e8f077e20e015952c065ceae75f82b30ee2d4a8e56a5c454ae44331aaa009d8c94fe043ba254c177bffae9f6ebeefebb7daf9f7ce4d27fac0274dc328ae - languageName: node - linkType: hard - "async-function@npm:^1.0.0": version: 1.0.0 resolution: "async-function@npm:1.0.0" @@ -10587,7 +9477,7 @@ __metadata: languageName: node linkType: hard -"async@npm:1.x, async@npm:^1.2.1, async@npm:^1.3.0, async@npm:^1.4.0": +"async@npm:1.x": version: 1.5.2 resolution: "async@npm:1.5.2" checksum: 10c0/9ee84592c393aad1047d1223004317ecc65a9a3f76101e0f4614a0818eac962e666510353400a3c9ea158df540579a293f486f3578e918c5e90a0f5ed52e8aea @@ -10633,14 +9523,7 @@ __metadata: languageName: node linkType: hard -"axe-core@npm:^4.10.0": - version: 4.10.3 - resolution: "axe-core@npm:4.10.3" - checksum: 10c0/1b1c24f435b2ffe89d76eca0001cbfff42dbf012ad9bd37398b70b11f0d614281a38a28bc3069e8972e3c90ec929a8937994bd24b0ebcbaab87b8d1e241ab0c7 - languageName: node - linkType: hard - -"axios@npm:^1.5.1, axios@npm:^1.6.2, axios@npm:^1.7.2, axios@npm:^1.7.7": +"axios@npm:^1.5.1, axios@npm:^1.6.2, axios@npm:^1.7.2": version: 1.9.0 resolution: "axios@npm:1.9.0" dependencies: @@ -10651,13 +9534,6 @@ __metadata: languageName: node linkType: hard -"axobject-query@npm:^4.1.0": - version: 4.1.0 - resolution: "axobject-query@npm:4.1.0" - checksum: 10c0/c470e4f95008f232eadd755b018cb55f16c03ccf39c027b941cd8820ac6b68707ce5d7368a46756db4256fbc91bb4ead368f84f7fb034b2b7932f082f6dc0775 - languageName: node - linkType: hard - "b4a@npm:^1.0.1, b4a@npm:^1.6.4": version: 1.6.7 resolution: "b4a@npm:1.6.7" @@ -10716,17 +9592,6 @@ __metadata: languageName: node linkType: hard -"babel-plugin-macros@npm:^3.1.0": - version: 3.1.0 - resolution: "babel-plugin-macros@npm:3.1.0" - dependencies: - "@babel/runtime": "npm:^7.12.5" - cosmiconfig: "npm:^7.0.0" - resolve: "npm:^1.19.0" - checksum: 10c0/c6dfb15de96f67871d95bd2e8c58b0c81edc08b9b087dc16755e7157f357dc1090a8dc60ebab955e92587a9101f02eba07e730adc253a1e4cf593ca3ebd3839c - languageName: node - linkType: hard - "babel-plugin-polyfill-corejs2@npm:^0.4.10": version: 0.4.13 resolution: "babel-plugin-polyfill-corejs2@npm:0.4.13" @@ -10818,28 +9683,6 @@ __metadata: languageName: node linkType: hard -"backend-api@workspace:sdk/tests/api-server": - version: 0.0.0-use.local - resolution: "backend-api@workspace:sdk/tests/api-server" - dependencies: - "@elysiajs/swagger": "npm:^1.2.0" - "@openpassport/zk-kit-imt": "npm:^0.0.5" - "@openpassport/zk-kit-lean-imt": "npm:^0.0.6" - "@selfxyz/core": "npm:^0.0.3" - "@types/pg": "npm:^8.11.11" - bun-types: "npm:latest" - dotenv: "npm:^16.4.7" - elysia: "npm:latest" - logixlysia: "npm:^4.1.1" - pg: "npm:^8.13.1" - poseidon-lite: "npm:^0.3.0" - snarkjs: "npm:^0.7.5" - swagger: "npm:^0.7.5" - typescript: "npm:^5.8.3" - viem: "npm:^2.22.23" - languageName: unknown - linkType: soft - "balanced-match@npm:^1.0.0": version: 1.0.2 resolution: "balanced-match@npm:1.0.2" @@ -10946,21 +9789,6 @@ __metadata: languageName: node linkType: hard -"base@npm:^0.11.1": - version: 0.11.2 - resolution: "base@npm:0.11.2" - dependencies: - cache-base: "npm:^1.0.1" - class-utils: "npm:^0.3.5" - component-emitter: "npm:^1.2.1" - define-property: "npm:^1.0.0" - isobject: "npm:^3.0.1" - mixin-deep: "npm:^1.2.0" - pascalcase: "npm:^0.1.1" - checksum: 10c0/30a2c0675eb52136b05ef496feb41574d9f0bb2d6d677761da579c00a841523fccf07f1dbabec2337b5f5750f428683b8ca60d89e56a1052c4ae1c0cd05de64d - languageName: node - linkType: hard - "basic-ftp@npm:^5.0.2": version: 5.0.5 resolution: "basic-ftp@npm:5.0.5" @@ -10995,13 +9823,6 @@ __metadata: languageName: node linkType: hard -"binary-extensions@npm:^1.0.0": - version: 1.13.1 - resolution: "binary-extensions@npm:1.13.1" - checksum: 10c0/2d616938ac23d828ec3fbe0dea429b566fd2c137ddc38f166f16561ccd58029deac3fa9fddb489ab13d679c8fb5f1bd0e82824041299e5e39d8dd3cc68fbb9f9 - languageName: node - linkType: hard - "binary-extensions@npm:^2.0.0": version: 2.3.0 resolution: "binary-extensions@npm:2.3.0" @@ -11009,15 +9830,6 @@ __metadata: languageName: node linkType: hard -"bindings@npm:^1.5.0": - version: 1.5.0 - resolution: "bindings@npm:1.5.0" - dependencies: - file-uri-to-path: "npm:1.0.0" - checksum: 10c0/3dab2491b4bb24124252a91e656803eac24292473e56554e35bbfe3cc1875332cfa77600c3bac7564049dc95075bf6fcc63a4609920ff2d64d0fe405fcf0d4ba - languageName: node - linkType: hard - "bl@npm:^4.1.0": version: 4.1.0 resolution: "bl@npm:4.1.0" @@ -11096,23 +9908,6 @@ __metadata: languageName: node linkType: hard -"body-parser@npm:1.12.4": - version: 1.12.4 - resolution: "body-parser@npm:1.12.4" - dependencies: - bytes: "npm:1.0.0" - content-type: "npm:~1.0.1" - debug: "npm:~2.2.0" - depd: "npm:~1.0.1" - iconv-lite: "npm:0.4.8" - on-finished: "npm:~2.2.1" - qs: "npm:2.4.2" - raw-body: "npm:~2.0.1" - type-is: "npm:~1.6.2" - checksum: 10c0/5562e8d42531f1c0e49695541df4639a02b331a006ab9b4921035deb37606885ce56413f920e46a8d0beac74b659c041ce6588451fad5e9cbb91bbad60787f3f - languageName: node - linkType: hard - "boolbase@npm:^1.0.0": version: 1.0.0 resolution: "boolbase@npm:1.0.0" @@ -11120,21 +9915,6 @@ __metadata: languageName: node linkType: hard -"boxen@npm:^1.2.1": - version: 1.3.0 - resolution: "boxen@npm:1.3.0" - dependencies: - ansi-align: "npm:^2.0.0" - camelcase: "npm:^4.0.0" - chalk: "npm:^2.0.1" - cli-boxes: "npm:^1.0.0" - string-width: "npm:^2.0.0" - term-size: "npm:^1.2.0" - widest-line: "npm:^2.0.0" - checksum: 10c0/9df2e59dd6622cee184aaffc017b3b3d506f1f70cddb0a7c19d22c865db4222faa9940512a7a6e2065f48500f9310a04d27af2037b1afeb2143e79430c9af476 - languageName: node - linkType: hard - "boxen@npm:^5.1.2": version: 5.1.2 resolution: "boxen@npm:5.1.2" @@ -11170,24 +9950,6 @@ __metadata: languageName: node linkType: hard -"braces@npm:^2.3.1, braces@npm:^2.3.2": - version: 2.3.2 - resolution: "braces@npm:2.3.2" - dependencies: - arr-flatten: "npm:^1.1.0" - array-unique: "npm:^0.3.2" - extend-shallow: "npm:^2.0.1" - fill-range: "npm:^4.0.0" - isobject: "npm:^3.0.1" - repeat-element: "npm:^1.1.2" - snapdragon: "npm:^0.8.1" - snapdragon-node: "npm:^2.0.1" - split-string: "npm:^3.0.2" - to-regex: "npm:^3.0.1" - checksum: 10c0/72b27ea3ea2718f061c29e70fd6e17606e37c65f5801abddcf0b0052db1de7d60f3bf92cfc220ab57b44bd0083a5f69f9d03b3461d2816cfe9f9398207acc728 - languageName: node - linkType: hard - "braces@npm:^3.0.3, braces@npm:~3.0.2": version: 3.0.3 resolution: "braces@npm:3.0.3" @@ -11318,34 +10080,6 @@ __metadata: languageName: node linkType: hard -"bun-types@npm:latest": - version: 1.2.14 - resolution: "bun-types@npm:1.2.14" - dependencies: - "@types/node": "npm:*" - checksum: 10c0/d840798950293eb7023f8d715304eef388bbe7947e06df78afd25ed399d708e36f1164c8d32ed840f3d1f9f235bd72334503806bacf36a6be4c0e2da68f3c2ec - languageName: node - linkType: hard - -"busboy@npm:1.6.0": - version: 1.6.0 - resolution: "busboy@npm:1.6.0" - dependencies: - streamsearch: "npm:^1.1.0" - checksum: 10c0/fa7e836a2b82699b6e074393428b91ae579d4f9e21f5ac468e1b459a244341d722d2d22d10920cdd849743dbece6dca11d72de939fb75a7448825cf2babfba1f - languageName: node - linkType: hard - -"busboy@npm:^0.2.11": - version: 0.2.14 - resolution: "busboy@npm:0.2.14" - dependencies: - dicer: "npm:0.2.5" - readable-stream: "npm:1.1.x" - checksum: 10c0/660ce531347a03210f46080c2447030c41f60202be0d8dd1544482786341a497b1d4d8941e3c7c9b5e6ed4edc42003c28c9451e1fde87dd94010df69bb27cc38 - languageName: node - linkType: hard - "bytes-iec@npm:^3.1.1": version: 3.1.1 resolution: "bytes-iec@npm:3.1.1" @@ -11353,20 +10087,6 @@ __metadata: languageName: node linkType: hard -"bytes@npm:1.0.0": - version: 1.0.0 - resolution: "bytes@npm:1.0.0" - checksum: 10c0/46f38408f9bf41c7c82b4e8118ab22f3f83fcebeecc4b93a71867608a3f6f25ab446d72438054daf0059234f2522e3711a241a06a0836f9b5e3e025d2da8d9af - languageName: node - linkType: hard - -"bytes@npm:2.1.0": - version: 2.1.0 - resolution: "bytes@npm:2.1.0" - checksum: 10c0/09a120e49870543597d4e7b0dd32acdad4747a141719850c541d3d93c68193d31fe3f3d54bc1990edd3bf49fa9f95965cef0a13a36db97975ebb44c58b5db1f5 - languageName: node - linkType: hard - "bytes@npm:3.1.2": version: 3.1.2 resolution: "bytes@npm:3.1.2" @@ -11401,23 +10121,6 @@ __metadata: languageName: node linkType: hard -"cache-base@npm:^1.0.1": - version: 1.0.1 - resolution: "cache-base@npm:1.0.1" - dependencies: - collection-visit: "npm:^1.0.0" - component-emitter: "npm:^1.2.1" - get-value: "npm:^2.0.6" - has-value: "npm:^1.0.0" - isobject: "npm:^3.0.1" - set-value: "npm:^2.0.0" - to-object-path: "npm:^0.3.0" - union-value: "npm:^1.0.0" - unset-value: "npm:^1.0.0" - checksum: 10c0/a7142e25c73f767fa520957dcd179b900b86eac63b8cfeaa3b2a35e18c9ca5968aa4e2d2bed7a3e7efd10f13be404344cfab3a4156217e71f9bdb95940bb9c8c - languageName: node - linkType: hard - "cacheable-lookup@npm:^5.0.3": version: 5.0.4 resolution: "cacheable-lookup@npm:5.0.4" @@ -11504,20 +10207,6 @@ __metadata: languageName: node linkType: hard -"camelcase-css@npm:^2.0.1": - version: 2.0.1 - resolution: "camelcase-css@npm:2.0.1" - checksum: 10c0/1a1a3137e8a781e6cbeaeab75634c60ffd8e27850de410c162cce222ea331cd1ba5364e8fb21c95e5ca76f52ac34b81a090925ca00a87221355746d049c6e273 - languageName: node - linkType: hard - -"camelcase@npm:^4.0.0": - version: 4.1.0 - resolution: "camelcase@npm:4.1.0" - checksum: 10c0/54c0b6a85b54fb4e96a9d834a9d0d8f760fd608ab6752a6789042b5e1c38d3dd60f878d2c590d005046445d32d77f6e05e568a91fe8db3e282da0a1560d83058 - languageName: node - linkType: hard - "camelcase@npm:^5.0.0, camelcase@npm:^5.3.1": version: 5.3.1 resolution: "camelcase@npm:5.3.1" @@ -11532,20 +10221,13 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.30001579, caniuse-lite@npm:^1.0.30001716": +"caniuse-lite@npm:^1.0.30001716": version: 1.0.30001718 resolution: "caniuse-lite@npm:1.0.30001718" checksum: 10c0/67f9ad09bc16443e28d14f265d6e468480cd8dc1900d0d8b982222de80c699c4f2306599c3da8a3fa7139f110d4b30d49dbac78f215470f479abb6ffe141d5d3 languageName: node linkType: hard -"capture-stack-trace@npm:^1.0.0": - version: 1.0.2 - resolution: "capture-stack-trace@npm:1.0.2" - checksum: 10c0/9f910506dcbe82dbfadf81a9e8c7cff478dd64ea2de319d01762de32940cdb082217686215a8ed389a540e683779fe56ac4b9a2957d1bfdd8c730d08e5f12ca5 - languageName: node - linkType: hard - "caseless@npm:^0.12.0, caseless@npm:~0.12.0": version: 0.12.0 resolution: "caseless@npm:0.12.0" @@ -11625,20 +10307,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^1.0.0": - version: 1.1.3 - resolution: "chalk@npm:1.1.3" - dependencies: - ansi-styles: "npm:^2.2.1" - escape-string-regexp: "npm:^1.0.2" - has-ansi: "npm:^2.0.0" - strip-ansi: "npm:^3.0.0" - supports-color: "npm:^2.0.0" - checksum: 10c0/28c3e399ec286bb3a7111fd4225ebedb0d7b813aef38a37bca7c498d032459c265ef43404201d5fbb8d888d29090899c95335b4c0cda13e8b126ff15c541cef8 - languageName: node - linkType: hard - -"chalk@npm:^2.0.1, chalk@npm:^2.4.2": +"chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" dependencies: @@ -11669,13 +10338,6 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^5.3.0": - version: 5.4.1 - resolution: "chalk@npm:5.4.1" - checksum: 10c0/b23e88132c702f4855ca6d25cb5538b1114343e41472d5263ee8a37cccfccd9c4216d111e1097c6a27830407a1dc81fecdf2a56f2c63033d4dbbd88c10b0dcef - languageName: node - linkType: hard - "char-regex@npm:^1.0.2": version: 1.0.2 resolution: "char-regex@npm:1.0.2" @@ -11683,7 +10345,7 @@ __metadata: languageName: node linkType: hard -"charenc@npm:>= 0.0.1, charenc@npm:~0.0.1": +"charenc@npm:>= 0.0.1": version: 0.0.2 resolution: "charenc@npm:0.0.2" checksum: 10c0/a45ec39363a16799d0f9365c8dd0c78e711415113c6f14787a22462ef451f5013efae8a28f1c058f81fc01f2a6a16955f7a5fd0cd56247ce94a45349c89877d8 @@ -11713,30 +10375,7 @@ __metadata: languageName: node linkType: hard -"chokidar@npm:^2.1.8": - version: 2.1.8 - resolution: "chokidar@npm:2.1.8" - dependencies: - anymatch: "npm:^2.0.0" - async-each: "npm:^1.0.1" - braces: "npm:^2.3.2" - fsevents: "npm:^1.2.7" - glob-parent: "npm:^3.1.0" - inherits: "npm:^2.0.3" - is-binary-path: "npm:^1.0.0" - is-glob: "npm:^4.0.0" - normalize-path: "npm:^3.0.0" - path-is-absolute: "npm:^1.0.0" - readdirp: "npm:^2.2.1" - upath: "npm:^1.1.1" - dependenciesMeta: - fsevents: - optional: true - checksum: 10c0/5631cc00080224f9482cf5418dcbea111aec02fa8d81a8cfe37e47b9cf36089e071de52d503647e3a821a01426a40adc926ba899f657af86a51b8f8d4eef12a7 - languageName: node - linkType: hard - -"chokidar@npm:^3.5.3, chokidar@npm:^3.6.0": +"chokidar@npm:^3.5.3": version: 3.6.0 resolution: "chokidar@npm:3.6.0" dependencies: @@ -11826,13 +10465,6 @@ __metadata: languageName: node linkType: hard -"ci-info@npm:^1.5.0": - version: 1.6.0 - resolution: "ci-info@npm:1.6.0" - checksum: 10c0/5a74921e50e0be504ef811f00cb8dd6a547e1f4f2e709b7364b2de72a6fbc0215d86c88cd62c485a129090365d2a6367ca00344ced04e714860b22fbe10180c8 - languageName: node - linkType: hard - "ci-info@npm:^2.0.0": version: 2.0.0 resolution: "ci-info@npm:2.0.0" @@ -11978,18 +10610,6 @@ __metadata: languageName: node linkType: hard -"class-utils@npm:^0.3.5": - version: 0.3.6 - resolution: "class-utils@npm:0.3.6" - dependencies: - arr-union: "npm:^3.1.0" - define-property: "npm:^0.2.5" - isobject: "npm:^3.0.0" - static-extend: "npm:^0.1.1" - checksum: 10c0/d44f4afc7a3e48dba4c2d3fada5f781a1adeeff371b875c3b578bc33815c6c29d5d06483c2abfd43a32d35b104b27b67bfa39c2e8a422fa858068bd756cfbd42 - languageName: node - linkType: hard - "clean-stack@npm:^2.0.0": version: 2.2.0 resolution: "clean-stack@npm:2.2.0" @@ -11997,13 +10617,6 @@ __metadata: languageName: node linkType: hard -"cli-boxes@npm:^1.0.0": - version: 1.0.0 - resolution: "cli-boxes@npm:1.0.0" - checksum: 10c0/1f79cd17e39cc00710d85c2a2d33ead781d1215b72546b31cfb4da5b2edc1f12ef8f99af67afb8a79fa1f92ad6b54505cc245afb16eee5fa01772f87353ba6e4 - languageName: node - linkType: hard - "cli-boxes@npm:^2.2.1": version: 2.2.1 resolution: "cli-boxes@npm:2.2.1" @@ -12011,15 +10624,6 @@ __metadata: languageName: node linkType: hard -"cli-cursor@npm:^1.0.1": - version: 1.0.2 - resolution: "cli-cursor@npm:1.0.2" - dependencies: - restore-cursor: "npm:^1.0.1" - checksum: 10c0/a621ddfae6dde44c699c520ef416745d096b7d58255f3a2a2727b19db4a308085f33ca86e19f1bf3e4dc4d500c347c5c9ed62c4cfe1a23c2fd4b0419e1ff4e8b - languageName: node - linkType: hard - "cli-cursor@npm:^3.1.0": version: 3.1.0 resolution: "cli-cursor@npm:3.1.0" @@ -12063,20 +10667,6 @@ __metadata: languageName: node linkType: hard -"cli-width@npm:^1.0.1": - version: 1.1.1 - resolution: "cli-width@npm:1.1.1" - checksum: 10c0/257dd5c16b1c79ca571515dc5ff7872cbb8f0a7c98c4d2cc9a9498b2b1e9aec3794c2aa881ccf3dcc8fc0a5f2b4e4309d1a17758db36476ef13b4e5adb344fa8 - languageName: node - linkType: hard - -"client-only@npm:0.0.1": - version: 0.0.1 - resolution: "client-only@npm:0.0.1" - checksum: 10c0/9d6cfd0c19e1c96a434605added99dff48482152af791ec4172fb912a71cff9027ff174efd8cdb2160cc7f377543e0537ffc462d4f279bc4701de3f2a3c4b358 - languageName: node - linkType: hard - "clipanion@npm:^4.0.0-rc.2": version: 4.0.0-rc.4 resolution: "clipanion@npm:4.0.0-rc.4" @@ -12160,20 +10750,6 @@ __metadata: languageName: node linkType: hard -"clone@npm:^2.1.2": - version: 2.1.2 - resolution: "clone@npm:2.1.2" - checksum: 10c0/ed0601cd0b1606bc7d82ee7175b97e68d1dd9b91fd1250a3617b38d34a095f8ee0431d40a1a611122dcccb4f93295b4fdb94942aa763392b5fe44effa50c2d5e - languageName: node - linkType: hard - -"clsx@npm:^2.1.1": - version: 2.1.1 - resolution: "clsx@npm:2.1.1" - checksum: 10c0/c4c8eb865f8c82baab07e71bfa8897c73454881c4f99d6bc81585aecd7c441746c1399d08363dc096c550cceaf97bd4ce1e8854e1771e9998d9f94c4fe075839 - languageName: node - linkType: hard - "co@npm:^4.6.0": version: 4.6.0 resolution: "co@npm:4.6.0" @@ -12181,13 +10757,6 @@ __metadata: languageName: node linkType: hard -"code-point-at@npm:^1.0.0": - version: 1.1.0 - resolution: "code-point-at@npm:1.1.0" - checksum: 10c0/33f6b234084e46e6e369b6f0b07949392651b4dde70fc6a592a8d3dafa08d5bb32e3981a02f31f6fc323a26bc03a4c063a9d56834848695bda7611c2417ea2e6 - languageName: node - linkType: hard - "collect-v8-coverage@npm:^1.0.0": version: 1.0.2 resolution: "collect-v8-coverage@npm:1.0.2" @@ -12195,16 +10764,6 @@ __metadata: languageName: node linkType: hard -"collection-visit@npm:^1.0.0": - version: 1.0.0 - resolution: "collection-visit@npm:1.0.0" - dependencies: - map-visit: "npm:^1.0.0" - object-visit: "npm:^1.0.0" - checksum: 10c0/add72a8d1c37cb90e53b1aaa2c31bf1989bfb733f0b02ce82c9fa6828c7a14358dba2e4f8e698c02f69e424aeccae1ffb39acdeaf872ade2f41369e84a2fcf8a - languageName: node - linkType: hard - "color-convert@npm:^1.9.0": version: 1.9.3 resolution: "color-convert@npm:1.9.3" @@ -12278,7 +10837,7 @@ __metadata: languageName: node linkType: hard -"combined-stream@npm:^1.0.5, combined-stream@npm:^1.0.8": +"combined-stream@npm:^1.0.8": version: 1.0.8 resolution: "combined-stream@npm:1.0.8" dependencies: @@ -12318,20 +10877,6 @@ __metadata: languageName: node linkType: hard -"commander@npm:0.6.1": - version: 0.6.1 - resolution: "commander@npm:0.6.1" - checksum: 10c0/01dd500bbc8df9d523eaa01c022ec47055c1a308e5c275d3bed986366bd3acaf59a1750319877f15c3cf1a982240098d9469c003dad425a3a20d5db6054a378a - languageName: node - linkType: hard - -"commander@npm:2.3.0": - version: 2.3.0 - resolution: "commander@npm:2.3.0" - checksum: 10c0/cb41bc7f92b4af7c35c7084637e5a0e71d8774eac1088d2371e4be30dc310f8619d26389e71681af9fb3f8e0d291bf0723aba30eb84ebb6391963b8263c57c18 - languageName: node - linkType: hard - "commander@npm:^11.0.0": version: 11.1.0 resolution: "commander@npm:11.1.0" @@ -12346,20 +10891,13 @@ __metadata: languageName: node linkType: hard -"commander@npm:^2.20.0, commander@npm:^2.7.1, commander@npm:^2.8.1, commander@npm:^2.9.0": +"commander@npm:^2.20.0": version: 2.20.3 resolution: "commander@npm:2.20.3" checksum: 10c0/74c781a5248c2402a0a3e966a0a2bba3c054aad144f5c023364be83265e796b20565aa9feff624132ff629aa64e16999fa40a743c10c12f7c61e96a794b99288 languageName: node linkType: hard -"commander@npm:^4.0.0": - version: 4.1.1 - resolution: "commander@npm:4.1.1" - checksum: 10c0/84a76c08fe6cc08c9c93f62ac573d2907d8e79138999312c92d4155bc2325d487d64d13f669b2000c9f8caf70493c1be2dac74fec3c51d5a04f8bc3ae1830bab - languageName: node - linkType: hard - "commander@npm:^7.2.0": version: 7.2.0 resolution: "commander@npm:7.2.0" @@ -12400,20 +10938,6 @@ __metadata: languageName: node linkType: hard -"component-emitter@npm:^1.2.1, component-emitter@npm:^1.3.0": - version: 1.3.1 - resolution: "component-emitter@npm:1.3.1" - checksum: 10c0/e4900b1b790b5e76b8d71b328da41482118c0f3523a516a41be598dc2785a07fd721098d9bf6e22d89b19f4fa4e1025160dc00317ea111633a3e4f75c2b86032 - languageName: node - linkType: hard - -"component-emitter@npm:~1.2.0": - version: 1.2.1 - resolution: "component-emitter@npm:1.2.1" - checksum: 10c0/6c27bd7bba028776464cee6c1686c8e02cb9a576a11df93f1fc211ae3eb2de234ae90952d0b7fb3acc9c92c8baa389fa7389681b2e8689d2ca463e94f3ad30b2 - languageName: node - linkType: hard - "compressible@npm:~2.0.18": version: 2.0.18 resolution: "compressible@npm:2.0.18" @@ -12445,7 +10969,7 @@ __metadata: languageName: node linkType: hard -"concat-stream@npm:^1.5.2, concat-stream@npm:^1.6.0, concat-stream@npm:^1.6.2": +"concat-stream@npm:^1.6.0, concat-stream@npm:^1.6.2": version: 1.6.2 resolution: "concat-stream@npm:1.6.2" dependencies: @@ -12457,21 +10981,7 @@ __metadata: languageName: node linkType: hard -"configstore@npm:^3.0.0": - version: 3.1.5 - resolution: "configstore@npm:3.1.5" - dependencies: - dot-prop: "npm:^4.2.1" - graceful-fs: "npm:^4.1.2" - make-dir: "npm:^1.0.0" - unique-string: "npm:^1.0.0" - write-file-atomic: "npm:^2.0.0" - xdg-basedir: "npm:^3.0.0" - checksum: 10c0/a68edffee893b1803a108c4083dee481967f7eec232f83499bc86973d93d1e2728c1ea98cb1a4c7c583bc172abbdf197888ba0b0c12640631792186aa233918b - languageName: node - linkType: hard - -"connect@npm:^3.3.5, connect@npm:^3.6.5": +"connect@npm:^3.6.5": version: 3.7.0 resolution: "connect@npm:3.7.0" dependencies: @@ -12483,14 +10993,7 @@ __metadata: languageName: node linkType: hard -"content-type@npm:~1.0.1": - version: 1.0.5 - resolution: "content-type@npm:1.0.5" - checksum: 10c0/b76ebed15c000aee4678c3707e0860cb6abd4e680a598c0a26e17f0bfae723ec9cc2802f0ff1bc6e4d80603719010431d2231018373d4dde10f9ccff9dadf5af - languageName: node - linkType: hard - -"convert-source-map@npm:^1.5.0, convert-source-map@npm:^1.7.0": +"convert-source-map@npm:^1.7.0": version: 1.9.0 resolution: "convert-source-map@npm:1.9.0" checksum: 10c0/281da55454bf8126cbc6625385928c43479f2060984180c42f3a86c8b8c12720a24eac260624a7d1e090004028d2dee78602330578ceec1a08e27cb8bb0a8a5b @@ -12511,54 +11014,19 @@ __metadata: languageName: node linkType: hard -"cookie@npm:^1.0.2": - version: 1.0.2 - resolution: "cookie@npm:1.0.2" - checksum: 10c0/fd25fe79e8fbcfcaf6aa61cd081c55d144eeeba755206c058682257cb38c4bd6795c6620de3f064c740695bb65b7949ebb1db7a95e4636efb8357a335ad3f54b +"core-js-compat@npm:^3.40.0": + version: 3.42.0 + resolution: "core-js-compat@npm:3.42.0" + dependencies: + browserslist: "npm:^4.24.4" + checksum: 10c0/0138ce005c13ce642fc38e18e54a52a1c78ca8315ee6e4faad748d2a1b0ad2462ea615285ad4e6cf77afe48e47a868d898e64c70606c1eb1c9e6a9f19ee2b186 languageName: node linkType: hard -"cookiejar@npm:2.0.6": - version: 2.0.6 - resolution: "cookiejar@npm:2.0.6" - checksum: 10c0/e62e345b74f29c396720e0592c9f6b7de6b29250867cf5abf6a7e798e4ea2efcb811210439ab6243b5dc2cde9d992133214039b08f7e474142eef441b102a58d - languageName: node - linkType: hard - -"cookiejar@npm:^2.1.3": - version: 2.1.4 - resolution: "cookiejar@npm:2.1.4" - checksum: 10c0/2dae55611c6e1678f34d93984cbd4bda58f4fe3e5247cc4993f4a305cd19c913bbaf325086ed952e892108115073a747596453d3dc1c34947f47f731818b8ad1 - languageName: node - linkType: hard - -"copy-descriptor@npm:^0.1.0": - version: 0.1.1 - resolution: "copy-descriptor@npm:0.1.1" - checksum: 10c0/161f6760b7348c941007a83df180588fe2f1283e0867cc027182734e0f26134e6cc02de09aa24a95dc267b2e2025b55659eef76c8019df27bc2d883033690181 - languageName: node - linkType: hard - -"core-js-compat@npm:^3.40.0": - version: 3.42.0 - resolution: "core-js-compat@npm:3.42.0" - dependencies: - browserslist: "npm:^4.24.4" - checksum: 10c0/0138ce005c13ce642fc38e18e54a52a1c78ca8315ee6e4faad748d2a1b0ad2462ea615285ad4e6cf77afe48e47a868d898e64c70606c1eb1c9e6a9f19ee2b186 - languageName: node - linkType: hard - -"core-js@npm:^2.5.7": - version: 2.6.12 - resolution: "core-js@npm:2.6.12" - checksum: 10c0/00128efe427789120a06b819adc94cc72b96955acb331cb71d09287baf9bd37bebd191d91f1ee4939c893a050307ead4faea08876f09115112612b6a05684b63 - languageName: node - linkType: hard - -"core-util-is@npm:^1.0.2, core-util-is@npm:~1.0.0": - version: 1.0.3 - resolution: "core-util-is@npm:1.0.3" - checksum: 10c0/90a0e40abbddfd7618f8ccd63a74d88deea94e77d0e8dbbea059fa7ebebb8fbb4e2909667fe26f3a467073de1a542ebe6ae4c73a73745ac5833786759cd906c9 +"core-util-is@npm:^1.0.2, core-util-is@npm:~1.0.0": + version: 1.0.3 + resolution: "core-util-is@npm:1.0.3" + checksum: 10c0/90a0e40abbddfd7618f8ccd63a74d88deea94e77d0e8dbbea059fa7ebebb8fbb4e2909667fe26f3a467073de1a542ebe6ae4c73a73745ac5833786759cd906c9 languageName: node linkType: hard @@ -12574,19 +11042,6 @@ __metadata: languageName: node linkType: hard -"cosmiconfig@npm:^7.0.0": - version: 7.1.0 - resolution: "cosmiconfig@npm:7.1.0" - dependencies: - "@types/parse-json": "npm:^4.0.0" - import-fresh: "npm:^3.2.1" - parse-json: "npm:^5.0.0" - path-type: "npm:^4.0.0" - yaml: "npm:^1.10.0" - checksum: 10c0/b923ff6af581638128e5f074a5450ba12c0300b71302398ea38dbeabd33bbcaa0245ca9adbedfcf284a07da50f99ede5658c80bb3e39e2ce770a99d28a21ef03 - languageName: node - linkType: hard - "cosmiconfig@npm:^8.1.3": version: 8.3.6 resolution: "cosmiconfig@npm:8.3.6" @@ -12635,15 +11090,6 @@ __metadata: languageName: node linkType: hard -"create-error-class@npm:^3.0.0": - version: 3.0.2 - resolution: "create-error-class@npm:3.0.2" - dependencies: - capture-stack-trace: "npm:^1.0.0" - checksum: 10c0/e7978884999f7195b20a56c327acf1d742b45c721098691863bd2a933180aa411d5dbe790d3565f3eca6105b829a647497d52e3e00edf1d5c19c1d116def69b6 - languageName: node - linkType: hard - "create-hash@npm:^1.1.0, create-hash@npm:^1.1.2, create-hash@npm:^1.2.0": version: 1.2.0 resolution: "create-hash@npm:1.2.0" @@ -12695,17 +11141,6 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^5.0.1": - version: 5.1.0 - resolution: "cross-spawn@npm:5.1.0" - dependencies: - lru-cache: "npm:^4.0.1" - shebang-command: "npm:^1.2.0" - which: "npm:^1.2.9" - checksum: 10c0/1918621fddb9f8c61e02118b2dbf81f611ccd1544ceaca0d026525341832b8511ce2504c60f935dbc06b35e5ef156fe8c1e72708c27dd486f034e9c0e1e07201 - languageName: node - linkType: hard - "cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" @@ -12717,20 +11152,13 @@ __metadata: languageName: node linkType: hard -"crypt@npm:>= 0.0.1, crypt@npm:~0.0.1": +"crypt@npm:>= 0.0.1": version: 0.0.2 resolution: "crypt@npm:0.0.2" checksum: 10c0/adbf263441dd801665d5425f044647533f39f4612544071b1471962209d235042fb703c27eea2795c7c53e1dfc242405173003f83cf4f4761a633d11f9653f18 languageName: node linkType: hard -"crypto-random-string@npm:^1.0.0": - version: 1.0.0 - resolution: "crypto-random-string@npm:1.0.0" - checksum: 10c0/0cb4dbbb895656919d1de11ba43829a3527edddb85a9c49c9d4c4eb783d3b03fc9f371cefee62c87082fd8758db2798a52a9cad48a7381826190d3c2cf858e4a - languageName: node - linkType: hard - "crypto@npm:^1.0.1": version: 1.0.1 resolution: "crypto@npm:1.0.1" @@ -12788,15 +11216,6 @@ __metadata: languageName: node linkType: hard -"cssesc@npm:^3.0.0": - version: 3.0.0 - resolution: "cssesc@npm:3.0.0" - bin: - cssesc: bin/cssesc - checksum: 10c0/6bcfd898662671be15ae7827120472c5667afb3d7429f1f917737f3bf84c4176003228131b643ae74543f17a394446247df090c597bb9a728cce298606ed0aa7 - languageName: node - linkType: hard - "csso@npm:^5.0.5": version: 5.0.5 resolution: "csso@npm:5.0.5" @@ -12806,27 +11225,13 @@ __metadata: languageName: node linkType: hard -"csstype@npm:^3.0.2, csstype@npm:^3.1.3": +"csstype@npm:^3.0.2": version: 3.1.3 resolution: "csstype@npm:3.1.3" checksum: 10c0/80c089d6f7e0c5b2bd83cf0539ab41474198579584fa10d86d0cafe0642202343cbc119e076a0b1aece191989477081415d66c9fefbf3c957fc2fc4b7009f248 languageName: node linkType: hard -"dag-map@npm:~1.0.0": - version: 1.0.2 - resolution: "dag-map@npm:1.0.2" - checksum: 10c0/1b5ee77cbc9caf61178db592ecc8fa8f6905fd4b0571176af74d2fece2332b68c0e9e8275f1c2c76bc1f0c84a9dc973f87233db7a06375bd13254fae9866867f - languageName: node - linkType: hard - -"damerau-levenshtein@npm:^1.0.8": - version: 1.0.8 - resolution: "damerau-levenshtein@npm:1.0.8" - checksum: 10c0/4c2647e0f42acaee7d068756c1d396e296c3556f9c8314bac1ac63ffb236217ef0e7e58602b18bb2173deec7ec8e0cac8e27cccf8f5526666b4ff11a13ad54a3 - languageName: node - linkType: hard - "data-uri-to-buffer@npm:^6.0.2": version: 6.0.2 resolution: "data-uri-to-buffer@npm:6.0.2" @@ -12888,7 +11293,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:2, debug@npm:2.6.9, debug@npm:^2.1.3, debug@npm:^2.2.0, debug@npm:^2.3.3, debug@npm:^2.6.9": +"debug@npm:2.6.9, debug@npm:^2.2.0, debug@npm:^2.6.9": version: 2.6.9 resolution: "debug@npm:2.6.9" dependencies: @@ -12897,15 +11302,6 @@ __metadata: languageName: node linkType: hard -"debug@npm:2.2.0, debug@npm:~2.2.0": - version: 2.2.0 - resolution: "debug@npm:2.2.0" - dependencies: - ms: "npm:0.7.1" - checksum: 10c0/d24d6200c9d9bef20e1dcb823a9895193a45c39505606468735f387bdd850a21baf4c7841df1787f9a02596cbf0f111d60726ba3fa7511e22198b91b33440fe9 - languageName: node - linkType: hard - "debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.4.0, debug@npm:^4.4.1": version: 4.4.1 resolution: "debug@npm:4.4.1" @@ -12930,15 +11326,6 @@ __metadata: languageName: node linkType: hard -"debug@npm:^3.2.6, debug@npm:^3.2.7": - version: 3.2.7 - resolution: "debug@npm:3.2.7" - dependencies: - ms: "npm:^2.1.1" - checksum: 10c0/37d96ae42cbc71c14844d2ae3ba55adf462ec89fd3a999459dec3833944cd999af6007ff29c780f1c61153bcaaf2c842d1e4ce1ec621e4fc4923244942e4a02a - languageName: node - linkType: hard - "debug@npm:~4.3.1, debug@npm:~4.3.2": version: 4.3.7 resolution: "debug@npm:4.3.7" @@ -12965,7 +11352,7 @@ __metadata: languageName: node linkType: hard -"decode-uri-component@npm:^0.2.0, decode-uri-component@npm:^0.2.2": +"decode-uri-component@npm:^0.2.2": version: 0.2.2 resolution: "decode-uri-component@npm:0.2.2" checksum: 10c0/1f4fa54eb740414a816b3f6c24818fbfcabd74ac478391e9f4e2282c994127db02010ce804f3d08e38255493cfe68608b3f5c8e09fd6efc4ae46c807691f7a31 @@ -13009,7 +11396,7 @@ __metadata: languageName: node linkType: hard -"deep-extend@npm:^0.6.0, deep-extend@npm:~0.6.0": +"deep-extend@npm:~0.6.0": version: 0.6.0 resolution: "deep-extend@npm:0.6.0" checksum: 10c0/1c6b0abcdb901e13a44c7d699116d3d4279fdb261983122a3783e7273844d5f2537dc2e1c454a23fcf645917f93fbf8d07101c1d03c015a87faa662755212566 @@ -13075,34 +11462,6 @@ __metadata: languageName: node linkType: hard -"define-property@npm:^0.2.5": - version: 0.2.5 - resolution: "define-property@npm:0.2.5" - dependencies: - is-descriptor: "npm:^0.1.0" - checksum: 10c0/9986915c0893818dedc9ca23eaf41370667762fd83ad8aa4bf026a28563120dbaacebdfbfbf2b18d3b929026b9c6ee972df1dbf22de8fafb5fe6ef18361e4750 - languageName: node - linkType: hard - -"define-property@npm:^1.0.0": - version: 1.0.0 - resolution: "define-property@npm:1.0.0" - dependencies: - is-descriptor: "npm:^1.0.0" - checksum: 10c0/d7cf09db10d55df305f541694ed51dafc776ad9bb8a24428899c9f2d36b11ab38dce5527a81458d1b5e7c389f8cbe803b4abad6e91a0037a329d153b84fc975e - languageName: node - linkType: hard - -"define-property@npm:^2.0.2": - version: 2.0.2 - resolution: "define-property@npm:2.0.2" - dependencies: - is-descriptor: "npm:^1.0.2" - isobject: "npm:^3.0.1" - checksum: 10c0/f91a08ad008fa764172a2c072adc7312f10217ade89ddaea23018321c6d71b2b68b8c229141ed2064179404e345c537f1a2457c379824813695b51a6ad3e4969 - languageName: node - linkType: hard - "degenerator@npm:^5.0.0": version: 5.0.1 resolution: "degenerator@npm:5.0.1" @@ -13135,13 +11494,6 @@ __metadata: languageName: node linkType: hard -"depd@npm:~1.0.1": - version: 1.0.1 - resolution: "depd@npm:1.0.1" - checksum: 10c0/c8453ebf9cf819e6847693278d34d21dc42a16c5f30099673339e809212d291d884837572478008a910b877eb69058be19f1aeb06c4c73ad574963fc98abd078 - languageName: node - linkType: hard - "destroy@npm:1.2.0": version: 1.2.0 resolution: "destroy@npm:1.2.0" @@ -13170,16 +11522,6 @@ __metadata: languageName: node linkType: hard -"dezalgo@npm:^1.0.4": - version: 1.0.4 - resolution: "dezalgo@npm:1.0.4" - dependencies: - asap: "npm:^2.0.0" - wrappy: "npm:1" - checksum: 10c0/8a870ed42eade9a397e6141fe5c025148a59ed52f1f28b1db5de216b4d57f0af7a257070c3af7ce3d5508c1ce9dd5009028a76f4b2cc9370dc56551d2355fad8 - languageName: node - linkType: hard - "diacritics@npm:1.3.0": version: 1.3.0 resolution: "diacritics@npm:1.3.0" @@ -13187,23 +11529,6 @@ __metadata: languageName: node linkType: hard -"dicer@npm:0.2.5": - version: 0.2.5 - resolution: "dicer@npm:0.2.5" - dependencies: - readable-stream: "npm:1.1.x" - streamsearch: "npm:0.1.2" - checksum: 10c0/c0520cee8c4d8c7e2db4f8fe30c0fdbf96d9623d53a65b54f4e0d9a89b76c3e0c397de54a1530c1d4b1788d1e87ff3ca5800e3ba93c748e0cd24827b505fb5e7 - languageName: node - linkType: hard - -"didyoumean@npm:^1.2.2": - version: 1.2.2 - resolution: "didyoumean@npm:1.2.2" - checksum: 10c0/95d0b53d23b851aacff56dfadb7ecfedce49da4232233baecfeecb7710248c4aa03f0aa8995062f0acafaf925adf8536bd7044a2e68316fd7d411477599bc27b - languageName: node - linkType: hard - "diff-sequences@npm:^29.6.3": version: 29.6.3 resolution: "diff-sequences@npm:29.6.3" @@ -13211,13 +11536,6 @@ __metadata: languageName: node linkType: hard -"diff@npm:1.4.0": - version: 1.4.0 - resolution: "diff@npm:1.4.0" - checksum: 10c0/516ce8f6a85e2025ea039cd7ce5491b0f8cda1a9d8a9c7998aa4a8a49ba94d24ff1c7e91e5b23e04ae78e1f788a19c03b24709bb619fa15d9627d657b5aa86f3 - languageName: node - linkType: hard - "diff@npm:^3.1.0": version: 3.5.0 resolution: "diff@npm:3.5.0" @@ -13282,16 +11600,6 @@ __metadata: languageName: node linkType: hard -"dom-helpers@npm:^5.0.1": - version: 5.2.1 - resolution: "dom-helpers@npm:5.2.1" - dependencies: - "@babel/runtime": "npm:^7.8.7" - csstype: "npm:^3.0.2" - checksum: 10c0/f735074d66dd759b36b158fa26e9d00c9388ee0e8c9b16af941c38f014a37fc80782de83afefd621681b19ac0501034b4f1c4a3bff5caa1b8667f0212b5e124c - languageName: node - linkType: hard - "dom-serializer@npm:^2.0.0": version: 2.0.0 resolution: "dom-serializer@npm:2.0.0" @@ -13340,15 +11648,6 @@ __metadata: languageName: node linkType: hard -"dot-prop@npm:^4.2.1": - version: 4.2.1 - resolution: "dot-prop@npm:4.2.1" - dependencies: - is-obj: "npm:^1.0.0" - checksum: 10c0/ea0a98871ef4de0cce05325979517a43b70eb3a3671254fce78f2629c125d5ddb69cfdd5570ace4e41d9f02ced06374ea0444d1aeae70290a19f73e02093318e - languageName: node - linkType: hard - "dotenv-cli@npm:^7.4.2": version: 7.4.4 resolution: "dotenv-cli@npm:7.4.4" @@ -13395,13 +11694,6 @@ __metadata: languageName: node linkType: hard -"duplexer3@npm:^0.1.4": - version: 0.1.5 - resolution: "duplexer3@npm:0.1.5" - checksum: 10c0/02195030d61c4d6a2a34eca71639f2ea5e05cb963490e5bd9527623c2ac7f50c33842a34d14777ea9cbfd9bc2be5a84065560b897d9fabb99346058a5b86ca98 - languageName: node - linkType: hard - "duplexer@npm:^0.1.2": version: 0.1.2 resolution: "duplexer@npm:0.1.2" @@ -13416,13 +11708,6 @@ __metadata: languageName: node linkType: hard -"ee-first@npm:1.1.0": - version: 1.1.0 - resolution: "ee-first@npm:1.1.0" - checksum: 10c0/a2c35602b8ea8bc65a56c2fecad8dfc0a1e6cfe242cda0b35bc21c8b99dfb2d0b29d72183f7133c92b43526603b022f52dcb1c971c54022fa7d8152e5e73cbc6 - languageName: node - linkType: hard - "ee-first@npm:1.1.1": version: 1.1.1 resolution: "ee-first@npm:1.1.1" @@ -13463,30 +11748,6 @@ __metadata: languageName: node linkType: hard -"elysia@npm:^1.1.23, elysia@npm:latest": - version: 1.3.3 - resolution: "elysia@npm:1.3.3" - dependencies: - "@sinclair/typebox": "npm:^0.34.33" - cookie: "npm:^1.0.2" - exact-mirror: "npm:0.1.2" - fast-decode-uri-component: "npm:^1.0.1" - openapi-types: "npm:^12.1.3" - peerDependencies: - "@sinclair/typebox": ">= 0.34.0" - exact-mirror: ">= 0.0.9" - file-type: ">= 20.0.0" - openapi-types: ">= 12.0.0" - typescript: ">= 5.0.0" - dependenciesMeta: - "@sinclair/typebox": - optional: true - openapi-types: - optional: true - checksum: 10c0/61a339f6655acea2664e83fc11d860dac8b1b73161d723bce07d0e0599136e1bddd6e2a627846d5cade7408c090dbae98a4c34fdabe60618449887ccce720d54 - languageName: node - linkType: hard - "emittery@npm:^0.13.1": version: 0.13.1 resolution: "emittery@npm:0.13.1" @@ -13777,7 +12038,7 @@ __metadata: languageName: node linkType: hard -"es-shim-unscopables@npm:^1.0.2, es-shim-unscopables@npm:^1.1.0": +"es-shim-unscopables@npm:^1.0.2": version: 1.1.0 resolution: "es-shim-unscopables@npm:1.1.0" dependencies: @@ -13914,14 +12175,7 @@ __metadata: languageName: node linkType: hard -"escape-string-regexp@npm:1.0.2": - version: 1.0.2 - resolution: "escape-string-regexp@npm:1.0.2" - checksum: 10c0/df696f5330ee177510299abfaa2ead4be9aae024a22fd388acfb0b49fdfe8d45d15cbc6c960934fb073efd2fd68c80a9dee5d3a3ac30097baec08fd8de4b5cd5 - languageName: node - linkType: hard - -"escape-string-regexp@npm:^1.0.2, escape-string-regexp@npm:^1.0.5": +"escape-string-regexp@npm:^1.0.5": version: 1.0.5 resolution: "escape-string-regexp@npm:1.0.5" checksum: 10c0/a968ad453dd0c2724e14a4f20e177aaf32bb384ab41b674a8454afe9a41c5e6fe8903323e0a1052f56289d04bd600f81278edf140b0fcc02f5cac98d0f5b5371 @@ -13998,30 +12252,6 @@ __metadata: languageName: node linkType: hard -"eslint-config-next@npm:14.2.8": - version: 14.2.8 - resolution: "eslint-config-next@npm:14.2.8" - dependencies: - "@next/eslint-plugin-next": "npm:14.2.8" - "@rushstack/eslint-patch": "npm:^1.3.3" - "@typescript-eslint/eslint-plugin": "npm:^5.4.2 || ^6.0.0 || 7.0.0 - 7.2.0" - "@typescript-eslint/parser": "npm:^5.4.2 || ^6.0.0 || 7.0.0 - 7.2.0" - eslint-import-resolver-node: "npm:^0.3.6" - eslint-import-resolver-typescript: "npm:^3.5.2" - eslint-plugin-import: "npm:^2.28.1" - eslint-plugin-jsx-a11y: "npm:^6.7.1" - eslint-plugin-react: "npm:^7.33.2" - eslint-plugin-react-hooks: "npm:^4.5.0 || 5.0.0-canary-7118f5dd7-20230705" - peerDependencies: - eslint: ^7.23.0 || ^8.0.0 - typescript: ">=3.3.1" - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/932538864965157d94e6ad32f674afee40fb72d81070550e29bce1b5c8c52f5221f9ddbf483622a29507c760b6317ee7c660590ad8454d23e232a31e6371cc0b - languageName: node - linkType: hard - "eslint-config-prettier@npm:^10.1.2": version: 10.1.2 resolution: "eslint-config-prettier@npm:10.1.2" @@ -14044,53 +12274,6 @@ __metadata: languageName: node linkType: hard -"eslint-import-resolver-node@npm:^0.3.6, eslint-import-resolver-node@npm:^0.3.9": - version: 0.3.9 - resolution: "eslint-import-resolver-node@npm:0.3.9" - dependencies: - debug: "npm:^3.2.7" - is-core-module: "npm:^2.13.0" - resolve: "npm:^1.22.4" - checksum: 10c0/0ea8a24a72328a51fd95aa8f660dcca74c1429806737cf10261ab90cfcaaf62fd1eff664b76a44270868e0a932711a81b250053942595bcd00a93b1c1575dd61 - languageName: node - linkType: hard - -"eslint-import-resolver-typescript@npm:^3.5.2": - version: 3.10.1 - resolution: "eslint-import-resolver-typescript@npm:3.10.1" - dependencies: - "@nolyfill/is-core-module": "npm:1.0.39" - debug: "npm:^4.4.0" - get-tsconfig: "npm:^4.10.0" - is-bun-module: "npm:^2.0.0" - stable-hash: "npm:^0.0.5" - tinyglobby: "npm:^0.2.13" - unrs-resolver: "npm:^1.6.2" - peerDependencies: - eslint: "*" - eslint-plugin-import: "*" - eslint-plugin-import-x: "*" - peerDependenciesMeta: - eslint-plugin-import: - optional: true - eslint-plugin-import-x: - optional: true - checksum: 10c0/02ba72cf757753ab9250806c066d09082e00807b7b6525d7687e1c0710bc3f6947e39120227fe1f93dabea3510776d86fb3fd769466ba3c46ce67e9f874cb702 - languageName: node - linkType: hard - -"eslint-module-utils@npm:^2.12.0": - version: 2.12.0 - resolution: "eslint-module-utils@npm:2.12.0" - dependencies: - debug: "npm:^3.2.7" - peerDependenciesMeta: - eslint: - optional: true - checksum: 10c0/4d8b46dcd525d71276f9be9ffac1d2be61c9d54cc53c992e6333cf957840dee09381842b1acbbb15fc6b255ebab99cd481c5007ab438e5455a14abe1a0468558 - languageName: node - linkType: hard - "eslint-plugin-eslint-comments@npm:^3.2.0": version: 3.2.0 resolution: "eslint-plugin-eslint-comments@npm:3.2.0" @@ -14116,35 +12299,6 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-import@npm:^2.28.1": - version: 2.31.0 - resolution: "eslint-plugin-import@npm:2.31.0" - dependencies: - "@rtsao/scc": "npm:^1.1.0" - array-includes: "npm:^3.1.8" - array.prototype.findlastindex: "npm:^1.2.5" - array.prototype.flat: "npm:^1.3.2" - array.prototype.flatmap: "npm:^1.3.2" - debug: "npm:^3.2.7" - doctrine: "npm:^2.1.0" - eslint-import-resolver-node: "npm:^0.3.9" - eslint-module-utils: "npm:^2.12.0" - hasown: "npm:^2.0.2" - is-core-module: "npm:^2.15.1" - is-glob: "npm:^4.0.3" - minimatch: "npm:^3.1.2" - object.fromentries: "npm:^2.0.8" - object.groupby: "npm:^1.0.3" - object.values: "npm:^1.2.0" - semver: "npm:^6.3.1" - string.prototype.trimend: "npm:^1.0.8" - tsconfig-paths: "npm:^3.15.0" - peerDependencies: - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 - checksum: 10c0/e21d116ddd1900e091ad120b3eb68c5dd5437fe2c930f1211781cd38b246f090a6b74d5f3800b8255a0ed29782591521ad44eb21c5534960a8f1fb4040fd913a - languageName: node - linkType: hard - "eslint-plugin-jest@npm:^27.9.0": version: 27.9.0 resolution: "eslint-plugin-jest@npm:27.9.0" @@ -14181,31 +12335,6 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-jsx-a11y@npm:^6.7.1": - version: 6.10.2 - resolution: "eslint-plugin-jsx-a11y@npm:6.10.2" - dependencies: - aria-query: "npm:^5.3.2" - array-includes: "npm:^3.1.8" - array.prototype.flatmap: "npm:^1.3.2" - ast-types-flow: "npm:^0.0.8" - axe-core: "npm:^4.10.0" - axobject-query: "npm:^4.1.0" - damerau-levenshtein: "npm:^1.0.8" - emoji-regex: "npm:^9.2.2" - hasown: "npm:^2.0.2" - jsx-ast-utils: "npm:^3.3.5" - language-tags: "npm:^1.0.9" - minimatch: "npm:^3.1.2" - object.fromentries: "npm:^2.0.8" - safe-regex-test: "npm:^1.0.3" - string.prototype.includes: "npm:^2.0.1" - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 - checksum: 10c0/d93354e03b0cf66f018d5c50964e074dffe4ddf1f9b535fa020d19c4ae45f89c1a16e9391ca61ac3b19f7042c751ac0d361a056a65cbd1de24718a53ff8daa6e - languageName: node - linkType: hard - "eslint-plugin-prettier@npm:^5.2.6": version: 5.2.6 resolution: "eslint-plugin-prettier@npm:5.2.6" @@ -14226,15 +12355,6 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-react-hooks@npm:^4.5.0 || 5.0.0-canary-7118f5dd7-20230705": - version: 5.0.0-canary-7118f5dd7-20230705 - resolution: "eslint-plugin-react-hooks@npm:5.0.0-canary-7118f5dd7-20230705" - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - checksum: 10c0/554c4e426bfeb126155510dcba8345391426af147ee629f1c56c9ef6af08340d11008213e4e15b0138830af2c4439d7158da2091987f7efb01aeab662c44b274 - languageName: node - linkType: hard - "eslint-plugin-react-hooks@npm:^4.6.0": version: 4.6.2 resolution: "eslint-plugin-react-hooks@npm:4.6.2" @@ -14262,7 +12382,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-react@npm:^7.30.1, eslint-plugin-react@npm:^7.33.2": +"eslint-plugin-react@npm:^7.30.1": version: 7.37.5 resolution: "eslint-plugin-react@npm:7.37.5" dependencies: @@ -14340,7 +12460,7 @@ __metadata: languageName: node linkType: hard -"eslint@npm:^8, eslint@npm:^8.19.0": +"eslint@npm:^8.19.0": version: 8.57.1 resolution: "eslint@npm:8.57.1" dependencies: @@ -14669,13 +12789,6 @@ __metadata: languageName: node linkType: hard -"eventemitter3@npm:5.0.1": - version: 5.0.1 - resolution: "eventemitter3@npm:5.0.1" - checksum: 10c0/4ba5c00c506e6c786b4d6262cfbce90ddc14c10d4667e5c83ae993c9de88aa856033994dd2b35b83e8dc1170e224e66a319fa80adc4c32adcd2379bbc75da814 - languageName: node - linkType: hard - "events@npm:^3.2.0, events@npm:^3.3.0": version: 3.3.0 resolution: "events@npm:3.3.0" @@ -14694,33 +12807,6 @@ __metadata: languageName: node linkType: hard -"exact-mirror@npm:0.1.2": - version: 0.1.2 - resolution: "exact-mirror@npm:0.1.2" - peerDependencies: - "@sinclair/typebox": ^0.34.15 - peerDependenciesMeta: - "@sinclair/typebox": - optional: true - checksum: 10c0/26e8924494b6a1e3db4bca9376a33da0b50821f486158fd6bda46f82af863ff856117b4ca5b864004400668550bf219879c117e8179683c418f8847bd0507b96 - languageName: node - linkType: hard - -"execa@npm:^0.7.0": - version: 0.7.0 - resolution: "execa@npm:0.7.0" - dependencies: - cross-spawn: "npm:^5.0.1" - get-stream: "npm:^3.0.0" - is-stream: "npm:^1.1.0" - npm-run-path: "npm:^2.0.0" - p-finally: "npm:^1.0.0" - signal-exit: "npm:^3.0.0" - strip-eof: "npm:^1.0.0" - checksum: 10c0/812f1776e2a6b2226532e43c1af87d8a12e26de03a06e7e043f653acf5565e0656f5f6c64d66726fefa17178ac129caaa419a50905934e7c4a846417abb25d4a - languageName: node - linkType: hard - "execa@npm:^5.0.0, execa@npm:^5.1.1": version: 5.1.1 resolution: "execa@npm:5.1.1" @@ -14738,13 +12824,6 @@ __metadata: languageName: node linkType: hard -"exit-hook@npm:^1.0.0": - version: 1.1.1 - resolution: "exit-hook@npm:1.1.1" - checksum: 10c0/6485772b1f5fdc5c8bf0cf9e9ba430f5b1e1ced2976be0bc6474b695358be32374a59370f5a3cec452c1b786b5f181035f3a10c58f9c639d7a7218e1b49e1a3a - languageName: node - linkType: hard - "exit@npm:^0.1.2": version: 0.1.2 resolution: "exit@npm:0.1.2" @@ -14752,21 +12831,6 @@ __metadata: languageName: node linkType: hard -"expand-brackets@npm:^2.1.4": - version: 2.1.4 - resolution: "expand-brackets@npm:2.1.4" - dependencies: - debug: "npm:^2.3.3" - define-property: "npm:^0.2.5" - extend-shallow: "npm:^2.0.1" - posix-character-classes: "npm:^0.1.0" - regex-not: "npm:^1.0.0" - snapdragon: "npm:^0.8.1" - to-regex: "npm:^3.0.1" - checksum: 10c0/3e2fb95d2d7d7231486493fd65db913927b656b6fcdfcce41e139c0991a72204af619ad4acb1be75ed994ca49edb7995ef241dbf8cf44dc3c03d211328428a87 - languageName: node - linkType: hard - "expect@npm:*, expect@npm:^29.0.0, expect@npm:^29.7.0": version: 29.7.0 resolution: "expect@npm:29.7.0" @@ -14796,48 +12860,6 @@ __metadata: languageName: node linkType: hard -"extend-shallow@npm:^2.0.1": - version: 2.0.1 - resolution: "extend-shallow@npm:2.0.1" - dependencies: - is-extendable: "npm:^0.1.0" - checksum: 10c0/ee1cb0a18c9faddb42d791b2d64867bd6cfd0f3affb711782eb6e894dd193e2934a7f529426aac7c8ddb31ac5d38000a00aa2caf08aa3dfc3e1c8ff6ba340bd9 - languageName: node - linkType: hard - -"extend-shallow@npm:^3.0.0, extend-shallow@npm:^3.0.2": - version: 3.0.2 - resolution: "extend-shallow@npm:3.0.2" - dependencies: - assign-symbols: "npm:^1.0.0" - is-extendable: "npm:^1.0.1" - checksum: 10c0/f39581b8f98e3ad94995e33214fff725b0297cf09f2725b6f624551cfb71e0764accfd0af80becc0182af5014d2a57b31b85ec999f9eb8a6c45af81752feac9a - languageName: node - linkType: hard - -"extend@npm:3.0.0": - version: 3.0.0 - resolution: "extend@npm:3.0.0" - checksum: 10c0/67a867fd39abcd36f3d11e99c6e2808d0237214239ca7a194278b1a91790945a3755e22fd4e16521a247e511f9bce866142b483e1ca61d33d7c2317aa98ecf5a - languageName: node - linkType: hard - -"extglob@npm:^2.0.4": - version: 2.0.4 - resolution: "extglob@npm:2.0.4" - dependencies: - array-unique: "npm:^0.3.2" - define-property: "npm:^1.0.0" - expand-brackets: "npm:^2.1.4" - extend-shallow: "npm:^2.0.1" - fragment-cache: "npm:^0.2.1" - regex-not: "npm:^1.0.0" - snapdragon: "npm:^0.8.1" - to-regex: "npm:^3.0.1" - checksum: 10c0/e1a891342e2010d046143016c6c03d58455c2c96c30bf5570ea07929984ee7d48fad86b363aee08f7a8a638f5c3a66906429b21ecb19bc8e90df56a001cd282c - languageName: node - linkType: hard - "extract-zip@npm:2.0.1, extract-zip@npm:^2.0.1": version: 2.0.1 resolution: "extract-zip@npm:2.0.1" @@ -14862,13 +12884,6 @@ __metadata: languageName: node linkType: hard -"fast-decode-uri-component@npm:^1.0.1": - version: 1.0.1 - resolution: "fast-decode-uri-component@npm:1.0.1" - checksum: 10c0/039d50c2e99d64f999c3f2126c23fbf75a04a4117e218a149ca0b1d2aeb8c834b7b19d643b9d35d4eabce357189a6a94085f78cf48869e6e26cc59b036284bc3 - languageName: node - linkType: hard - "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" @@ -14917,13 +12932,6 @@ __metadata: languageName: node linkType: hard -"fast-safe-stringify@npm:^2.1.1": - version: 2.1.1 - resolution: "fast-safe-stringify@npm:2.1.1" - checksum: 10c0/d90ec1c963394919828872f21edaa3ad6f1dddd288d2bd4e977027afff09f5db40f94e39536d4646f7e01761d704d72d51dce5af1b93717f3489ef808f5f4e4d - languageName: node - linkType: hard - "fast-uri@npm:^3.0.1": version: 3.0.6 resolution: "fast-uri@npm:3.0.6" @@ -15055,16 +13063,6 @@ __metadata: languageName: node linkType: hard -"figures@npm:^1.3.5": - version: 1.7.0 - resolution: "figures@npm:1.7.0" - dependencies: - escape-string-regexp: "npm:^1.0.5" - object-assign: "npm:^4.1.0" - checksum: 10c0/a10942b0eec3372bf61822ab130d2bbecdf527d551b0b013fbe7175b7a0238ead644ee8930a1a3cb872fb9ab2ec27df30e303765a3b70b97852e2e9ee43bdff3 - languageName: node - linkType: hard - "file-entry-cache@npm:^6.0.1": version: 6.0.1 resolution: "file-entry-cache@npm:6.0.1" @@ -15074,13 +13072,6 @@ __metadata: languageName: node linkType: hard -"file-uri-to-path@npm:1.0.0": - version: 1.0.0 - resolution: "file-uri-to-path@npm:1.0.0" - checksum: 10c0/3b545e3a341d322d368e880e1c204ef55f1d45cdea65f7efc6c6ce9e0c4d22d802d5629320eb779d006fe59624ac17b0e848d83cc5af7cd101f206cb704f5519 - languageName: node - linkType: hard - "filelist@npm:^1.0.4": version: 1.0.4 resolution: "filelist@npm:1.0.4" @@ -15090,21 +13081,9 @@ __metadata: languageName: node linkType: hard -"fill-range@npm:^4.0.0": - version: 4.0.0 - resolution: "fill-range@npm:4.0.0" - dependencies: - extend-shallow: "npm:^2.0.1" - is-number: "npm:^3.0.0" - repeat-string: "npm:^1.6.1" - to-regex-range: "npm:^2.1.0" - checksum: 10c0/ccd57b7c43d7e28a1f8a60adfa3c401629c08e2f121565eece95e2386ebc64dedc7128d8c3448342aabf19db0c55a34f425f148400c7a7be9a606ba48749e089 - languageName: node - linkType: hard - -"fill-range@npm:^7.1.1": - version: 7.1.1 - resolution: "fill-range@npm:7.1.1" +"fill-range@npm:^7.1.1": + version: 7.1.1 + resolution: "fill-range@npm:7.1.1" dependencies: to-regex-range: "npm:^5.0.1" checksum: 10c0/b75b691bbe065472f38824f694c2f7449d7f5004aa950426a2c28f0306c60db9b880c0b0e4ed819997ffb882d1da02cfcfc819bddc94d71627f5269682edf018 @@ -15162,13 +13141,6 @@ __metadata: languageName: node linkType: hard -"find-root@npm:^1.1.0": - version: 1.1.0 - resolution: "find-root@npm:1.1.0" - checksum: 10c0/1abc7f3bf2f8d78ff26d9e00ce9d0f7b32e5ff6d1da2857bcdf4746134c422282b091c672cde0572cac3840713487e0a7a636af9aa1b74cb11894b447a521efa - languageName: node - linkType: hard - "find-up@npm:^3.0.0": version: 3.0.0 resolution: "find-up@npm:3.0.0" @@ -15281,7 +13253,7 @@ __metadata: languageName: node linkType: hard -"for-in@npm:^1.0.1, for-in@npm:^1.0.2": +"for-in@npm:^1.0.1": version: 1.0.2 resolution: "for-in@npm:1.0.2" checksum: 10c0/42bb609d564b1dc340e1996868b67961257fd03a48d7fdafd4f5119530b87f962be6b4d5b7e3a3fc84c9854d149494b1d358e0b0ce9837e64c4c6603a49451d6 @@ -15307,17 +13279,6 @@ __metadata: languageName: node linkType: hard -"form-data@npm:1.0.0-rc3": - version: 1.0.0-rc3 - resolution: "form-data@npm:1.0.0-rc3" - dependencies: - async: "npm:^1.4.0" - combined-stream: "npm:^1.0.5" - mime-types: "npm:^2.1.3" - checksum: 10c0/d67674a76f46253f69aebdc5c1c86aa123385940d147346b2f801681656ab5df6b82bd9568483e1579fd53bf277795f2da7592c6a842893465ef69e9073c342f - languageName: node - linkType: hard - "form-data@npm:^2.2.0": version: 2.5.3 resolution: "form-data@npm:2.5.3" @@ -15343,25 +13304,6 @@ __metadata: languageName: node linkType: hard -"formidable@npm:^2.0.1": - version: 2.1.5 - resolution: "formidable@npm:2.1.5" - dependencies: - "@paralleldrive/cuid2": "npm:^2.2.2" - dezalgo: "npm:^1.0.4" - once: "npm:^1.4.0" - qs: "npm:^6.11.0" - checksum: 10c0/2c68ca6cccc1ac3de497c50236631fafea8e1a09396d88b4dd2dc9db6029b5abaeb6747b8b97ebc1143cd40cf62c27ba485b8c6317088c066fc999af3ac621d4 - languageName: node - linkType: hard - -"formidable@npm:~1.0.14": - version: 1.0.17 - resolution: "formidable@npm:1.0.17" - checksum: 10c0/651c7394574ab6b451467200495bcb5064776419d883e6f82512f31019a0528de90c729d28d89d519eb00cb456302206aa389a4d63d2aba69eef5653ba863714 - languageName: node - linkType: hard - "fp-ts@npm:1.19.3": version: 1.19.3 resolution: "fp-ts@npm:1.19.3" @@ -15376,15 +13318,6 @@ __metadata: languageName: node linkType: hard -"fragment-cache@npm:^0.2.1": - version: 0.2.1 - resolution: "fragment-cache@npm:0.2.1" - dependencies: - map-cache: "npm:^0.2.2" - checksum: 10c0/5891d1c1d1d5e1a7fb3ccf28515c06731476fa88f7a50f4ede8a0d8d239a338448e7f7cc8b73db48da19c229fa30066104fe6489862065a4f1ed591c42fbeabf - languageName: node - linkType: hard - "framer-motion@npm:^6.5.1": version: 6.5.1 resolution: "framer-motion@npm:6.5.1" @@ -15422,18 +13355,6 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^0.24.0": - version: 0.24.0 - resolution: "fs-extra@npm:0.24.0" - dependencies: - graceful-fs: "npm:^4.1.2" - jsonfile: "npm:^2.1.0" - path-is-absolute: "npm:^1.0.0" - rimraf: "npm:^2.2.8" - checksum: 10c0/bd60b201302789155de4f5c4c2bfcc389a077cf4aaea47fe8f23c5c209cd2dc00cdaa1181978572e38404ed47ccfda2f0e68bfd2616af4d554318a4ecb925233 - languageName: node - linkType: hard - "fs-extra@npm:^10.0.0": version: 10.1.0 resolution: "fs-extra@npm:10.1.0" @@ -15518,17 +13439,6 @@ __metadata: languageName: node linkType: hard -"fsevents@npm:^1.2.7": - version: 1.2.13 - resolution: "fsevents@npm:1.2.13" - dependencies: - bindings: "npm:^1.5.0" - nan: "npm:^2.12.1" - checksum: 10c0/4427ff08db9ee7327f2c3ad58ec56f9096a917eed861bfffaa2e2be419479cdf37d00750869ab9ecbf5f59f32ad999bd59577d73fc639193e6c0ce52bb253e02 - conditions: os=darwin - languageName: node - linkType: hard - "fsevents@npm:^2.3.2, fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": version: 2.3.3 resolution: "fsevents@npm:2.3.3" @@ -15539,16 +13449,6 @@ __metadata: languageName: node linkType: hard -"fsevents@patch:fsevents@npm%3A^1.2.7#optional!builtin": - version: 1.2.13 - resolution: "fsevents@patch:fsevents@npm%3A1.2.13#optional!builtin::version=1.2.13&hash=d11327" - dependencies: - bindings: "npm:^1.5.0" - nan: "npm:^2.12.1" - conditions: os=darwin - languageName: node - linkType: hard - "fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": version: 2.3.3 resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" @@ -15663,13 +13563,6 @@ __metadata: languageName: node linkType: hard -"get-stream@npm:^3.0.0": - version: 3.0.0 - resolution: "get-stream@npm:3.0.0" - checksum: 10c0/003f5f3b8870da59c6aafdf6ed7e7b07b48c2f8629cd461bd3900726548b6b8cfa2e14d6b7814fbb08f07a42f4f738407fa70b989928b2783a76b278505bba22 - languageName: node - linkType: hard - "get-stream@npm:^5.1.0": version: 5.2.0 resolution: "get-stream@npm:5.2.0" @@ -15697,7 +13590,7 @@ __metadata: languageName: node linkType: hard -"get-tsconfig@npm:^4.10.0, get-tsconfig@npm:^4.7.5": +"get-tsconfig@npm:^4.7.5": version: 4.10.1 resolution: "get-tsconfig@npm:4.10.1" dependencies: @@ -15717,13 +13610,6 @@ __metadata: languageName: node linkType: hard -"get-value@npm:^2.0.3, get-value@npm:^2.0.6": - version: 2.0.6 - resolution: "get-value@npm:2.0.6" - checksum: 10c0/f069c132791b357c8fc4adfe9e2929b0a2c6e95f98ca7bc6fcbc27f8a302e552f86b4ae61ec56d9e9ac2544b93b6a39743d479866a37b43fcc104088ba74f0d9 - languageName: node - linkType: hard - "ghost-testrpc@npm:^0.0.2": version: 0.0.2 resolution: "ghost-testrpc@npm:0.0.2" @@ -15736,16 +13622,6 @@ __metadata: languageName: node linkType: hard -"glob-parent@npm:^3.1.0": - version: 3.1.0 - resolution: "glob-parent@npm:3.1.0" - dependencies: - is-glob: "npm:^3.1.0" - path-dirname: "npm:^1.0.0" - checksum: 10c0/bfa89ce5ae1dfea4c2ece7b61d2ea230d87fcbec7472915cfdb3f4caf688a91ecb0dc86ae39b1e17505adce7e64cae3b971d64dc66091f3a0131169fd631b00d - languageName: node - linkType: hard - "glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": version: 5.1.2 resolution: "glob-parent@npm:5.1.2" @@ -15771,31 +13647,6 @@ __metadata: languageName: node linkType: hard -"glob@npm:10.3.10": - version: 10.3.10 - resolution: "glob@npm:10.3.10" - dependencies: - foreground-child: "npm:^3.1.0" - jackspeak: "npm:^2.3.5" - minimatch: "npm:^9.0.1" - minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" - path-scurry: "npm:^1.10.1" - bin: - glob: dist/esm/bin.mjs - checksum: 10c0/13d8a1feb7eac7945f8c8480e11cd4a44b24d26503d99a8d8ac8d5aefbf3e9802a2b6087318a829fad04cb4e829f25c5f4f1110c68966c498720dd261c7e344d - languageName: node - linkType: hard - -"glob@npm:3.2.11": - version: 3.2.11 - resolution: "glob@npm:3.2.11" - dependencies: - inherits: "npm:2" - minimatch: "npm:0.3" - checksum: 10c0/d3ca265ee7a3cec543f49d93ac20925c8b2fa66a0f87ffaf3004ef9cef62414a55cb0b0f22a1e8e3f7b77154e6b9afdfaf589099276b3c6402e8a23849c5cc25 - languageName: node - linkType: hard - "glob@npm:7.1.7": version: 7.1.7 resolution: "glob@npm:7.1.7" @@ -15810,7 +13661,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^10.2.2, glob@npm:^10.3.10": +"glob@npm:^10.2.2": version: 10.4.5 resolution: "glob@npm:10.4.5" dependencies: @@ -15866,15 +13717,6 @@ __metadata: languageName: node linkType: hard -"global-dirs@npm:^0.1.0": - version: 0.1.1 - resolution: "global-dirs@npm:0.1.1" - dependencies: - ini: "npm:^1.3.4" - checksum: 10c0/3608072e58962396c124ad5a1cfb3f99ee76c998654a3432d82977b3c3eeb09dc8a5a2a9849b2b8113906c8d0aad89ce362c22e97cec5fe34405bbf4f3cdbe7a - languageName: node - linkType: hard - "global-modules@npm:^2.0.0": version: 2.0.0 resolution: "global-modules@npm:2.0.0" @@ -15977,25 +13819,6 @@ __metadata: languageName: node linkType: hard -"got@npm:^6.7.1": - version: 6.7.1 - resolution: "got@npm:6.7.1" - dependencies: - create-error-class: "npm:^3.0.0" - duplexer3: "npm:^0.1.4" - get-stream: "npm:^3.0.0" - is-redirect: "npm:^1.0.0" - is-retry-allowed: "npm:^1.0.0" - is-stream: "npm:^1.0.0" - lowercase-keys: "npm:^1.0.0" - safe-buffer: "npm:^5.0.1" - timed-out: "npm:^4.0.0" - unzip-response: "npm:^2.0.1" - url-parse-lax: "npm:^1.0.0" - checksum: 10c0/10a3b2254b3c1dd61a93f7c3dd3061bfc13c4c7c1fc9a7cfa348e5d4f619c20dcf8f8638da4a46372ea9a646fd56fe4cf291174c8a50ab4c8f1f70809c767a15 - languageName: node - linkType: hard - "graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.3, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" @@ -16017,22 +13840,6 @@ __metadata: languageName: node linkType: hard -"graphlib@npm:^2.1.1": - version: 2.1.8 - resolution: "graphlib@npm:2.1.8" - dependencies: - lodash: "npm:^4.17.15" - checksum: 10c0/41c525e4d91a6d8b4e8da1883bf4e85689a547e908557ccc53f64db9141bdfb351b9162a79f13cae81c5b3a410027f59e4fc1edc1ea442234ec08e629859b188 - languageName: node - linkType: hard - -"growl@npm:1.9.2": - version: 1.9.2 - resolution: "growl@npm:1.9.2" - checksum: 10c0/e3191e0fafb218c0d0d404198a94c32a53b21504cde9f01781907897504b7f1a63fe4038a4e197af8b0f375a64f98019213eb294be99d7fc7cf281f3ce5f6e75 - languageName: node - linkType: hard - "gzip-size@npm:^6.0.0": version: 6.0.0 resolution: "gzip-size@npm:6.0.0" @@ -16042,7 +13849,7 @@ __metadata: languageName: node linkType: hard -"handlebars@npm:^4.0.1, handlebars@npm:^4.0.5": +"handlebars@npm:^4.0.1": version: 4.7.8 resolution: "handlebars@npm:4.7.8" dependencies: @@ -16145,15 +13952,6 @@ __metadata: languageName: node linkType: hard -"has-ansi@npm:^2.0.0": - version: 2.0.0 - resolution: "has-ansi@npm:2.0.0" - dependencies: - ansi-regex: "npm:^2.0.0" - checksum: 10c0/f54e4887b9f8f3c4bfefd649c48825b3c093987c92c27880ee9898539e6f01aed261e82e73153c3f920fde0db5bf6ebd58deb498ed1debabcb4bc40113ccdf05 - languageName: node - linkType: hard - "has-bigints@npm:^1.0.2": version: 1.1.0 resolution: "has-bigints@npm:1.1.0" @@ -16223,45 +14021,6 @@ __metadata: languageName: node linkType: hard -"has-value@npm:^0.3.1": - version: 0.3.1 - resolution: "has-value@npm:0.3.1" - dependencies: - get-value: "npm:^2.0.3" - has-values: "npm:^0.1.4" - isobject: "npm:^2.0.0" - checksum: 10c0/7a7c2e9d07bc9742c81806150adb154d149bc6155267248c459cd1ce2a64b0759980d26213260e4b7599c8a3754551179f155ded88d0533a0d2bc7bc29028432 - languageName: node - linkType: hard - -"has-value@npm:^1.0.0": - version: 1.0.0 - resolution: "has-value@npm:1.0.0" - dependencies: - get-value: "npm:^2.0.6" - has-values: "npm:^1.0.0" - isobject: "npm:^3.0.0" - checksum: 10c0/17cdccaf50f8aac80a109dba2e2ee5e800aec9a9d382ef9deab66c56b34269e4c9ac720276d5ffa722764304a1180ae436df077da0dd05548cfae0209708ba4d - languageName: node - linkType: hard - -"has-values@npm:^0.1.4": - version: 0.1.4 - resolution: "has-values@npm:0.1.4" - checksum: 10c0/a8f00ad862c20289798c35243d5bd0b0a97dd44b668c2204afe082e0265f2d0bf3b89fc8cc0ef01a52b49f10aa35cf85c336ee3a5f1cac96ed490f5e901cdbf2 - languageName: node - linkType: hard - -"has-values@npm:^1.0.0": - version: 1.0.0 - resolution: "has-values@npm:1.0.0" - dependencies: - is-number: "npm:^3.0.0" - kind-of: "npm:^4.0.0" - checksum: 10c0/a6f2a1cc6b2e43eacc68e62e71ad6890def7f4b13d2ef06b4ad3ee156c23e470e6df144b9b467701908e17633411f1075fdff0cab45fb66c5e0584d89b25f35e - languageName: node - linkType: hard - "hash-base@npm:^3.0.0": version: 3.1.0 resolution: "hash-base@npm:3.1.0" @@ -16283,7 +14042,7 @@ __metadata: languageName: node linkType: hard -"hasown@npm:^2.0.0, hasown@npm:^2.0.2": +"hasown@npm:^2.0.2": version: 2.0.2 resolution: "hasown@npm:2.0.2" dependencies: @@ -16390,7 +14149,7 @@ __metadata: languageName: node linkType: hard -"hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.1, hoist-non-react-statics@npm:^3.3.2": +"hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.2": version: 3.3.2 resolution: "hoist-non-react-statics@npm:3.3.2" dependencies: @@ -16399,13 +14158,6 @@ __metadata: languageName: node linkType: hard -"hookable@npm:^5.5.3": - version: 5.5.3 - resolution: "hookable@npm:5.5.3" - checksum: 10c0/275f4cc84d27f8d48c5a5cd5685b6c0fea9291be9deea5bff0cfa72856ed566abde1dcd8cb1da0f9a70b4da3d7ec0d60dc3554c4edbba647058cc38816eced3d - languageName: node - linkType: hard - "hoopy@npm:^0.1.4": version: 0.1.4 resolution: "hoopy@npm:0.1.4" @@ -16526,13 +14278,6 @@ __metadata: languageName: node linkType: hard -"iconv-lite@npm:0.4.8": - version: 0.4.8 - resolution: "iconv-lite@npm:0.4.8" - checksum: 10c0/43c3a63b10f9a86a38fb72ec4b325e870a2af577b31cc1a9f8cc3f35787a84a1cc7e101b9add3ee19d1c77c03873e2b8827aa2dfefcaa13923c67194dcd3e54a - languageName: node - linkType: hard - "iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2": version: 0.6.3 resolution: "iconv-lite@npm:0.6.3" @@ -16549,14 +14294,7 @@ __metadata: languageName: node linkType: hard -"ignore-by-default@npm:^1.0.1": - version: 1.0.1 - resolution: "ignore-by-default@npm:1.0.1" - checksum: 10c0/9ab6e70e80f7cc12735def7ecb5527cfa56ab4e1152cd64d294522827f2dcf1f6d85531241537dc3713544e88dd888f65cb3c49c7b2cddb9009087c75274e533 - languageName: node - linkType: hard - -"ignore@npm:^5.0.5, ignore@npm:^5.1.1, ignore@npm:^5.2.0, ignore@npm:^5.2.4, ignore@npm:^5.3.1": +"ignore@npm:^5.0.5, ignore@npm:^5.1.1, ignore@npm:^5.2.0, ignore@npm:^5.3.1": version: 5.3.2 resolution: "ignore@npm:5.3.2" checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337 @@ -16615,13 +14353,6 @@ __metadata: languageName: node linkType: hard -"import-lazy@npm:^2.1.0": - version: 2.1.0 - resolution: "import-lazy@npm:2.1.0" - checksum: 10c0/c5e5f507d26ee23c5b2ed64577155810361ac37863b322cae0c17f16b6a8cdd15adf370288384ddd95ef9de05602fb8d87bf76ff835190eb037333c84db8062c - languageName: node - linkType: hard - "import-local@npm:^3.0.2": version: 3.2.0 resolution: "import-local@npm:3.2.0" @@ -16658,7 +14389,7 @@ __metadata: languageName: node linkType: hard -"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.1, inherits@npm:~2.0.3, inherits@npm:~2.0.4": +"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3, inherits@npm:~2.0.4": version: 2.0.4 resolution: "inherits@npm:2.0.4" checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 @@ -16672,33 +14403,13 @@ __metadata: languageName: node linkType: hard -"ini@npm:^1.3.4, ini@npm:^1.3.5, ini@npm:~1.3.0": +"ini@npm:^1.3.5": version: 1.3.8 resolution: "ini@npm:1.3.8" checksum: 10c0/ec93838d2328b619532e4f1ff05df7909760b6f66d9c9e2ded11e5c1897d6f2f9980c54dd638f88654b00919ce31e827040631eab0a3969e4d1abefa0719516a languageName: node linkType: hard -"inquirer@npm:^0.10.0": - version: 0.10.1 - resolution: "inquirer@npm:0.10.1" - dependencies: - ansi-escapes: "npm:^1.1.0" - ansi-regex: "npm:^2.0.0" - chalk: "npm:^1.0.0" - cli-cursor: "npm:^1.0.1" - cli-width: "npm:^1.0.1" - figures: "npm:^1.3.5" - lodash: "npm:^3.3.1" - readline2: "npm:^1.0.1" - run-async: "npm:^0.1.0" - rx-lite: "npm:^3.1.2" - strip-ansi: "npm:^3.0.0" - through: "npm:^2.3.6" - checksum: 10c0/9a46497073342e8ab778e86958b55c2c2763335157a05686eaa1f7121242eef66a33f963e611117f06a628f4fb05d7f376b51efea6e19cda5e5edbf7d3b0a711 - languageName: node - linkType: hard - "int64-buffer@npm:^0.1.9": version: 0.1.10 resolution: "int64-buffer@npm:0.1.10" @@ -16752,15 +14463,6 @@ __metadata: languageName: node linkType: hard -"is-accessor-descriptor@npm:^1.0.1": - version: 1.0.1 - resolution: "is-accessor-descriptor@npm:1.0.1" - dependencies: - hasown: "npm:^2.0.0" - checksum: 10c0/d034034074c5ffeb6c868e091083182279db1a956f49f8d1494cecaa0f8b99d706556ded2a9b20d9aa290549106eef8204d67d8572902e06dcb1add6db6b524d - languageName: node - linkType: hard - "is-arguments@npm:^1.0.4": version: 1.2.0 resolution: "is-arguments@npm:1.2.0" @@ -16818,15 +14520,6 @@ __metadata: languageName: node linkType: hard -"is-binary-path@npm:^1.0.0": - version: 1.0.1 - resolution: "is-binary-path@npm:1.0.1" - dependencies: - binary-extensions: "npm:^1.0.0" - checksum: 10c0/16e456fa3782eaf3d8e28d382b750507e3d54ff6694df8a1b2c6498da321e2ead311de9c42e653d8fb3213de72bac204b5f97e4a110cda8a72f17b1c1b4eb643 - languageName: node - linkType: hard - "is-binary-path@npm:~2.1.0": version: 2.1.0 resolution: "is-binary-path@npm:2.1.0" @@ -16846,22 +14539,6 @@ __metadata: languageName: node linkType: hard -"is-buffer@npm:^1.1.5, is-buffer@npm:~1.1.1": - version: 1.1.6 - resolution: "is-buffer@npm:1.1.6" - checksum: 10c0/ae18aa0b6e113d6c490ad1db5e8df9bdb57758382b313f5a22c9c61084875c6396d50bbf49315f5b1926d142d74dfb8d31b40d993a383e0a158b15fea7a82234 - languageName: node - linkType: hard - -"is-bun-module@npm:^2.0.0": - version: 2.0.0 - resolution: "is-bun-module@npm:2.0.0" - dependencies: - semver: "npm:^7.7.1" - checksum: 10c0/7d27a0679cfa5be1f5052650391f9b11040cd70c48d45112e312c56bc6b6ca9c9aea70dcce6cc40b1e8947bfff8567a5c5715d3b066fb478522dab46ea379240 - languageName: node - linkType: hard - "is-callable@npm:^1.2.7": version: 1.2.7 resolution: "is-callable@npm:1.2.7" @@ -16869,18 +14546,7 @@ __metadata: languageName: node linkType: hard -"is-ci@npm:^1.0.10": - version: 1.2.1 - resolution: "is-ci@npm:1.2.1" - dependencies: - ci-info: "npm:^1.5.0" - bin: - is-ci: bin.js - checksum: 10c0/56d8e0e404c5ee9eb4cc846b9fbed043bac587633a8b10caad35b1e4b11edccae742037c4bc2196203e5929643bd257a4caac23b65e99b372a54e68d187bacc9 - languageName: node - linkType: hard - -"is-core-module@npm:^2.13.0, is-core-module@npm:^2.15.1, is-core-module@npm:^2.16.0": +"is-core-module@npm:^2.13.0, is-core-module@npm:^2.16.0": version: 2.16.1 resolution: "is-core-module@npm:2.16.1" dependencies: @@ -16889,15 +14555,6 @@ __metadata: languageName: node linkType: hard -"is-data-descriptor@npm:^1.0.1": - version: 1.0.1 - resolution: "is-data-descriptor@npm:1.0.1" - dependencies: - hasown: "npm:^2.0.0" - checksum: 10c0/ad3acc372e3227f87eb8cdba112c343ca2a67f1885aecf64f02f901cb0858a1fc9488ad42135ab102e9d9e71a62b3594740790bb103a9ba5da830a131a89e3e8 - languageName: node - linkType: hard - "is-data-view@npm:^1.0.1, is-data-view@npm:^1.0.2": version: 1.0.2 resolution: "is-data-view@npm:1.0.2" @@ -16919,26 +14576,6 @@ __metadata: languageName: node linkType: hard -"is-descriptor@npm:^0.1.0": - version: 0.1.7 - resolution: "is-descriptor@npm:0.1.7" - dependencies: - is-accessor-descriptor: "npm:^1.0.1" - is-data-descriptor: "npm:^1.0.1" - checksum: 10c0/f5960b9783f508aec570465288cb673d4b3cc4aae4e6de970c3afd9a8fc1351edcb85d78b2cce2ec5251893a423f73263cab3bb94cf365a8d71b5d510a116392 - languageName: node - linkType: hard - -"is-descriptor@npm:^1.0.0, is-descriptor@npm:^1.0.2": - version: 1.0.3 - resolution: "is-descriptor@npm:1.0.3" - dependencies: - is-accessor-descriptor: "npm:^1.0.1" - is-data-descriptor: "npm:^1.0.1" - checksum: 10c0/b4ee667ea787d3a0be4e58536087fd0587de2b0b6672fbfe288f5b8d831ac4b79fd987f31d6c2d4e5543a42c97a87428bc5215ce292a1a47070147793878226f - languageName: node - linkType: hard - "is-directory@npm:^0.3.1": version: 0.3.1 resolution: "is-directory@npm:0.3.1" @@ -16955,30 +14592,14 @@ __metadata: languageName: node linkType: hard -"is-extendable@npm:^0.1.0, is-extendable@npm:^0.1.1": +"is-extendable@npm:^0.1.1": version: 0.1.1 resolution: "is-extendable@npm:0.1.1" checksum: 10c0/dd5ca3994a28e1740d1e25192e66eed128e0b2ff161a7ea348e87ae4f616554b486854de423877a2a2c171d5f7cd6e8093b91f54533bc88a59ee1c9838c43879 languageName: node linkType: hard -"is-extendable@npm:^1.0.1": - version: 1.0.1 - resolution: "is-extendable@npm:1.0.1" - dependencies: - is-plain-object: "npm:^2.0.4" - checksum: 10c0/1d6678a5be1563db6ecb121331c819c38059703f0179f52aa80c242c223ee9c6b66470286636c0e63d7163e4d905c0a7d82a096e0b5eaeabb51b9f8d0af0d73f - languageName: node - linkType: hard - -"is-extglob@npm:^1.0.0": - version: 1.0.0 - resolution: "is-extglob@npm:1.0.0" - checksum: 10c0/1ce5366d19958f36069a45ca996c1e51ab607f42a01eb0505f0ccffe8f9c91f5bcba6e971605efd8b4d4dfd0111afa3c8df3e1746db5b85b9a8f933f5e7286b7 - languageName: node - linkType: hard - -"is-extglob@npm:^2.1.0, is-extglob@npm:^2.1.1": +"is-extglob@npm:^2.1.1": version: 2.1.1 resolution: "is-extglob@npm:2.1.1" checksum: 10c0/5487da35691fbc339700bbb2730430b07777a3c21b9ebaecb3072512dfd7b4ba78ac2381a87e8d78d20ea08affb3f1971b4af629173a6bf435ff8a4c47747912 @@ -16994,15 +14615,6 @@ __metadata: languageName: node linkType: hard -"is-fullwidth-code-point@npm:^1.0.0": - version: 1.0.0 - resolution: "is-fullwidth-code-point@npm:1.0.0" - dependencies: - number-is-nan: "npm:^1.0.0" - checksum: 10c0/12acfcf16142f2d431bf6af25d68569d3198e81b9799b4ae41058247aafcc666b0127d64384ea28e67a746372611fcbe9b802f69175287aba466da3eddd5ba0f - languageName: node - linkType: hard - "is-fullwidth-code-point@npm:^2.0.0": version: 2.0.0 resolution: "is-fullwidth-code-point@npm:2.0.0" @@ -17036,24 +14648,6 @@ __metadata: languageName: node linkType: hard -"is-glob@npm:^2.0.0": - version: 2.0.1 - resolution: "is-glob@npm:2.0.1" - dependencies: - is-extglob: "npm:^1.0.0" - checksum: 10c0/ef156806af0924983325c9218a8b8a838fa50e1a104ed2a11fe94829a5b27c1b05a4c8cf98d96cb3a7fea539c21f14ae2081e1a248f3d5a9eea62f2d4e9f8b0c - languageName: node - linkType: hard - -"is-glob@npm:^3.1.0": - version: 3.1.0 - resolution: "is-glob@npm:3.1.0" - dependencies: - is-extglob: "npm:^2.1.0" - checksum: 10c0/ba816a35dcf5285de924a8a4654df7b183a86381d73ea3bbf3df3cc61b3ba61fdddf90ee205709a2235b210ee600ee86e5e8600093cf291a662607fd032e2ff4 - languageName: node - linkType: hard - "is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3, is-glob@npm:~4.0.1": version: 4.0.3 resolution: "is-glob@npm:4.0.3" @@ -17070,16 +14664,6 @@ __metadata: languageName: node linkType: hard -"is-installed-globally@npm:^0.1.0": - version: 0.1.0 - resolution: "is-installed-globally@npm:0.1.0" - dependencies: - global-dirs: "npm:^0.1.0" - is-path-inside: "npm:^1.0.0" - checksum: 10c0/e5664812205367240bf7229e56410a4d33a83843e32642938dc5d0ba6d53e5125b24ea9aefcf5d35bc3ab8a868469d631624ce59dead1d6ceadf88b19cca6ab7 - languageName: node - linkType: hard - "is-interactive@npm:^1.0.0": version: 1.0.0 resolution: "is-interactive@npm:1.0.0" @@ -17087,15 +14671,6 @@ __metadata: languageName: node linkType: hard -"is-invalid-path@npm:^0.1.0": - version: 0.1.0 - resolution: "is-invalid-path@npm:0.1.0" - dependencies: - is-glob: "npm:^2.0.0" - checksum: 10c0/9f7f74825ddcbd70ceb0aca1155d2961f3767a7a0f1351c255d25047cc7dece161b755d0698aaf8f201693d96ea12e04b4afa00ee9b4f8f47ab5ec2adbe96df8 - languageName: node - linkType: hard - "is-map@npm:^2.0.3": version: 2.0.3 resolution: "is-map@npm:2.0.3" @@ -17103,13 +14678,6 @@ __metadata: languageName: node linkType: hard -"is-npm@npm:^1.0.0": - version: 1.0.0 - resolution: "is-npm@npm:1.0.0" - checksum: 10c0/6d9a9cfbb849ad631e3050d1dad140ded91a10f374b57ff6ccb688b4ee8d5fd139e6aa2c5ab4342b8119242c9c4cba041876fb4046fcae52e76eb073db71dfe7 - languageName: node - linkType: hard - "is-number-object@npm:^1.1.1": version: 1.1.1 resolution: "is-number-object@npm:1.1.1" @@ -17120,15 +14688,6 @@ __metadata: languageName: node linkType: hard -"is-number@npm:^3.0.0": - version: 3.0.0 - resolution: "is-number@npm:3.0.0" - dependencies: - kind-of: "npm:^3.0.2" - checksum: 10c0/e639c54640b7f029623df24d3d103901e322c0c25ea5bde97cd723c2d0d4c05857a8364ab5c58d963089dbed6bf1d0ffe975cb6aef917e2ad0ccbca653d31b4f - languageName: node - linkType: hard - "is-number@npm:^7.0.0": version: 7.0.0 resolution: "is-number@npm:7.0.0" @@ -17136,22 +14695,6 @@ __metadata: languageName: node linkType: hard -"is-obj@npm:^1.0.0": - version: 1.0.1 - resolution: "is-obj@npm:1.0.1" - checksum: 10c0/5003acba0af7aa47dfe0760e545a89bbac89af37c12092c3efadc755372cdaec034f130e7a3653a59eb3c1843cfc72ca71eaf1a6c3bafe5a0bab3611a47f9945 - languageName: node - linkType: hard - -"is-path-inside@npm:^1.0.0": - version: 1.0.1 - resolution: "is-path-inside@npm:1.0.1" - dependencies: - path-is-inside: "npm:^1.0.1" - checksum: 10c0/093ab1324e33a95c2d057e1450e1936ee7a3ed25b78c8dc42f576f3dc3489dd8788d431ea2969bb0e081f005de1571792ea99cf7b1b69ab2dd4ca477ae7a8e51 - languageName: node - linkType: hard - "is-path-inside@npm:^3.0.3": version: 3.0.3 resolution: "is-path-inside@npm:3.0.3" @@ -17166,7 +14709,7 @@ __metadata: languageName: node linkType: hard -"is-plain-object@npm:^2.0.3, is-plain-object@npm:^2.0.4": +"is-plain-object@npm:^2.0.4": version: 2.0.4 resolution: "is-plain-object@npm:2.0.4" dependencies: @@ -17175,13 +14718,6 @@ __metadata: languageName: node linkType: hard -"is-redirect@npm:^1.0.0": - version: 1.0.0 - resolution: "is-redirect@npm:1.0.0" - checksum: 10c0/4fb24eaa61548d276499ec5e2f7efbc4ed823b68c7ee3bdfbf29d0f6c45d19c07f417bf3dd86110285c28a35481b46a9996921739b7b84bb8ba5216f250d40de - languageName: node - linkType: hard - "is-regex@npm:^1.2.1": version: 1.2.1 resolution: "is-regex@npm:1.2.1" @@ -17194,13 +14730,6 @@ __metadata: languageName: node linkType: hard -"is-retry-allowed@npm:^1.0.0": - version: 1.2.0 - resolution: "is-retry-allowed@npm:1.2.0" - checksum: 10c0/a80f14e1e11c27a58f268f2927b883b635703e23a853cb7b8436e3456bf2ea3efd5082a4e920093eec7bd372c1ce6ea7cea78a9376929c211039d0cc4a393a44 - languageName: node - linkType: hard - "is-set@npm:^2.0.3": version: 2.0.3 resolution: "is-set@npm:2.0.3" @@ -17217,13 +14746,6 @@ __metadata: languageName: node linkType: hard -"is-stream@npm:^1.0.0, is-stream@npm:^1.1.0": - version: 1.1.0 - resolution: "is-stream@npm:1.1.0" - checksum: 10c0/b8ae7971e78d2e8488d15f804229c6eed7ed36a28f8807a1815938771f4adff0e705218b7dab968270433f67103e4fef98062a0beea55d64835f705ee72c7002 - languageName: node - linkType: hard - "is-stream@npm:^2.0.0": version: 2.0.1 resolution: "is-stream@npm:2.0.1" @@ -17268,15 +14790,6 @@ __metadata: languageName: node linkType: hard -"is-valid-path@npm:^0.1.1": - version: 0.1.1 - resolution: "is-valid-path@npm:0.1.1" - dependencies: - is-invalid-path: "npm:^0.1.0" - checksum: 10c0/05c3533b8d98ac469bec9849e6ee73a07e1f9857e2043c75a9a45d21bae5e11fafb625808d7bd1aaf5cc63e842876c636f9888388a959ee9c33975c7b603c6ba - languageName: node - linkType: hard - "is-weakmap@npm:^2.0.2": version: 2.0.2 resolution: "is-weakmap@npm:2.0.2" @@ -17303,13 +14816,6 @@ __metadata: languageName: node linkType: hard -"is-windows@npm:^1.0.2": - version: 1.0.2 - resolution: "is-windows@npm:1.0.2" - checksum: 10c0/b32f418ab3385604a66f1b7a3ce39d25e8881dee0bd30816dc8344ef6ff9df473a732bcc1ec4e84fe99b2f229ae474f7133e8e93f9241686cfcf7eebe53ba7a5 - languageName: node - linkType: hard - "is-wsl@npm:^1.1.0": version: 1.1.0 resolution: "is-wsl@npm:1.1.0" @@ -17326,14 +14832,7 @@ __metadata: languageName: node linkType: hard -"isarray@npm:0.0.1": - version: 0.0.1 - resolution: "isarray@npm:0.0.1" - checksum: 10c0/ed1e62da617f71fe348907c71743b5ed550448b455f8d269f89a7c7ddb8ae6e962de3dab6a74a237b06f5eb7f6ece7a45ada8ce96d87fe972926530f91ae3311 - languageName: node - linkType: hard - -"isarray@npm:1.0.0, isarray@npm:^1.0.0, isarray@npm:~1.0.0": +"isarray@npm:^1.0.0, isarray@npm:~1.0.0": version: 1.0.0 resolution: "isarray@npm:1.0.0" checksum: 10c0/18b5be6669be53425f0b84098732670ed4e727e3af33bc7f948aac01782110eb9a18b3b329c5323bcdd3acdaae547ee077d3951317e7f133bff7105264b3003d @@ -17361,31 +14860,13 @@ __metadata: languageName: node linkType: hard -"isobject@npm:^2.0.0": - version: 2.1.0 - resolution: "isobject@npm:2.1.0" - dependencies: - isarray: "npm:1.0.0" - checksum: 10c0/c4cafec73b3b2ee11be75dff8dafd283b5728235ac099b07d7873d5182553a707768e208327bbc12931b9422d8822280bf88d894a0024ff5857b3efefb480e7b - languageName: node - linkType: hard - -"isobject@npm:^3.0.0, isobject@npm:^3.0.1": +"isobject@npm:^3.0.1": version: 3.0.1 resolution: "isobject@npm:3.0.1" checksum: 10c0/03344f5064a82f099a0cd1a8a407f4c0d20b7b8485e8e816c39f249e9416b06c322e8dec5b842b6bb8a06de0af9cb48e7bc1b5352f0fadc2f0abac033db3d4db languageName: node linkType: hard -"isows@npm:1.0.7": - version: 1.0.7 - resolution: "isows@npm:1.0.7" - peerDependencies: - ws: "*" - checksum: 10c0/43c41fe89c7c07258d0be3825f87e12da8ac9023c5b5ae6741ec00b2b8169675c04331ea73ef8c172d37a6747066f4dc93947b17cd369f92828a3b3e741afbda - languageName: node - linkType: hard - "istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0": version: 3.2.2 resolution: "istanbul-lib-coverage@npm:3.2.2" @@ -17465,19 +14946,6 @@ __metadata: languageName: node linkType: hard -"jackspeak@npm:^2.3.5": - version: 2.3.6 - resolution: "jackspeak@npm:2.3.6" - dependencies: - "@isaacs/cliui": "npm:^8.0.2" - "@pkgjs/parseargs": "npm:^0.11.0" - dependenciesMeta: - "@pkgjs/parseargs": - optional: true - checksum: 10c0/f01d8f972d894cd7638bc338e9ef5ddb86f7b208ce177a36d718eac96ec86638a6efa17d0221b10073e64b45edc2ce15340db9380b1f5d5c5d000cbc517dc111 - languageName: node - linkType: hard - "jackspeak@npm:^3.1.2": version: 3.4.3 resolution: "jackspeak@npm:3.4.3" @@ -17491,18 +14959,6 @@ __metadata: languageName: node linkType: hard -"jade@npm:0.26.3": - version: 0.26.3 - resolution: "jade@npm:0.26.3" - dependencies: - commander: "npm:0.6.1" - mkdirp: "npm:0.3.0" - bin: - jade: ./bin/jade - checksum: 10c0/5fac05818e7203de6e2ba1afa06f522070054166dba95621ec57be891011f6767cdbc30d56e4987b94da89ad84ff28fcf06c6d91b7779c21a3dd0800d67dd6bc - languageName: node - linkType: hard - "jake@npm:^10.8.5": version: 10.9.2 resolution: "jake@npm:10.9.2" @@ -17967,15 +15423,6 @@ __metadata: languageName: node linkType: hard -"jiti@npm:^1.21.6": - version: 1.21.7 - resolution: "jiti@npm:1.21.7" - bin: - jiti: bin/jiti.js - checksum: 10c0/77b61989c758ff32407cdae8ddc77f85e18e1a13fc4977110dbd2e05fc761842f5f71bce684d9a01316e1c4263971315a111385759951080bbfe17cbb5de8f7a - languageName: node - linkType: hard - "jiti@npm:^2.4.2": version: 2.4.2 resolution: "jiti@npm:2.4.2" @@ -18040,13 +15487,6 @@ __metadata: languageName: node linkType: hard -"js-string-escape@npm:^1.0.1": - version: 1.0.1 - resolution: "js-string-escape@npm:1.0.1" - checksum: 10c0/2c33b9ff1ba6b84681c51ca0997e7d5a1639813c95d5b61cb7ad47e55cc28fa4a0b1935c3d218710d8e6bcee5d0cd8c44755231e3a4e45fc604534d9595a3628 - languageName: node - linkType: hard - "js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" @@ -18054,7 +15494,7 @@ __metadata: languageName: node linkType: hard -"js-yaml@npm:3.x, js-yaml@npm:^3.10.0, js-yaml@npm:^3.13.1, js-yaml@npm:^3.3.0, js-yaml@npm:^3.3.1, js-yaml@npm:^3.8.3": +"js-yaml@npm:3.x, js-yaml@npm:^3.10.0, js-yaml@npm:^3.13.1": version: 3.14.1 resolution: "js-yaml@npm:3.14.1" dependencies: @@ -18175,40 +15615,6 @@ __metadata: languageName: node linkType: hard -"json-refs@npm:^2.1.5": - version: 2.1.7 - resolution: "json-refs@npm:2.1.7" - dependencies: - commander: "npm:^2.9.0" - graphlib: "npm:^2.1.1" - js-yaml: "npm:^3.8.3" - native-promise-only: "npm:^0.8.1" - path-loader: "npm:^1.0.2" - slash: "npm:^1.0.0" - uri-js: "npm:^3.0.2" - bin: - json-refs: ./bin/json-refs - checksum: 10c0/c67aab9e874cf2dbcd6d06df2ada034410c9af053c3c14d1d3c60c64e8903773555c3f1dcd4ddfaf0532b8804ee19b0f5eddc21cecbec67e081d491e719bd41c - languageName: node - linkType: hard - -"json-schema-deref-sync@npm:^0.6.0": - version: 0.6.0 - resolution: "json-schema-deref-sync@npm:0.6.0" - dependencies: - clone: "npm:^2.1.2" - dag-map: "npm:~1.0.0" - is-valid-path: "npm:^0.1.1" - lodash: "npm:^4.17.11" - md5: "npm:~2.2.0" - memory-cache: "npm:~0.2.0" - mpath: "npm:~0.5.0" - traverse: "npm:~0.6.6" - valid-url: "npm:~1.0.9" - checksum: 10c0/aed431cb0a3a4dbaebce4fcf571a40df9e9f3978ef555367e1ac4a707613cc4eba0f9b2b3bffb4d4da701fe5dd35e22b75d9bfb3760c4c43220e30e2ca053b7f - languageName: node - linkType: hard - "json-schema-traverse@npm:^0.4.1": version: 0.4.1 resolution: "json-schema-traverse@npm:0.4.1" @@ -18288,18 +15694,6 @@ __metadata: languageName: node linkType: hard -"jsonfile@npm:^2.1.0": - version: 2.4.0 - resolution: "jsonfile@npm:2.4.0" - dependencies: - graceful-fs: "npm:^4.1.6" - dependenciesMeta: - graceful-fs: - optional: true - checksum: 10c0/02ad746d9490686519b3369bc9572694076eb982e1b4982c5ad9b91bc3c0ad30d10c866bb26b7a87f0c4025a80222cd2962cb57083b5a6a475a9031eab8c8962 - languageName: node - linkType: hard - "jsonfile@npm:^4.0.0": version: 4.0.0 resolution: "jsonfile@npm:4.0.0" @@ -18357,7 +15751,7 @@ __metadata: languageName: node linkType: hard -"jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.3.5": +"jsx-ast-utils@npm:^2.4.1 || ^3.0.0": version: 3.3.5 resolution: "jsx-ast-utils@npm:3.3.5" dependencies: @@ -18390,24 +15784,6 @@ __metadata: languageName: node linkType: hard -"kind-of@npm:^3.0.2, kind-of@npm:^3.0.3, kind-of@npm:^3.2.0": - version: 3.2.2 - resolution: "kind-of@npm:3.2.2" - dependencies: - is-buffer: "npm:^1.1.5" - checksum: 10c0/7e34bc29d4b02c997f92f080de34ebb92033a96736bbb0bb2410e033a7e5ae6571f1fa37b2d7710018f95361473b816c604234197f4f203f9cf149d8ef1574d9 - languageName: node - linkType: hard - -"kind-of@npm:^4.0.0": - version: 4.0.0 - resolution: "kind-of@npm:4.0.0" - dependencies: - is-buffer: "npm:^1.1.5" - checksum: 10c0/d6c44c75ee36898142dfc7106afbd50593216c37f96acb81a7ab33ca1a6938ce97d5692b8fc8fccd035f83811a9d97749d68771116441a48eedd0b68e2973165 - languageName: node - linkType: hard - "kind-of@npm:^5.0.0": version: 5.1.0 resolution: "kind-of@npm:5.1.0" @@ -18438,31 +15814,6 @@ __metadata: languageName: node linkType: hard -"language-subtag-registry@npm:^0.3.20": - version: 0.3.23 - resolution: "language-subtag-registry@npm:0.3.23" - checksum: 10c0/e9b05190421d2cd36dd6c95c28673019c927947cb6d94f40ba7e77a838629ee9675c94accf897fbebb07923187deb843b8fbb8935762df6edafe6c28dcb0b86c - languageName: node - linkType: hard - -"language-tags@npm:^1.0.9": - version: 1.0.9 - resolution: "language-tags@npm:1.0.9" - dependencies: - language-subtag-registry: "npm:^0.3.20" - checksum: 10c0/9ab911213c4bd8bd583c850201c17794e52cb0660d1ab6e32558aadc8324abebf6844e46f92b80a5d600d0fbba7eface2c207bfaf270a1c7fd539e4c3a880bff - languageName: node - linkType: hard - -"latest-version@npm:^3.0.0": - version: 3.1.0 - resolution: "latest-version@npm:3.1.0" - dependencies: - package-json: "npm:^4.0.0" - checksum: 10c0/a850d49d5008e9370e5afc5b2a6bc610c34499b5d9aeaa1cb41e80bfa64a3f666438c65c7d2db6ad3bd62f727d4b805c63e1444bc9c3ad6d51d1c1ebce66758c - languageName: node - linkType: hard - "leven@npm:^3.1.0": version: 3.1.0 resolution: "leven@npm:3.1.0" @@ -18535,7 +15886,7 @@ __metadata: languageName: node linkType: hard -"lilconfig@npm:^3.0.0, lilconfig@npm:^3.1.3": +"lilconfig@npm:^3.1.3": version: 3.1.3 resolution: "lilconfig@npm:3.1.3" checksum: 10c0/f5604e7240c5c275743561442fbc5abf2a84ad94da0f5adc71d25e31fa8483048de3dcedcb7a44112a942fed305fd75841cdf6c9681c7f640c63f1049e9a5dcc @@ -18593,13 +15944,6 @@ __metadata: languageName: node linkType: hard -"lodash-compat@npm:^3.10.0": - version: 3.10.2 - resolution: "lodash-compat@npm:3.10.2" - checksum: 10c0/9546d151acfc3487f825aaa5cf94ac6c32936bee4719ef17ddd3b51a00b589eaef6c06ac68635312887d9d421eed4fd7f8969b25bd883739a92c902b5c2d8086 - languageName: node - linkType: hard - "lodash-es@npm:^4.17.10": version: 4.17.21 resolution: "lodash-es@npm:4.17.21" @@ -18607,175 +15951,6 @@ __metadata: languageName: node linkType: hard -"lodash._arraypool@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash._arraypool@npm:2.4.1" - checksum: 10c0/caf2f7b20b288385699df05a29f24d7958c9e47199e15d70c4f5018983a011adabdd7158d635eb91ebc1bdc84c2791dece3f1c8850322c063eeaadeb317f9862 - languageName: node - linkType: hard - -"lodash._basebind@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash._basebind@npm:2.4.1" - dependencies: - lodash._basecreate: "npm:~2.4.1" - lodash._setbinddata: "npm:~2.4.1" - lodash._slice: "npm:~2.4.1" - lodash.isobject: "npm:~2.4.1" - checksum: 10c0/b6c0a3ac71ceb39f7b9f636efcfe0a74ddcf24f9e96429ff3e9025db3382e3240bc3c254b0a0f5b7680565c0c5b99ac37b2a69d0370a36c363c19e09e5967857 - languageName: node - linkType: hard - -"lodash._baseclone@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash._baseclone@npm:2.4.1" - dependencies: - lodash._getarray: "npm:~2.4.1" - lodash._releasearray: "npm:~2.4.1" - lodash._slice: "npm:~2.4.1" - lodash.assign: "npm:~2.4.1" - lodash.foreach: "npm:~2.4.1" - lodash.forown: "npm:~2.4.1" - lodash.isarray: "npm:~2.4.1" - lodash.isobject: "npm:~2.4.1" - checksum: 10c0/c237e2515f3c39b951be5193c0b7e5ec6421d425d3386818464623fc07c0edb970012e7cd4d103dd69f1838bcb5d89477aad27af95885b2ae2de1d4e0eb2a725 - languageName: node - linkType: hard - -"lodash._basecreate@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash._basecreate@npm:2.4.1" - dependencies: - lodash._isnative: "npm:~2.4.1" - lodash.isobject: "npm:~2.4.1" - lodash.noop: "npm:~2.4.1" - checksum: 10c0/b2edb54d55e49ab955294df1c2ea4ffc0c298a4ff7e738dd04e6b2a256272ac052abf4018ee926536ee862290a9694b9e882044085388c3a5acae7228011767d - languageName: node - linkType: hard - -"lodash._basecreatecallback@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash._basecreatecallback@npm:2.4.1" - dependencies: - lodash._setbinddata: "npm:~2.4.1" - lodash.bind: "npm:~2.4.1" - lodash.identity: "npm:~2.4.1" - lodash.support: "npm:~2.4.1" - checksum: 10c0/294f15e00ea4fd894fa75e01b0ad9a0829f0f2d2e0623e35ead7848154712df91b48de6cfcf8d4bd54f1cb7d10625b39747782d996667c1b74dd7236adac69b8 - languageName: node - linkType: hard - -"lodash._basecreatewrapper@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash._basecreatewrapper@npm:2.4.1" - dependencies: - lodash._basecreate: "npm:~2.4.1" - lodash._setbinddata: "npm:~2.4.1" - lodash._slice: "npm:~2.4.1" - lodash.isobject: "npm:~2.4.1" - checksum: 10c0/ef12e3c74b7cf0b47d4fbd0f58f09053a08553e93decc6c8b6896349a91d56bc05f95b50b18cf303ff07182ddbb05a6d58f536eb8418bfcc37a7c63d29c847e5 - languageName: node - linkType: hard - -"lodash._createwrapper@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash._createwrapper@npm:2.4.1" - dependencies: - lodash._basebind: "npm:~2.4.1" - lodash._basecreatewrapper: "npm:~2.4.1" - lodash._slice: "npm:~2.4.1" - lodash.isfunction: "npm:~2.4.1" - checksum: 10c0/79af16e1a987fc74e0b4acc4e4a16cd6ce4c435876c3535eea99bc3cbaefcd5c240c3d0f5777010c4d6918cdf2ca0ba1874bf62c62442c3ba1e815a045421442 - languageName: node - linkType: hard - -"lodash._getarray@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash._getarray@npm:2.4.1" - dependencies: - lodash._arraypool: "npm:~2.4.1" - checksum: 10c0/3246969b623b87bd73762bcf19b68e68efaddbb966c9832b9a25932150ee1fa80effa79a93ab90f5ab89b65cbcae22a209a830433a270f7e3595da54228cf33d - languageName: node - linkType: hard - -"lodash._isnative@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash._isnative@npm:2.4.1" - checksum: 10c0/4e09ed09e1e52ae81a14b19e1da1a2c98f2dc189feb2ed8d91fd193283a5208099d2840ffdc1aa8d51b0fe766fd4ac828a29724382bc3268fb91735e6345d4b7 - languageName: node - linkType: hard - -"lodash._maxpoolsize@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash._maxpoolsize@npm:2.4.1" - checksum: 10c0/6d490a1504fdad9f963c0a67266871355a79101e089a66ea0f6f7a16cf5b14a610068f8a82d636fd6a9f4a7b8fe93965ab8e114c88a116a964a2589a2227c5b3 - languageName: node - linkType: hard - -"lodash._objecttypes@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash._objecttypes@npm:2.4.1" - checksum: 10c0/edb72879107c6072d67aa733eebf534c67a1963118f961e18d46834ed33e1d58f11b491b1709f1217cc1b8d4ca5336618ed3994f4f7d89dbd4cef5cc11d7bf73 - languageName: node - linkType: hard - -"lodash._releasearray@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash._releasearray@npm:2.4.1" - dependencies: - lodash._arraypool: "npm:~2.4.1" - lodash._maxpoolsize: "npm:~2.4.1" - checksum: 10c0/8d2a97143a733f01dc9928fb79f95847bd879448fd049f9a6d9068cd70921c06a3b2e013e9bb9bbceee1729cef3cd3b2486b72fe8e52a3e3a942d1785552d720 - languageName: node - linkType: hard - -"lodash._setbinddata@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash._setbinddata@npm:2.4.1" - dependencies: - lodash._isnative: "npm:~2.4.1" - lodash.noop: "npm:~2.4.1" - checksum: 10c0/3e9a60768b138994c03526357f70a37fa89296aff7ff748f28909fb093b42729b3f8fe5da58d38024a94b982fe14c2f4b55bd337f13ba97803d0e02dd1bcaa22 - languageName: node - linkType: hard - -"lodash._shimkeys@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash._shimkeys@npm:2.4.1" - dependencies: - lodash._objecttypes: "npm:~2.4.1" - checksum: 10c0/bd9aa121195bdc515d7af4e282c85d72a764d8107ab83be2f90f8541276bf5f3c8b13e8d31b85ebccb49f52ca688a07cf26139a7f3435011cfa989ab7a368db1 - languageName: node - linkType: hard - -"lodash._slice@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash._slice@npm:2.4.1" - checksum: 10c0/cfc3214cf71f9fd96eb9e61ad71504b4982143fe1f9e9c41122af65fefd4c566d0f6014b8fadaa04d1c56fd8bf8930cc21387663f5432eb2d3e6e84cd7dbacba - languageName: node - linkType: hard - -"lodash.assign@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash.assign@npm:2.4.1" - dependencies: - lodash._basecreatecallback: "npm:~2.4.1" - lodash._objecttypes: "npm:~2.4.1" - lodash.keys: "npm:~2.4.1" - checksum: 10c0/ce96af4545ea1e98282faf8f446ff533014b7a142a54a606ea2c3c3369377b8de199365aa2e9098f325a567132db3529894bb220874fd9a25fa049b1bf851c88 - languageName: node - linkType: hard - -"lodash.bind@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash.bind@npm:2.4.1" - dependencies: - lodash._createwrapper: "npm:~2.4.1" - lodash._slice: "npm:~2.4.1" - checksum: 10c0/b0b8c7656417e44c257efb0b06c57b1cdd8542682074e6522b99fe67fabfc2fed59c849d6e4746093d9de344adc32f4367edd7806b466ff486350760c26885d9 - languageName: node - linkType: hard - "lodash.camelcase@npm:^4.3.0": version: 4.3.0 resolution: "lodash.camelcase@npm:4.3.0" @@ -18783,16 +15958,6 @@ __metadata: languageName: node linkType: hard -"lodash.clonedeep@npm:^2.4.1": - version: 2.4.1 - resolution: "lodash.clonedeep@npm:2.4.1" - dependencies: - lodash._baseclone: "npm:~2.4.1" - lodash._basecreatecallback: "npm:~2.4.1" - checksum: 10c0/99d416a6a62a284be48f4aa3d6beaec5a22f7e350d23d1708977a22305b8a1b3af07cccadb8dd5a31341c859c4e047490c2d2f942aee40085faff63c15fc0df5 - languageName: node - linkType: hard - "lodash.clonedeep@npm:^4.5.0": version: 4.5.0 resolution: "lodash.clonedeep@npm:4.5.0" @@ -18807,50 +15972,6 @@ __metadata: languageName: node linkType: hard -"lodash.foreach@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash.foreach@npm:2.4.1" - dependencies: - lodash._basecreatecallback: "npm:~2.4.1" - lodash.forown: "npm:~2.4.1" - checksum: 10c0/794df75c9d5c44d474359ae19ab472f45890ff1fda8a07c0aaf7e7141417855d671f0f30ce374ae553e13fd708ac38ccad7ac23723108d837280f0dc0887eb05 - languageName: node - linkType: hard - -"lodash.forown@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash.forown@npm:2.4.1" - dependencies: - lodash._basecreatecallback: "npm:~2.4.1" - lodash._objecttypes: "npm:~2.4.1" - lodash.keys: "npm:~2.4.1" - checksum: 10c0/a324e538e6ff40dc575e37122eab8b04bdd89919c806ff07af6db40ed8e657efb595cd154e646d7b7f4fec69e2c8587a100f1203516f76dbf7738ee93fad70bb - languageName: node - linkType: hard - -"lodash.get@npm:^4.0.0": - version: 4.4.2 - resolution: "lodash.get@npm:4.4.2" - checksum: 10c0/48f40d471a1654397ed41685495acb31498d5ed696185ac8973daef424a749ca0c7871bf7b665d5c14f5cc479394479e0307e781f61d5573831769593411be6e - languageName: node - linkType: hard - -"lodash.identity@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash.identity@npm:2.4.1" - checksum: 10c0/b58784222f0b011e71aa45a7d2ad2f46e6d03f3e2ae96803e0feabd2d8a71e8e76f4686130dc598dc3d4dcbb565d5caef6dfffabfe32e142e624d78f8fa228e4 - languageName: node - linkType: hard - -"lodash.isarray@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash.isarray@npm:2.4.1" - dependencies: - lodash._isnative: "npm:~2.4.1" - checksum: 10c0/2b869606580d8fa0e03f47565ed40e1dad4f0fad45c954552444b840de833ec4299e646413f8e83092a6c2aa4cead1c6b29fb3f03aa349861064ce28f7763472 - languageName: node - linkType: hard - "lodash.isempty@npm:^4.4.0": version: 4.4.0 resolution: "lodash.isempty@npm:4.4.0" @@ -18858,7 +15979,7 @@ __metadata: languageName: node linkType: hard -"lodash.isequal@npm:^4.0.0, lodash.isequal@npm:^4.5.0": +"lodash.isequal@npm:^4.5.0": version: 4.5.0 resolution: "lodash.isequal@npm:4.5.0" checksum: 10c0/dfdb2356db19631a4b445d5f37868a095e2402292d59539a987f134a8778c62a2810c2452d11ae9e6dcac71fc9de40a6fedcb20e2952a15b431ad8b29e50e28f @@ -18872,13 +15993,6 @@ __metadata: languageName: node linkType: hard -"lodash.isfunction@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash.isfunction@npm:2.4.1" - checksum: 10c0/727cc623cbcc6dde02e1ea3bd5b08f8a536ba55104d37ba911c90bdbea0f57ca9da673b3ab64869d8b851e800fdc59d78e21262446384147355c47a15e09a72f - languageName: node - linkType: hard - "lodash.isobject@npm:^3.0.2": version: 3.0.2 resolution: "lodash.isobject@npm:3.0.2" @@ -18886,15 +16000,6 @@ __metadata: languageName: node linkType: hard -"lodash.isobject@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash.isobject@npm:2.4.1" - dependencies: - lodash._objecttypes: "npm:~2.4.1" - checksum: 10c0/836a7567947bb01c054bdf4f1c8cc533d5dd053362368f16e5e5cdd1c5cfcf0ff219929e911b671cd9ae536f48318e41abb13a3557e5ec33fd400e262cf58792 - languageName: node - linkType: hard - "lodash.isstring@npm:^4.0.1": version: 4.0.1 resolution: "lodash.isstring@npm:4.0.1" @@ -18902,17 +16007,6 @@ __metadata: languageName: node linkType: hard -"lodash.keys@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash.keys@npm:2.4.1" - dependencies: - lodash._isnative: "npm:~2.4.1" - lodash._shimkeys: "npm:~2.4.1" - lodash.isobject: "npm:~2.4.1" - checksum: 10c0/73d0e3e29415a4a636d09ca6e5f58d1cf545ea67ade2627c8a86c42fea4744dda9031af25bbd90c32006765a3b9847fb58655f30e046a08553b038f552f6dbff - languageName: node - linkType: hard - "lodash.merge@npm:^4.6.2": version: 4.6.2 resolution: "lodash.merge@npm:4.6.2" @@ -18920,22 +16014,6 @@ __metadata: languageName: node linkType: hard -"lodash.noop@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash.noop@npm:2.4.1" - checksum: 10c0/d30f7d2cc3d8a162a5c621b1687d3b0428c9a10fe1ce71aa7fae9620d1219de12bff2a3db8c269bf8d22937392541675a307a3012e8b00f992fae6e2eada7c94 - languageName: node - linkType: hard - -"lodash.support@npm:~2.4.1": - version: 2.4.1 - resolution: "lodash.support@npm:2.4.1" - dependencies: - lodash._isnative: "npm:~2.4.1" - checksum: 10c0/6d46ff622c1e01326fa2823d51394b2a221f2fbf463c6b89a28eeb912bd8d3f339b2d307bf58472c4049abfa4e8d1d466df96f8590755113fb1ede3410728f1a - languageName: node - linkType: hard - "lodash.throttle@npm:^4.1.1": version: 4.1.1 resolution: "lodash.throttle@npm:4.1.1" @@ -18950,20 +16028,13 @@ __metadata: languageName: node linkType: hard -"lodash@npm:4.17.21, lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.12, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.20, lodash@npm:^4.17.21": +"lodash@npm:4.17.21, lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.20, lodash@npm:^4.17.21": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: 10c0/d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c languageName: node linkType: hard -"lodash@npm:^3.10.0, lodash@npm:^3.3.1": - version: 3.10.1 - resolution: "lodash@npm:3.10.1" - checksum: 10c0/f5f6d3d87503c3f1db27d49b30a00bb38dc1bd9de716c5febe8970259cc7b447149a0e320452ccaf5996a7a4abd63d94df341bb91bd8d336584ad518d8eab144 - languageName: node - linkType: hard - "log-symbols@npm:^4.1.0": version: 4.1.0 resolution: "log-symbols@npm:4.1.0" @@ -18974,18 +16045,6 @@ __metadata: languageName: node linkType: hard -"logixlysia@npm:^4.1.1": - version: 4.2.7 - resolution: "logixlysia@npm:4.2.7" - dependencies: - chalk: "npm:^5.3.0" - elysia: "npm:^1.1.23" - peerDependencies: - typescript: ^5.2.2 - conditions: (os=darwin | os=linux | os=win32) - languageName: node - linkType: hard - "logkitty@npm:^0.7.1": version: 0.7.1 resolution: "logkitty@npm:0.7.1" @@ -19078,13 +16137,6 @@ __metadata: languageName: node linkType: hard -"lowercase-keys@npm:^1.0.0": - version: 1.0.1 - resolution: "lowercase-keys@npm:1.0.1" - checksum: 10c0/56776a8e1ef1aca98ecf6c19b30352ae1cf257b65b8ac858b7d8a0e8b348774d12a9b41aa7f59bfea51bff44bc7a198ab63ba4406bfba60dba008799618bef66 - languageName: node - linkType: hard - "lowercase-keys@npm:^2.0.0": version: 2.0.0 resolution: "lowercase-keys@npm:2.0.0" @@ -19092,13 +16144,6 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:2": - version: 2.7.3 - resolution: "lru-cache@npm:2.7.3" - checksum: 10c0/699702a9e374fd48cb507c55ecf655409337b3f6356a78e620e64e34c675bd988377fd4e3bb1db6e05a03b10e1758ba55877ca90a01c8d7ab2bea05cc49190d8 - languageName: node - linkType: hard - "lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": version: 10.4.3 resolution: "lru-cache@npm:10.4.3" @@ -19106,16 +16151,6 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^4.0.1": - version: 4.1.5 - resolution: "lru-cache@npm:4.1.5" - dependencies: - pseudomap: "npm:^1.0.2" - yallist: "npm:^2.1.2" - checksum: 10c0/1ca5306814e5add9ec63556d6fd9b24a4ecdeaef8e9cea52cbf30301e6b88c8d8ddc7cab45b59b56eb763e6c45af911585dc89925a074ab65e1502e3fe8103cf - languageName: node - linkType: hard - "lru-cache@npm:^5.1.1": version: 5.1.1 resolution: "lru-cache@npm:5.1.1" @@ -19148,15 +16183,6 @@ __metadata: languageName: node linkType: hard -"make-dir@npm:^1.0.0": - version: 1.3.0 - resolution: "make-dir@npm:1.3.0" - dependencies: - pify: "npm:^3.0.0" - checksum: 10c0/5eb94f47d7ef41d89d1b8eef6539b8950d5bd99eeba093a942bfd327faa37d2d62227526b88b73633243a2ec7972d21eb0f4e5d62ae4e02a79e389f4a7bb3022 - languageName: node - linkType: hard - "make-dir@npm:^2.0.0, make-dir@npm:^2.1.0": version: 2.1.0 resolution: "make-dir@npm:2.1.0" @@ -19211,22 +16237,6 @@ __metadata: languageName: node linkType: hard -"map-cache@npm:^0.2.2": - version: 0.2.2 - resolution: "map-cache@npm:0.2.2" - checksum: 10c0/05e3eb005c1b80b9f949ca007687640e8c5d0fc88dc45c3c3ab4902a3bec79d66a58f3e3b04d6985d90cd267c629c7b46c977e9c34433e8c11ecfcbb9f0fa290 - languageName: node - linkType: hard - -"map-visit@npm:^1.0.0": - version: 1.0.0 - resolution: "map-visit@npm:1.0.0" - dependencies: - object-visit: "npm:^1.0.0" - checksum: 10c0/fb3475e5311939a6147e339999113db607adc11c7c3cd3103e5e9dbf502898416ecba6b1c7c649c6d4d12941de00cee58b939756bdf20a9efe7d4fa5a5738b73 - languageName: node - linkType: hard - "markdown-table@npm:^1.1.3": version: 1.1.3 resolution: "markdown-table@npm:1.1.3" @@ -19259,17 +16269,6 @@ __metadata: languageName: node linkType: hard -"md5@npm:~2.2.0": - version: 2.2.1 - resolution: "md5@npm:2.2.1" - dependencies: - charenc: "npm:~0.0.1" - crypt: "npm:~0.0.1" - is-buffer: "npm:~1.1.1" - checksum: 10c0/e9e7de197a100169f27b956af63ece22348b2d06d40162c8d380d13dcbb7a307c95956857d0cb5ed92059f6448bbdce2d54bc6b922f8e6a36284c303ecc1612d - languageName: node - linkType: hard - "mdn-data@npm:2.0.14": version: 2.0.14 resolution: "mdn-data@npm:2.0.14" @@ -19291,13 +16290,6 @@ __metadata: languageName: node linkType: hard -"media-typer@npm:0.3.0": - version: 0.3.0 - resolution: "media-typer@npm:0.3.0" - checksum: 10c0/d160f31246907e79fed398470285f21bafb45a62869dc469b1c8877f3f064f5eabc4bcc122f9479b8b605bc5c76187d7871cf84c4ee3ecd3e487da1993279928 - languageName: node - linkType: hard - "memoize-one@npm:^5.0.0": version: 5.2.1 resolution: "memoize-one@npm:5.2.1" @@ -19305,13 +16297,6 @@ __metadata: languageName: node linkType: hard -"memory-cache@npm:~0.2.0": - version: 0.2.0 - resolution: "memory-cache@npm:0.2.0" - checksum: 10c0/d4fe58865dfdc252db18ae152ab6c9d62868cfc42d5e7f6cf30732fcf27f5f1f8d7b179c3b6f26f31a28ab1cc5c3937215c60aa9e8ad7ea8ff35e79f69ef14da - languageName: node - linkType: hard - "memorystream@npm:^0.3.1": version: 0.3.1 resolution: "memorystream@npm:0.3.1" @@ -19342,13 +16327,6 @@ __metadata: languageName: node linkType: hard -"methods@npm:^1.1.2, methods@npm:~1.1.1": - version: 1.1.2 - resolution: "methods@npm:1.1.2" - checksum: 10c0/bdf7cc72ff0a33e3eede03708c08983c4d7a173f91348b4b1e4f47d4cdbf734433ad971e7d1e8c77247d9e5cd8adb81ea4c67b0a2db526b758b2233d7814b8b2 - languageName: node - linkType: hard - "metro-babel-transformer@npm:0.80.12": version: 0.80.12 resolution: "metro-babel-transformer@npm:0.80.12" @@ -19833,27 +16811,6 @@ __metadata: languageName: node linkType: hard -"micromatch@npm:^3.1.10, micromatch@npm:^3.1.4": - version: 3.1.10 - resolution: "micromatch@npm:3.1.10" - dependencies: - arr-diff: "npm:^4.0.0" - array-unique: "npm:^0.3.2" - braces: "npm:^2.3.1" - define-property: "npm:^2.0.2" - extend-shallow: "npm:^3.0.2" - extglob: "npm:^2.0.4" - fragment-cache: "npm:^0.2.1" - kind-of: "npm:^6.0.2" - nanomatch: "npm:^1.2.9" - object.pick: "npm:^1.3.0" - regex-not: "npm:^1.0.0" - snapdragon: "npm:^0.8.1" - to-regex: "npm:^3.0.2" - checksum: 10c0/531a32e7ac92bef60657820202be71b63d0f945c08a69cc4c239c0b19372b751483d464a850a2e3a5ff6cc9060641e43d44c303af104c1a27493d137d8af017f - languageName: node - linkType: hard - "micromatch@npm:^4.0.0, micromatch@npm:^4.0.2, micromatch@npm:^4.0.4, micromatch@npm:^4.0.8": version: 4.0.8 resolution: "micromatch@npm:4.0.8" @@ -19878,7 +16835,7 @@ __metadata: languageName: node linkType: hard -"mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:^2.1.3, mime-types@npm:^2.1.35, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": +"mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:^2.1.35, mime-types@npm:~2.1.34": version: 2.1.35 resolution: "mime-types@npm:2.1.35" dependencies: @@ -19887,15 +16844,6 @@ __metadata: languageName: node linkType: hard -"mime@npm:1.3.4": - version: 1.3.4 - resolution: "mime@npm:1.3.4" - bin: - mime: cli.js - checksum: 10c0/06ca13fe3be58eedfadc4351ca735c19ad25f2f8f0ecc746c1b2e780934829cc0e4b303269f0abfc919ecb6f149f1b648700f996d2b7935fb23208f7357438d4 - languageName: node - linkType: hard - "mime@npm:1.6.0": version: 1.6.0 resolution: "mime@npm:1.6.0" @@ -19905,7 +16853,7 @@ __metadata: languageName: node linkType: hard -"mime@npm:2.6.0, mime@npm:^2.4.1": +"mime@npm:^2.4.1": version: 2.6.0 resolution: "mime@npm:2.6.0" bin: @@ -19956,16 +16904,6 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:0.3": - version: 0.3.0 - resolution: "minimatch@npm:0.3.0" - dependencies: - lru-cache: "npm:2" - sigmund: "npm:~1.0.0" - checksum: 10c0/c9809c0f0bb04b9af8f3bdf3d0c285e94c3b08a961d4916e22bc89d1f94771a98af7e22accc9622fb4cd543c6028882ab38fdaa22f4d8ee7026b7aa6670425e4 - languageName: node - linkType: hard - "minimatch@npm:2 || 3, minimatch@npm:^3.0.2, minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" @@ -19975,15 +16913,6 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:9.0.3": - version: 9.0.3 - resolution: "minimatch@npm:9.0.3" - dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10c0/85f407dcd38ac3e180f425e86553911d101455ca3ad5544d6a7cec16286657e4f8a9aa6695803025c55e31e35a91a2252b5dc8e7d527211278b8b65b4dbd5eac - languageName: node - linkType: hard - "minimatch@npm:^5.0.1, minimatch@npm:^5.1.6": version: 5.1.6 resolution: "minimatch@npm:5.1.6" @@ -19993,7 +16922,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^9.0.1, minimatch@npm:^9.0.4": +"minimatch@npm:^9.0.4": version: 9.0.5 resolution: "minimatch@npm:9.0.5" dependencies: @@ -20002,13 +16931,6 @@ __metadata: languageName: node linkType: hard -"minimist@npm:0.0.8": - version: 0.0.8 - resolution: "minimist@npm:0.0.8" - checksum: 10c0/d0a998c3042922dbcd5f23566b52811d6977649ad089fd75dd89e8a9bff27634194900818b2dfb1b873f204edb902d0c8cdea9cb8dca8488b301f69bd522d5dc - languageName: node - linkType: hard - "minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6": version: 1.2.8 resolution: "minimist@npm:1.2.8" @@ -20116,16 +17038,6 @@ __metadata: languageName: node linkType: hard -"mixin-deep@npm:^1.2.0": - version: 1.3.2 - resolution: "mixin-deep@npm:1.3.2" - dependencies: - for-in: "npm:^1.0.2" - is-extendable: "npm:^1.0.1" - checksum: 10c0/cb39ffb73c377222391af788b4c83d1a6cecb2d9fceb7015384f8deb46e151a9b030c21ef59a79cb524d4557e3f74c7248ab948a62a6e7e296b42644863d183b - languageName: node - linkType: hard - "mixin-object@npm:^2.0.1": version: 2.0.1 resolution: "mixin-object@npm:2.0.1" @@ -20136,25 +17048,7 @@ __metadata: languageName: node linkType: hard -"mkdirp@npm:0.3.0": - version: 0.3.0 - resolution: "mkdirp@npm:0.3.0" - checksum: 10c0/cd9e54878490571df79770de1cdceba48ab6682c004616666d23a38315feaf5822d443aeb500ac298a12d7f6f5e11dc05cea3207d500e547d938218bf22d8629 - languageName: node - linkType: hard - -"mkdirp@npm:0.5.1": - version: 0.5.1 - resolution: "mkdirp@npm:0.5.1" - dependencies: - minimist: "npm:0.0.8" - bin: - mkdirp: bin/cmd.js - checksum: 10c0/e5ff572d761240a06dbfc69e1ea303d5482815a1f66033b999bd9d78583fcdc9ef63e99e61d396bbd57eca45b388af80a7f7f35f63510619c991c9d44c75341c - languageName: node - linkType: hard - -"mkdirp@npm:0.5.x, mkdirp@npm:^0.5.1, mkdirp@npm:^0.5.4": +"mkdirp@npm:0.5.x, mkdirp@npm:^0.5.1": version: 0.5.6 resolution: "mkdirp@npm:0.5.6" dependencies: @@ -20223,27 +17117,6 @@ __metadata: languageName: node linkType: hard -"mocha@npm:^2.2.1": - version: 2.5.3 - resolution: "mocha@npm:2.5.3" - dependencies: - commander: "npm:2.3.0" - debug: "npm:2.2.0" - diff: "npm:1.4.0" - escape-string-regexp: "npm:1.0.2" - glob: "npm:3.2.11" - growl: "npm:1.9.2" - jade: "npm:0.26.3" - mkdirp: "npm:0.5.1" - supports-color: "npm:1.2.0" - to-iso-string: "npm:0.0.2" - bin: - _mocha: ./bin/_mocha - mocha: ./bin/mocha - checksum: 10c0/9d9b4097b592f7409973d347ecb6cbd82475135cb81e3198be94703353cc9c6bae9d4116db621fb084d7dcc0858db477b46dd54b4a56b2f696296afe5a56a559 - languageName: node - linkType: hard - "mochawesome-report-generator@npm:^6.2.0": version: 6.2.0 resolution: "mochawesome-report-generator@npm:6.2.0" @@ -20306,20 +17179,6 @@ __metadata: languageName: node linkType: hard -"mpath@npm:~0.5.0": - version: 0.5.2 - resolution: "mpath@npm:0.5.2" - checksum: 10c0/ff624fc83925e0661b70d49902903e1e859b08faaef22ce7bdb6497f8cf2665a56c2877c72be7079aa253f37055058610520b35245c0d545185ffcdc2b85603e - languageName: node - linkType: hard - -"ms@npm:0.7.1": - version: 0.7.1 - resolution: "ms@npm:0.7.1" - checksum: 10c0/caeb29c1eef02d38f03781d1937a59ddef897be8686c146507a9d33cda7fa4de678d0c6091f8ce7e45bf35585e655d398d9d5103e5197fd919643c46356887cc - languageName: node - linkType: hard - "ms@npm:2.0.0": version: 2.0.0 resolution: "ms@npm:2.0.0" @@ -20334,7 +17193,7 @@ __metadata: languageName: node linkType: hard -"ms@npm:2.1.3, ms@npm:^2.1.1, ms@npm:^2.1.3": +"ms@npm:2.1.3, ms@npm:^2.1.3": version: 2.1.3 resolution: "ms@npm:2.1.3" checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 @@ -20355,49 +17214,6 @@ __metadata: languageName: node linkType: hard -"multer@npm:^1.1.0": - version: 1.4.4 - resolution: "multer@npm:1.4.4" - dependencies: - append-field: "npm:^1.0.0" - busboy: "npm:^0.2.11" - concat-stream: "npm:^1.5.2" - mkdirp: "npm:^0.5.4" - object-assign: "npm:^4.1.1" - on-finished: "npm:^2.3.0" - type-is: "npm:^1.6.4" - xtend: "npm:^4.0.0" - checksum: 10c0/ae7505b440b833bffe4d4b712659fc880b3a3735db1190745e738138b069b2344d0d17e3985c93f0aee287d795572dbb7a90af31ec33bd1293cbf90366934b7b - languageName: node - linkType: hard - -"mute-stream@npm:0.0.5": - version: 0.0.5 - resolution: "mute-stream@npm:0.0.5" - checksum: 10c0/562d334db46e4334f473e9e9c4993df7227fa1ba0c3f7eb453e1db666b0f0e3be45315b4d01bfa722784752e51acf72e37bb982d0bd2768fe6a431eb4dbb17ab - languageName: node - linkType: hard - -"mz@npm:^2.7.0": - version: 2.7.0 - resolution: "mz@npm:2.7.0" - dependencies: - any-promise: "npm:^1.0.0" - object-assign: "npm:^4.0.1" - thenify-all: "npm:^1.0.0" - checksum: 10c0/103114e93f87362f0b56ab5b2e7245051ad0276b646e3902c98397d18bb8f4a77f2ea4a2c9d3ad516034ea3a56553b60d3f5f78220001ca4c404bd711bd0af39 - languageName: node - linkType: hard - -"nan@npm:^2.12.1": - version: 2.22.2 - resolution: "nan@npm:2.22.2" - dependencies: - node-gyp: "npm:latest" - checksum: 10c0/971f963b8120631880fa47a389c71b00cadc1c1b00ef8f147782a3f4387d4fc8195d0695911272d57438c11562fb27b24c4ae5f8c05d5e4eeb4478ba51bb73c5 - languageName: node - linkType: hard - "nanoassert@npm:^2.0.0": version: 2.0.0 resolution: "nanoassert@npm:2.0.0" @@ -20414,7 +17230,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.3.11, nanoid@npm:^3.3.6, nanoid@npm:^3.3.8": +"nanoid@npm:^3.3.11": version: 3.3.11 resolution: "nanoid@npm:3.3.11" bin: @@ -20423,7 +17239,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^5.1.0, nanoid@npm:^5.1.5": +"nanoid@npm:^5.1.0": version: 5.1.5 resolution: "nanoid@npm:5.1.5" bin: @@ -20432,25 +17248,6 @@ __metadata: languageName: node linkType: hard -"nanomatch@npm:^1.2.9": - version: 1.2.13 - resolution: "nanomatch@npm:1.2.13" - dependencies: - arr-diff: "npm:^4.0.0" - array-unique: "npm:^0.3.2" - define-property: "npm:^2.0.2" - extend-shallow: "npm:^3.0.2" - fragment-cache: "npm:^0.2.1" - is-windows: "npm:^1.0.2" - kind-of: "npm:^6.0.2" - object.pick: "npm:^1.3.0" - regex-not: "npm:^1.0.0" - snapdragon: "npm:^0.8.1" - to-regex: "npm:^3.0.1" - checksum: 10c0/0f5cefa755ca2e20c86332821995effb24acb79551ddaf51c1b9112628cad234a0d8fd9ac6aa56ad1f8bfad6ff6ae86e851acb960943249d9fa44b091479953a - languageName: node - linkType: hard - "nanospinner@npm:^1.2.2": version: 1.2.2 resolution: "nanospinner@npm:1.2.2" @@ -20460,22 +17257,6 @@ __metadata: languageName: node linkType: hard -"napi-postinstall@npm:^0.2.2": - version: 0.2.4 - resolution: "napi-postinstall@npm:0.2.4" - bin: - napi-postinstall: lib/cli.js - checksum: 10c0/e8c357d7e27848c4af7becf2796afff245a2fc8ba176e1b133410bb1c9934a66d4bc542d0c9f04c73b0ba34ee0486b30b6cd1c62ed3aa36797d394200c9a2a8b - languageName: node - linkType: hard - -"native-promise-only@npm:^0.8.1": - version: 0.8.1 - resolution: "native-promise-only@npm:0.8.1" - checksum: 10c0/c1b41128ca9806818e12d0b84f7c71e88b1fa00f0f4857767d96206dbdd0af6755305103f55c583b045533185ffca863b0c34116ade507ff7ba2e417e076a5ac - languageName: node - linkType: hard - "natural-compare@npm:^1.4.0": version: 1.4.0 resolution: "natural-compare@npm:1.4.0" @@ -20533,122 +17314,6 @@ __metadata: languageName: node linkType: hard -"next@npm:14.2.8": - version: 14.2.8 - resolution: "next@npm:14.2.8" - dependencies: - "@next/env": "npm:14.2.8" - "@next/swc-darwin-arm64": "npm:14.2.8" - "@next/swc-darwin-x64": "npm:14.2.8" - "@next/swc-linux-arm64-gnu": "npm:14.2.8" - "@next/swc-linux-arm64-musl": "npm:14.2.8" - "@next/swc-linux-x64-gnu": "npm:14.2.8" - "@next/swc-linux-x64-musl": "npm:14.2.8" - "@next/swc-win32-arm64-msvc": "npm:14.2.8" - "@next/swc-win32-ia32-msvc": "npm:14.2.8" - "@next/swc-win32-x64-msvc": "npm:14.2.8" - "@swc/helpers": "npm:0.5.5" - busboy: "npm:1.6.0" - caniuse-lite: "npm:^1.0.30001579" - graceful-fs: "npm:^4.2.11" - postcss: "npm:8.4.31" - styled-jsx: "npm:5.1.1" - peerDependencies: - "@opentelemetry/api": ^1.1.0 - "@playwright/test": ^1.41.2 - react: ^18.2.0 - react-dom: ^18.2.0 - sass: ^1.3.0 - dependenciesMeta: - "@next/swc-darwin-arm64": - optional: true - "@next/swc-darwin-x64": - optional: true - "@next/swc-linux-arm64-gnu": - optional: true - "@next/swc-linux-arm64-musl": - optional: true - "@next/swc-linux-x64-gnu": - optional: true - "@next/swc-linux-x64-musl": - optional: true - "@next/swc-win32-arm64-msvc": - optional: true - "@next/swc-win32-ia32-msvc": - optional: true - "@next/swc-win32-x64-msvc": - optional: true - peerDependenciesMeta: - "@opentelemetry/api": - optional: true - "@playwright/test": - optional: true - sass: - optional: true - bin: - next: dist/bin/next - checksum: 10c0/ceead5258f80dc2a4e911cb3e8c224ce5487c726587a79ea0a510192305f2e66a17a002841c3c0b195fd568c9a35160f563042417d3807eb5f6538c7630615de - languageName: node - linkType: hard - -"next@npm:^14.2.8": - version: 14.2.29 - resolution: "next@npm:14.2.29" - dependencies: - "@next/env": "npm:14.2.29" - "@next/swc-darwin-arm64": "npm:14.2.29" - "@next/swc-darwin-x64": "npm:14.2.29" - "@next/swc-linux-arm64-gnu": "npm:14.2.29" - "@next/swc-linux-arm64-musl": "npm:14.2.29" - "@next/swc-linux-x64-gnu": "npm:14.2.29" - "@next/swc-linux-x64-musl": "npm:14.2.29" - "@next/swc-win32-arm64-msvc": "npm:14.2.29" - "@next/swc-win32-ia32-msvc": "npm:14.2.29" - "@next/swc-win32-x64-msvc": "npm:14.2.29" - "@swc/helpers": "npm:0.5.5" - busboy: "npm:1.6.0" - caniuse-lite: "npm:^1.0.30001579" - graceful-fs: "npm:^4.2.11" - postcss: "npm:8.4.31" - styled-jsx: "npm:5.1.1" - peerDependencies: - "@opentelemetry/api": ^1.1.0 - "@playwright/test": ^1.41.2 - react: ^18.2.0 - react-dom: ^18.2.0 - sass: ^1.3.0 - dependenciesMeta: - "@next/swc-darwin-arm64": - optional: true - "@next/swc-darwin-x64": - optional: true - "@next/swc-linux-arm64-gnu": - optional: true - "@next/swc-linux-arm64-musl": - optional: true - "@next/swc-linux-x64-gnu": - optional: true - "@next/swc-linux-x64-musl": - optional: true - "@next/swc-win32-arm64-msvc": - optional: true - "@next/swc-win32-ia32-msvc": - optional: true - "@next/swc-win32-x64-msvc": - optional: true - peerDependenciesMeta: - "@opentelemetry/api": - optional: true - "@playwright/test": - optional: true - sass: - optional: true - bin: - next: dist/bin/next - checksum: 10c0/369a56f09f337804325c4049fac7ae1609717b8e3317c5f4fb9f59b29a682bcf37aaaa7e50ad5251f9ffef60a4450b976644d053a951548b15f428d861514d49 - languageName: node - linkType: hard - "no-case@npm:^3.0.4": version: 3.0.4 resolution: "no-case@npm:3.0.4" @@ -20798,26 +17463,6 @@ __metadata: languageName: node linkType: hard -"nodemon@npm:^1.3.7": - version: 1.19.4 - resolution: "nodemon@npm:1.19.4" - dependencies: - chokidar: "npm:^2.1.8" - debug: "npm:^3.2.6" - ignore-by-default: "npm:^1.0.1" - minimatch: "npm:^3.0.4" - pstree.remy: "npm:^1.1.7" - semver: "npm:^5.7.1" - supports-color: "npm:^5.5.0" - touch: "npm:^3.1.0" - undefsafe: "npm:^2.0.2" - update-notifier: "npm:^2.5.0" - bin: - nodemon: ./bin/nodemon.js - checksum: 10c0/4337afa4848c4809de89d6b4f14b9c3ee2374d4b7cd9ae6e2efaf08cc0245fdd69937874a66d54ee642f9ce9a413a14f49b496fd768036ce64939b924f1dcaf7 - languageName: node - linkType: hard - "nofilter@npm:^3.1.0": version: 3.1.0 resolution: "nofilter@npm:3.1.0" @@ -20847,15 +17492,6 @@ __metadata: languageName: node linkType: hard -"normalize-path@npm:^2.1.1": - version: 2.1.1 - resolution: "normalize-path@npm:2.1.1" - dependencies: - remove-trailing-separator: "npm:^1.0.1" - checksum: 10c0/db814326ff88057437233361b4c7e9cac7b54815b051b57f2d341ce89b1d8ec8cbd43e7fa95d7652b3b69ea8fcc294b89b8530d556a84d1bdace94229e1e9a8b - languageName: node - linkType: hard - "normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0": version: 3.0.0 resolution: "normalize-path@npm:3.0.0" @@ -20870,15 +17506,6 @@ __metadata: languageName: node linkType: hard -"npm-run-path@npm:^2.0.0": - version: 2.0.2 - resolution: "npm-run-path@npm:2.0.2" - dependencies: - path-key: "npm:^2.0.0" - checksum: 10c0/95549a477886f48346568c97b08c4fda9cdbf7ce8a4fbc2213f36896d0d19249e32d68d7451bdcbca8041b5fba04a6b2c4a618beaf19849505c05b700740f1de - languageName: node - linkType: hard - "npm-run-path@npm:^4.0.1": version: 4.0.1 resolution: "npm-run-path@npm:4.0.1" @@ -20904,13 +17531,6 @@ __metadata: languageName: node linkType: hard -"number-is-nan@npm:^1.0.0": - version: 1.0.1 - resolution: "number-is-nan@npm:1.0.1" - checksum: 10c0/cb97149006acc5cd512c13c1838223abdf202e76ddfa059c5e8e7507aff2c3a78cd19057516885a2f6f5b576543dc4f7b6f3c997cc7df53ae26c260855466df5 - languageName: node - linkType: hard - "number-to-bn@npm:1.7.0": version: 1.7.0 resolution: "number-to-bn@npm:1.7.0" @@ -20939,31 +17559,13 @@ __metadata: languageName: node linkType: hard -"object-assign@npm:^4.0.1, object-assign@npm:^4.1.0, object-assign@npm:^4.1.1": +"object-assign@npm:^4.1.0, object-assign@npm:^4.1.1": version: 4.1.1 resolution: "object-assign@npm:4.1.1" checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414 languageName: node linkType: hard -"object-copy@npm:^0.1.0": - version: 0.1.0 - resolution: "object-copy@npm:0.1.0" - dependencies: - copy-descriptor: "npm:^0.1.0" - define-property: "npm:^0.2.5" - kind-of: "npm:^3.0.3" - checksum: 10c0/79314b05e9d626159a04f1d913f4c4aba9eae8848511cf5f4c8e3b04bb3cc313b65f60357f86462c959a14c2d58380fedf89b6b32ecec237c452a5ef3900a293 - languageName: node - linkType: hard - -"object-hash@npm:^3.0.0": - version: 3.0.0 - resolution: "object-hash@npm:3.0.0" - checksum: 10c0/a06844537107b960c1c8b96cd2ac8592a265186bfa0f6ccafe0d34eabdb526f6fa81da1f37c43df7ed13b12a4ae3457a16071603bcd39d8beddb5f08c37b0f47 - languageName: node - linkType: hard - "object-inspect@npm:^1.13.3, object-inspect@npm:^1.13.4": version: 1.13.4 resolution: "object-inspect@npm:1.13.4" @@ -20978,15 +17580,6 @@ __metadata: languageName: node linkType: hard -"object-visit@npm:^1.0.0": - version: 1.0.1 - resolution: "object-visit@npm:1.0.1" - dependencies: - isobject: "npm:^3.0.0" - checksum: 10c0/086b475bda24abd2318d2b187c3e928959b89f5cb5883d6fe5a42d03719b61fc18e765f658de9ac8730e67ba9ff26d61e73d991215948ff9ecefe771e0071029 - languageName: node - linkType: hard - "object.assign@npm:^4.1.4, object.assign@npm:^4.1.7": version: 4.1.7 resolution: "object.assign@npm:4.1.7" @@ -21040,27 +17633,7 @@ __metadata: languageName: node linkType: hard -"object.groupby@npm:^1.0.3": - version: 1.0.3 - resolution: "object.groupby@npm:1.0.3" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.2" - checksum: 10c0/60d0455c85c736fbfeda0217d1a77525956f76f7b2495edeca9e9bbf8168a45783199e77b894d30638837c654d0cc410e0e02cbfcf445bc8de71c3da1ede6a9c - languageName: node - linkType: hard - -"object.pick@npm:^1.3.0": - version: 1.3.0 - resolution: "object.pick@npm:1.3.0" - dependencies: - isobject: "npm:^3.0.1" - checksum: 10c0/cd316ec986e49895a28f2df9182de9cdeee57cd2a952c122aacc86344c28624fe002d9affc4f48b5014ec7c033da9942b08821ddb44db8c5bac5b3ec54bdc31e - languageName: node - linkType: hard - -"object.values@npm:^1.0.3, object.values@npm:^1.1.6, object.values@npm:^1.2.0, object.values@npm:^1.2.1": +"object.values@npm:^1.0.3, object.values@npm:^1.1.6, object.values@npm:^1.2.1": version: 1.2.1 resolution: "object.values@npm:1.2.1" dependencies: @@ -21079,14 +17652,7 @@ __metadata: languageName: node linkType: hard -"obuf@npm:~1.1.2": - version: 1.1.2 - resolution: "obuf@npm:1.1.2" - checksum: 10c0/520aaac7ea701618eacf000fc96ae458e20e13b0569845800fc582f81b386731ab22d55354b4915d58171db00e79cfcd09c1638c02f89577ef092b38c65b7d81 - languageName: node - linkType: hard - -"on-finished@npm:2.4.1, on-finished@npm:^2.3.0": +"on-finished@npm:2.4.1": version: 2.4.1 resolution: "on-finished@npm:2.4.1" dependencies: @@ -21095,15 +17661,6 @@ __metadata: languageName: node linkType: hard -"on-finished@npm:~2.2.1": - version: 2.2.1 - resolution: "on-finished@npm:2.2.1" - dependencies: - ee-first: "npm:1.1.0" - checksum: 10c0/e7a73549a4c658b62e5cca495385557c7338a5d858cd81981ecb39011a0731497747b846e74f926ae8139bebc955e61c1f4c1ea09a146af9220e41a9ffe6a3d9 - languageName: node - linkType: hard - "on-finished@npm:~2.3.0": version: 2.3.0 resolution: "on-finished@npm:2.3.0" @@ -21129,13 +17686,6 @@ __metadata: languageName: node linkType: hard -"onetime@npm:^1.0.0": - version: 1.1.0 - resolution: "onetime@npm:1.1.0" - checksum: 10c0/612a15af7966d9df486fe7a91da115b383137f3794709785deb13ecbcabbd9ad1fa983f4ba1f6076c143d454a7da5e6590e8da4d411ff7f06c8a180eb45011f5 - languageName: node - linkType: hard - "onetime@npm:^5.1.0, onetime@npm:^5.1.2": version: 5.1.2 resolution: "onetime@npm:5.1.2" @@ -21175,13 +17725,6 @@ __metadata: languageName: node linkType: hard -"openapi-types@npm:^12.1.3": - version: 12.1.3 - resolution: "openapi-types@npm:12.1.3" - checksum: 10c0/4ad4eb91ea834c237edfa6ab31394e87e00c888fc2918009763389c00d02342345195d6f302d61c3fd807f17723cd48df29b47b538b68375b3827b3758cd520f - languageName: node - linkType: hard - "opencollective-postinstall@npm:^2.0.3": version: 2.0.3 resolution: "opencollective-postinstall@npm:2.0.3" @@ -21270,27 +17813,6 @@ __metadata: languageName: node linkType: hard -"ox@npm:0.7.1": - version: 0.7.1 - resolution: "ox@npm:0.7.1" - dependencies: - "@adraffy/ens-normalize": "npm:^1.10.1" - "@noble/ciphers": "npm:^1.3.0" - "@noble/curves": "npm:^1.6.0" - "@noble/hashes": "npm:^1.5.0" - "@scure/bip32": "npm:^1.5.0" - "@scure/bip39": "npm:^1.4.0" - abitype: "npm:^1.0.6" - eventemitter3: "npm:5.0.1" - peerDependencies: - typescript: ">=5.4.0" - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/15370d76f7e5fe1b06c5b9986bc709a8c433e4242660900b3d1adb2a56c8f762a2010a9166bdb95bdf531806cde7891911456c7ec8ba135fc232a5d5037ac673 - languageName: node - linkType: hard - "p-cancelable@npm:^2.0.0": version: 2.1.1 resolution: "p-cancelable@npm:2.1.1" @@ -21298,13 +17820,6 @@ __metadata: languageName: node linkType: hard -"p-finally@npm:^1.0.0": - version: 1.0.0 - resolution: "p-finally@npm:1.0.0" - checksum: 10c0/6b8552339a71fe7bd424d01d8451eea92d379a711fc62f6b2fe64cad8a472c7259a236c9a22b4733abca0b5666ad503cb497792a0478c5af31ded793d00937e7 - languageName: node - linkType: hard - "p-limit@npm:^2.0.0, p-limit@npm:^2.2.0": version: 2.3.0 resolution: "p-limit@npm:2.3.0" @@ -21406,18 +17921,6 @@ __metadata: languageName: node linkType: hard -"package-json@npm:^4.0.0": - version: 4.0.1 - resolution: "package-json@npm:4.0.1" - dependencies: - got: "npm:^6.7.1" - registry-auth-token: "npm:^3.0.1" - registry-url: "npm:^3.0.3" - semver: "npm:^5.1.0" - checksum: 10c0/e3c213b9764547024dd80bb7913dada29f487de1dd3d24ef63c152d661cb75ae28ccd965bac3b9e33d0cdaf7cfe2527995e8d00b9e9e2973b7c53bf19ce522a3 - languageName: node - linkType: hard - "pako@npm:^2.1.0": version: 2.1.0 resolution: "pako@npm:2.1.0" @@ -21451,7 +17954,7 @@ __metadata: languageName: node linkType: hard -"parse-json@npm:^5.0.0, parse-json@npm:^5.2.0": +"parse-json@npm:^5.2.0": version: 5.2.0 resolution: "parse-json@npm:5.2.0" dependencies: @@ -21463,20 +17966,13 @@ __metadata: languageName: node linkType: hard -"parseurl@npm:^1.3.0, parseurl@npm:~1.3.3": +"parseurl@npm:~1.3.3": version: 1.3.3 resolution: "parseurl@npm:1.3.3" checksum: 10c0/90dd4760d6f6174adb9f20cf0965ae12e23879b5f5464f38e92fce8073354341e4b3b76fa3d878351efe7d01e617121955284cfd002ab087fba1a0726ec0b4f5 languageName: node linkType: hard -"pascalcase@npm:^0.1.1": - version: 0.1.1 - resolution: "pascalcase@npm:0.1.1" - checksum: 10c0/48dfe90618e33810bf58211d8f39ad2c0262f19ad6354da1ba563935b5f429f36409a1fb9187c220328f7a4dc5969917f8e3e01ee089b5f1627b02aefe39567b - languageName: node - linkType: hard - "patch-package@npm:^8.0.0": version: 8.0.0 resolution: "patch-package@npm:8.0.0" @@ -21502,7 +17998,7 @@ __metadata: languageName: node linkType: hard -"path-dirname@npm:^1.0.0, path-dirname@npm:^1.0.2": +"path-dirname@npm:^1.0.2": version: 1.0.2 resolution: "path-dirname@npm:1.0.2" checksum: 10c0/71e59be2bada7c91f62b976245fd421b7cb01fde3207fe53a82d8880621ad04fd8b434e628c9cf4e796259fc168a107d77cd56837725267c5b2c58cefe2c4e1b @@ -21530,20 +18026,6 @@ __metadata: languageName: node linkType: hard -"path-is-inside@npm:^1.0.1": - version: 1.0.2 - resolution: "path-is-inside@npm:1.0.2" - checksum: 10c0/7fdd4b41672c70461cce734fc222b33e7b447fa489c7c4377c95e7e6852d83d69741f307d88ec0cc3b385b41cb4accc6efac3c7c511cd18512e95424f5fa980c - languageName: node - linkType: hard - -"path-key@npm:^2.0.0": - version: 2.0.1 - resolution: "path-key@npm:2.0.1" - checksum: 10c0/dd2044f029a8e58ac31d2bf34c34b93c3095c1481942960e84dd2faa95bbb71b9b762a106aead0646695330936414b31ca0bd862bf488a937ad17c8c5d73b32b - languageName: node - linkType: hard - "path-key@npm:^3.0.0, path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" @@ -21551,16 +18033,6 @@ __metadata: languageName: node linkType: hard -"path-loader@npm:^1.0.2": - version: 1.0.12 - resolution: "path-loader@npm:1.0.12" - dependencies: - native-promise-only: "npm:^0.8.1" - superagent: "npm:^7.1.6" - checksum: 10c0/e559ed3694264e43501a0ed6f905307c282fe65197a918f3963fb81f1c570bd979d157339e86527fad57b220446a84a5ed512b186703f0c6080f2fa858e91ada - languageName: node - linkType: hard - "path-parse@npm:^1.0.6, path-parse@npm:^1.0.7": version: 1.0.7 resolution: "path-parse@npm:1.0.7" @@ -21568,7 +18040,7 @@ __metadata: languageName: node linkType: hard -"path-scurry@npm:^1.10.1, path-scurry@npm:^1.11.1": +"path-scurry@npm:^1.11.1": version: 1.11.1 resolution: "path-scurry@npm:1.11.1" dependencies: @@ -21578,15 +18050,6 @@ __metadata: languageName: node linkType: hard -"path-to-regexp@npm:^1.2.0": - version: 1.9.0 - resolution: "path-to-regexp@npm:1.9.0" - dependencies: - isarray: "npm:0.0.1" - checksum: 10c0/de9ddb01b84d9c2c8e2bed18630d8d039e2d6f60a6538595750fa08c7a6482512257464c8da50616f266ab2cdd2428387e85f3b089e4c3f25d0c537e898a0751 - languageName: node - linkType: hard - "path-type@npm:^4.0.0": version: 4.0.0 resolution: "path-type@npm:4.0.0" @@ -21604,13 +18067,6 @@ __metadata: languageName: node linkType: hard -"pathe@npm:^1.1.2": - version: 1.1.2 - resolution: "pathe@npm:1.1.2" - checksum: 10c0/64ee0a4e587fb0f208d9777a6c56e4f9050039268faaaaecd50e959ef01bf847b7872785c36483fa5cdcdbdfdb31fef2ff222684d4fc21c330ab60395c681897 - languageName: node - linkType: hard - "pathval@npm:^1.1.1": version: 1.1.1 resolution: "pathval@npm:1.1.1" @@ -21645,109 +18101,6 @@ __metadata: languageName: node linkType: hard -"pg-cloudflare@npm:^1.2.5": - version: 1.2.5 - resolution: "pg-cloudflare@npm:1.2.5" - checksum: 10c0/48b9105ef027c7b3f57ef88ceaec3634cd82120059bd68273cce06989a1ec547e0b0fbb5d1afdd0711824f409c8b410f9bdec2f6c8034728992d3658c0b36f86 - languageName: node - linkType: hard - -"pg-connection-string@npm:^2.9.0": - version: 2.9.0 - resolution: "pg-connection-string@npm:2.9.0" - checksum: 10c0/7145d00688200685a9d9931a7fc8d61c75f348608626aef88080ece956ceb4ff1cbdee29c3284e41b7a3345bab0e4f50f9edc256e270bfa3a563af4ea78bb490 - languageName: node - linkType: hard - -"pg-int8@npm:1.0.1": - version: 1.0.1 - resolution: "pg-int8@npm:1.0.1" - checksum: 10c0/be6a02d851fc2a4ae3e9de81710d861de3ba35ac927268973eb3cb618873a05b9424656df464dd43bd7dc3fc5295c3f5b3c8349494f87c7af50ec59ef14e0b98 - languageName: node - linkType: hard - -"pg-numeric@npm:1.0.2": - version: 1.0.2 - resolution: "pg-numeric@npm:1.0.2" - checksum: 10c0/43dd9884e7b52c79ddc28d2d282d7475fce8bba13452d33c04ceb2e0a65f561edf6699694e8e1c832ff9093770496363183c950dd29608e1bdd98f344b25bca9 - languageName: node - linkType: hard - -"pg-pool@npm:^3.10.0": - version: 3.10.0 - resolution: "pg-pool@npm:3.10.0" - peerDependencies: - pg: ">=8.0" - checksum: 10c0/b36162dc98c0ad88cd26f3d65f3e3932c3f870abe7a88905f16fc98282e8131692903e482720ebc9698cb08851c9b19242ff16a50af7f9434c8bb0b5d33a9a9a - languageName: node - linkType: hard - -"pg-protocol@npm:*, pg-protocol@npm:^1.10.0": - version: 1.10.0 - resolution: "pg-protocol@npm:1.10.0" - checksum: 10c0/7d0d64fe9df50262d907fd476454e1e36f41f5f66044c3ba6aa773fb8add1d350a9c162306e5c33e99bdfbdcc1140dd4ca74f66eda41d0aaceb5853244dcdb65 - languageName: node - linkType: hard - -"pg-types@npm:2.2.0": - version: 2.2.0 - resolution: "pg-types@npm:2.2.0" - dependencies: - pg-int8: "npm:1.0.1" - postgres-array: "npm:~2.0.0" - postgres-bytea: "npm:~1.0.0" - postgres-date: "npm:~1.0.4" - postgres-interval: "npm:^1.1.0" - checksum: 10c0/ab3f8069a323f601cd2d2279ca8c425447dab3f9b61d933b0601d7ffc00d6200df25e26a4290b2b0783b59278198f7dd2ed03e94c4875797919605116a577c65 - languageName: node - linkType: hard - -"pg-types@npm:^4.0.1": - version: 4.0.2 - resolution: "pg-types@npm:4.0.2" - dependencies: - pg-int8: "npm:1.0.1" - pg-numeric: "npm:1.0.2" - postgres-array: "npm:~3.0.1" - postgres-bytea: "npm:~3.0.0" - postgres-date: "npm:~2.1.0" - postgres-interval: "npm:^3.0.0" - postgres-range: "npm:^1.1.1" - checksum: 10c0/780fccda2f3fa2a34e85a72e8e7dadb7d88fbe71ce88f126cb3313f333ad836d02488ec4ff3d94d0c1e5846f735d6e6c6281f8059e6b8919d2180429acaec3e2 - languageName: node - linkType: hard - -"pg@npm:^8.13.1": - version: 8.16.0 - resolution: "pg@npm:8.16.0" - dependencies: - pg-cloudflare: "npm:^1.2.5" - pg-connection-string: "npm:^2.9.0" - pg-pool: "npm:^3.10.0" - pg-protocol: "npm:^1.10.0" - pg-types: "npm:2.2.0" - pgpass: "npm:1.0.5" - peerDependencies: - pg-native: ">=3.0.1" - dependenciesMeta: - pg-cloudflare: - optional: true - peerDependenciesMeta: - pg-native: - optional: true - checksum: 10c0/24542229c7e5cbf69d654de32e8cdc8302c73f1338e56728543cb16364fb319d5689e03fa704b69a208105c7065c867cfccb9dbccccea2020bb5c64ead785713 - languageName: node - linkType: hard - -"pgpass@npm:1.0.5": - version: 1.0.5 - resolution: "pgpass@npm:1.0.5" - dependencies: - split2: "npm:^4.1.0" - checksum: 10c0/5ea6c9b2de04c33abb08d33a2dded303c4a3c7162a9264519cbe85c0a9857d712463140ba42fad0c7cd4b21f644dd870b45bb2e02fcbe505b4de0744fd802c1d - languageName: node - linkType: hard - "picocolors@npm:^1.0.0, picocolors@npm:^1.1.0, picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" @@ -21769,20 +18122,6 @@ __metadata: languageName: node linkType: hard -"pify@npm:^2.3.0": - version: 2.3.0 - resolution: "pify@npm:2.3.0" - checksum: 10c0/551ff8ab830b1052633f59cb8adc9ae8407a436e06b4a9718bcb27dc5844b83d535c3a8512b388b6062af65a98c49bdc0dd523d8b2617b188f7c8fee457158dc - languageName: node - linkType: hard - -"pify@npm:^3.0.0": - version: 3.0.0 - resolution: "pify@npm:3.0.0" - checksum: 10c0/fead19ed9d801f1b1fcd0638a1ac53eabbb0945bf615f2f8806a8b646565a04a1b0e7ef115c951d225f042cca388fdc1cd3add46d10d1ed6951c20bd2998af10 - languageName: node - linkType: hard - "pify@npm:^4.0.1": version: 4.0.1 resolution: "pify@npm:4.0.1" @@ -21790,7 +18129,7 @@ __metadata: languageName: node linkType: hard -"pirates@npm:^4.0.1, pirates@npm:^4.0.4, pirates@npm:^4.0.6": +"pirates@npm:^4.0.4, pirates@npm:^4.0.6": version: 4.0.7 resolution: "pirates@npm:4.0.7" checksum: 10c0/a51f108dd811beb779d58a76864bbd49e239fa40c7984cd11596c75a121a8cc789f1c8971d8bb15f0dbf9d48b76c05bb62fcbce840f89b688c0fa64b37e8478a @@ -21869,13 +18208,6 @@ __metadata: languageName: node linkType: hard -"posix-character-classes@npm:^0.1.0": - version: 0.1.1 - resolution: "posix-character-classes@npm:0.1.1" - checksum: 10c0/cce88011548a973b4af58361cd8f5f7b5a6faff8eef0901565802f067bcabf82597e920d4c97c22068464be3cbc6447af589f6cc8a7d813ea7165be60a0395bc - languageName: node - linkType: hard - "possible-typed-array-names@npm:^1.0.0": version: 1.1.0 resolution: "possible-typed-array-names@npm:1.1.0" @@ -21883,165 +18215,6 @@ __metadata: languageName: node linkType: hard -"postcss-import@npm:^15.1.0": - version: 15.1.0 - resolution: "postcss-import@npm:15.1.0" - dependencies: - postcss-value-parser: "npm:^4.0.0" - read-cache: "npm:^1.0.0" - resolve: "npm:^1.1.7" - peerDependencies: - postcss: ^8.0.0 - checksum: 10c0/518aee5c83ea6940e890b0be675a2588db68b2582319f48c3b4e06535a50ea6ee45f7e63e4309f8754473245c47a0372632378d1d73d901310f295a92f26f17b - languageName: node - linkType: hard - -"postcss-js@npm:^4.0.1": - version: 4.0.1 - resolution: "postcss-js@npm:4.0.1" - dependencies: - camelcase-css: "npm:^2.0.1" - peerDependencies: - postcss: ^8.4.21 - checksum: 10c0/af35d55cb873b0797d3b42529514f5318f447b134541844285c9ac31a17497297eb72296902967911bb737a75163441695737300ce2794e3bd8c70c13a3b106e - languageName: node - linkType: hard - -"postcss-load-config@npm:^4.0.2": - version: 4.0.2 - resolution: "postcss-load-config@npm:4.0.2" - dependencies: - lilconfig: "npm:^3.0.0" - yaml: "npm:^2.3.4" - peerDependencies: - postcss: ">=8.0.9" - ts-node: ">=9.0.0" - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true - checksum: 10c0/3d7939acb3570b0e4b4740e483d6e555a3e2de815219cb8a3c8fc03f575a6bde667443aa93369c0be390af845cb84471bf623e24af833260de3a105b78d42519 - languageName: node - linkType: hard - -"postcss-nested@npm:^6.2.0": - version: 6.2.0 - resolution: "postcss-nested@npm:6.2.0" - dependencies: - postcss-selector-parser: "npm:^6.1.1" - peerDependencies: - postcss: ^8.2.14 - checksum: 10c0/7f9c3f2d764191a39364cbdcec350f26a312431a569c9ef17408021424726b0d67995ff5288405e3724bb7152a4c92f73c027e580ec91e798800ed3c52e2bc6e - languageName: node - linkType: hard - -"postcss-selector-parser@npm:^6.1.1, postcss-selector-parser@npm:^6.1.2": - version: 6.1.2 - resolution: "postcss-selector-parser@npm:6.1.2" - dependencies: - cssesc: "npm:^3.0.0" - util-deprecate: "npm:^1.0.2" - checksum: 10c0/523196a6bd8cf660bdf537ad95abd79e546d54180f9afb165a4ab3e651ac705d0f8b8ce6b3164fb9e3279ce482c5f751a69eb2d3a1e8eb0fd5e82294fb3ef13e - languageName: node - linkType: hard - -"postcss-value-parser@npm:^4.0.0": - version: 4.2.0 - resolution: "postcss-value-parser@npm:4.2.0" - checksum: 10c0/f4142a4f56565f77c1831168e04e3effd9ffcc5aebaf0f538eee4b2d465adfd4b85a44257bb48418202a63806a7da7fe9f56c330aebb3cac898e46b4cbf49161 - languageName: node - linkType: hard - -"postcss@npm:8.4.31": - version: 8.4.31 - resolution: "postcss@npm:8.4.31" - dependencies: - nanoid: "npm:^3.3.6" - picocolors: "npm:^1.0.0" - source-map-js: "npm:^1.0.2" - checksum: 10c0/748b82e6e5fc34034dcf2ae88ea3d11fd09f69b6c50ecdd3b4a875cfc7cdca435c958b211e2cb52355422ab6fccb7d8f2f2923161d7a1b281029e4a913d59acf - languageName: node - linkType: hard - -"postcss@npm:^8, postcss@npm:^8.4.47": - version: 8.5.3 - resolution: "postcss@npm:8.5.3" - dependencies: - nanoid: "npm:^3.3.8" - picocolors: "npm:^1.1.1" - source-map-js: "npm:^1.2.1" - checksum: 10c0/b75510d7b28c3ab728c8733dd01538314a18c52af426f199a3c9177e63eb08602a3938bfb66b62dc01350b9aed62087eabbf229af97a1659eb8d3513cec823b3 - languageName: node - linkType: hard - -"postgres-array@npm:~2.0.0": - version: 2.0.0 - resolution: "postgres-array@npm:2.0.0" - checksum: 10c0/cbd56207e4141d7fbf08c86f2aebf21fa7064943d3f808ec85f442ff94b48d891e7a144cc02665fb2de5dbcb9b8e3183a2ac749959e794b4a4cfd379d7a21d08 - languageName: node - linkType: hard - -"postgres-array@npm:~3.0.1": - version: 3.0.4 - resolution: "postgres-array@npm:3.0.4" - checksum: 10c0/47f3e648da512bacdd6a5ed55cf770605ec271330789faeece0fd13805a49f376d6e5c9e0e353377be11a9545e727dceaa2473566c505432bf06366ccd04c6b2 - languageName: node - linkType: hard - -"postgres-bytea@npm:~1.0.0": - version: 1.0.0 - resolution: "postgres-bytea@npm:1.0.0" - checksum: 10c0/febf2364b8a8953695cac159eeb94542ead5886792a9627b97e33f6b5bb6e263bc0706ab47ec221516e79fbd6b2452d668841830fb3b49ec6c0fc29be61892ce - languageName: node - linkType: hard - -"postgres-bytea@npm:~3.0.0": - version: 3.0.0 - resolution: "postgres-bytea@npm:3.0.0" - dependencies: - obuf: "npm:~1.1.2" - checksum: 10c0/41c79cc48aa730c5ba3eda6ab989a940034f07a1f57b8f2777dce56f1b8cca16c5870582932b5b10cc605048aef9b6157e06253c871b4717cafc6d00f55376aa - languageName: node - linkType: hard - -"postgres-date@npm:~1.0.4": - version: 1.0.7 - resolution: "postgres-date@npm:1.0.7" - checksum: 10c0/0ff91fccc64003e10b767fcfeefb5eaffbc522c93aa65d5051c49b3c4ce6cb93ab091a7d22877a90ad60b8874202c6f1d0f935f38a7235ed3b258efd54b97ca9 - languageName: node - linkType: hard - -"postgres-date@npm:~2.1.0": - version: 2.1.0 - resolution: "postgres-date@npm:2.1.0" - checksum: 10c0/00a7472c10788f6b0d08d24108bf1eb80858de1bd6317740198a564918ea4a69b80c98148167b92ae688abd606483020d0de0dd3a36f3ea9a3e26bbeef3464f4 - languageName: node - linkType: hard - -"postgres-interval@npm:^1.1.0": - version: 1.2.0 - resolution: "postgres-interval@npm:1.2.0" - dependencies: - xtend: "npm:^4.0.0" - checksum: 10c0/c1734c3cb79e7f22579af0b268a463b1fa1d084e742a02a7a290c4f041e349456f3bee3b4ee0bb3f226828597f7b76deb615c1b857db9a742c45520100456272 - languageName: node - linkType: hard - -"postgres-interval@npm:^3.0.0": - version: 3.0.0 - resolution: "postgres-interval@npm:3.0.0" - checksum: 10c0/8b570b30ea37c685e26d136d34460f246f98935a1533defc4b53bb05ee23ae3dc7475b718ec7ea607a57894d8c6b4f1adf67ca9cc83a75bdacffd427d5c68de8 - languageName: node - linkType: hard - -"postgres-range@npm:^1.1.1": - version: 1.1.4 - resolution: "postgres-range@npm:1.1.4" - checksum: 10c0/254494ef81df208e0adeae6b66ce394aba37914ea14c7ece55a45fb6691b7db04bee74c825380a47c887a9f87158fd3d86f758f9cc60b76d3a38ce5aca7912e8 - languageName: node - linkType: hard - "postinstall-postinstall@npm:^2.1.0": version: 2.1.0 resolution: "postinstall-postinstall@npm:2.1.0" @@ -22063,13 +18236,6 @@ __metadata: languageName: node linkType: hard -"prepend-http@npm:^1.0.1": - version: 1.0.4 - resolution: "prepend-http@npm:1.0.4" - checksum: 10c0/c6c173ca439e58163ba7bea7cbba52a1ed11e3e3da1c048da296f37d4b7654f78f7304e03f76d5923f4b83af7e2d55533e0f79064209c75b743ccddee13904f8 - languageName: node - linkType: hard - "prettier-linter-helpers@npm:^1.0.0": version: 1.0.0 resolution: "prettier-linter-helpers@npm:1.0.0" @@ -22190,7 +18356,7 @@ __metadata: languageName: node linkType: hard -"prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1": +"prop-types@npm:^15.7.2, prop-types@npm:^15.8.1": version: 15.8.1 resolution: "prop-types@npm:15.8.1" dependencies: @@ -22240,13 +18406,6 @@ __metadata: languageName: node linkType: hard -"pseudomap@npm:^1.0.2": - version: 1.0.2 - resolution: "pseudomap@npm:1.0.2" - checksum: 10c0/5a91ce114c64ed3a6a553aa7d2943868811377388bb31447f9d8028271bae9b05b340fe0b6961a64e45b9c72946aeb0a4ab635e8f7cb3715ffd0ff2beeb6a679 - languageName: node - linkType: hard - "psl@npm:^1.9.0": version: 1.15.0 resolution: "psl@npm:1.15.0" @@ -22256,13 +18415,6 @@ __metadata: languageName: node linkType: hard -"pstree.remy@npm:^1.1.7": - version: 1.1.8 - resolution: "pstree.remy@npm:1.1.8" - checksum: 10c0/30f78c88ce6393cb3f7834216cb6e282eb83c92ccb227430d4590298ab2811bc4a4745f850a27c5178e79a8f3e316591de0fec87abc19da648c2b3c6eb766d14 - languageName: node - linkType: hard - "pump@npm:^3.0.0": version: 3.0.2 resolution: "pump@npm:3.0.2" @@ -22325,28 +18477,7 @@ __metadata: languageName: node linkType: hard -"qs@npm:2.3.3": - version: 2.3.3 - resolution: "qs@npm:2.3.3" - checksum: 10c0/4c02f03f77e50219799f52608dd72f57389ea364be499f5e8b02d505377cb93f6414239e00b3a7342b0d05a730ad85b3ffb5e7f0a5ba2f3d8ef7303283c01e17 - languageName: node - linkType: hard - -"qs@npm:2.4.2": - version: 2.4.2 - resolution: "qs@npm:2.4.2" - checksum: 10c0/50228c5c2129766e04f8aec41c70e3e1d235484ac8e83352d6ac723d58e91642082abc0172122dc27e13e8c6a28a8d3b9fc499fe120c48dc764ddf27f498fb51 - languageName: node - linkType: hard - -"qs@npm:^4.0.0": - version: 4.0.0 - resolution: "qs@npm:4.0.0" - checksum: 10c0/23a656b2193ded17fbc2fbb08e5294f1657fc4b4cc62de4d8808b330854022a34b8394d2507bcf9998982d26ce5e3822b039ee3523fe8590223d4a156e08e998 - languageName: node - linkType: hard - -"qs@npm:^6.10.3, qs@npm:^6.11.0, qs@npm:^6.4.0": +"qs@npm:^6.4.0": version: 6.14.0 resolution: "qs@npm:6.14.0" dependencies: @@ -22466,30 +18597,6 @@ __metadata: languageName: node linkType: hard -"raw-body@npm:~2.0.1": - version: 2.0.2 - resolution: "raw-body@npm:2.0.2" - dependencies: - bytes: "npm:2.1.0" - iconv-lite: "npm:0.4.8" - checksum: 10c0/a2c15f2862b278b1550d45624cce27838fa1ffe19429fa8c4ae977c66e36642827a74a7ef049a415ccba4b1595c2fb55d595d55ec1c1ae65f8cd2582203ccae6 - languageName: node - linkType: hard - -"rc@npm:^1.0.1, rc@npm:^1.1.6": - version: 1.2.8 - resolution: "rc@npm:1.2.8" - dependencies: - deep-extend: "npm:^0.6.0" - ini: "npm:~1.3.0" - minimist: "npm:^1.2.0" - strip-json-comments: "npm:~2.0.1" - bin: - rc: ./cli.js - checksum: 10c0/24a07653150f0d9ac7168e52943cc3cb4b7a22c0e43c7dff3219977c2fdca5a2760a304a029c20811a0e79d351f57d46c9bde216193a0f73978496afc2b85b15 - languageName: node - linkType: hard - "react-devtools-core@npm:^5.3.1": version: 5.3.2 resolution: "react-devtools-core@npm:5.3.2" @@ -22510,7 +18617,7 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:^18, react-dom@npm:^18.0.0": +"react-dom@npm:^18.0.0": version: 18.3.1 resolution: "react-dom@npm:18.3.1" dependencies: @@ -22563,7 +18670,7 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^19.0.0, react-is@npm:^19.1.0": +"react-is@npm:^19.1.0": version: 19.1.0 resolution: "react-is@npm:19.1.0" checksum: 10c0/b6c6cadd172d5d39f66d493700d137a5545c294a62ce0f8ec793d59794c97d2bed6bad227626f16bd0e90004ed7fdc8ed662a004e6edcf5d2b7ecb6e3040ea6b @@ -22997,22 +19104,7 @@ __metadata: languageName: node linkType: hard -"react-transition-group@npm:^4.4.5": - version: 4.4.5 - resolution: "react-transition-group@npm:4.4.5" - dependencies: - "@babel/runtime": "npm:^7.5.5" - dom-helpers: "npm:^5.0.1" - loose-envify: "npm:^1.4.0" - prop-types: "npm:^15.6.2" - peerDependencies: - react: ">=16.6.0" - react-dom: ">=16.6.0" - checksum: 10c0/2ba754ba748faefa15f87c96dfa700d5525054a0141de8c75763aae6734af0740e77e11261a1e8f4ffc08fd9ab78510122e05c21c2d79066c38bb6861a886c82 - languageName: node - linkType: hard - -"react@npm:^18, react@npm:^18.0.0, react@npm:^18.3.1": +"react@npm:^18.0.0, react@npm:^18.3.1": version: 18.3.1 resolution: "react@npm:18.3.1" dependencies: @@ -23021,39 +19113,6 @@ __metadata: languageName: node linkType: hard -"read-cache@npm:^1.0.0": - version: 1.0.0 - resolution: "read-cache@npm:1.0.0" - dependencies: - pify: "npm:^2.3.0" - checksum: 10c0/90cb2750213c7dd7c80cb420654344a311fdec12944e81eb912cd82f1bc92aea21885fa6ce442e3336d9fccd663b8a7a19c46d9698e6ca55620848ab932da814 - languageName: node - linkType: hard - -"readable-stream@npm:1.0.27-1": - version: 1.0.27-1 - resolution: "readable-stream@npm:1.0.27-1" - dependencies: - core-util-is: "npm:~1.0.0" - inherits: "npm:~2.0.1" - isarray: "npm:0.0.1" - string_decoder: "npm:~0.10.x" - checksum: 10c0/b887546e0a2c9e3204141be697d96f7966c4f25110925d9cd6714cf451d750b77ad873fd176ed03e40e4cb5da52f35a382ddd50e306e3f5fd37e238044897cd3 - languageName: node - linkType: hard - -"readable-stream@npm:1.1.x": - version: 1.1.14 - resolution: "readable-stream@npm:1.1.14" - dependencies: - core-util-is: "npm:~1.0.0" - inherits: "npm:~2.0.1" - isarray: "npm:0.0.1" - string_decoder: "npm:~0.10.x" - checksum: 10c0/b7f41b16b305103d598e3c8964fa30d52d6e0b5d9fdad567588964521691c24b279c7a8bb71f11927c3613acf355bac72d8396885a43d50425b2caafd49bc83d - languageName: node - linkType: hard - "readable-stream@npm:3, readable-stream@npm:^3.0.0, readable-stream@npm:^3.4.0, readable-stream@npm:^3.5.0, readable-stream@npm:^3.6.0": version: 3.6.2 resolution: "readable-stream@npm:3.6.2" @@ -23065,7 +19124,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^2.0.2, readable-stream@npm:^2.2.2, readable-stream@npm:~2.3.6": +"readable-stream@npm:^2.2.2, readable-stream@npm:~2.3.6": version: 2.3.8 resolution: "readable-stream@npm:2.3.8" dependencies: @@ -23087,20 +19146,9 @@ __metadata: abort-controller: "npm:^3.0.0" buffer: "npm:^6.0.3" events: "npm:^3.3.0" - process: "npm:^0.11.10" - string_decoder: "npm:^1.3.0" - checksum: 10c0/fd86d068da21cfdb10f7a4479f2e47d9c0a9b0c862fc0c840a7e5360201580a55ac399c764b12a4f6fa291f8cee74d9c4b7562e0d53b3c4b2769f2c98155d957 - languageName: node - linkType: hard - -"readdirp@npm:^2.2.1": - version: 2.2.1 - resolution: "readdirp@npm:2.2.1" - dependencies: - graceful-fs: "npm:^4.1.11" - micromatch: "npm:^3.1.10" - readable-stream: "npm:^2.0.2" - checksum: 10c0/770d177372ff2212d382d425d55ca48301fcbf3231ab3827257bbcca7ff44fb51fe4af6acc2dda8512dc7f29da390e9fbea5b2b3fc724b86e85cc828395b7797 + process: "npm:^0.11.10" + string_decoder: "npm:^1.3.0" + checksum: 10c0/fd86d068da21cfdb10f7a4479f2e47d9c0a9b0c862fc0c840a7e5360201580a55ac399c764b12a4f6fa291f8cee74d9c4b7562e0d53b3c4b2769f2c98155d957 languageName: node linkType: hard @@ -23120,17 +19168,6 @@ __metadata: languageName: node linkType: hard -"readline2@npm:^1.0.1": - version: 1.0.1 - resolution: "readline2@npm:1.0.1" - dependencies: - code-point-at: "npm:^1.0.0" - is-fullwidth-code-point: "npm:^1.0.0" - mute-stream: "npm:0.0.5" - checksum: 10c0/8b245192a925d5829d0b243c89dfc70646f4842f9ee968528f8b2f60b1c3277446cc007a4a2a1c91360dc1a7a8025d9b30567b6684bee4962179428e1ac02d86 - languageName: node - linkType: hard - "readline@npm:^1.3.0": version: 1.3.0 resolution: "readline@npm:1.3.0" @@ -23178,13 +19215,6 @@ __metadata: languageName: node linkType: hard -"reduce-component@npm:1.0.1": - version: 1.0.1 - resolution: "reduce-component@npm:1.0.1" - checksum: 10c0/a06392549d3783c626daff88e49ca29d02390b27028a37a75116c3f36b544ad1772d32332b0f374990545287edf4403159de990d0678fb799b254ebbe113fa71 - languageName: node - linkType: hard - "reduce-flatten@npm:^2.0.0": version: 2.0.0 resolution: "reduce-flatten@npm:2.0.0" @@ -23245,16 +19275,6 @@ __metadata: languageName: node linkType: hard -"regex-not@npm:^1.0.0, regex-not@npm:^1.0.2": - version: 1.0.2 - resolution: "regex-not@npm:1.0.2" - dependencies: - extend-shallow: "npm:^3.0.2" - safe-regex: "npm:^1.1.0" - checksum: 10c0/a0f8d6045f63b22e9759db10e248369c443b41cedd7dba0922d002b66c2734bc2aef0d98c4d45772d1f756245f4c5203856b88b9624bba2a58708858a8d485d6 - languageName: node - linkType: hard - "regexp.prototype.flags@npm:^1.5.3, regexp.prototype.flags@npm:^1.5.4": version: 1.5.4 resolution: "regexp.prototype.flags@npm:1.5.4" @@ -23283,25 +19303,6 @@ __metadata: languageName: node linkType: hard -"registry-auth-token@npm:^3.0.1": - version: 3.4.0 - resolution: "registry-auth-token@npm:3.4.0" - dependencies: - rc: "npm:^1.1.6" - safe-buffer: "npm:^5.0.1" - checksum: 10c0/44c0cbf380bcf0af02996b7d0215e2f789c97d2c762bb420fd844b34588bf77ab0cf94fbe33eeaf945456ff022dbfebec4309cf5ef110a653aa3696134efd081 - languageName: node - linkType: hard - -"registry-url@npm:^3.0.3": - version: 3.1.0 - resolution: "registry-url@npm:3.1.0" - dependencies: - rc: "npm:^1.0.1" - checksum: 10c0/345cf9638f99d95863d92800b3f595ac312c19d6865595e499fbeb33fcda04021a0dbdafbb5e61a838a89a558bc239d78752a1f90eb68cf53fdf0d91da816a7c - languageName: node - linkType: hard - "regjsgen@npm:^0.8.0": version: 0.8.0 resolution: "regjsgen@npm:0.8.0" @@ -23320,20 +19321,6 @@ __metadata: languageName: node linkType: hard -"remove-trailing-separator@npm:^1.0.1": - version: 1.1.0 - resolution: "remove-trailing-separator@npm:1.1.0" - checksum: 10c0/3568f9f8f5af3737b4aee9e6e1e8ec4be65a92da9cb27f989e0893714d50aa95ed2ff02d40d1fa35e1b1a234dc9c2437050ef356704a3999feaca6667d9e9bfc - languageName: node - linkType: hard - -"repeat-element@npm:^1.1.2": - version: 1.1.4 - resolution: "repeat-element@npm:1.1.4" - checksum: 10c0/81aa8d82bc845780803ef52df3533fa399974b99df571d0bb86e91f0ffca9ee4b9c4e8e5e72af087938cc28d2aef93d106a6d01da685d72ce96455b90a9f9f69 - languageName: node - linkType: hard - "repeat-string@npm:^1.6.1": version: 1.6.1 resolution: "repeat-string@npm:1.6.1" @@ -23424,13 +19411,6 @@ __metadata: languageName: node linkType: hard -"resolve-url@npm:^0.2.1": - version: 0.2.1 - resolution: "resolve-url@npm:0.2.1" - checksum: 10c0/c285182cfcddea13a12af92129ce0569be27fb0074ffaefbd3ba3da2eac2acecdfc996d435c4982a9fa2b4708640e52837c9153a5ab9255886a00b0b9e8d2a54 - languageName: node - linkType: hard - "resolve.exports@npm:^2.0.0": version: 2.0.3 resolution: "resolve.exports@npm:2.0.3" @@ -23454,7 +19434,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.6, resolve@npm:^1.1.7, resolve@npm:^1.14.2, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.4, resolve@npm:^1.22.8": +"resolve@npm:^1.1.6, resolve@npm:^1.1.7, resolve@npm:^1.14.2, resolve@npm:^1.20.0": version: 1.22.10 resolution: "resolve@npm:1.22.10" dependencies: @@ -23496,7 +19476,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.1.6#optional!builtin, resolve@patch:resolve@npm%3A^1.1.7#optional!builtin, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin, resolve@patch:resolve@npm%3A^1.22.8#optional!builtin": +"resolve@patch:resolve@npm%3A^1.1.6#optional!builtin, resolve@patch:resolve@npm%3A^1.1.7#optional!builtin, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin": version: 1.22.10 resolution: "resolve@patch:resolve@npm%3A1.22.10#optional!builtin::version=1.22.10&hash=c3c19d" dependencies: @@ -23531,16 +19511,6 @@ __metadata: languageName: node linkType: hard -"restore-cursor@npm:^1.0.1": - version: 1.0.1 - resolution: "restore-cursor@npm:1.0.1" - dependencies: - exit-hook: "npm:^1.0.0" - onetime: "npm:^1.0.0" - checksum: 10c0/5bab0d0131b91d5f4445cccf8e43dfde39c4de007c4792be5d03ea245439a96162a307285dd6684e81cc43ff205ec85ba21daa07ceae827b18a4f32ddaf7b7b1 - languageName: node - linkType: hard - "restore-cursor@npm:^3.1.0": version: 3.1.0 resolution: "restore-cursor@npm:3.1.0" @@ -23551,13 +19521,6 @@ __metadata: languageName: node linkType: hard -"ret@npm:~0.1.10": - version: 0.1.15 - resolution: "ret@npm:0.1.15" - checksum: 10c0/01f77cad0f7ea4f955852c03d66982609893edc1240c0c964b4c9251d0f9fb6705150634060d169939b096d3b77f4c84d6b6098a5b5d340160898c8581f1f63f - languageName: node - linkType: hard - "retry@npm:^0.12.0": version: 0.12.0 resolution: "retry@npm:0.12.0" @@ -23572,7 +19535,7 @@ __metadata: languageName: node linkType: hard -"rimraf@npm:^2.2.8, rimraf@npm:^2.6.3": +"rimraf@npm:^2.6.3": version: 2.7.1 resolution: "rimraf@npm:2.7.1" dependencies: @@ -23626,15 +19589,6 @@ __metadata: languageName: node linkType: hard -"run-async@npm:^0.1.0": - version: 0.1.0 - resolution: "run-async@npm:0.1.0" - dependencies: - once: "npm:^1.3.0" - checksum: 10c0/059e76d49f56d30e71e6baab6844bb8729889d0e28b4a2e586e8bb18163cc71c7aba16172ab77ae40f3f0a63bb502babdb71907277e9b8aac3ecd7498f5a0c41 - languageName: node - linkType: hard - "run-parallel@npm:^1.1.9": version: 1.2.0 resolution: "run-parallel@npm:1.2.0" @@ -23644,13 +19598,6 @@ __metadata: languageName: node linkType: hard -"rx-lite@npm:^3.1.2": - version: 3.1.2 - resolution: "rx-lite@npm:3.1.2" - checksum: 10c0/be2ce693f96cfe0b6dc2a5bb1fe28613edd0226238043f783facf97c76e91cde46c2f25a1b18337c97f27bba610d696d96b55040ba7a10088480902ba179fa03 - languageName: node - linkType: hard - "safe-array-concat@npm:^1.1.2, safe-array-concat@npm:^1.1.3": version: 1.1.3 resolution: "safe-array-concat@npm:1.1.3" @@ -23688,7 +19635,7 @@ __metadata: languageName: node linkType: hard -"safe-regex-test@npm:^1.0.3, safe-regex-test@npm:^1.1.0": +"safe-regex-test@npm:^1.1.0": version: 1.1.0 resolution: "safe-regex-test@npm:1.1.0" dependencies: @@ -23699,15 +19646,6 @@ __metadata: languageName: node linkType: hard -"safe-regex@npm:^1.1.0": - version: 1.1.0 - resolution: "safe-regex@npm:1.1.0" - dependencies: - ret: "npm:~0.1.10" - checksum: 10c0/547d58aa5184cbef368fd5ed5f28d20f911614748c5da6b35f53fd6626396707587251e6e3d1e3010fd3ff1212e413841b8825eaa5f317017ca62a30899af31a - languageName: node - linkType: hard - "safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0, safer-buffer@npm:^2.1.0, safer-buffer@npm:~2.1.0": version: 2.1.2 resolution: "safer-buffer@npm:2.1.2" @@ -23715,15 +19653,6 @@ __metadata: languageName: node linkType: hard -"sanitize-filename@npm:^1.3.0": - version: 1.6.3 - resolution: "sanitize-filename@npm:1.6.3" - dependencies: - truncate-utf8-bytes: "npm:^1.0.0" - checksum: 10c0/16ff47556a6e54e228c28db096bedd303da67b030d4bea4925fd71324932d6b02c7b0446f00ad33987b25b6414f24ae968e01a1a1679ce599542e82c4b07eb1f - languageName: node - linkType: hard - "sc-istanbul@npm:^0.4.5": version: 0.4.6 resolution: "sc-istanbul@npm:0.4.6" @@ -23823,15 +19752,6 @@ __metadata: languageName: node linkType: hard -"semver-diff@npm:^2.0.0": - version: 2.1.0 - resolution: "semver-diff@npm:2.1.0" - dependencies: - semver: "npm:^5.0.3" - checksum: 10c0/5825827a82e848908c6b6f9248aad4a15fe5baeed74ae41d67cf6d96107425028a5a5432e17abf10f0696719b0efcbbc34b47d071a70fb85e11cb451feb637e6 - languageName: node - linkType: hard - "semver@npm:7.6.0": version: 7.6.0 resolution: "semver@npm:7.6.0" @@ -23843,7 +19763,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^5.0.3, semver@npm:^5.1.0, semver@npm:^5.5.0, semver@npm:^5.6.0, semver@npm:^5.7.1": +"semver@npm:^5.5.0, semver@npm:^5.6.0": version: 5.7.2 resolution: "semver@npm:5.7.2" bin: @@ -23907,7 +19827,7 @@ __metadata: languageName: node linkType: hard -"serve-static@npm:^1.10.0, serve-static@npm:^1.13.1, serve-static@npm:^1.16.2, serve-static@npm:^1.9.2": +"serve-static@npm:^1.13.1, serve-static@npm:^1.16.2": version: 1.16.2 resolution: "serve-static@npm:1.16.2" dependencies: @@ -23963,18 +19883,6 @@ __metadata: languageName: node linkType: hard -"set-value@npm:^2.0.0, set-value@npm:^2.0.1": - version: 2.0.1 - resolution: "set-value@npm:2.0.1" - dependencies: - extend-shallow: "npm:^2.0.1" - is-extendable: "npm:^0.1.1" - is-plain-object: "npm:^2.0.3" - split-string: "npm:^3.0.1" - checksum: 10c0/4c40573c4f6540456e4b38b95f570272c4cfbe1d12890ad4057886da8535047cd772dfadf5b58e2e87aa244dfb4c57e3586f6716b976fc47c5144b6b09e1811b - languageName: node - linkType: hard - "setimmediate@npm:^1.0.5": version: 1.0.5 resolution: "setimmediate@npm:1.0.5" @@ -24031,15 +19939,6 @@ __metadata: languageName: node linkType: hard -"shebang-command@npm:^1.2.0": - version: 1.2.0 - resolution: "shebang-command@npm:1.2.0" - dependencies: - shebang-regex: "npm:^1.0.0" - checksum: 10c0/7b20dbf04112c456b7fc258622dafd566553184ac9b6938dd30b943b065b21dabd3776460df534cc02480db5e1b6aec44700d985153a3da46e7db7f9bd21326d - languageName: node - linkType: hard - "shebang-command@npm:^2.0.0": version: 2.0.0 resolution: "shebang-command@npm:2.0.0" @@ -24049,13 +19948,6 @@ __metadata: languageName: node linkType: hard -"shebang-regex@npm:^1.0.0": - version: 1.0.0 - resolution: "shebang-regex@npm:1.0.0" - checksum: 10c0/9abc45dee35f554ae9453098a13fdc2f1730e525a5eb33c51f096cc31f6f10a4b38074c1ebf354ae7bffa7229506083844008dfc3bb7818228568c0b2dc1fff2 - languageName: node - linkType: hard - "shebang-regex@npm:^3.0.0": version: 3.0.0 resolution: "shebang-regex@npm:3.0.0" @@ -24138,14 +20030,7 @@ __metadata: languageName: node linkType: hard -"sigmund@npm:~1.0.0": - version: 1.0.1 - resolution: "sigmund@npm:1.0.1" - checksum: 10c0/0cc9cf0acf4ee1e29bc324ec60b81865c30c4cf6738c6677646b101df1b1b1663759106d96de4199648e5fff3d1d2468ba06ec437cfcef16ee8ff19133fcbb9d - languageName: node - linkType: hard - -"signal-exit@npm:^3.0.0, signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": +"signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": version: 3.0.7 resolution: "signal-exit@npm:3.0.7" checksum: 10c0/25d272fa73e146048565e08f3309d5b942c1979a6f4a58a8c59d5fa299728e9c2fcd1a759ec870863b1fd38653670240cd420dad2ad9330c71f36608a6a1c912 @@ -24192,13 +20077,6 @@ __metadata: languageName: node linkType: hard -"slash@npm:^1.0.0": - version: 1.0.0 - resolution: "slash@npm:1.0.0" - checksum: 10c0/3944659885d905480f98810542fd314f3e1006eaad25ec78227a7835a469d9ed66fc3dd90abc7377dd2e71f4b5473e8f766bd08198fdd25152a80792e9ed464c - languageName: node - linkType: hard - "slash@npm:^2.0.0": version: 2.0.0 resolution: "slash@npm:2.0.0" @@ -24252,42 +20130,6 @@ __metadata: languageName: node linkType: hard -"snapdragon-node@npm:^2.0.1": - version: 2.1.1 - resolution: "snapdragon-node@npm:2.1.1" - dependencies: - define-property: "npm:^1.0.0" - isobject: "npm:^3.0.0" - snapdragon-util: "npm:^3.0.1" - checksum: 10c0/7616e6a1ca054afe3ad8defda17ebe4c73b0800d2e0efd635c44ee1b286f8ac7900517314b5330862ce99b28cd2782348ee78bae573ff0f55832ad81d9657f3f - languageName: node - linkType: hard - -"snapdragon-util@npm:^3.0.1": - version: 3.0.1 - resolution: "snapdragon-util@npm:3.0.1" - dependencies: - kind-of: "npm:^3.2.0" - checksum: 10c0/4441856d343399ba7f37f79681949d51b922e290fcc07e7bc94655a50f584befa4fb08f40c3471cd160e004660161964d8ff140cba49baa59aa6caba774240e3 - languageName: node - linkType: hard - -"snapdragon@npm:^0.8.1": - version: 0.8.2 - resolution: "snapdragon@npm:0.8.2" - dependencies: - base: "npm:^0.11.1" - debug: "npm:^2.2.0" - define-property: "npm:^0.2.5" - extend-shallow: "npm:^2.0.1" - map-cache: "npm:^0.2.2" - source-map: "npm:^0.5.6" - source-map-resolve: "npm:^0.5.0" - use: "npm:^3.1.0" - checksum: 10c0/dfdac1f73d47152d72fc07f4322da09bbddfa31c1c9c3ae7346f252f778c45afa5b03e90813332f02f04f6de8003b34a168c456f8bb719024d092f932520ffca - languageName: node - linkType: hard - "snarkjs@https://github.com/sampritipanda/snarkjs.git#fef81fc51d17a734637555c6edbd585ecda02d9e": version: 0.5.0 resolution: "snarkjs@https://github.com/sampritipanda/snarkjs.git#commit=fef81fc51d17a734637555c6edbd585ecda02d9e" @@ -24463,26 +20305,13 @@ __metadata: languageName: node linkType: hard -"source-map-js@npm:^1.0.1, source-map-js@npm:^1.0.2, source-map-js@npm:^1.2.1": +"source-map-js@npm:^1.0.1": version: 1.2.1 resolution: "source-map-js@npm:1.2.1" checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf languageName: node linkType: hard -"source-map-resolve@npm:^0.5.0": - version: 0.5.3 - resolution: "source-map-resolve@npm:0.5.3" - dependencies: - atob: "npm:^2.1.2" - decode-uri-component: "npm:^0.2.0" - resolve-url: "npm:^0.2.1" - source-map-url: "npm:^0.4.0" - urix: "npm:^0.1.0" - checksum: 10c0/410acbe93882e058858d4c1297be61da3e1533f95f25b95903edddc1fb719654e705663644677542d1fb78a66390238fad1a57115fc958a0724cf9bb509caf57 - languageName: node - linkType: hard - "source-map-support@npm:0.5.13": version: 0.5.13 resolution: "source-map-support@npm:0.5.13" @@ -24503,14 +20332,7 @@ __metadata: languageName: node linkType: hard -"source-map-url@npm:^0.4.0": - version: 0.4.1 - resolution: "source-map-url@npm:0.4.1" - checksum: 10c0/f8af0678500d536c7f643e32094d6718a4070ab4ca2d2326532512cfbe2d5d25a45849b4b385879326f2d7523bb3b686d0360dd347a3cda09fd89a5c28d4bc58 - languageName: node - linkType: hard - -"source-map@npm:^0.5.6, source-map@npm:^0.5.7": +"source-map@npm:^0.5.6": version: 0.5.7 resolution: "source-map@npm:0.5.7" checksum: 10c0/904e767bb9c494929be013017380cbba013637da1b28e5943b566031e29df04fba57edf3f093e0914be094648b577372bd8ad247fa98cfba9c600794cd16b599 @@ -24540,13 +20362,6 @@ __metadata: languageName: node linkType: hard -"spark-md5@npm:^1.0.0": - version: 1.0.1 - resolution: "spark-md5@npm:1.0.1" - checksum: 10c0/af4c247c8f1f101344b82aa9403c45ff451ade53ad859dc77f360db6d1dbad25d5495c8bebc17a18aac084af70d928ef7fb041ec4dfd59bbe0c00cceae8e2b52 - languageName: node - linkType: hard - "split-on-first@npm:^1.0.0": version: 1.1.0 resolution: "split-on-first@npm:1.1.0" @@ -24554,15 +20369,6 @@ __metadata: languageName: node linkType: hard -"split-string@npm:^3.0.1, split-string@npm:^3.0.2": - version: 3.1.0 - resolution: "split-string@npm:3.1.0" - dependencies: - extend-shallow: "npm:^3.0.0" - checksum: 10c0/72d7cd625445c7af215130e1e2bc183013bb9dd48a074eda1d35741e2b0dcb355e6df5b5558a62543a24dcec37dd1d6eb7a6228ff510d3c9de0f3dc1d1da8a70 - languageName: node - linkType: hard - "split2@npm:^3.0.0": version: 3.2.2 resolution: "split2@npm:3.2.2" @@ -24572,13 +20378,6 @@ __metadata: languageName: node linkType: hard -"split2@npm:^4.1.0": - version: 4.2.0 - resolution: "split2@npm:4.2.0" - checksum: 10c0/b292beb8ce9215f8c642bb68be6249c5a4c7f332fc8ecadae7be5cbdf1ea95addc95f0459ef2e7ad9d45fd1064698a097e4eb211c83e772b49bc0ee423e91534 - languageName: node - linkType: hard - "sprintf-js@npm:^1.1.3": version: 1.1.3 resolution: "sprintf-js@npm:1.1.3" @@ -24602,13 +20401,6 @@ __metadata: languageName: node linkType: hard -"stable-hash@npm:^0.0.5": - version: 0.0.5 - resolution: "stable-hash@npm:0.0.5" - checksum: 10c0/ca670cb6d172f1c834950e4ec661e2055885df32fee3ebf3647c5df94993b7c2666a5dbc1c9a62ee11fc5c24928579ec5e81bb5ad31971d355d5a341aab493b3 - languageName: node - linkType: hard - "stack-utils@npm:^2.0.3": version: 2.0.6 resolution: "stack-utils@npm:2.0.6" @@ -24643,16 +20435,6 @@ __metadata: languageName: node linkType: hard -"static-extend@npm:^0.1.1": - version: 0.1.2 - resolution: "static-extend@npm:0.1.2" - dependencies: - define-property: "npm:^0.2.5" - object-copy: "npm:^0.1.0" - checksum: 10c0/284f5865a9e19d079f1badbcd70d5f9f82e7a08393f818a220839cd5f71729e89105e1c95322bd28e833161d484cee671380ca443869ae89578eef2bf55c0653 - languageName: node - linkType: hard - "statuses@npm:2.0.1": version: 2.0.1 resolution: "statuses@npm:2.0.1" @@ -24677,20 +20459,6 @@ __metadata: languageName: node linkType: hard -"streamsearch@npm:0.1.2": - version: 0.1.2 - resolution: "streamsearch@npm:0.1.2" - checksum: 10c0/408a3db5b5643c1d6eb65c9d8ccc011b4857bfca41946d808b7f165b5b85f47755b2ff56ec1c4bbbeb5a496afcde9adfea12f9f67bd09ff3f04ae3f1f58d37c6 - languageName: node - linkType: hard - -"streamsearch@npm:^1.1.0": - version: 1.1.0 - resolution: "streamsearch@npm:1.1.0" - checksum: 10c0/fbd9aecc2621364384d157f7e59426f4bfd385e8b424b5aaa79c83a6f5a1c8fd2e4e3289e95de1eb3511cb96bb333d6281a9919fafce760e4edb35b2cd2facab - languageName: node - linkType: hard - "streamx@npm:^2.15.0, streamx@npm:^2.21.0": version: 2.22.0 resolution: "streamx@npm:2.22.0" @@ -24757,7 +20525,7 @@ __metadata: languageName: node linkType: hard -"string-width@npm:^2.0.0, string-width@npm:^2.1.1": +"string-width@npm:^2.1.1": version: 2.1.1 resolution: "string-width@npm:2.1.1" dependencies: @@ -24778,17 +20546,6 @@ __metadata: languageName: node linkType: hard -"string.prototype.includes@npm:^2.0.1": - version: 2.0.1 - resolution: "string.prototype.includes@npm:2.0.1" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.3" - checksum: 10c0/25ce9c9b49128352a2618fbe8758b46f945817a58a4420f4799419e40a8d28f116e176c7590d767d5327a61e75c8f32c86171063f48e389b9fdd325f1bd04ee5 - languageName: node - linkType: hard - "string.prototype.matchall@npm:^4.0.12": version: 4.0.12 resolution: "string.prototype.matchall@npm:4.0.12" @@ -24860,7 +20617,7 @@ __metadata: languageName: node linkType: hard -"string.prototype.trimend@npm:^1.0.3, string.prototype.trimend@npm:^1.0.8, string.prototype.trimend@npm:^1.0.9": +"string.prototype.trimend@npm:^1.0.3, string.prototype.trimend@npm:^1.0.9": version: 1.0.9 resolution: "string.prototype.trimend@npm:1.0.9" dependencies: @@ -24905,13 +20662,6 @@ __metadata: languageName: node linkType: hard -"string@npm:^3.3.0": - version: 3.3.3 - resolution: "string@npm:3.3.3" - checksum: 10c0/6991ab28add3276ca5334739054dcd4a03f35c0c0e7220f4be19d3cf70b7aa339633a03063f77b3d9ab1e0f7b6b0844c6248dff19f810de015fd45fdd38ff3e0 - languageName: node - linkType: hard - "string_decoder@npm:^1.1.1, string_decoder@npm:^1.3.0": version: 1.3.0 resolution: "string_decoder@npm:1.3.0" @@ -24921,13 +20671,6 @@ __metadata: languageName: node linkType: hard -"string_decoder@npm:~0.10.x": - version: 0.10.31 - resolution: "string_decoder@npm:0.10.31" - checksum: 10c0/1c628d78f974aa7539c496029f48e7019acc32487fc695464f9d6bdfec98edd7d933a06b3216bc2016918f6e75074c611d84430a53cb0e43071597d6c1ac5e25 - languageName: node - linkType: hard - "string_decoder@npm:~1.1.1": version: 1.1.1 resolution: "string_decoder@npm:1.1.1" @@ -24946,15 +20689,6 @@ __metadata: languageName: node linkType: hard -"strip-ansi@npm:^3.0.0": - version: 3.0.1 - resolution: "strip-ansi@npm:3.0.1" - dependencies: - ansi-regex: "npm:^2.0.0" - checksum: 10c0/f6e7fbe8e700105dccf7102eae20e4f03477537c74b286fd22cfc970f139002ed6f0d9c10d0e21aa9ed9245e0fa3c9275930e8795c5b947da136e4ecb644a70f - languageName: node - linkType: hard - "strip-ansi@npm:^4.0.0": version: 4.0.0 resolution: "strip-ansi@npm:4.0.0" @@ -24996,13 +20730,6 @@ __metadata: languageName: node linkType: hard -"strip-eof@npm:^1.0.0": - version: 1.0.0 - resolution: "strip-eof@npm:1.0.0" - checksum: 10c0/f336beed8622f7c1dd02f2cbd8422da9208fae81daf184f73656332899978919d5c0ca84dc6cfc49ad1fc4dd7badcde5412a063cf4e0d7f8ed95a13a63f68f45 - languageName: node - linkType: hard - "strip-final-newline@npm:^2.0.0": version: 2.0.0 resolution: "strip-final-newline@npm:2.0.0" @@ -25035,13 +20762,6 @@ __metadata: languageName: node linkType: hard -"strip-json-comments@npm:~2.0.1": - version: 2.0.1 - resolution: "strip-json-comments@npm:2.0.1" - checksum: 10c0/b509231cbdee45064ff4f9fd73609e2bcc4e84a4d508e9dd0f31f70356473fde18abfb5838c17d56fb236f5a06b102ef115438de0600b749e818a35fbbc48c43 - languageName: node - linkType: hard - "strnum@npm:^1.1.1": version: 1.1.2 resolution: "strnum@npm:1.1.2" @@ -25059,47 +20779,6 @@ __metadata: languageName: node linkType: hard -"styled-jsx@npm:5.1.1": - version: 5.1.1 - resolution: "styled-jsx@npm:5.1.1" - dependencies: - client-only: "npm:0.0.1" - peerDependencies: - react: ">= 16.8.0 || 17.x.x || ^18.0.0-0" - peerDependenciesMeta: - "@babel/core": - optional: true - babel-plugin-macros: - optional: true - checksum: 10c0/42655cdadfa5388f8a48bb282d6b450df7d7b8cf066ac37038bd0499d3c9f084815ebd9ff9dfa12a218fd4441338851db79603498d7557207009c1cf4d609835 - languageName: node - linkType: hard - -"stylis@npm:4.2.0": - version: 4.2.0 - resolution: "stylis@npm:4.2.0" - checksum: 10c0/a7128ad5a8ed72652c6eba46bed4f416521bc9745a460ef5741edc725252cebf36ee45e33a8615a7057403c93df0866ab9ee955960792db210bb80abd5ac6543 - languageName: node - linkType: hard - -"sucrase@npm:^3.35.0": - version: 3.35.0 - resolution: "sucrase@npm:3.35.0" - dependencies: - "@jridgewell/gen-mapping": "npm:^0.3.2" - commander: "npm:^4.0.0" - glob: "npm:^10.3.10" - lines-and-columns: "npm:^1.1.6" - mz: "npm:^2.7.0" - pirates: "npm:^4.0.1" - ts-interface-checker: "npm:^0.1.9" - bin: - sucrase: bin/sucrase - sucrase-node: bin/sucrase-node - checksum: 10c0/ac85f3359d2c2ecbf5febca6a24ae9bf96c931f05fde533c22a94f59c6a74895e5d5f0e871878dfd59c2697a75ebb04e4b2224ef0bfc24ca1210735c2ec191ef - languageName: node - linkType: hard - "sudo-prompt@npm:^9.0.0": version: 9.2.1 resolution: "sudo-prompt@npm:9.2.1" @@ -25107,44 +20786,6 @@ __metadata: languageName: node linkType: hard -"superagent@npm:^1.2.0": - version: 1.8.5 - resolution: "superagent@npm:1.8.5" - dependencies: - component-emitter: "npm:~1.2.0" - cookiejar: "npm:2.0.6" - debug: "npm:2" - extend: "npm:3.0.0" - form-data: "npm:1.0.0-rc3" - formidable: "npm:~1.0.14" - methods: "npm:~1.1.1" - mime: "npm:1.3.4" - qs: "npm:2.3.3" - readable-stream: "npm:1.0.27-1" - reduce-component: "npm:1.0.1" - checksum: 10c0/636198862a8bad386adc9fbe5f129a2617893fb79dbc007b6c7e92be9a114a7b3aed32c08adf00d286fa8726e6b5d51b8d46345a037a0066d7764b0c41bde4f9 - languageName: node - linkType: hard - -"superagent@npm:^7.1.6": - version: 7.1.6 - resolution: "superagent@npm:7.1.6" - dependencies: - component-emitter: "npm:^1.3.0" - cookiejar: "npm:^2.1.3" - debug: "npm:^4.3.4" - fast-safe-stringify: "npm:^2.1.1" - form-data: "npm:^4.0.0" - formidable: "npm:^2.0.1" - methods: "npm:^1.1.2" - mime: "npm:2.6.0" - qs: "npm:^6.10.3" - readable-stream: "npm:^3.6.0" - semver: "npm:^7.3.7" - checksum: 10c0/af956af1524dda3878df6f694d62bddb63daa747c2a429984b7304e4a5d355b81caaeb5d2049cdbeba207abba06b0d215008755a4f1b4d2c823e0eeaf6a4fad4 - languageName: node - linkType: hard - "superstruct@npm:^0.6.2": version: 0.6.2 resolution: "superstruct@npm:0.6.2" @@ -25155,22 +20796,6 @@ __metadata: languageName: node linkType: hard -"supports-color@npm:1.2.0": - version: 1.2.0 - resolution: "supports-color@npm:1.2.0" - bin: - supports-color: cli.js - checksum: 10c0/7a3df5814fe5b3676b2f11f7de4bbeb64be182335ae9dd7738101fc8c78df87e0100b2a0104ec29658009195abd4f50f04574e93e6adc7c7e84c288e9731a8ca - languageName: node - linkType: hard - -"supports-color@npm:^2.0.0": - version: 2.0.0 - resolution: "supports-color@npm:2.0.0" - checksum: 10c0/570e0b63be36cccdd25186350a6cb2eaad332a95ff162fa06d9499982315f2fe4217e69dd98e862fbcd9c81eaff300a825a1fe7bf5cc752e5b84dfed042b0dda - languageName: node - linkType: hard - "supports-color@npm:^3.1.0": version: 3.2.3 resolution: "supports-color@npm:3.2.3" @@ -25180,7 +20805,7 @@ __metadata: languageName: node linkType: hard -"supports-color@npm:^5.3.0, supports-color@npm:^5.5.0": +"supports-color@npm:^5.3.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" dependencies: @@ -25214,120 +20839,27 @@ __metadata: languageName: node linkType: hard -"svg-parser@npm:^2.0.4": - version: 2.0.4 - resolution: "svg-parser@npm:2.0.4" - checksum: 10c0/02f6cb155dd7b63ebc2f44f36365bc294543bebb81b614b7628f1af3c54ab64f7e1cec20f06e252bf95bdde78441ae295a412c68ad1678f16a6907d924512b7a - languageName: node - linkType: hard - -"svgo@npm:^3.0.2": - version: 3.3.2 - resolution: "svgo@npm:3.3.2" - dependencies: - "@trysound/sax": "npm:0.2.0" - commander: "npm:^7.2.0" - css-select: "npm:^5.1.0" - css-tree: "npm:^2.3.1" - css-what: "npm:^6.1.0" - csso: "npm:^5.0.5" - picocolors: "npm:^1.0.0" - bin: - svgo: ./bin/svgo - checksum: 10c0/a6badbd3d1d6dbb177f872787699ab34320b990d12e20798ecae915f0008796a0f3c69164f1485c9def399e0ce0a5683eb4a8045e51a5e1c364bb13a0d9f79e1 - languageName: node - linkType: hard - -"swagger-converter@npm:^0.1.7": - version: 0.1.7 - resolution: "swagger-converter@npm:0.1.7" - dependencies: - lodash.clonedeep: "npm:^2.4.1" - checksum: 10c0/c8255154600b4775570a5cf291aa3bde868b8fbf475564fdaa1b3f454ded67c01b6a8bee8fe9494701678883ef9061d793b8fb7ee271c08cbe134e0e940379fb - languageName: node - linkType: hard - -"swagger-converter@npm:^0.2.0": - version: 0.2.0 - resolution: "swagger-converter@npm:0.2.0" - dependencies: - URIjs: "npm:^1.16.0" - checksum: 10c0/0b2295e2548abdeeffff95af006e4a6bd578a24ec6a231bcedfb4d99617c707fd7bb4c3474b66852caedde89394b0b7c124a735146f43bf8662f4323a0f6ccd0 - languageName: node - linkType: hard - -"swagger-editor@npm:^2.9.2": - version: 2.10.5 - resolution: "swagger-editor@npm:2.10.5" - checksum: 10c0/f172ed637222581db374bbbfdd29778de2ac8904fd88fdecb2575f3446b42073940f26246d3ccd31bcb2cd9906fa0edddae18a095eb6914cf41ff1b314f9271f - languageName: node - linkType: hard - -"swagger-test-templates@npm:^1.2.0": - version: 1.6.0 - resolution: "swagger-test-templates@npm:1.6.0" - dependencies: - handlebars: "npm:^4.0.5" - js-string-escape: "npm:^1.0.1" - json-schema-deref-sync: "npm:^0.6.0" - lodash: "npm:^4.17.12" - sanitize-filename: "npm:^1.3.0" - string: "npm:^3.3.0" - checksum: 10c0/33dce75f56bfc4d720c964b48806339a95f251af5d5fbb15c587ac6669af7bd5c64823f802b868fb0dde60df4157365b7bfca9904faa411018e29182a041a141 +"svg-parser@npm:^2.0.4": + version: 2.0.4 + resolution: "svg-parser@npm:2.0.4" + checksum: 10c0/02f6cb155dd7b63ebc2f44f36365bc294543bebb81b614b7628f1af3c54ab64f7e1cec20f06e252bf95bdde78441ae295a412c68ad1678f16a6907d924512b7a languageName: node linkType: hard -"swagger-tools@npm:^0.9.0": - version: 0.9.16 - resolution: "swagger-tools@npm:0.9.16" +"svgo@npm:^3.0.2": + version: 3.3.2 + resolution: "svgo@npm:3.3.2" dependencies: - async: "npm:^1.3.0" - body-parser: "npm:1.12.4" - commander: "npm:^2.8.1" - debug: "npm:^2.2.0" - js-yaml: "npm:^3.3.1" - json-refs: "npm:^2.1.5" - lodash-compat: "npm:^3.10.0" - multer: "npm:^1.1.0" - parseurl: "npm:^1.3.0" - path-to-regexp: "npm:^1.2.0" - qs: "npm:^4.0.0" - serve-static: "npm:^1.10.0" - spark-md5: "npm:^1.0.0" - string: "npm:^3.3.0" - superagent: "npm:^1.2.0" - swagger-converter: "npm:^0.1.7" - traverse: "npm:^0.6.6" - z-schema: "npm:^3.15.4" - bin: - swagger-tools: ./bin/swagger-tools - checksum: 10c0/3810d37eaf3295d8949ff2574b491b83bceb9222cdcb8124d280509a4521128364ecc0a0b09756e2e1bf65737e3ade6f72d530015ebed4c4159edc06828cc413 - languageName: node - linkType: hard - -"swagger@npm:^0.7.5": - version: 0.7.5 - resolution: "swagger@npm:0.7.5" - dependencies: - async: "npm:^1.2.1" - commander: "npm:^2.7.1" - connect: "npm:^3.3.5" - debug: "npm:^2.1.3" - fs-extra: "npm:^0.24.0" - inquirer: "npm:^0.10.0" - js-yaml: "npm:^3.3.0" - lodash: "npm:^3.10.0" - mocha: "npm:^2.2.1" - nodemon: "npm:^1.3.7" - serve-static: "npm:^1.9.2" - swagger-converter: "npm:^0.2.0" - swagger-editor: "npm:^2.9.2" - swagger-test-templates: "npm:^1.2.0" - swagger-tools: "npm:^0.9.0" + "@trysound/sax": "npm:0.2.0" + commander: "npm:^7.2.0" + css-select: "npm:^5.1.0" + css-tree: "npm:^2.3.1" + css-what: "npm:^6.1.0" + csso: "npm:^5.0.5" + picocolors: "npm:^1.0.0" bin: - swagger: bin/swagger.js - swagger-project: bin/swagger-project.js - checksum: 10c0/c8532853520c6066a4cc6840011604f59b5dec2c3f15c65cb643a3b744f23819e6aa05e198be6fde30500e126816c6420b60ad715121d17c52be1906898a6fd9 + svgo: ./bin/svgo + checksum: 10c0/a6badbd3d1d6dbb177f872787699ab34320b990d12e20798ecae915f0008796a0f3c69164f1485c9def399e0ce0a5683eb4a8045e51a5e1c364bb13a0d9f79e1 languageName: node linkType: hard @@ -25393,39 +20925,6 @@ __metadata: languageName: node linkType: hard -"tailwindcss@npm:^3.4.1": - version: 3.4.17 - resolution: "tailwindcss@npm:3.4.17" - dependencies: - "@alloc/quick-lru": "npm:^5.2.0" - arg: "npm:^5.0.2" - chokidar: "npm:^3.6.0" - didyoumean: "npm:^1.2.2" - dlv: "npm:^1.1.3" - fast-glob: "npm:^3.3.2" - glob-parent: "npm:^6.0.2" - is-glob: "npm:^4.0.3" - jiti: "npm:^1.21.6" - lilconfig: "npm:^3.1.3" - micromatch: "npm:^4.0.8" - normalize-path: "npm:^3.0.0" - object-hash: "npm:^3.0.0" - picocolors: "npm:^1.1.1" - postcss: "npm:^8.4.47" - postcss-import: "npm:^15.1.0" - postcss-js: "npm:^4.0.1" - postcss-load-config: "npm:^4.0.2" - postcss-nested: "npm:^6.2.0" - postcss-selector-parser: "npm:^6.1.2" - resolve: "npm:^1.22.8" - sucrase: "npm:^3.35.0" - bin: - tailwind: lib/cli.js - tailwindcss: lib/cli.js - checksum: 10c0/cc42c6e7fdf88a5507a0d7fea37f1b4122bec158977f8c017b2ae6828741f9e6f8cb90282c6bf2bd5951fd1220a53e0a50ca58f5c1c00eb7f5d9f8b80dc4523c - languageName: node - linkType: hard - "tamagui@npm:1.126.14": version: 1.126.14 resolution: "tamagui@npm:1.126.14" @@ -25604,15 +21103,6 @@ __metadata: languageName: node linkType: hard -"term-size@npm:^1.2.0": - version: 1.2.0 - resolution: "term-size@npm:1.2.0" - dependencies: - execa: "npm:^0.7.0" - checksum: 10c0/2fbb2668cdd3b5e63038c28355145e98789d16143fc6754462cd4a194706c7153f15c2a6f05f579ffed27bcf2f35bdf752007927457128cc9a9ce3ec20075649 - languageName: node - linkType: hard - "terser-webpack-plugin@npm:^5.3.11": version: 5.3.14 resolution: "terser-webpack-plugin@npm:5.3.14" @@ -25660,31 +21150,6 @@ __metadata: languageName: node linkType: hard -"test-web-app@workspace:sdk/tests/web-app": - version: 0.0.0-use.local - resolution: "test-web-app@workspace:sdk/tests/web-app" - dependencies: - "@emotion/react": "npm:^11.13.3" - "@emotion/styled": "npm:^11.13.0" - "@mui/material": "npm:^6.0.2" - "@selfxyz/common": "workspace:^" - "@selfxyz/qrcode": "workspace:^" - "@types/node": "npm:^20" - "@types/react": "npm:^18" - "@types/react-dom": "npm:^18" - axios: "npm:^1.7.7" - eslint: "npm:^8" - eslint-config-next: "npm:14.2.8" - next: "npm:14.2.8" - postcss: "npm:^8" - react: "npm:^18" - react-dom: "npm:^18" - tailwindcss: "npm:^3.4.1" - typescript: "npm:^5" - uuid: "npm:^11.1.0" - languageName: unknown - linkType: soft - "text-decoder@npm:^1.1.0": version: 1.2.3 resolution: "text-decoder@npm:1.2.3" @@ -25720,24 +21185,6 @@ __metadata: languageName: node linkType: hard -"thenify-all@npm:^1.0.0": - version: 1.6.0 - resolution: "thenify-all@npm:1.6.0" - dependencies: - thenify: "npm:>= 3.1.0 < 4" - checksum: 10c0/9b896a22735e8122754fe70f1d65f7ee691c1d70b1f116fda04fea103d0f9b356e3676cb789506e3909ae0486a79a476e4914b0f92472c2e093d206aed4b7d6b - languageName: node - linkType: hard - -"thenify@npm:>= 3.1.0 < 4": - version: 3.3.1 - resolution: "thenify@npm:3.3.1" - dependencies: - any-promise: "npm:^1.0.0" - checksum: 10c0/f375aeb2b05c100a456a30bc3ed07ef03a39cbdefe02e0403fb714b8c7e57eeaad1a2f5c4ecfb9ce554ce3db9c2b024eba144843cd9e344566d9fcee73b04767 - languageName: node - linkType: hard - "throat@npm:^5.0.0": version: 5.0.0 resolution: "throat@npm:5.0.0" @@ -25764,20 +21211,13 @@ __metadata: languageName: node linkType: hard -"through@npm:^2.3.6, through@npm:^2.3.8": +"through@npm:^2.3.8": version: 2.3.8 resolution: "through@npm:2.3.8" checksum: 10c0/4b09f3774099de0d4df26d95c5821a62faee32c7e96fb1f4ebd54a2d7c11c57fe88b0a0d49cf375de5fee5ae6bf4eb56dbbf29d07366864e2ee805349970d3cc languageName: node linkType: hard -"timed-out@npm:^4.0.0": - version: 4.0.1 - resolution: "timed-out@npm:4.0.1" - checksum: 10c0/86f03ffce5b80c5a066e02e59e411d3fbbfcf242b19290ba76817b4180abd1b85558489586b6022b798fb1cf26fc644c0ce0efb9c271d67ec83fada4b9542a56 - languageName: node - linkType: hard - "tiny-hashes@npm:^1.0.1": version: 1.0.1 resolution: "tiny-hashes@npm:1.0.1" @@ -25785,7 +21225,7 @@ __metadata: languageName: node linkType: hard -"tinyglobby@npm:^0.2.11, tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.13, tinyglobby@npm:^0.2.6": +"tinyglobby@npm:^0.2.11, tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.6": version: 0.2.14 resolution: "tinyglobby@npm:0.2.14" dependencies: @@ -25834,32 +21274,6 @@ __metadata: languageName: node linkType: hard -"to-iso-string@npm:0.0.2": - version: 0.0.2 - resolution: "to-iso-string@npm:0.0.2" - checksum: 10c0/bffeac1e4de0f4cbc14aed39f5dec7fbc32f5b43fb768b5e818e2675dda719dcd5744857874cd02b01c6bef9481bd2518867dc43eb23dd8822ef6c089a4fe293 - languageName: node - linkType: hard - -"to-object-path@npm:^0.3.0": - version: 0.3.0 - resolution: "to-object-path@npm:0.3.0" - dependencies: - kind-of: "npm:^3.0.2" - checksum: 10c0/731832a977614c03a770363ad2bd9e9c82f233261861724a8e612bb90c705b94b1a290a19f52958e8e179180bb9b71121ed65e245691a421467726f06d1d7fc3 - languageName: node - linkType: hard - -"to-regex-range@npm:^2.1.0": - version: 2.1.1 - resolution: "to-regex-range@npm:2.1.1" - dependencies: - is-number: "npm:^3.0.0" - repeat-string: "npm:^1.6.1" - checksum: 10c0/440d82dbfe0b2e24f36dd8a9467240406ad1499fc8b2b0f547372c22ed1d092ace2a3eb522bb09bfd9c2f39bf1ca42eb78035cf6d2b8c9f5c78da3abc96cd949 - languageName: node - linkType: hard - "to-regex-range@npm:^5.0.1": version: 5.0.1 resolution: "to-regex-range@npm:5.0.1" @@ -25869,18 +21283,6 @@ __metadata: languageName: node linkType: hard -"to-regex@npm:^3.0.1, to-regex@npm:^3.0.2": - version: 3.0.2 - resolution: "to-regex@npm:3.0.2" - dependencies: - define-property: "npm:^2.0.2" - extend-shallow: "npm:^3.0.2" - regex-not: "npm:^1.0.2" - safe-regex: "npm:^1.1.0" - checksum: 10c0/99d0b8ef397b3f7abed4bac757b0f0bb9f52bfd39167eb7105b144becfaa9a03756892352d01ac6a911f0c1ceef9f81db68c46899521a3eed054082042796120 - languageName: node - linkType: hard - "toidentifier@npm:1.0.1": version: 1.0.1 resolution: "toidentifier@npm:1.0.1" @@ -25888,15 +21290,6 @@ __metadata: languageName: node linkType: hard -"touch@npm:^3.1.0": - version: 3.1.1 - resolution: "touch@npm:3.1.1" - bin: - nodetouch: bin/nodetouch.js - checksum: 10c0/d2e4d269a42c846a22a29065b9af0b263de58effc85a1764bb7a2e8fc4b47700e9e2fcbd7eb1f5bffbb7c73d860f93600cef282b93ddac8f0b62321cb498b36e - languageName: node - linkType: hard - "tr46@npm:~0.0.3": version: 0.0.3 resolution: "tr46@npm:0.0.3" @@ -25904,17 +21297,6 @@ __metadata: languageName: node linkType: hard -"traverse@npm:^0.6.6, traverse@npm:~0.6.6": - version: 0.6.11 - resolution: "traverse@npm:0.6.11" - dependencies: - gopd: "npm:^1.2.0" - typedarray.prototype.slice: "npm:^1.0.5" - which-typed-array: "npm:^1.1.18" - checksum: 10c0/2b57662da3061ed2aa9977a6a3e315fc19f2cfdeb691700a88c12f4d460146abdb4d726740f47a9ca5fa84d3c50096b76ee50047d1a71c2afb168852ad264e36 - languageName: node - linkType: hard - "treeify@npm:^1.1.0": version: 1.1.0 resolution: "treeify@npm:1.1.0" @@ -25922,15 +21304,6 @@ __metadata: languageName: node linkType: hard -"truncate-utf8-bytes@npm:^1.0.0": - version: 1.0.2 - resolution: "truncate-utf8-bytes@npm:1.0.2" - dependencies: - utf8-byte-length: "npm:^1.0.1" - checksum: 10c0/af2b431fc4314f119b551e5fccfad49d4c0ef82e13ba9ca61be6567801195b08e732ce9643542e8ad1b3df44f3df2d7345b3dd34f723954b6bb43a14584d6b3c - languageName: node - linkType: hard - "tryer@npm:^1.0.1": version: 1.0.1 resolution: "tryer@npm:1.0.1" @@ -25938,7 +21311,7 @@ __metadata: languageName: node linkType: hard -"ts-api-utils@npm:^1.0.1, ts-api-utils@npm:^1.3.0": +"ts-api-utils@npm:^1.3.0": version: 1.4.3 resolution: "ts-api-utils@npm:1.4.3" peerDependencies: @@ -25979,13 +21352,6 @@ __metadata: languageName: node linkType: hard -"ts-interface-checker@npm:^0.1.9": - version: 0.1.13 - resolution: "ts-interface-checker@npm:0.1.13" - checksum: 10c0/232509f1b84192d07b81d1e9b9677088e590ac1303436da1e92b296e9be8e31ea042e3e1fd3d29b1742ad2c959e95afe30f63117b8f1bc3a3850070a5142fea7 - languageName: node - linkType: hard - "ts-loader@npm:^9.5.1": version: 9.5.2 resolution: "ts-loader@npm:9.5.2" @@ -26075,7 +21441,7 @@ __metadata: languageName: node linkType: hard -"tsconfig-paths@npm:^3.15.0, tsconfig-paths@npm:^3.5.0": +"tsconfig-paths@npm:^3.5.0": version: 3.15.0 resolution: "tsconfig-paths@npm:3.15.0" dependencies: @@ -26229,23 +21595,6 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^4.20.0": - version: 4.41.0 - resolution: "type-fest@npm:4.41.0" - checksum: 10c0/f5ca697797ed5e88d33ac8f1fec21921839871f808dc59345c9cf67345bfb958ce41bd821165dbf3ae591cedec2bf6fe8882098dfdd8dc54320b859711a2c1e4 - languageName: node - linkType: hard - -"type-is@npm:^1.6.4, type-is@npm:~1.6.2": - version: 1.6.18 - resolution: "type-is@npm:1.6.18" - dependencies: - media-typer: "npm:0.3.0" - mime-types: "npm:~2.1.24" - checksum: 10c0/a23daeb538591b7efbd61ecf06b6feb2501b683ffdc9a19c74ef5baba362b4347e42f1b4ed81f5882a8c96a3bfff7f93ce3ffaf0cbbc879b532b04c97a55db9d - languageName: node - linkType: hard - "typechain@npm:^8.3.2": version: 8.3.2 resolution: "typechain@npm:8.3.2" @@ -26321,22 +21670,6 @@ __metadata: languageName: node linkType: hard -"typedarray.prototype.slice@npm:^1.0.5": - version: 1.0.5 - resolution: "typedarray.prototype.slice@npm:1.0.5" - dependencies: - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.9" - es-errors: "npm:^1.3.0" - get-proto: "npm:^1.0.1" - math-intrinsics: "npm:^1.1.0" - typed-array-buffer: "npm:^1.0.3" - typed-array-byte-offset: "npm:^1.0.4" - checksum: 10c0/4995828640f8079cfbc9e3b4b8fc2e0eeb109edd1a2596806325ae07306dba1cd947e6ed6f63391aa7d5af0ea4f40fddf1b6eb863f8a59869a9dfc5dcfd8eac2 - languageName: node - linkType: hard - "typedarray@npm:^0.0.6": version: 0.0.6 resolution: "typedarray@npm:0.0.6" @@ -26366,7 +21699,7 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^5, typescript@npm:^5.1.6, typescript@npm:^5.3.3, typescript@npm:^5.4.5, typescript@npm:^5.8.3": +"typescript@npm:^5.1.6, typescript@npm:^5.3.3, typescript@npm:^5.4.5, typescript@npm:^5.8.3": version: 5.8.3 resolution: "typescript@npm:5.8.3" bin: @@ -26386,7 +21719,7 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@npm%3A^5#optional!builtin, typescript@patch:typescript@npm%3A^5.1.6#optional!builtin, typescript@patch:typescript@npm%3A^5.3.3#optional!builtin, typescript@patch:typescript@npm%3A^5.4.5#optional!builtin, typescript@patch:typescript@npm%3A^5.8.3#optional!builtin": +"typescript@patch:typescript@npm%3A^5.1.6#optional!builtin, typescript@patch:typescript@npm%3A^5.3.3#optional!builtin, typescript@patch:typescript@npm%3A^5.4.5#optional!builtin, typescript@patch:typescript@npm%3A^5.8.3#optional!builtin": version: 5.8.3 resolution: "typescript@patch:typescript@npm%3A5.8.3#optional!builtin::version=5.8.3&hash=5786d5" bin: @@ -26441,13 +21774,6 @@ __metadata: languageName: node linkType: hard -"undefsafe@npm:^2.0.2": - version: 2.0.5 - resolution: "undefsafe@npm:2.0.5" - checksum: 10c0/96c0466a5fbf395917974a921d5d4eee67bca4b30d3a31ce7e621e0228c479cf893e783a109af6e14329b52fe2f0cb4108665fad2b87b0018c0df6ac771261d5 - languageName: node - linkType: hard - "underscore@npm:1.12.1": version: 1.12.1 resolution: "underscore@npm:1.12.1" @@ -26509,18 +21835,6 @@ __metadata: languageName: node linkType: hard -"union-value@npm:^1.0.0": - version: 1.0.1 - resolution: "union-value@npm:1.0.1" - dependencies: - arr-union: "npm:^3.1.0" - get-value: "npm:^2.0.6" - is-extendable: "npm:^0.1.1" - set-value: "npm:^2.0.1" - checksum: 10c0/8758d880cb9545f62ce9cfb9b791b2b7a206e0ff5cc4b9d7cd6581da2c6839837fbb45e639cf1fd8eef3cae08c0201b614b7c06dd9f5f70d9dbe7c5fe2fbf592 - languageName: node - linkType: hard - "unique-filename@npm:^4.0.0": version: 4.0.0 resolution: "unique-filename@npm:4.0.0" @@ -26539,15 +21853,6 @@ __metadata: languageName: node linkType: hard -"unique-string@npm:^1.0.0": - version: 1.0.0 - resolution: "unique-string@npm:1.0.0" - dependencies: - crypto-random-string: "npm:^1.0.0" - checksum: 10c0/79cc2a6515a51e6350c74f65c92246511966c47528f1119318cbe8d68a508842f4e5a2a81857a65f3919629397a525f820505116dd89cac425294598e35ca12c - languageName: node - linkType: hard - "universalify@npm:^0.1.0": version: 0.1.2 resolution: "universalify@npm:0.1.2" @@ -26569,91 +21874,6 @@ __metadata: languageName: node linkType: hard -"unrs-resolver@npm:^1.6.2": - version: 1.7.5 - resolution: "unrs-resolver@npm:1.7.5" - dependencies: - "@unrs/resolver-binding-darwin-arm64": "npm:1.7.5" - "@unrs/resolver-binding-darwin-x64": "npm:1.7.5" - "@unrs/resolver-binding-freebsd-x64": "npm:1.7.5" - "@unrs/resolver-binding-linux-arm-gnueabihf": "npm:1.7.5" - "@unrs/resolver-binding-linux-arm-musleabihf": "npm:1.7.5" - "@unrs/resolver-binding-linux-arm64-gnu": "npm:1.7.5" - "@unrs/resolver-binding-linux-arm64-musl": "npm:1.7.5" - "@unrs/resolver-binding-linux-ppc64-gnu": "npm:1.7.5" - "@unrs/resolver-binding-linux-riscv64-gnu": "npm:1.7.5" - "@unrs/resolver-binding-linux-riscv64-musl": "npm:1.7.5" - "@unrs/resolver-binding-linux-s390x-gnu": "npm:1.7.5" - "@unrs/resolver-binding-linux-x64-gnu": "npm:1.7.5" - "@unrs/resolver-binding-linux-x64-musl": "npm:1.7.5" - "@unrs/resolver-binding-wasm32-wasi": "npm:1.7.5" - "@unrs/resolver-binding-win32-arm64-msvc": "npm:1.7.5" - "@unrs/resolver-binding-win32-ia32-msvc": "npm:1.7.5" - "@unrs/resolver-binding-win32-x64-msvc": "npm:1.7.5" - napi-postinstall: "npm:^0.2.2" - dependenciesMeta: - "@unrs/resolver-binding-darwin-arm64": - optional: true - "@unrs/resolver-binding-darwin-x64": - optional: true - "@unrs/resolver-binding-freebsd-x64": - optional: true - "@unrs/resolver-binding-linux-arm-gnueabihf": - optional: true - "@unrs/resolver-binding-linux-arm-musleabihf": - optional: true - "@unrs/resolver-binding-linux-arm64-gnu": - optional: true - "@unrs/resolver-binding-linux-arm64-musl": - optional: true - "@unrs/resolver-binding-linux-ppc64-gnu": - optional: true - "@unrs/resolver-binding-linux-riscv64-gnu": - optional: true - "@unrs/resolver-binding-linux-riscv64-musl": - optional: true - "@unrs/resolver-binding-linux-s390x-gnu": - optional: true - "@unrs/resolver-binding-linux-x64-gnu": - optional: true - "@unrs/resolver-binding-linux-x64-musl": - optional: true - "@unrs/resolver-binding-wasm32-wasi": - optional: true - "@unrs/resolver-binding-win32-arm64-msvc": - optional: true - "@unrs/resolver-binding-win32-ia32-msvc": - optional: true - "@unrs/resolver-binding-win32-x64-msvc": - optional: true - checksum: 10c0/b71bc6fadb0f513b8db6e7166a6d0dd3e133b5091a1ef71eaf36878e116b0a7710de16a4e4c17a0f7a93395909177af445fddab711f5d26230acec76d1055677 - languageName: node - linkType: hard - -"unset-value@npm:^1.0.0": - version: 1.0.0 - resolution: "unset-value@npm:1.0.0" - dependencies: - has-value: "npm:^0.3.1" - isobject: "npm:^3.0.0" - checksum: 10c0/68a796dde4a373afdbf017de64f08490a3573ebee549136da0b3a2245299e7f65f647ef70dc13c4ac7f47b12fba4de1646fa0967a365638578fedce02b9c0b1f - languageName: node - linkType: hard - -"unzip-response@npm:^2.0.1": - version: 2.0.1 - resolution: "unzip-response@npm:2.0.1" - checksum: 10c0/8df383f28e87bcc1e0810343c435a524d62063841ace6cb507edeade4d74e78be76d32a84e35e7fa270a1b697ba86fd3e3c153224228a6db88e728576fa7e4f3 - languageName: node - linkType: hard - -"upath@npm:^1.1.1": - version: 1.2.0 - resolution: "upath@npm:1.2.0" - checksum: 10c0/3746f24099bf69dbf8234cecb671e1016e1f6b26bd306de4ff8966fb0bc463fa1014ffc48646b375de1ab573660e3a0256f6f2a87218b2dfa1779a84ef6992fa - languageName: node - linkType: hard - "update-browserslist-db@npm:^1.1.3": version: 1.1.3 resolution: "update-browserslist-db@npm:1.1.3" @@ -26668,33 +21888,6 @@ __metadata: languageName: node linkType: hard -"update-notifier@npm:^2.5.0": - version: 2.5.0 - resolution: "update-notifier@npm:2.5.0" - dependencies: - boxen: "npm:^1.2.1" - chalk: "npm:^2.0.1" - configstore: "npm:^3.0.0" - import-lazy: "npm:^2.1.0" - is-ci: "npm:^1.0.10" - is-installed-globally: "npm:^0.1.0" - is-npm: "npm:^1.0.0" - latest-version: "npm:^3.0.0" - semver-diff: "npm:^2.0.0" - xdg-basedir: "npm:^3.0.0" - checksum: 10c0/f6b82e655f115b67e829a9f10fe75d2c3afae84a51941478791bfa49023e2c35386790deb8f53d7149fa7e323d6cec1ab9580d92c84e99c7aca3f00e1cfe5efe - languageName: node - linkType: hard - -"uri-js@npm:^3.0.2": - version: 3.0.2 - resolution: "uri-js@npm:3.0.2" - dependencies: - punycode: "npm:^2.1.0" - checksum: 10c0/8c24d7f2b1821f76f9f4f838f6afa406eef277ef86b93a4e20b8570cd5685f16862fa9c4b2f7db0e787fb172b90c1c1da313da8064ac3e93167b0ff81f91ac80 - languageName: node - linkType: hard - "uri-js@npm:^4.2.2": version: 4.4.1 resolution: "uri-js@npm:4.4.1" @@ -26704,22 +21897,6 @@ __metadata: languageName: node linkType: hard -"urix@npm:^0.1.0": - version: 0.1.0 - resolution: "urix@npm:0.1.0" - checksum: 10c0/264f1b29360c33c0aec5fb9819d7e28f15d1a3b83175d2bcc9131efe8583f459f07364957ae3527f1478659ec5b2d0f1ad401dfb625f73e4d424b3ae35fc5fc0 - languageName: node - linkType: hard - -"url-parse-lax@npm:^1.0.0": - version: 1.0.0 - resolution: "url-parse-lax@npm:1.0.0" - dependencies: - prepend-http: "npm:^1.0.1" - checksum: 10c0/7578d90d18297c0896ab3c98350b61b59be56211baad543ea55eb570dfbd403b0987e499a817abb55d755df6f47ec2e748a49bd09f8d39766066a6871853cea1 - languageName: node - linkType: hard - "urlpattern-polyfill@npm:10.0.0": version: 10.0.0 resolution: "urlpattern-polyfill@npm:10.0.0" @@ -26788,20 +21965,6 @@ __metadata: languageName: node linkType: hard -"use@npm:^3.1.0": - version: 3.1.1 - resolution: "use@npm:3.1.1" - checksum: 10c0/75b48673ab80d5139c76922630d5a8a44e72ed58dbaf54dee1b88352d10e1c1c1fc332066c782d8ae9a56503b85d3dc67ff6d2ffbd9821120466d1280ebb6d6e - languageName: node - linkType: hard - -"utf8-byte-length@npm:^1.0.1": - version: 1.0.5 - resolution: "utf8-byte-length@npm:1.0.5" - checksum: 10c0/e69bda3299608f4cc75976da9fb74ac94801a58b9ca29fdad03a20ec952e7477d7f226c12716b5f36bd4cff8151d1d152d02ee1df3752f017d4b2c725ce3e47a - languageName: node - linkType: hard - "utf8@npm:3.0.0": version: 3.0.0 resolution: "utf8@npm:3.0.0" @@ -26809,7 +21972,7 @@ __metadata: languageName: node linkType: hard -"util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2, util-deprecate@npm:~1.0.1": +"util-deprecate@npm:^1.0.1, util-deprecate@npm:~1.0.1": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2" checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942 @@ -26899,20 +22062,6 @@ __metadata: languageName: node linkType: hard -"valid-url@npm:~1.0.9": - version: 1.0.9 - resolution: "valid-url@npm:1.0.9" - checksum: 10c0/3995e65f9942dbcb1621754c0f9790335cec61e9e9310c0a809e9ae0e2ae91bb7fc6a471fba788e979db0418d9806639f681ecebacc869bc8c3de88efa562ee6 - languageName: node - linkType: hard - -"validator@npm:^10.0.0": - version: 10.11.0 - resolution: "validator@npm:10.11.0" - checksum: 10c0/3e32a0a00b28012369c44aef1437b21a095640e0576580f97310d214f7eb0fb8c465099a1d8493d2d4117d9d342a43ae176cf184917f83e95a8eb4449652b4e1 - languageName: node - linkType: hard - "validator@npm:^13.6.0": version: 13.15.15 resolution: "validator@npm:13.15.15" @@ -26927,27 +22076,6 @@ __metadata: languageName: node linkType: hard -"viem@npm:^2.22.23": - version: 2.30.4 - resolution: "viem@npm:2.30.4" - dependencies: - "@noble/curves": "npm:1.9.1" - "@noble/hashes": "npm:1.8.0" - "@scure/bip32": "npm:1.7.0" - "@scure/bip39": "npm:1.6.0" - abitype: "npm:1.0.8" - isows: "npm:1.0.7" - ox: "npm:0.7.1" - ws: "npm:8.18.2" - peerDependencies: - typescript: ">=5.0.4" - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/fae6b5106ede843f6d2227e6135746379059c2b90b92a286e732555b4670f3c10caa82f4cb527184f15b7499547891cd45ac17aac2761a9158f9df0c3b9b1f27 - languageName: node - linkType: hard - "vlq@npm:^1.0.0": version: 1.0.1 resolution: "vlq@npm:1.0.1" @@ -27185,7 +22313,7 @@ __metadata: languageName: node linkType: hard -"which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.18, which-typed-array@npm:^1.1.19, which-typed-array@npm:^1.1.2": +"which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.19, which-typed-array@npm:^1.1.2": version: 1.1.19 resolution: "which-typed-array@npm:1.1.19" dependencies: @@ -27200,7 +22328,7 @@ __metadata: languageName: node linkType: hard -"which@npm:^1.1.1, which@npm:^1.2.9, which@npm:^1.3.1": +"which@npm:^1.1.1, which@npm:^1.3.1": version: 1.3.1 resolution: "which@npm:1.3.1" dependencies: @@ -27233,15 +22361,6 @@ __metadata: languageName: node linkType: hard -"widest-line@npm:^2.0.0": - version: 2.0.1 - resolution: "widest-line@npm:2.0.1" - dependencies: - string-width: "npm:^2.1.1" - checksum: 10c0/c8c908c737b522a8cf46254bc85b3b0c9e6934a054840d9b01ea7f36442aa11c8393579fa57bc9ef9a5c5ea69f49e78783ce27b8a8ebab4f855ca044efa584fa - languageName: node - linkType: hard - "widest-line@npm:^3.1.0": version: 3.1.0 resolution: "widest-line@npm:3.1.0" @@ -27322,7 +22441,7 @@ __metadata: languageName: node linkType: hard -"write-file-atomic@npm:^2.0.0, write-file-atomic@npm:^2.3.0": +"write-file-atomic@npm:^2.3.0": version: 2.4.3 resolution: "write-file-atomic@npm:2.4.3" dependencies: @@ -27388,21 +22507,6 @@ __metadata: languageName: node linkType: hard -"ws@npm:8.18.2": - version: 8.18.2 - resolution: "ws@npm:8.18.2" - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ">=5.0.2" - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - checksum: 10c0/4b50f67931b8c6943c893f59c524f0e4905bbd183016cfb0f2b8653aa7f28dad4e456b9d99d285bbb67cca4fedd9ce90dfdfaa82b898a11414ebd66ee99141e4 - languageName: node - linkType: hard - "ws@npm:^6.2.2, ws@npm:^6.2.3": version: 6.2.3 resolution: "ws@npm:6.2.3" @@ -27427,13 +22531,6 @@ __metadata: languageName: node linkType: hard -"xdg-basedir@npm:^3.0.0": - version: 3.0.0 - resolution: "xdg-basedir@npm:3.0.0" - checksum: 10c0/c3be36400d8a69c9154ce6ccff98832dae0d04f8bacda806f609d3955beb23dc7c9dde724438b81e6128bf253d440a2bfe0239dd37d70333ab625c4e170b77b2 - languageName: node - linkType: hard - "xmlhttprequest-ssl@npm:~2.1.1": version: 2.1.2 resolution: "xmlhttprequest-ssl@npm:2.1.2" @@ -27448,7 +22545,7 @@ __metadata: languageName: node linkType: hard -"xtend@npm:^4.0.0, xtend@npm:~4.0.1": +"xtend@npm:~4.0.1": version: 4.0.2 resolution: "xtend@npm:4.0.2" checksum: 10c0/366ae4783eec6100f8a02dff02ac907bf29f9a00b82ac0264b4d8b832ead18306797e283cf19de776538babfdcb2101375ec5646b59f08c52128ac4ab812ed0e @@ -27469,13 +22566,6 @@ __metadata: languageName: node linkType: hard -"yallist@npm:^2.1.2": - version: 2.1.2 - resolution: "yallist@npm:2.1.2" - checksum: 10c0/0b9e25aa00adf19e01d2bcd4b208aee2b0db643d9927131797b7af5ff69480fc80f1c3db738cbf3946f0bddf39d8f2d0a5709c644fd42d4aa3a4e6e786c087b5 - languageName: node - linkType: hard - "yallist@npm:^3.0.2": version: 3.1.1 resolution: "yallist@npm:3.1.1" @@ -27497,14 +22587,7 @@ __metadata: languageName: node linkType: hard -"yaml@npm:^1.10.0": - version: 1.10.2 - resolution: "yaml@npm:1.10.2" - checksum: 10c0/5c28b9eb7adc46544f28d9a8d20c5b3cb1215a886609a2fd41f51628d8aaa5878ccd628b755dbcd29f6bb4921bd04ffbc6dcc370689bb96e594e2f9813d2605f - languageName: node - linkType: hard - -"yaml@npm:^2.2.1, yaml@npm:^2.2.2, yaml@npm:^2.3.4": +"yaml@npm:^2.2.1, yaml@npm:^2.2.2": version: 2.8.0 resolution: "yaml@npm:2.8.0" bin: @@ -27629,31 +22712,6 @@ __metadata: languageName: node linkType: hard -"z-schema@npm:^3.15.4": - version: 3.25.1 - resolution: "z-schema@npm:3.25.1" - dependencies: - commander: "npm:^2.7.1" - core-js: "npm:^2.5.7" - lodash.get: "npm:^4.0.0" - lodash.isequal: "npm:^4.0.0" - validator: "npm:^10.0.0" - dependenciesMeta: - commander: - optional: true - bin: - z-schema: ./bin/z-schema - checksum: 10c0/df6c0f211a4a85d0ce35b717e05bc636ad6368ed492a7567efabaa47b1d25d967cb19cf55e88ae6af3787517aafe6a8da85d076419680b530f5aa9b58c7a1a62 - languageName: node - linkType: hard - -"zhead@npm:^2.2.4": - version: 2.2.4 - resolution: "zhead@npm:2.2.4" - checksum: 10c0/3d166fb661f1b7fdf8a0ef2222d9e574ab241e72141f2f1fda62a9250ca73aabf2eaf0d66046a3984cd24d1dd9bac231338c6271684d6b8caa6b66af7c45f275 - languageName: node - linkType: hard - "zod@npm:3.22.4": version: 3.22.4 resolution: "zod@npm:3.22.4" @@ -27661,13 +22719,6 @@ __metadata: languageName: node linkType: hard -"zod@npm:^3.23.8": - version: 3.25.32 - resolution: "zod@npm:3.25.32" - checksum: 10c0/de0bc052a7666578b3d5dd42bc522f02f27e1c798236439c0f6b6bc1b311a221706aebdafb1f58399d5f558b1fab7860c6970e096fe8d6947743bc791d567c4b - languageName: node - linkType: hard - "zustand@npm:^4.5.2": version: 4.5.7 resolution: "zustand@npm:4.5.7" From 4f18c75041bb47c1862169eef82c22067642a83a Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer <98749896+remicolin@users.noreply.github.com> Date: Mon, 16 Jun 2025 09:52:02 -0400 Subject: [PATCH 2/5] update contracts (#628) * remove sdk/tests (#622) * remove sdk/tests * chore: update yarn.lock --------- Co-authored-by: Ayman * fix: add range check on paddedInLength of shaBytesDynamic (#623) * fix ci (#626) * implement self uups upgradeable (#592) * implement self uups upgradeable * small changes in identityVerificationHubImplV2 * delete aderyn.toml * chore: add custom verifier * chnage return output * feat: use self structs and a Generic output struct * feat: add userIdentifier, nullifier, forbiddencountries to returned output * add root view functions from registry * fix: build and compilation errors * add userDefined data into selfVerificationRoot * "resolve conflicts" * fix compilation problem * fix how to register verification config * test: CustomVerifier * fix verification root and hub integration * add scope check in hub impl * replace poseidon hash to ripemd+sha256 * add todo list * feat: refactor and add test cases for generic formatter * add performUserIdentifierCheck in basicVerification * change how to handle additionalData and fix stack too deep * start adding test codes * fix dependency problems in monorepo * fix: forbidden countries (#612) LGTM! * able to run test code * pass happy path * delete unused codes * change error code name, add caller address validation and add scripts to run test and build in monorepo * add all test cases in vcAndDisclose flow * remove comment out * chore: use actual user identifier outputs * success in registration tests * cover all cases * pass contractVersion instead of circuitVersion * fix disclose test * chore: add natspecs for ImplHubV2, CustomVerifier and GenericFormatter * change val name and remove unused lines * add val name change * remove userIdentifier from return data * feat: use GenericDiscloseOutput struct in verfication hook fix test cases for user identifier * chore: change the function order for Hub Impl V2 (#625) * fix nat specs * add nat spec in SelfStructs --------- Co-authored-by: Ayman Co-authored-by: Nesopie <87437291+Nesopie@users.noreply.github.com> * prettier (#629) --------- Co-authored-by: Ayman Co-authored-by: Vishalkulkarni45 <109329073+Vishalkulkarni45@users.noreply.github.com> Co-authored-by: nicoshark Co-authored-by: Nesopie <87437291+Nesopie@users.noreply.github.com> --- .../utils/crypto/bigInt/bigInt.circom | 44 +- .../hasher/shaBytes/dynamic/sha1Bytes.circom | 12 +- .../scripts/build/build_disclose_circuits.sh | 1 + circuits/scripts/build/common.sh | 14 +- .../IdentityVerificationHubImplV2.sol | 1135 ++++++++++------- .../abstract/SelfVerificationRoot.sol | 318 ++--- .../constants/CircuitConstantsV2.sol | 4 +- contracts/contracts/example/Airdrop.sol | 658 +++++----- contracts/contracts/example/HappyBirthday.sol | 402 +++--- .../contracts/example/SelfPassportERC721.sol | 438 +++---- .../interfaces/IIdentityVerificationHubV2.sol | 226 ++-- .../interfaces/ISelfVerificationRoot.sol | 70 +- .../libraries/CircuitAttributeHandler.sol | 6 +- .../libraries/CircuitAttributeHandlerV2.sol | 36 +- .../contracts/libraries/CustomVerifier.sol | 217 ++++ contracts/contracts/libraries/Formatter.sol | 55 +- .../contracts/libraries/GenericFormatter.sol | 73 ++ .../libraries/IdCardAttributeHandler.sol | 6 +- contracts/contracts/libraries/SelfStructs.sol | 124 ++ .../registry/IdentityRegistryIdCard.sol | 19 - .../registry/IdentityRegistryIdCardImplV1.sol | 3 - .../contracts/tests/TestCustomVerifier.sol | 15 + .../tests/TestSelfVerificationRoot.sol | 89 ++ .../contracts/tests/testGenericFormatter.sol | 34 + .../disclose/Verifier_vc_and_disclose_id.sol | 307 +++++ ...id_sha256_sha256_sha256_rsa_65537_4096.sol | 59 +- contracts/hardhat.config.ts | 6 +- contracts/ignition/modules/hub/deployHub.ts | 9 +- .../modules/verifiers/deployAllVerifiers.ts | 12 +- contracts/package.json | 64 +- contracts/scripts/README.md | 153 +++ contracts/scripts/dev.sh | 140 ++ contracts/scripts/setHubV2.ts | 13 +- contracts/scripts/setRegistry.ts | 11 +- contracts/scripts/setRegistryId.ts | 17 +- contracts/scripts/test.sh | 185 +++ contracts/test/example/airdrop.test.ts | 23 +- .../commitmentRegistration.test.ts | 8 +- contracts/test/integration/endToEnd.test.ts | 34 +- .../test/integration/vcAndDisclose.test.ts | 19 +- contracts/test/integration/verifyAll.test.ts | 28 +- contracts/test/unit/CustomVerifier.test.ts | 411 ++++++ contracts/test/unit/GenericFormatter.test.ts | 165 +++ contracts/test/unit/IdentityRegistry.test.ts | 2 +- contracts/test/unit/formatter.test.ts | 27 +- contracts/test/utils/constants.ts | 1 + contracts/test/utils/deploymentV2.ts | 239 ++++ contracts/test/utils/formatter.ts | 32 +- contracts/test/utils/generateProof.ts | 219 +++- .../utils/pubkeys/serialized_csca_tree.json | 90 -- .../utils/pubkeys/serialized_dsc_tree.json | 1 - contracts/test/utils/types.ts | 62 +- contracts/test/v2/discloseId.test.ts | 903 +++++++++++++ contracts/test/v2/disclosePassport.test.ts | 924 ++++++++++++++ contracts/test/v2/hubOther.test.ts | 186 +++ contracts/test/v2/registerId.test.ts | 266 ++++ contracts/test/v2/registerPassport.test.ts | 268 ++++ contracts/yarnrc.yml | 1 + 58 files changed, 6901 insertions(+), 1983 deletions(-) create mode 100644 contracts/contracts/libraries/CustomVerifier.sol create mode 100644 contracts/contracts/libraries/GenericFormatter.sol create mode 100644 contracts/contracts/libraries/SelfStructs.sol delete mode 100644 contracts/contracts/registry/IdentityRegistryIdCard.sol create mode 100644 contracts/contracts/tests/TestCustomVerifier.sol create mode 100644 contracts/contracts/tests/TestSelfVerificationRoot.sol create mode 100644 contracts/contracts/tests/testGenericFormatter.sol create mode 100644 contracts/contracts/verifiers/disclose/Verifier_vc_and_disclose_id.sol create mode 100644 contracts/scripts/README.md create mode 100755 contracts/scripts/dev.sh create mode 100755 contracts/scripts/test.sh create mode 100644 contracts/test/unit/CustomVerifier.test.ts create mode 100644 contracts/test/unit/GenericFormatter.test.ts create mode 100644 contracts/test/utils/deploymentV2.ts delete mode 100644 contracts/test/utils/pubkeys/serialized_csca_tree.json delete mode 100644 contracts/test/utils/pubkeys/serialized_dsc_tree.json create mode 100644 contracts/test/v2/discloseId.test.ts create mode 100644 contracts/test/v2/disclosePassport.test.ts create mode 100644 contracts/test/v2/hubOther.test.ts create mode 100644 contracts/test/v2/registerId.test.ts create mode 100644 contracts/test/v2/registerPassport.test.ts create mode 100644 contracts/yarnrc.yml diff --git a/circuits/circuits/utils/crypto/bigInt/bigInt.circom b/circuits/circuits/utils/crypto/bigInt/bigInt.circom index e62828119..47fecc79c 100644 --- a/circuits/circuits/utils/crypto/bigInt/bigInt.circom +++ b/circuits/circuits/utils/crypto/bigInt/bigInt.circom @@ -8,7 +8,7 @@ include "../int/arithmetic.circom"; include "@openpassport/zk-email-circuits/lib/bigint.circom"; // What BigInt in this lib means -// We represent big number as array of chunks with some shunk_size (will be explained later) +// We represent big number as array of chunks with some shunk_size (will be explained later) // for this example we will use N for number, n for chunk size and k for chunk_number: // N[k]; // Number can be calculated by this formula: @@ -31,14 +31,14 @@ template BigMultModP(CHUNK_SIZE, CHUNK_NUMBER_GREATER, CHUNK_NUMBER_LESS, CHUNK_ signal output div[CHUNK_NUMBER_DIV]; signal output mod[CHUNK_NUMBER_MODULUS]; - + component mult = BigMultOverflow(CHUNK_SIZE, CHUNK_NUMBER_GREATER, CHUNK_NUMBER_LESS); mult.in1 <== in1; mult.in2 <== in2; var reduced[200] = reduce_overflow_dl(CHUNK_SIZE, CHUNK_NUMBER_BASE - 1, CHUNK_NUMBER_BASE, mult.out); var long_division[2][200] = long_div_dl(CHUNK_SIZE, CHUNK_NUMBER_MODULUS, CHUNK_NUMBER_DIV - 1, reduced, modulus); - + for (var i = 0; i < CHUNK_NUMBER_DIV; i++){ div[i] <-- long_division[0][i]; @@ -51,26 +51,26 @@ template BigMultModP(CHUNK_SIZE, CHUNK_NUMBER_GREATER, CHUNK_NUMBER_LESS, CHUNK_ modChecks[i].in <== mod[i]; } - + component greaterThan = BigGreaterThan(CHUNK_SIZE, CHUNK_NUMBER_MODULUS); - + greaterThan.in[0] <== modulus; greaterThan.in[1] <== mod; greaterThan.out === 1; - + component mult2; if (CHUNK_NUMBER_DIV >= CHUNK_NUMBER_MODULUS){ mult2 = BigMultNonEqualOverflow(CHUNK_SIZE, CHUNK_NUMBER_DIV, CHUNK_NUMBER_MODULUS); - + mult2.in1 <== div; mult2.in2 <== modulus; } else { mult2 = BigMultNonEqualOverflow(CHUNK_SIZE, CHUNK_NUMBER_MODULUS, CHUNK_NUMBER_DIV); - + mult2.in2 <== div; mult2.in1 <== modulus; } - + component isZero = BigIntIsZero(CHUNK_SIZE, CHUNK_SIZE * 2 + log_ceil(CHUNK_NUMBER_MODULUS + CHUNK_NUMBER_DIV - 1), CHUNK_NUMBER_BASE - 1); for (var i = 0; i < CHUNK_NUMBER_MODULUS; i++) { isZero.in[i] <== mult.out[i] - mult2.out[i] - mod[i]; @@ -84,9 +84,9 @@ template BigMultModP(CHUNK_SIZE, CHUNK_NUMBER_GREATER, CHUNK_NUMBER_LESS, CHUNK_ // in[0] <= in[1] template BigLessEqThan(CHUNK_SIZE, CHUNK_NUMBER){ signal input in[2][CHUNK_NUMBER]; - + signal output out; - + component lessThan[CHUNK_NUMBER]; component isEqual[CHUNK_NUMBER]; signal result[CHUNK_NUMBER]; @@ -94,12 +94,12 @@ template BigLessEqThan(CHUNK_SIZE, CHUNK_NUMBER){ lessThan[i] = LessThan(CHUNK_SIZE); lessThan[i].in[0] <== in[0][i]; lessThan[i].in[1] <== in[1][i]; - + isEqual[i] = IsEqual(); isEqual[i].in[0] <== in[0][i]; isEqual[i].in[1] <== in[1][i]; } - + for (var i = 0; i < CHUNK_NUMBER; i++){ if (i == 0){ result[i] <== lessThan[i].out + isEqual[i].out; @@ -107,17 +107,17 @@ template BigLessEqThan(CHUNK_SIZE, CHUNK_NUMBER){ result[i] <== lessThan[i].out + isEqual[i].out * result[i - 1]; } } - + out <== result[CHUNK_NUMBER - 1]; - + } // in[0] > in[1] template BigGreaterThan(CHUNK_SIZE, CHUNK_NUMBER){ signal input in[2][CHUNK_NUMBER]; - + signal output out; - + component lessEqThan = BigLessEqThan(CHUNK_SIZE, CHUNK_NUMBER); lessEqThan.in <== in; out <== 1 - lessEqThan.out; @@ -149,20 +149,20 @@ template BigModInv(CHUNK_SIZE, CHUNK_NUMBER) { signal input in[CHUNK_NUMBER]; signal input modulus[CHUNK_NUMBER]; signal output out[CHUNK_NUMBER]; - - + + var inv[200] = mod_inv_dl(CHUNK_SIZE, CHUNK_NUMBER, in, modulus); for (var i = 0; i < CHUNK_NUMBER; i++) { out[i] <-- inv[i]; } - + component mult = BigMultModP(CHUNK_SIZE, CHUNK_NUMBER, CHUNK_NUMBER, CHUNK_NUMBER); mult.in1 <== in; mult.in2 <== out; mult.modulus <== modulus; - + mult.mod[0] === 1; for (var i = 1; i < CHUNK_NUMBER; i++) { mult.mod[i] === 0; } -} \ No newline at end of file +} diff --git a/circuits/circuits/utils/crypto/hasher/shaBytes/dynamic/sha1Bytes.circom b/circuits/circuits/utils/crypto/hasher/shaBytes/dynamic/sha1Bytes.circom index d45616059..979e84102 100644 --- a/circuits/circuits/utils/crypto/hasher/shaBytes/dynamic/sha1Bytes.circom +++ b/circuits/circuits/utils/crypto/hasher/shaBytes/dynamic/sha1Bytes.circom @@ -28,7 +28,7 @@ template Sha1Bytes(max_num_bytes) { for (var i = 0; i < 160; i++) { out[i] <== sha.out[i]; } - + } //Adapted from @openpassport/zk-email-circuits/helpers/sha256general.circom @@ -66,9 +66,9 @@ template Sha1General(maxBitsPadded) { component he0 = H_sha1(4); component sha1compression[maxBlocks]; - + for (i=0; i address) internal _attestationIdToRegistry; - mapping(bytes32 => address) internal _attestationIdToDiscloseVerifier; -} +contract IdentityVerificationHubImplV2 is ImplRoot { + /// @custom:storage-location erc7201:self.storage.IdentityVerificationHub + struct IdentityVerificationHubStorage { + uint256 _circuitVersion; + mapping(bytes32 attestationId => address registry) _registries; + mapping(bytes32 attestationId => mapping(uint256 sigTypeId => address registerCircuitVerifier)) _registerCircuitVerifiers; + mapping(bytes32 attestationId => mapping(uint256 sigTypeId => address dscCircuitVerifier)) _dscCircuitVerifiers; + mapping(bytes32 attestationId => address discloseVerifiers) _discloseVerifiers; + } -/** - * @title IdentityVerificationHubImplV2 - * @notice Implementation contract for the Identity Verification Hub. - * @dev Provides functions for registering commitments and verifying groth16 proofs and inclusion proofs. - */ -contract IdentityVerificationHubImplV2 is IdentityVerificationHubStorageV2, IIdentityVerificationHubV2 { - using Formatter for uint256; + /// @custom:storage-location erc7201:self.storage.IdentityVerificationHubV2 + struct IdentityVerificationHubV2Storage { + mapping(bytes32 configId => SelfStructs.VerificationConfigV2) _v2VerificationConfigs; + } + // We should consider to add bridge address + // address bridgeAddress; - uint256 constant MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH = 40; + /// @dev keccak256(abi.encode(uint256(keccak256("self.storage.IdentityVerificationHub")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant IDENTITYVERIFICATIONHUB_STORAGE_LOCATION = + 0x2ade7eace21710c689ddef374add52ace9783e33bac626e58e73a9d190173d00; - // ==================================================== - // Events - // ==================================================== + /// @dev keccak256(abi.encode(uint256(keccak256("self.storage.IdentityVerificationHubV2")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant IDENTITYVERIFICATIONHUBV2_STORAGE_LOCATION = + 0xf9b5980dcec1a8b0609576a1f453bb2cad4732a0ea02bb89154d44b14a306c00; - event HubInitialized( - bytes32[] attestationIds, - address[] registryAddresses, - address[] vcAndDiscloseCircuitVerifiers, - uint256[] registerCircuitVerifierIds, - address[] registerCircuitVerifiers, - uint256[] dscCircuitVerifierIds, - address[] dscCircuitVerifiers - ); + /** + * @notice Returns the storage struct for the main IdentityVerificationHub. + * @dev Uses ERC-7201 storage pattern for upgradeable contracts. + * @return $ The storage struct reference. + */ + function _getIdentityVerificationHubStorage() private pure returns (IdentityVerificationHubStorage storage $) { + assembly { + $.slot := IDENTITYVERIFICATIONHUB_STORAGE_LOCATION + } + } + + /** + * @notice Returns the storage struct for IdentityVerificationHub V2 features. + * @dev Uses ERC-7201 storage pattern for upgradeable contracts. + * @return $ The V2 storage struct reference. + */ + function _getIdentityVerificationHubV2Storage() private pure returns (IdentityVerificationHubV2Storage storage $) { + assembly { + $.slot := IDENTITYVERIFICATIONHUBV2_STORAGE_LOCATION + } + } + + /** + * @notice Emitted when the Hub V2 is successfully initialized. + */ + event HubInitializedV2(); + /** + * @notice Emitted when a verification config V2 is set. + * @param configId The configuration identifier (generated from config hash). + * @param config The verification configuration that was set. + */ + event VerificationConfigV2Set(bytes32 indexed configId, SelfStructs.VerificationConfigV2 config); /** * @notice Emitted when the registry address is updated. + * @param attestationId The attestation identifier. * @param registry The new registry address. */ event RegistryUpdated(bytes32 attestationId, address registry); /** * @notice Emitted when the VC and Disclose circuit verifier is updated. + * @param attestationId The attestation identifier. * @param vcAndDiscloseCircuitVerifier The new VC and Disclose circuit verifier address. */ event VcAndDiscloseCircuitUpdated(bytes32 attestationId, address vcAndDiscloseCircuitVerifier); @@ -102,67 +101,74 @@ contract IdentityVerificationHubImplV2 is IdentityVerificationHubStorageV2, IIde // Errors // ==================================================== - /// @notice Thrown when the lengths of provided arrays do not match. - /// @dev Used when initializing or updating arrays that must have equal length. - error LENGTH_MISMATCH(); + /// @notice Thrown when arrays have mismatched lengths in batch operations. + /// @dev Ensures that all input arrays have the same length for batch updates. + error LengthMismatch(); /// @notice Thrown when no verifier is set for a given signature type. /// @dev Indicates that the mapping lookup for the verifier returned the zero address. - error NO_VERIFIER_SET(); + error NoVerifierSet(); /// @notice Thrown when the current date in the proof is not within the valid range. /// @dev Ensures that the provided proof's date is within one day of the expected start time. - error CURRENT_DATE_NOT_IN_VALID_RANGE(); - - /// @notice Thrown when the 'older than' attribute in the proof is invalid. - /// @dev The 'older than' value derived from the proof does not match the expected criteria. - error INVALID_OLDER_THAN(); - - /// @notice Thrown when the provided forbidden countries list is invalid. - /// @dev The forbidden countries list in the proof does not match the expected packed data. - error INVALID_FORBIDDEN_COUNTRIES(); - - /// @notice Thrown when the OFAC check fails. - /// @dev Indicates that the proof did not satisfy the required OFAC conditions. - error INVALID_OFAC(); + error CurrentDateNotInValidRange(); /// @notice Thrown when the register circuit proof is invalid. /// @dev The register circuit verifier did not validate the provided proof. - error INVALID_REGISTER_PROOF(); + error InvalidRegisterProof(); /// @notice Thrown when the DSC circuit proof is invalid. /// @dev The DSC circuit verifier did not validate the provided proof. - error INVALID_DSC_PROOF(); + error InvalidDscProof(); /// @notice Thrown when the VC and Disclose proof is invalid. /// @dev The VC and Disclose circuit verifier did not validate the provided proof. - error INVALID_VC_AND_DISCLOSE_PROOF(); + error InvalidVcAndDiscloseProof(); - /// @notice Thrown when the provided commitment root is invalid. - /// @dev Used in proofs to ensure that the commitment root matches the expected value in the registry. - error INVALID_COMMITMENT_ROOT(); + /// @notice Thrown when the provided identity commitment root is invalid. + /// @dev Used in proofs to ensure that the identity commitment root matches the expected value in the registry. + error InvalidIdentityCommitmentRoot(); - /// @notice Thrown when the provided OFAC root is invalid. - /// @dev Indicates that the OFAC root from the proof does not match the expected OFAC root. - error INVALID_OFAC_ROOT(); + /// @notice Thrown when the provided DSC commitment root is invalid. + /// @dev Used in proofs to ensure that the DSC commitment root matches the expected value in the registry. + error InvalidDscCommitmentRoot(); /// @notice Thrown when the provided CSCA root is invalid. /// @dev Indicates that the CSCA root from the DSC proof does not match the expected CSCA root. - error INVALID_CSCA_ROOT(); + error InvalidCscaRoot(); + + /// @notice Thrown when an invalid attestation ID is provided. + /// @dev The attestation ID must be a supported type (e.g., E_PASSPORT or EU_ID_CARD). + error InvalidAttestationId(); + + /// @notice Thrown when the scope in the header doesn't match the scope in the proof. + /// @dev Ensures that the scope value in the header matches the scope value in the proof. + error ScopeMismatch(); + + /// @notice Thrown when cross-chain verification is attempted but not yet supported. + /// @dev Cross-chain bridging functionality is not implemented yet. + error CrossChainIsNotSupportedYet(); - /// @notice Thrown when the revealed data type is invalid or not supported. - /// @dev Raised during the processing of revealed data if it does not match any supported type. - error INVALID_REVEALED_DATA_TYPE(); + /// @notice Thrown when the input data is too short for decoding. + /// @dev The input data must be at least 97 bytes (1 + 31 + 32 + 32 + 1 minimum). + error InputTooShort(); - error INVALID_ATTESTATION_ID(); + /// @notice Thrown when the user context data is too short for decoding. + /// @dev The user context data must be at least 96 bytes (32 + 32 + 32 minimum). + error UserContextDataTooShort(); + + /// @notice Thrown when the user identifier hash does not match the proof user identifier. + /// @dev Ensures that the user context data hash matches the user identifier in the proof. + error InvalidUserIdentifierInProof(); // ==================================================== // Constructor // ==================================================== /** - * @notice Constructor that disables initializers. - * @dev Prevents direct initialization of the implementation contract. + * @notice Constructor that disables initializers for the implementation contract. + * @dev This prevents the implementation contract from being initialized directly. + * The actual initialization should only happen through the proxy. */ constructor() { _disableInitializers(); @@ -172,124 +178,30 @@ contract IdentityVerificationHubImplV2 is IdentityVerificationHubStorageV2, IIde // Initializer // ==================================================== - function initialize( - bytes32[] memory attestationIds, - address[] memory registryAddresses, - address[] memory vcAndDiscloseCircuitVerifierAddresses, - uint256[] memory registerCircuitVerifierIds, - address[] memory registerCircuitVerifierAddresses, - uint256[] memory dscCircuitVerifierIds, - address[] memory dscCircuitVerifierAddresses - ) external initializer { - __ImplRoot_init(); - if (attestationIds.length != registryAddresses.length) { - revert LENGTH_MISMATCH(); - } - if (attestationIds.length != vcAndDiscloseCircuitVerifierAddresses.length) { - revert LENGTH_MISMATCH(); - } - if (registerCircuitVerifierIds.length != registerCircuitVerifierAddresses.length) { - revert LENGTH_MISMATCH(); - } - if (dscCircuitVerifierIds.length != dscCircuitVerifierAddresses.length) { - revert LENGTH_MISMATCH(); - } - for (uint256 i = 0; i < attestationIds.length; i++) { - _attestationIdToRegistry[attestationIds[i]] = registryAddresses[i]; - _attestationIdToDiscloseVerifier[attestationIds[i]] = vcAndDiscloseCircuitVerifierAddresses[i]; - } - for (uint256 i = 0; i < registerCircuitVerifierIds.length; i++) { - _sigTypeToRegisterCircuitVerifiers[registerCircuitVerifierIds[i]] = registerCircuitVerifierAddresses[i]; - } - for (uint256 i = 0; i < dscCircuitVerifierIds.length; i++) { - _sigTypeToDscCircuitVerifiers[dscCircuitVerifierIds[i]] = dscCircuitVerifierAddresses[i]; - } - emit HubInitialized( - attestationIds, - registryAddresses, - vcAndDiscloseCircuitVerifierAddresses, - registerCircuitVerifierIds, - registerCircuitVerifierAddresses, - dscCircuitVerifierIds, - dscCircuitVerifierAddresses - ); - } - - // ==================================================== - // External View Functions - // ==================================================== - - /** - * @notice Retrieves the registry address. - * @return The address of the Identity Registry. - */ - function registry(bytes32 attestationId) external view virtual onlyProxy returns (address) { - return _attestationIdToRegistry[attestationId]; - } - - /** - * @notice Retrieves the VC and Disclose circuit verifier address. - * @return The address of the VC and Disclose circuit verifier. - */ - function vcAndDiscloseCircuitVerifier(bytes32 attestationId) external view virtual onlyProxy returns (address) { - return _attestationIdToDiscloseVerifier[attestationId]; - } - - /** - * @notice Retrieves the register circuit verifier address for a given signature type. - * @param typeId The signature type identifier. - * @return The register circuit verifier address. - */ - function sigTypeToRegisterCircuitVerifiers(uint256 typeId) external view virtual onlyProxy returns (address) { - return _sigTypeToRegisterCircuitVerifiers[typeId]; - } - /** - * @notice Retrieves the DSC circuit verifier address for a given signature type. - * @param typeId The signature type identifier. - * @return The DSC circuit verifier address. + * @notice Initializes the Identity Verification Hub V2 contract. + * @dev Sets up the contract state including circuit version and emits initialization event. + * This function can only be called once due to the initializer modifier. + * The circuit version is set to 2 for V2 hub compatibility. */ - function sigTypeToDscCircuitVerifiers(uint256 typeId) external view virtual onlyProxy returns (address) { - return _sigTypeToDscCircuitVerifiers[typeId]; - } + function initialize() external initializer { + __ImplRoot_init(); - /** - * @notice Verifies a VC and Disclose proof using unified bytes interface. - * @dev Supports both passport and ID card proofs through a unified interface. - * @param proofData Encoded proof data containing all necessary verification parameters. - * @return result Encoded verification result containing all relevant data. - */ - function verifyVcAndDisclose( - bytes calldata proofData - ) external view virtual onlyProxy returns (bytes memory result) { - // Decode the attestation ID from the first 32 bytes - bytes32 attestationId; - assembly { - attestationId := calldataload(proofData.offset) - } + // Initialize circuit version to 2 for V2 hub + IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage(); + $._circuitVersion = 2; - if (attestationId == AttestationId.E_PASSPORT) { - // Passport proof - VcAndDiscloseHubProof memory proof = _decodePassportProof(proofData[32:]); - VcAndDiscloseVerificationResult memory passportResult = _verifyPassportVcAndDisclose(proof); - return _encodePassportResult(passportResult); - } else if (attestationId == AttestationId.EU_ID_CARD) { - // ID Card proof - IdCardVcAndDiscloseHubProof memory proof = _decodeIdCardProof(proofData[32:]); - IdCardVcAndDiscloseVerificationResult memory idCardResult = _verifyEuIdVcAndDisclose(proof); - return _encodeIdCardResult(idCardResult); - } else { - revert INVALID_ATTESTATION_ID(); - } + emit HubInitializedV2(); } // ==================================================== - // External Functions - Registration + // External Functions // ==================================================== /** - * @notice Registers a passport commitment using a register circuit proof. - * @dev Verifies the proof and then calls the Identity Registry to register the commitment. + * @notice Registers a commitment using a register circuit proof. + * @dev Verifies the register circuit proof and then calls the Identity Registry to register the commitment. + * @param attestationId The attestation ID. * @param registerCircuitVerifierId The identifier for the register circuit verifier to use. * @param registerCircuitProof The register circuit proof data. */ @@ -299,20 +211,21 @@ contract IdentityVerificationHubImplV2 is IdentityVerificationHubStorageV2, IIde IRegisterCircuitVerifier.RegisterCircuitProof memory registerCircuitProof ) external virtual onlyProxy { _verifyRegisterProof(attestationId, registerCircuitVerifierId, registerCircuitProof); + IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage(); if (attestationId == AttestationId.E_PASSPORT) { - IIdentityRegistryV1(_attestationIdToRegistry[attestationId]).registerCommitment( + IIdentityRegistryV1($._registries[attestationId]).registerCommitment( attestationId, registerCircuitProof.pubSignals[CircuitConstantsV2.REGISTER_NULLIFIER_INDEX], registerCircuitProof.pubSignals[CircuitConstantsV2.REGISTER_COMMITMENT_INDEX] ); } else if (attestationId == AttestationId.EU_ID_CARD) { - IIdentityRegistryIdCardV1(_attestationIdToRegistry[attestationId]).registerCommitment( + IIdentityRegistryIdCardV1($._registries[attestationId]).registerCommitment( attestationId, registerCircuitProof.pubSignals[CircuitConstantsV2.REGISTER_NULLIFIER_INDEX], registerCircuitProof.pubSignals[CircuitConstantsV2.REGISTER_COMMITMENT_INDEX] ); } else { - revert INVALID_ATTESTATION_ID(); + revert InvalidAttestationId(); } } @@ -328,29 +241,64 @@ contract IdentityVerificationHubImplV2 is IdentityVerificationHubStorageV2, IIde IDscCircuitVerifier.DscCircuitProof memory dscCircuitProof ) external virtual onlyProxy { _verifyDscProof(attestationId, dscCircuitVerifierId, dscCircuitProof); + IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage(); if (attestationId == AttestationId.E_PASSPORT) { - IIdentityRegistryV1(_attestationIdToRegistry[attestationId]).registerDscKeyCommitment( + IIdentityRegistryV1($._registries[attestationId]).registerDscKeyCommitment( dscCircuitProof.pubSignals[CircuitConstantsV2.DSC_TREE_LEAF_INDEX] ); } else if (attestationId == AttestationId.EU_ID_CARD) { - IIdentityRegistryIdCardV1(_attestationIdToRegistry[attestationId]).registerDscKeyCommitment( + IIdentityRegistryIdCardV1($._registries[attestationId]).registerDscKeyCommitment( dscCircuitProof.pubSignals[CircuitConstantsV2.DSC_TREE_LEAF_INDEX] ); } else { - revert INVALID_ATTESTATION_ID(); + revert InvalidAttestationId(); } } - // ==================================================== - // External Functions - Only Owner - // ==================================================== + /** + * @notice Sets verification config in V2 storage (owner only) + * @dev The configId is automatically generated from the config content using sha256(abi.encode(config)) + * @param config The verification configuration + * @return configId The generated config ID + */ + function setVerificationConfigV2( + SelfStructs.VerificationConfigV2 memory config + ) external virtual onlyProxy onlyOwner returns (bytes32 configId) { + configId = generateConfigId(config); + IdentityVerificationHubV2Storage storage $v2 = _getIdentityVerificationHubV2Storage(); + $v2._v2VerificationConfigs[configId] = config; + + emit VerificationConfigV2Set(configId, config); + } + + /** + * @notice Main verification function with new structured input format. + * @dev Orchestrates the complete verification process including proof validation and result handling. + * This function decodes the input, executes the verification flow, and handles the result based on destination chain. + * @param baseVerificationInput The base verification input containing header and proof data. + * @param userContextData The user context data containing config ID, destination chain ID, user identifier, and additional data. + */ + function verify(bytes calldata baseVerificationInput, bytes calldata userContextData) external virtual onlyProxy { + (SelfStructs.HubInputHeader memory header, bytes calldata proofData) = _decodeInput(baseVerificationInput); + + // Perform verification and get output along with user data + (bytes memory output, uint256 destChainId, bytes memory userDataToPass) = _executeVerificationFlow( + header, + proofData, + userContextData + ); + + // Use destChainId and userDataToPass returned from _executeVerificationFlow + _handleVerificationResult(destChainId, output, userDataToPass); + } /** * @notice Updates the registry address. * @param registryAddress The new registry address. */ function updateRegistry(bytes32 attestationId, address registryAddress) external virtual onlyProxy onlyOwner { - _attestationIdToRegistry[attestationId] = registryAddress; + IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage(); + $._registries[attestationId] = registryAddress; emit RegistryUpdated(attestationId, registryAddress); } @@ -362,173 +310,372 @@ contract IdentityVerificationHubImplV2 is IdentityVerificationHubStorageV2, IIde bytes32 attestationId, address vcAndDiscloseCircuitVerifierAddress ) external virtual onlyProxy onlyOwner { - _attestationIdToDiscloseVerifier[attestationId] = vcAndDiscloseCircuitVerifierAddress; + IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage(); + $._discloseVerifiers[attestationId] = vcAndDiscloseCircuitVerifierAddress; emit VcAndDiscloseCircuitUpdated(attestationId, vcAndDiscloseCircuitVerifierAddress); } /** * @notice Updates the register circuit verifier for a specific signature type. + * @param attestationId The attestation identifier. * @param typeId The signature type identifier. * @param verifierAddress The new register circuit verifier address. */ function updateRegisterCircuitVerifier( + bytes32 attestationId, uint256 typeId, address verifierAddress ) external virtual onlyProxy onlyOwner { - _sigTypeToRegisterCircuitVerifiers[typeId] = verifierAddress; + IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage(); + $._registerCircuitVerifiers[attestationId][typeId] = verifierAddress; emit RegisterCircuitVerifierUpdated(typeId, verifierAddress); } /** * @notice Updates the DSC circuit verifier for a specific signature type. + * @param attestationId The attestation identifier. * @param typeId The signature type identifier. * @param verifierAddress The new DSC circuit verifier address. */ - function updateDscVerifier(uint256 typeId, address verifierAddress) external virtual onlyProxy onlyOwner { - _sigTypeToDscCircuitVerifiers[typeId] = verifierAddress; + function updateDscVerifier( + bytes32 attestationId, + uint256 typeId, + address verifierAddress + ) external virtual onlyProxy onlyOwner { + IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage(); + $._dscCircuitVerifiers[attestationId][typeId] = verifierAddress; emit DscCircuitVerifierUpdated(typeId, verifierAddress); } /** * @notice Batch updates register circuit verifiers. + * @param attestationIds An array of attestation identifiers. * @param typeIds An array of signature type identifiers. * @param verifierAddresses An array of new register circuit verifier addresses. */ function batchUpdateRegisterCircuitVerifiers( + bytes32[] calldata attestationIds, uint256[] calldata typeIds, address[] calldata verifierAddresses ) external virtual onlyProxy onlyOwner { - if (typeIds.length != verifierAddresses.length) { - revert LENGTH_MISMATCH(); + if (attestationIds.length != typeIds.length || attestationIds.length != verifierAddresses.length) { + revert LengthMismatch(); } - for (uint256 i = 0; i < typeIds.length; i++) { - _sigTypeToRegisterCircuitVerifiers[typeIds[i]] = verifierAddresses[i]; + IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage(); + for (uint256 i = 0; i < attestationIds.length; i++) { + $._registerCircuitVerifiers[attestationIds[i]][typeIds[i]] = verifierAddresses[i]; emit RegisterCircuitVerifierUpdated(typeIds[i], verifierAddresses[i]); } } /** * @notice Batch updates DSC circuit verifiers. + * @param attestationIds An array of attestation identifiers. * @param typeIds An array of signature type identifiers. * @param verifierAddresses An array of new DSC circuit verifier addresses. */ function batchUpdateDscCircuitVerifiers( + bytes32[] calldata attestationIds, uint256[] calldata typeIds, address[] calldata verifierAddresses ) external virtual onlyProxy onlyOwner { - if (typeIds.length != verifierAddresses.length) { - revert LENGTH_MISMATCH(); + if (attestationIds.length != typeIds.length || attestationIds.length != verifierAddresses.length) { + revert LengthMismatch(); } - for (uint256 i = 0; i < typeIds.length; i++) { - _sigTypeToDscCircuitVerifiers[typeIds[i]] = verifierAddresses[i]; + IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage(); + for (uint256 i = 0; i < attestationIds.length; i++) { + $._dscCircuitVerifiers[attestationIds[i]][typeIds[i]] = verifierAddresses[i]; emit DscCircuitVerifierUpdated(typeIds[i], verifierAddresses[i]); } } // ==================================================== - // Internal Functions + // External View Functions // ==================================================== /** - * @notice Internal function to verify passport VC and Disclose proof. + * @notice Returns the registry address for a given attestation ID. + * @param attestationId The attestation ID to query. + * @return The registry address associated with the attestation ID. */ - function _verifyPassportVcAndDisclose( - VcAndDiscloseHubProof memory proof - ) internal view returns (VcAndDiscloseVerificationResult memory) { - VcAndDiscloseVerificationResult memory result; - CircuitConstantsV2.DiscloseIndices memory indices = CircuitConstantsV2.getDiscloseIndices( - AttestationId.E_PASSPORT - ); + function registry(bytes32 attestationId) external view virtual onlyProxy returns (address) { + IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage(); + return $._registries[attestationId]; + } - result.identityCommitmentRoot = _verifyVcAndDiscloseProof( - AttestationId.E_PASSPORT, - proof.vcAndDiscloseProof, - proof.olderThanEnabled, - proof.olderThan, - proof.ofacEnabled, - proof.forbiddenCountriesEnabled, - proof.forbiddenCountriesListPacked - ); + /** + * @notice Returns the disclose verifier address for a given attestation ID. + * @param attestationId The attestation ID to query. + * @return The disclose verifier address associated with the attestation ID. + */ + function discloseVerifier(bytes32 attestationId) external view virtual onlyProxy returns (address) { + IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage(); + return $._discloseVerifiers[attestationId]; + } - for (uint256 i = 0; i < 3; i++) { - result.revealedDataPacked[i] = proof.vcAndDiscloseProof.pubSignals[indices.revealedDataPackedIndex + i]; + /** + * @notice Returns the register circuit verifier address for a given attestation ID and type ID. + * @param attestationId The attestation ID to query. + * @param typeId The type ID to query. + * @return The register circuit verifier address associated with the attestation ID and type ID. + */ + function registerCircuitVerifiers( + bytes32 attestationId, + uint256 typeId + ) external view virtual onlyProxy returns (address) { + IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage(); + return $._registerCircuitVerifiers[attestationId][typeId]; + } + + /** + * @notice Returns the DSC circuit verifier address for a given attestation ID and type ID. + * @param attestationId The attestation ID to query. + * @param typeId The type ID to query. + * @return The DSC circuit verifier address associated with the attestation ID and type ID. + */ + function dscCircuitVerifiers( + bytes32 attestationId, + uint256 typeId + ) external view virtual onlyProxy returns (address) { + IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage(); + return $._dscCircuitVerifiers[attestationId][typeId]; + } + + /** + * @notice Returns the merkle root timestamp for a given attestation ID and root. + * @param attestationId The attestation ID to query. + * @param root The merkle root to query. + * @return The merkle root timestamp associated with the attestation ID and root. + */ + function rootTimestamp(bytes32 attestationId, uint256 root) external view virtual onlyProxy returns (uint256) { + IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage(); + address registryAddress = $._registries[attestationId]; + + if (attestationId == AttestationId.E_PASSPORT) { + return IIdentityRegistryV1(registryAddress).rootTimestamps(root); + } else if (attestationId == AttestationId.EU_ID_CARD) { + return IIdentityRegistryIdCardV1(registryAddress).rootTimestamps(root); + } else { + revert InvalidAttestationId(); } - for (uint256 i = 0; i < 4; i++) { - result.forbiddenCountriesListPacked[i] = proof.vcAndDiscloseProof.pubSignals[ - indices.forbiddenCountriesListPackedIndex + i - ]; + } + + /** + * @notice Returns the identity commitment merkle root for a given attestation ID. + * @param attestationId The attestation ID to query. + * @return The identity commitment merkle root associated with the attestation ID. + */ + function getIdentityCommitmentMerkleRoot(bytes32 attestationId) external view virtual onlyProxy returns (uint256) { + IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage(); + address registryAddress = $._registries[attestationId]; + + if (attestationId == AttestationId.E_PASSPORT) { + return IIdentityRegistryV1(registryAddress).getIdentityCommitmentMerkleRoot(); + } else if (attestationId == AttestationId.EU_ID_CARD) { + return IIdentityRegistryIdCardV1(registryAddress).getIdentityCommitmentMerkleRoot(); + } else { + revert InvalidAttestationId(); } - result.nullifier = proof.vcAndDiscloseProof.pubSignals[indices.nullifierIndex]; - result.attestationId = proof.vcAndDiscloseProof.pubSignals[indices.attestationIdIndex]; - result.userIdentifier = proof.vcAndDiscloseProof.pubSignals[indices.userIdentifierIndex]; - result.scope = proof.vcAndDiscloseProof.pubSignals[indices.scopeIndex]; - return result; } /** - * @notice Internal function to verify ID card VC and Disclose proof. + * @notice Checks if a verification config exists + * @param configId The configuration identifier + * @return exists Whether the config exists */ - function _verifyEuIdVcAndDisclose( - IdCardVcAndDiscloseHubProof memory proof - ) internal view returns (IdCardVcAndDiscloseVerificationResult memory) { - IdCardVcAndDiscloseVerificationResult memory result; - CircuitConstantsV2.DiscloseIndices memory indices = CircuitConstantsV2.getDiscloseIndices( - AttestationId.EU_ID_CARD - ); + function verificationConfigV2Exists(bytes32 configId) external view virtual onlyProxy returns (bool exists) { + SelfStructs.VerificationConfigV2 memory config = getVerificationConfigV2(configId); + return generateConfigId(config) == configId; + } - result.identityCommitmentRoot = _verifyVcAndDiscloseProof( - AttestationId.EU_ID_CARD, - proof.vcAndDiscloseProof, - proof.olderThanEnabled, - proof.olderThan, - _convertOfacFlags(proof.ofacEnabled), - proof.forbiddenCountriesEnabled, - proof.forbiddenCountriesListPacked - ); + // ==================================================== + // Public Functions + // ==================================================== - for (uint256 i = 0; i < 4; i++) { - result.revealedDataPacked[i] = proof.vcAndDiscloseProof.pubSignals[indices.revealedDataPackedIndex + i]; + /** + * @notice Generates a config ID from a verification config + * @param config The verification configuration + * @return The generated config ID (sha256 hash of encoded config) + */ + function generateConfigId(SelfStructs.VerificationConfigV2 memory config) public pure returns (bytes32) { + return sha256(abi.encode(config)); + } + + // ==================================================== + // Internal Functions + // ==================================================== + + /** + * @notice Executes the complete verification flow. + * @dev Processes user context data, retrieves verification config, performs basic verification, + * executes custom verification logic, and formats the output. + * @param header The decoded hub input header containing verification parameters. + * @param proofData The raw proof data to be decoded and verified. + * @param userContextData The user-provided context data. + * @return output The formatted verification output. + * @return destChainId The destination chain identifier. + * @return userDataToPass The remaining user data to pass through. + */ + function _executeVerificationFlow( + SelfStructs.HubInputHeader memory header, + bytes memory proofData, + bytes calldata userContextData + ) internal returns (bytes memory output, uint256 destChainId, bytes memory userDataToPass) { + bytes32 configId; + uint256 userIdentifier; + bytes calldata remainingData; + { + uint256 _destChainId; + (configId, _destChainId, userIdentifier, remainingData) = _decodeUserContextData(userContextData); + destChainId = _destChainId; } - for (uint256 i = 0; i < 4; i++) { - result.forbiddenCountriesListPacked[i] = proof.vcAndDiscloseProof.pubSignals[ - indices.forbiddenCountriesListPackedIndex + i - ]; + + { + bytes memory config = _getVerificationConfigById(configId); + + bytes memory proofOutput = _basicVerification( + header, + _decodeVcAndDiscloseProof(proofData), + userContextData, + userIdentifier + ); + + SelfStructs.GenericDiscloseOutputV2 memory genericDiscloseOutput = CustomVerifier.customVerify( + header.attestationId, + config, + proofOutput + ); + + output = _formatVerificationOutput(header.contractVersion, genericDiscloseOutput); } - result.nullifier = proof.vcAndDiscloseProof.pubSignals[indices.nullifierIndex]; - result.attestationId = proof.vcAndDiscloseProof.pubSignals[indices.attestationIdIndex]; - result.userIdentifier = proof.vcAndDiscloseProof.pubSignals[indices.userIdentifierIndex]; - result.scope = proof.vcAndDiscloseProof.pubSignals[indices.scopeIndex]; - return result; + + userDataToPass = remainingData; } + /** + * @notice Handles verification result based on destination chain. + * @dev Routes the verification result to the appropriate handler based on whether + * the destination is the current chain or requires cross-chain bridging. + * @param destChainId The destination chain identifier. + * @param output The verification output data. + * @param userDataToPass The user data to pass to the result handler. + */ + function _handleVerificationResult(uint256 destChainId, bytes memory output, bytes memory userDataToPass) internal { + if (destChainId == block.chainid) { + ISelfVerificationRoot(msg.sender).onVerificationSuccess(output, userDataToPass); + } else { + // Call external bridge + // _handleBridge() + revert CrossChainIsNotSupportedYet(); + } + } + + /** + * @notice Unified basic verification function for both passport and ID card proofs. + * @dev Performs four core verification steps: scopeCheck, rootCheck, currentDateCheck, groth16 proof verification + * @param header The hub input header containing scope and attestation information + * @param vcAndDiscloseProof The VC and Disclose proof data + * @param userContextData The user context data for validation + * @param userIdentifier The user identifier for proof validation + * @return output The verification result encoded as bytes (PassportOutput or EuIdOutput) + */ + function _basicVerification( + SelfStructs.HubInputHeader memory header, + IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory vcAndDiscloseProof, + bytes calldata userContextData, + uint256 userIdentifier + ) internal returns (bytes memory output) { + // Scope 1: Basic checks (scope and user identifier) + { + CircuitConstantsV2.DiscloseIndices memory indices = CircuitConstantsV2.getDiscloseIndices( + header.attestationId + ); + _performScopeCheck(header.scope, vcAndDiscloseProof, indices); + _performUserIdentifierCheck(userContextData, vcAndDiscloseProof, header.attestationId, indices); + } + + // Scope 2: Root and date checks + { + CircuitConstantsV2.DiscloseIndices memory indices = CircuitConstantsV2.getDiscloseIndices( + header.attestationId + ); + _performRootCheck(header.attestationId, vcAndDiscloseProof, indices); + _performCurrentDateCheck(vcAndDiscloseProof, indices); + } + + // Scope 3: Groth16 proof verification + _performGroth16ProofVerification(header.attestationId, vcAndDiscloseProof); + + // Scope 4: Create and return output + { + CircuitConstantsV2.DiscloseIndices memory indices = CircuitConstantsV2.getDiscloseIndices( + header.attestationId + ); + return _createVerificationOutput(header.attestationId, vcAndDiscloseProof, indices, userIdentifier); + } + } + + // ==================================================== + // Internal View Functions + // ==================================================== + + /** + * @notice Gets verification config from V2 storage + * @param configId The configuration identifier + * @return The verification configuration + */ + function getVerificationConfigV2( + bytes32 configId + ) internal view virtual onlyProxy returns (SelfStructs.VerificationConfigV2 memory) { + IdentityVerificationHubV2Storage storage $v2 = _getIdentityVerificationHubV2Storage(); + return $v2._v2VerificationConfigs[configId]; + } + + /** + * @notice Gets verification config by configId + */ + function _getVerificationConfigById(bytes32 configId) internal view returns (bytes memory config) { + IdentityVerificationHubV2Storage storage $v2 = _getIdentityVerificationHubV2Storage(); + SelfStructs.VerificationConfigV2 memory verificationConfig = $v2._v2VerificationConfigs[configId]; + config = GenericFormatter.formatV2Config(verificationConfig); + } + + /** + * @notice Verifies the register circuit proof. + * @dev Uses the register circuit verifier specified by registerCircuitVerifierId. + * @param attestationId The attestation ID. + * @param registerCircuitVerifierId The identifier for the register circuit verifier. + * @param registerCircuitProof The register circuit proof data. + */ function _verifyRegisterProof( bytes32 attestationId, uint256 registerCircuitVerifierId, IRegisterCircuitVerifier.RegisterCircuitProof memory registerCircuitProof ) internal view { - address verifier = _sigTypeToRegisterCircuitVerifiers[registerCircuitVerifierId]; + IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage(); + address verifier = $._registerCircuitVerifiers[attestationId][registerCircuitVerifierId]; if (verifier == address(0)) { - revert NO_VERIFIER_SET(); + revert NoVerifierSet(); } if (attestationId == AttestationId.E_PASSPORT) { if ( - !IIdentityRegistryV1(_attestationIdToRegistry[attestationId]).checkDscKeyCommitmentMerkleRoot( + !IIdentityRegistryV1($._registries[attestationId]).checkDscKeyCommitmentMerkleRoot( registerCircuitProof.pubSignals[CircuitConstantsV2.REGISTER_MERKLE_ROOT_INDEX] ) ) { - revert INVALID_COMMITMENT_ROOT(); + revert InvalidDscCommitmentRoot(); } } else if (attestationId == AttestationId.EU_ID_CARD) { if ( - !IIdentityRegistryIdCardV1(_attestationIdToRegistry[attestationId]).checkDscKeyCommitmentMerkleRoot( + !IIdentityRegistryIdCardV1($._registries[attestationId]).checkDscKeyCommitmentMerkleRoot( registerCircuitProof.pubSignals[CircuitConstantsV2.REGISTER_MERKLE_ROOT_INDEX] ) ) { - revert INVALID_COMMITMENT_ROOT(); + revert InvalidDscCommitmentRoot(); } } else { - revert INVALID_ATTESTATION_ID(); + revert InvalidAttestationId(); } if ( @@ -539,7 +686,7 @@ contract IdentityVerificationHubImplV2 is IdentityVerificationHubStorageV2, IIde registerCircuitProof.pubSignals ) ) { - revert INVALID_REGISTER_PROOF(); + revert InvalidRegisterProof(); } } @@ -554,29 +701,30 @@ contract IdentityVerificationHubImplV2 is IdentityVerificationHubStorageV2, IIde uint256 dscCircuitVerifierId, IDscCircuitVerifier.DscCircuitProof memory dscCircuitProof ) internal view { - address verifier = _sigTypeToDscCircuitVerifiers[dscCircuitVerifierId]; + IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage(); + address verifier = $._dscCircuitVerifiers[attestationId][dscCircuitVerifierId]; if (verifier == address(0)) { - revert NO_VERIFIER_SET(); + revert NoVerifierSet(); } if (attestationId == AttestationId.E_PASSPORT) { if ( - !IIdentityRegistryV1(_attestationIdToRegistry[attestationId]).checkCscaRoot( + !IIdentityRegistryV1($._registries[attestationId]).checkCscaRoot( dscCircuitProof.pubSignals[CircuitConstantsV2.DSC_CSCA_ROOT_INDEX] ) ) { - revert INVALID_CSCA_ROOT(); + revert InvalidCscaRoot(); } } else if (attestationId == AttestationId.EU_ID_CARD) { if ( - !IIdentityRegistryIdCardV1(_attestationIdToRegistry[attestationId]).checkCscaRoot( + !IIdentityRegistryIdCardV1($._registries[attestationId]).checkCscaRoot( dscCircuitProof.pubSignals[CircuitConstantsV2.DSC_CSCA_ROOT_INDEX] ) ) { - revert INVALID_CSCA_ROOT(); + revert InvalidCscaRoot(); } } else { - revert INVALID_ATTESTATION_ID(); + revert InvalidAttestationId(); } if ( @@ -587,7 +735,7 @@ contract IdentityVerificationHubImplV2 is IdentityVerificationHubStorageV2, IIde dscCircuitProof.pubSignals ) ) { - revert INVALID_DSC_PROOF(); + revert InvalidDscProof(); } } @@ -601,201 +749,288 @@ contract IdentityVerificationHubImplV2 is IdentityVerificationHubStorageV2, IIde } /** - * @notice Unified internal verification function for both passport and ID card proofs. - * @dev Handles the common verification logic for both proof types. + * @notice Performs scope validation + */ + function _performScopeCheck( + uint256 headerScope, + IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory vcAndDiscloseProof, + CircuitConstantsV2.DiscloseIndices memory indices + ) internal view { + // Get scope from proof using the scope index from indices + uint256 proofScope = vcAndDiscloseProof.pubSignals[indices.scopeIndex]; + + if (headerScope != proofScope) { + revert ScopeMismatch(); + } + } + + /** + * @notice Performs identity commitment root verification */ - function _verifyVcAndDiscloseProof( + function _performRootCheck( bytes32 attestationId, IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory vcAndDiscloseProof, - bool olderThanEnabled, - uint256 olderThan, - bool[3] memory ofacEnabled, - bool forbiddenCountriesEnabled, - uint256[4] memory forbiddenCountriesListPacked - ) internal view returns (uint256 identityCommitmentRoot) { - // Get indices for the specific attestation type - CircuitConstantsV2.DiscloseIndices memory indices = CircuitConstantsV2.getDiscloseIndices(attestationId); - bool isPassport = (attestationId == AttestationId.E_PASSPORT); - - // verify identity commitment root - if (isPassport) { - if ( - !IIdentityRegistryV1(_attestationIdToRegistry[attestationId]).checkIdentityCommitmentRoot( - vcAndDiscloseProof.pubSignals[indices.merkleRootIndex] - ) - ) { - revert INVALID_COMMITMENT_ROOT(); + CircuitConstantsV2.DiscloseIndices memory indices + ) internal view { + IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage(); + uint256 merkleRoot = vcAndDiscloseProof.pubSignals[indices.merkleRootIndex]; + + address registryAddress = $._registries[attestationId]; + + if (registryAddress == address(0)) { + revert("Registry not set for attestation ID"); + } + + if (attestationId == AttestationId.E_PASSPORT) { + if (!IIdentityRegistryV1($._registries[attestationId]).checkIdentityCommitmentRoot(merkleRoot)) { + revert InvalidIdentityCommitmentRoot(); } - } else { - if ( - !IIdentityRegistryIdCardV1(_attestationIdToRegistry[attestationId]).checkIdentityCommitmentRoot( - vcAndDiscloseProof.pubSignals[indices.merkleRootIndex] - ) - ) { - revert INVALID_COMMITMENT_ROOT(); + } else if (attestationId == AttestationId.EU_ID_CARD) { + if (!IIdentityRegistryIdCardV1($._registries[attestationId]).checkIdentityCommitmentRoot(merkleRoot)) { + revert InvalidIdentityCommitmentRoot(); } + } else { + revert InvalidAttestationId(); } + } - // verify current date + /** + * @notice Performs current date validation + */ + function _performCurrentDateCheck( + IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory vcAndDiscloseProof, + CircuitConstantsV2.DiscloseIndices memory indices + ) internal view { uint[6] memory dateNum; for (uint256 i = 0; i < 6; i++) { dateNum[i] = vcAndDiscloseProof.pubSignals[indices.currentDateIndex + i]; } uint currentTimestamp = Formatter.proofDateToUnixTimestamp(dateNum); - if ( - currentTimestamp < _getStartOfDayTimestamp() - 1 days + 1 || - currentTimestamp > _getStartOfDayTimestamp() + 1 days - 1 - ) { - revert CURRENT_DATE_NOT_IN_VALID_RANGE(); - } - - // verify attributes - if (isPassport) { - uint256[3] memory revealedDataPacked; - for (uint256 i = 0; i < 3; i++) { - revealedDataPacked[i] = vcAndDiscloseProof.pubSignals[indices.revealedDataPackedIndex + i]; - } + uint startOfDay = _getStartOfDayTimestamp(); - if (olderThanEnabled) { - if ( - !CircuitAttributeHandlerV2.compareOlderThan( - attestationId, - Formatter.fieldElementsToBytes(revealedDataPacked), - olderThan - ) - ) { - revert INVALID_OLDER_THAN(); - } - } - - if (ofacEnabled[0] || ofacEnabled[1] || ofacEnabled[2]) { - if ( - !CircuitAttributeHandlerV2.compareOfac( - attestationId, - Formatter.fieldElementsToBytes(revealedDataPacked), - ofacEnabled[0], - ofacEnabled[1], - ofacEnabled[2] - ) - ) { - revert INVALID_OFAC(); - } - if ( - !IIdentityRegistryV1(_attestationIdToRegistry[attestationId]).checkOfacRoots( - vcAndDiscloseProof.pubSignals[indices.passportNoSmtRootIndex], - vcAndDiscloseProof.pubSignals[indices.namedobSmtRootIndex], - vcAndDiscloseProof.pubSignals[indices.nameyobSmtRootIndex] - ) - ) { - revert INVALID_OFAC_ROOT(); - } - } - } else { - uint256[4] memory revealedDataPacked; - for (uint256 i = 0; i < 4; i++) { - revealedDataPacked[i] = vcAndDiscloseProof.pubSignals[indices.revealedDataPackedIndex + i]; - } - - if (olderThanEnabled) { - if ( - !CircuitAttributeHandlerV2.compareOlderThan( - attestationId, - Formatter.fieldElementsToBytesIdCard(revealedDataPacked), - olderThan - ) - ) { - revert INVALID_OLDER_THAN(); - } - } - - if (ofacEnabled[1] || ofacEnabled[2]) { - if ( - !CircuitAttributeHandlerV2.compareOfac( - attestationId, - Formatter.fieldElementsToBytesIdCard(revealedDataPacked), - false, // Document number OFAC not applicable for ID cards - ofacEnabled[1], - ofacEnabled[2] - ) - ) { - revert INVALID_OFAC(); - } - if ( - !IIdentityRegistryIdCardV1(_attestationIdToRegistry[attestationId]).checkOfacRoots( - vcAndDiscloseProof.pubSignals[indices.namedobSmtRootIndex], - vcAndDiscloseProof.pubSignals[indices.nameyobSmtRootIndex] - ) - ) { - revert INVALID_OFAC_ROOT(); - } - } + if (currentTimestamp < startOfDay - 1 days + 1 || currentTimestamp > startOfDay + 1 days - 1) { + revert CurrentDateNotInValidRange(); } + } - if (forbiddenCountriesEnabled) { - for (uint256 i = 0; i < 4; i++) { - if ( - forbiddenCountriesListPacked[i] != - vcAndDiscloseProof.pubSignals[indices.forbiddenCountriesListPackedIndex + i] - ) { - revert INVALID_FORBIDDEN_COUNTRIES(); - } - } - } + /** + * @notice Performs Groth16 proof verification + */ + function _performGroth16ProofVerification( + bytes32 attestationId, + IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory vcAndDiscloseProof + ) internal view { + IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage(); - // verify the proof using the VC and Disclose circuit verifier if ( - !IVcAndDiscloseCircuitVerifier(_attestationIdToDiscloseVerifier[attestationId]).verifyProof( + !IVcAndDiscloseCircuitVerifier($._discloseVerifiers[attestationId]).verifyProof( vcAndDiscloseProof.a, vcAndDiscloseProof.b, vcAndDiscloseProof.c, vcAndDiscloseProof.pubSignals ) ) { - revert INVALID_VC_AND_DISCLOSE_PROOF(); + revert InvalidVcAndDiscloseProof(); } + } - return vcAndDiscloseProof.pubSignals[indices.merkleRootIndex]; + // ==================================================== + // Internal Pure Functions + // ==================================================== + + /** + * @notice Decodes the input data to extract the header and proof data. + * @param baseVerificationInput The input data to decode. Format: | 1 byte contractVersion | 31 bytes buffer | 32 bytes scope | 32 bytes attestationId | user defined data | + * @return header The header of the input data. + * @return proofData The proof data of the input data. + */ + function _decodeInput( + bytes calldata baseVerificationInput + ) internal pure returns (SelfStructs.HubInputHeader memory header, bytes calldata proofData) { + if (baseVerificationInput.length < 97) { + revert InputTooShort(); + } + header.contractVersion = uint8(baseVerificationInput[0]); + header.scope = uint256(bytes32(baseVerificationInput[32:64])); + header.attestationId = bytes32(baseVerificationInput[64:96]); + proofData = baseVerificationInput[96:]; } /** - * @notice Converts ID card OFAC flags (2 elements) to passport format (3 elements). + * @notice Decodes userContextData to extract configId, destChainId, and userIdentifier + * @param userContextData User-defined data in format: | 32 bytes configId | 32 bytes destChainId | 32 bytes userIdentifier | data | + * @return configId The configuration identifier + * @return destChainId The destination chain identifier + * @return userIdentifier The user identifier + * @return remainingData The remaining data after the first 96 bytes */ - function _convertOfacFlags(bool[2] memory idCardOfacEnabled) internal pure returns (bool[3] memory) { - bool[3] memory passportOfacEnabled; - passportOfacEnabled[0] = false; // ID cards don't have passport number OFAC - passportOfacEnabled[1] = idCardOfacEnabled[0]; // name and DOB OFAC - passportOfacEnabled[2] = idCardOfacEnabled[1]; // name and YOB OFAC - return passportOfacEnabled; + function _decodeUserContextData( + bytes calldata userContextData + ) + internal + pure + returns (bytes32 configId, uint256 destChainId, uint256 userIdentifier, bytes calldata remainingData) + { + if (userContextData.length < 96) { + revert UserContextDataTooShort(); + } + configId = bytes32(userContextData[0:32]); + destChainId = uint256(bytes32(userContextData[32:64])); + userIdentifier = uint256(bytes32(userContextData[64:96])); + remainingData = userContextData[96:]; } /** - * @notice Decodes passport proof data from bytes. + * @notice Formats verification output based on contract version. + * @dev Converts the generic disclosure output to the appropriate struct format based on version. + * @param contractVersion The contract version to determine output format. + * @param genericDiscloseOutput The generic disclosure output to format. + * @return output The formatted output as bytes. */ - function _decodePassportProof(bytes memory data) internal pure returns (VcAndDiscloseHubProof memory) { - return abi.decode(data, (VcAndDiscloseHubProof)); + function _formatVerificationOutput( + uint256 contractVersion, + SelfStructs.GenericDiscloseOutputV2 memory genericDiscloseOutput + ) internal pure returns (bytes memory output) { + if (contractVersion == 2) { + output = GenericFormatter.toV2Struct(genericDiscloseOutput); + } } /** - * @notice Decodes ID card proof data from bytes. + * @notice Creates verification output based on attestation type. + * @dev Routes to the appropriate output creation function based on the attestation ID. + * @param attestationId The attestation identifier (passport or EU ID card). + * @param vcAndDiscloseProof The VC and Disclose proof data. + * @param indices The circuit-specific indices for extracting proof values. + * @param userIdentifier The user identifier to include in the output. + * @return The encoded verification output. */ - function _decodeIdCardProof(bytes memory data) internal pure returns (IdCardVcAndDiscloseHubProof memory) { - return abi.decode(data, (IdCardVcAndDiscloseHubProof)); + function _createVerificationOutput( + bytes32 attestationId, + IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory vcAndDiscloseProof, + CircuitConstantsV2.DiscloseIndices memory indices, + uint256 userIdentifier + ) internal pure returns (bytes memory) { + if (attestationId == AttestationId.E_PASSPORT) { + return _createPassportOutput(vcAndDiscloseProof, indices, attestationId, userIdentifier); + } else if (attestationId == AttestationId.EU_ID_CARD) { + return _createEuIdOutput(vcAndDiscloseProof, indices, attestationId, userIdentifier); + } else { + revert InvalidAttestationId(); + } } /** - * @notice Encodes passport verification result to bytes. + * @notice Creates passport output struct. + * @dev Constructs a PassportOutput struct from the proof data and encodes it. + * @param vcAndDiscloseProof The VC and Disclose proof containing passport data. + * @param indices The circuit-specific indices for extracting proof values. + * @param attestationId The attestation identifier. + * @param userIdentifier The user identifier. + * @return The encoded PassportOutput struct. */ - function _encodePassportResult(VcAndDiscloseVerificationResult memory result) internal pure returns (bytes memory) { - return abi.encode(result); + function _createPassportOutput( + IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory vcAndDiscloseProof, + CircuitConstantsV2.DiscloseIndices memory indices, + bytes32 attestationId, + uint256 userIdentifier + ) internal pure returns (bytes memory) { + SelfStructs.PassportOutput memory passportOutput; + passportOutput.attestationId = uint256(attestationId); + passportOutput.userIdentifier = userIdentifier; + passportOutput.nullifier = vcAndDiscloseProof.pubSignals[indices.nullifierIndex]; + + // Extract revealed data + uint256[3] memory revealedDataPacked; + for (uint256 i = 0; i < 3; i++) { + revealedDataPacked[i] = vcAndDiscloseProof.pubSignals[indices.revealedDataPackedIndex + i]; + } + passportOutput.revealedDataPacked = Formatter.fieldElementsToBytes(revealedDataPacked); + + // Extract forbidden countries list + for (uint256 i = 0; i < 4; i++) { + passportOutput.forbiddenCountriesListPacked[i] = vcAndDiscloseProof.pubSignals[ + indices.forbiddenCountriesListPackedIndex + i + ]; + } + + return abi.encode(passportOutput); } /** - * @notice Encodes ID card verification result to bytes. + * @notice Creates EU ID output struct. + * @dev Constructs an EuIdOutput struct from the proof data and encodes it. + * @param vcAndDiscloseProof The VC and Disclose proof containing EU ID card data. + * @param indices The circuit-specific indices for extracting proof values. + * @param attestationId The attestation identifier. + * @param userIdentifier The user identifier. + * @return The encoded EuIdOutput struct. */ - function _encodeIdCardResult( - IdCardVcAndDiscloseVerificationResult memory result + function _createEuIdOutput( + IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory vcAndDiscloseProof, + CircuitConstantsV2.DiscloseIndices memory indices, + bytes32 attestationId, + uint256 userIdentifier ) internal pure returns (bytes memory) { - return abi.encode(result); + SelfStructs.EuIdOutput memory euIdOutput; + euIdOutput.attestationId = uint256(attestationId); + euIdOutput.userIdentifier = userIdentifier; + euIdOutput.nullifier = vcAndDiscloseProof.pubSignals[indices.nullifierIndex]; + + // Extract revealed data + uint256[4] memory revealedDataPacked; + for (uint256 i = 0; i < 4; i++) { + revealedDataPacked[i] = vcAndDiscloseProof.pubSignals[indices.revealedDataPackedIndex + i]; + } + euIdOutput.revealedDataPacked = Formatter.fieldElementsToBytesIdCard(revealedDataPacked); + + // Extract forbidden countries list + for (uint256 i = 0; i < 4; i++) { + euIdOutput.forbiddenCountriesListPacked[i] = vcAndDiscloseProof.pubSignals[ + indices.forbiddenCountriesListPackedIndex + i + ]; + } + + return abi.encode(euIdOutput); + } + + /** + * @notice Decodes VC and Disclose proof from bytes data. + * @dev Simple wrapper around abi.decode for type safety and clarity. + * @param data The encoded proof data. + * @return The decoded VcAndDiscloseProof struct. + */ + function _decodeVcAndDiscloseProof( + bytes memory data + ) internal pure returns (IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory) { + return abi.decode(data, (IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof)); + } + + /** + * @notice Performs user identifier validation. + * @dev Validates that the user identifier in the proof matches the hash of the user context data. + * Uses SHA256 followed by RIPEMD160 hashing for consistency with circuit implementation. + * @param userContextData The user context data to hash and compare. + * @param vcAndDiscloseProof The VC and Disclose proof containing the user identifier. + * @param attestationId The attestation identifier (used for getting correct indices). + * @param indices The circuit-specific indices for extracting the user identifier from proof. + */ + function _performUserIdentifierCheck( + bytes calldata userContextData, + IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory vcAndDiscloseProof, + bytes32 attestationId, + CircuitConstantsV2.DiscloseIndices memory indices + ) internal pure { + // Get the user identifier index for this attestation type + uint256 proofUserIdentifier = vcAndDiscloseProof.pubSignals[indices.userIdentifierIndex]; + + bytes32 sha256Hash = sha256(userContextData); + bytes20 ripemdHash = ripemd160(abi.encodePacked(sha256Hash)); + uint256 hashedValue = uint256(uint160(ripemdHash)); + + if (hashedValue != proofUserIdentifier) { + revert InvalidUserIdentifierInProof(); + } } } diff --git a/contracts/contracts/abstract/SelfVerificationRoot.sol b/contracts/contracts/abstract/SelfVerificationRoot.sol index 3ed14b602..c242c4f04 100644 --- a/contracts/contracts/abstract/SelfVerificationRoot.sol +++ b/contracts/contracts/abstract/SelfVerificationRoot.sol @@ -3,21 +3,23 @@ pragma solidity 0.8.28; import {IIdentityVerificationHubV2} from "../interfaces/IIdentityVerificationHubV2.sol"; import {ISelfVerificationRoot} from "../interfaces/ISelfVerificationRoot.sol"; -import {CircuitConstants} from "../constants/CircuitConstants.sol"; +import {CircuitConstantsV2} from "../constants/CircuitConstantsV2.sol"; import {AttestationId} from "../constants/AttestationId.sol"; /** * @title SelfVerificationRoot * @notice Abstract base contract to be integrated with self's verification infrastructure * @dev Provides base functionality for verifying and disclosing identity credentials + * @author Self Team */ abstract contract SelfVerificationRoot is ISelfVerificationRoot { // ==================================================== // Constants // ==================================================== - uint256 constant E_PASSPORT_REVEALED_DATA_LENGTH = 3; - uint256 constant EU_ID_CARD_REVEALED_DATA_LENGTH = 4; + /// @notice Contract version identifier used in verification process + /// @dev This version is included in the hub data for protocol compatibility + uint8 constant CONTRACT_VERSION = 2; // ==================================================== // Storage Variables @@ -27,143 +29,53 @@ abstract contract SelfVerificationRoot is ISelfVerificationRoot { /// @dev Used to validate that submitted proofs match the expected scope uint256 internal _scope; - /// @notice The contract version for validation - /// @dev Used to validate the contract version in relayer data - uint8 internal _contractVersion; - - /// @notice The attestation ID that proofs must match - /// @dev Used to validate that submitted proofs is generated with allowed attestation IDs - mapping(bytes32 attestationId => bool attestationIdEnabled) internal _attestationIdToEnabled; - - /// @notice Configuration settings for the verification process - /// @dev Contains settings for age verification, country restrictions, and OFAC checks - ISelfVerificationRoot.VerificationConfig internal _verificationConfig; - /// @notice Reference to the identity verification hub V2 contract /// @dev Immutable reference used for bytes-based proof verification IIdentityVerificationHubV2 internal immutable _identityVerificationHubV2; - // ==================================================== - // Circuit Constants - // ==================================================== - - // Make CircuitConstants available to inheriting contracts - uint256 internal constant REVEALED_DATA_PACKED_INDEX = CircuitConstants.VC_AND_DISCLOSE_REVEALED_DATA_PACKED_INDEX; - uint256 internal constant FORBIDDEN_COUNTRIES_LIST_PACKED_INDEX = - CircuitConstants.VC_AND_DISCLOSE_FORBIDDEN_COUNTRIES_LIST_PACKED_INDEX; - uint256 internal constant NULLIFIER_INDEX = CircuitConstants.VC_AND_DISCLOSE_NULLIFIER_INDEX; - uint256 internal constant ATTESTATION_ID_INDEX = CircuitConstants.VC_AND_DISCLOSE_ATTESTATION_ID_INDEX; - uint256 internal constant MERKLE_ROOT_INDEX = CircuitConstants.VC_AND_DISCLOSE_MERKLE_ROOT_INDEX; - uint256 internal constant CURRENT_DATE_INDEX = CircuitConstants.VC_AND_DISCLOSE_CURRENT_DATE_INDEX; - uint256 internal constant PASSPORT_NO_SMT_ROOT_INDEX = CircuitConstants.VC_AND_DISCLOSE_PASSPORT_NO_SMT_ROOT_INDEX; - uint256 internal constant NAME_DOB_SMT_ROOT_INDEX = CircuitConstants.VC_AND_DISCLOSE_NAME_DOB_SMT_ROOT_INDEX; - uint256 internal constant NAME_YOB_SMT_ROOT_INDEX = CircuitConstants.VC_AND_DISCLOSE_NAME_YOB_SMT_ROOT_INDEX; - uint256 internal constant SCOPE_INDEX = CircuitConstants.VC_AND_DISCLOSE_SCOPE_INDEX; - uint256 internal constant USER_IDENTIFIER_INDEX = CircuitConstants.VC_AND_DISCLOSE_USER_IDENTIFIER_INDEX; - - // ==================================================== - // Attestation ID - // ==================================================== - - bytes32 constant E_PASSPORT_ID = AttestationId.E_PASSPORT; - // ==================================================== // Errors // ==================================================== - /// @notice Error thrown when the proof's scope doesn't match the expected scope - /// @dev Triggered in verifySelfProof when scope validation fails - error InvalidScope(); - - /// @notice Error thrown when the proof's attestation ID doesn't match the expected ID - /// @dev Triggered in verifySelfProof when attestation ID validation fails - error InvalidAttestationId(); - - /// @notice Error thrown when the contract version doesn't match - /// @dev Triggered in verifySelfProof when contract version validation fails - error InvalidContractVersion(); - /// @notice Error thrown when the data format is invalid /// @dev Triggered when the provided bytes data doesn't have the expected format error InvalidDataFormat(); + /// @notice Error thrown when onVerificationSuccess is called by an unauthorized address + /// @dev Only the identity verification hub V2 contract can call onVerificationSuccess + error UnauthorizedCaller(); + // ==================================================== // Events // ==================================================== - /// @notice Emitted when the verification configuration is updated - event VerificationConfigUpdated(ISelfVerificationRoot.VerificationConfig indexed verificationConfig); - - /// @notice Emitted when the verification is successful - event VerificationSuccess( - uint256 indexed scope, - bytes32 indexed attestationId, - uint256 indexed nullifier, - uint256 userIdentifier, - uint256[] revealedDataPacked - ); - /// @notice Emitted when the scope is updated + /// @param newScope The new scope value that was set event ScopeUpdated(uint256 indexed newScope); - /// @notice Emitted when a new attestation ID is added - event AttestationIdAdded(bytes32 indexed attestationId); - - /// @notice Emitted when an attestation ID is removed - event AttestationIdRemoved(bytes32 indexed attestationId); - - /// @notice Emitted when the contract version is updated - event ContractVersionUpdated(uint8 indexed newContractVersion); - /** - * @notice Initializes the SelfVerificationRoot contract. - * @param identityVerificationHubV2Address The address of the Identity Verification Hub V2. - * @param scopeValue The expected proof scope for user registration. - * @param contractVersion The contract version for validation. - * @param attestationIds The expected attestation identifiers required in proofs. + * @notice Initializes the SelfVerificationRoot contract + * @dev Sets up the immutable reference to the hub contract and initial scope + * @param identityVerificationHubV2Address The address of the Identity Verification Hub V2 + * @param scopeValue The expected proof scope for user registration */ - constructor( - address identityVerificationHubV2Address, - uint256 scopeValue, - uint8 contractVersion, - bytes32[] memory attestationIds - ) { + constructor(address identityVerificationHubV2Address, uint256 scopeValue) { _identityVerificationHubV2 = IIdentityVerificationHubV2(identityVerificationHubV2Address); _scope = scopeValue; - _contractVersion = contractVersion; - - // Cache array length for gas optimization - uint256 length = attestationIds.length; - for (uint256 i; i < length; ) { - _attestationIdToEnabled[attestationIds[i]] = true; - unchecked { - ++i; - } - } } /** - * @notice Updates the verification configuration - * @dev Used to set or update verification parameters after contract deployment - * @param newVerificationConfig The new verification configuration to apply + * @notice Returns the current scope value + * @dev Public view function to access the current scope setting + * @return The scope value that proofs must match */ - function _setVerificationConfig(ISelfVerificationRoot.VerificationConfig memory newVerificationConfig) internal { - _verificationConfig = newVerificationConfig; - emit VerificationConfigUpdated(newVerificationConfig); - } - - /** - * @notice Returns the current verification configuration - * @dev Used to retrieve the current verification settings - * @return Current verification configuration - */ - function _getVerificationConfig() internal view returns (ISelfVerificationRoot.VerificationConfig memory) { - return _verificationConfig; + function scope() public view returns (uint256) { + return _scope; } /** * @notice Updates the scope value - * @dev Used to change the expected scope for proofs + * @dev Protected internal function to change the expected scope for proofs * @param newScope The new scope value to set */ function _setScope(uint256 newScope) internal { @@ -171,163 +83,85 @@ abstract contract SelfVerificationRoot is ISelfVerificationRoot { emit ScopeUpdated(newScope); } - /** - * @notice Updates the contract version - * @dev Used to change the expected contract version - * @param newContractVersion The new contract version to set - */ - function _setContractVersion(uint8 newContractVersion) internal { - _contractVersion = newContractVersion; - emit ContractVersionUpdated(newContractVersion); - } - - /** - * @notice Adds a new attestation ID to the allowed list - * @dev Used to add support for additional attestation types - * @param attestationId The attestation ID to add - */ - function _addAttestationId(bytes32 attestationId) internal { - _attestationIdToEnabled[attestationId] = true; - emit AttestationIdAdded(attestationId); - } - - /** - * @notice Removes an attestation ID from the allowed list - * @dev Used to revoke support for specific attestation types - * @param attestationId The attestation ID to remove - */ - function _removeAttestationId(bytes32 attestationId) internal { - _attestationIdToEnabled[attestationId] = false; - emit AttestationIdRemoved(attestationId); - } - /** * @notice Verifies a self-proof using the bytes-based interface * @dev Parses relayer data format and validates against contract settings before calling hub V2 - * @param relayerData Packed data from relayer in format: | 1 byte circuitVersion | 31 bytes buffer | 32 bytes attestationId | proof data | + * @param proofPayload Packed data from relayer in format: | 32 bytes attestationId | proof data | + * @param userContextData User-defined data in format: | 32 bytes configId | 32 bytes destChainId | 32 bytes userIdentifier | data | + * @custom:data-format proofPayload = | 32 bytes attestationId | proofData | + * @custom:data-format userContextData = | 32 bytes configId | 32 bytes destChainId | 32 bytes userIdentifier | data | + * @custom:data-format hubData = | 1 bytes contract version | 31 bytes buffer | 32 bytes scope | 32 bytes attestationId | proofData | */ - function verifySelfProof(bytes calldata relayerData) public { - // Minimum expected length: 1 + 31 + 32 = 64 bytes + proof data - if (relayerData.length < 64) { + function verifySelfProof(bytes calldata proofPayload, bytes calldata userContextData) public { + // Minimum expected length for proofData: 32 bytes attestationId + proof data + if (proofPayload.length < 32) { revert InvalidDataFormat(); } - // Parse the relayer data - uint8 circuitVersion = uint8(relayerData[0]); - // bytes31 buffer = bytes31(relayerData[1:32]); // Reserved for future use + // Minimum userDefinedData length: 32 (configId) + 32 (destChainId) + 32 (userIdentifier) = 96 bytes + if (userContextData.length < 96) { + revert InvalidDataFormat(); + } bytes32 attestationId; assembly { - // Load attestationId from offset 32 (after 1+31 bytes) - attestationId := calldataload(add(relayerData.offset, 32)) - } - - // Validate attestation ID against our stored allowed list - if (!_attestationIdToEnabled[attestationId]) { - revert InvalidAttestationId(); + // Load attestationId from the beginning of proofData (first 32 bytes) + attestationId := calldataload(proofPayload.offset) } - // Hub data should be | 1 byte circuitVersion | 1 byte contractVersion | 30 bytes buffer | 32 bytes attestationId | 32 bytes scope | proof data - bytes memory hubData = abi.encodePacked( - // 1 byte circuitVersion - circuitVersion, + // Hub data should be | 1 byte contractVersion | 31 bytes buffer | 32 bytes scope | 32 bytes attestationId | proof data + bytes memory baseVerificationInput = abi.encodePacked( // 1 byte contractVersion - _contractVersion, - // 30 bytes buffer (all zeros) - bytes30(0), - // 32 bytes attestationId - attestationId, + CONTRACT_VERSION, + // 31 bytes buffer (all zeros) + bytes31(0), // 32 bytes scope _scope, - // proof data (starts after 1+1+30+32+32 = 96 bytes) - relayerData[96:] + // 32 bytes attestationId + attestationId, + // proof data (starts after 32 bytes attestationId) + proofPayload[32:] ); // Call hub V2 verification - bytes memory result = _identityVerificationHubV2.verifyVcAndDisclose(hubData); - - // Decode the result to extract all verification data - // Note: Result format depends on attestation type (passport vs ID card) - uint256 userIdentifier; - uint256 nullifier; - uint256 scope; - uint256 identityCommitmentRoot; - uint256[] memory revealedDataPacked; - uint256[4] memory forbiddenCountriesListPacked; - - if (attestationId == AttestationId.E_PASSPORT) { - IIdentityVerificationHubV2.VcAndDiscloseVerificationResult memory passportResult = abi.decode( - result, - (IIdentityVerificationHubV2.VcAndDiscloseVerificationResult) - ); - - // Copy passport data using a for loop - revealedDataPacked = new uint256[](E_PASSPORT_REVEALED_DATA_LENGTH); - for (uint256 i = 0; i < E_PASSPORT_REVEALED_DATA_LENGTH; i++) { - revealedDataPacked[i] = passportResult.revealedDataPacked[i]; - } - - userIdentifier = passportResult.userIdentifier; - nullifier = passportResult.nullifier; - scope = passportResult.scope; - identityCommitmentRoot = passportResult.identityCommitmentRoot; - forbiddenCountriesListPacked = passportResult.forbiddenCountriesListPacked; - } else if (attestationId == AttestationId.EU_ID_CARD) { - IIdentityVerificationHubV2.IdCardVcAndDiscloseVerificationResult memory idCardResult = abi.decode( - result, - (IIdentityVerificationHubV2.IdCardVcAndDiscloseVerificationResult) - ); - - // Copy ID card data using a for loop - revealedDataPacked = new uint256[](EU_ID_CARD_REVEALED_DATA_LENGTH); - for (uint256 i = 0; i < EU_ID_CARD_REVEALED_DATA_LENGTH; i++) { - revealedDataPacked[i] = idCardResult.revealedDataPacked[i]; - } - - userIdentifier = idCardResult.userIdentifier; - nullifier = idCardResult.nullifier; - scope = idCardResult.scope; - identityCommitmentRoot = idCardResult.identityCommitmentRoot; - forbiddenCountriesListPacked = idCardResult.forbiddenCountriesListPacked; - } else { - revert InvalidAttestationId(); - } + _identityVerificationHubV2.verify(baseVerificationInput, userContextData); + } - // Validate scope against our stored scope - if (scope != _scope) { - revert InvalidScope(); + /** + * @notice Callback function called upon successful verification by the hub contract + * @dev Only callable by the identity verification hub V2 contract for security + * @param output The verification output data containing disclosed identity information + * @param userData The user-defined data passed through the verification process + * @custom:security Only the authorized hub contract can call this function + * @custom:flow This function decodes the output and calls the customizable verification hook + */ + function onVerificationSuccess(bytes memory output, bytes memory userData) public { + // Only allow the identity verification hub V2 to call this function + if (msg.sender != address(_identityVerificationHubV2)) { + revert UnauthorizedCaller(); } - emit VerificationSuccess(scope, attestationId, nullifier, userIdentifier, revealedDataPacked); - onBasicVerificationSuccess( - attestationId, - scope, - userIdentifier, - nullifier, - identityCommitmentRoot, - revealedDataPacked, - forbiddenCountriesListPacked + ISelfVerificationRoot.GenericDiscloseOutputV2 memory genericDiscloseOutput = abi.decode( + output, + (ISelfVerificationRoot.GenericDiscloseOutputV2) ); + + // Call the customizable verification hook + customVerificationHook(genericDiscloseOutput, userData); } /** - * @notice Hook called after successful verification - * @dev Virtual function to be overridden by derived contracts for custom business logic - * @param attestationId The attestation identifier from the proof - * @param scope The scope of the verification - * @param userIdentifier The user identifier from the proof - * @param nullifier The nullifier from the proof - * @param identityCommitmentRoot The root of the identity commitment - * @param revealedDataPacked The packed revealed data from the proof (E_PASSPORT_REVEALED_DATA_LENGTH for passport, EU_ID_CARD_REVEALED_DATA_LENGTH for ID card) - * @param forbiddenCountriesListPacked The packed forbidden countries list + * @notice Custom verification hook that can be overridden by implementing contracts + * @dev This function is called after successful verification and hub address validation + * @param output The verification output data from the hub containing disclosed identity information + * @param userData The user-defined data passed through the verification process + * @custom:override Override this function in derived contracts to add custom verification logic + * @custom:security This function is only called after proper authentication by the hub contract */ - function onBasicVerificationSuccess( - bytes32 attestationId, - uint256 scope, - uint256 userIdentifier, - uint256 nullifier, - uint256 identityCommitmentRoot, - uint256[] memory revealedDataPacked, - uint256[4] memory forbiddenCountriesListPacked - ) internal virtual; + function customVerificationHook( + ISelfVerificationRoot.GenericDiscloseOutputV2 memory output, + bytes memory userData + ) internal virtual { + // Default implementation is empty - override in derived contracts to add custom logic + } } diff --git a/contracts/contracts/constants/CircuitConstantsV2.sol b/contracts/contracts/constants/CircuitConstantsV2.sol index 62549a2dd..98734ad09 100644 --- a/contracts/contracts/constants/CircuitConstantsV2.sol +++ b/contracts/contracts/constants/CircuitConstantsV2.sol @@ -61,7 +61,7 @@ library CircuitConstantsV2 { uint256 nameyobSmtRootIndex; uint256 scopeIndex; uint256 userIdentifierIndex; - uint256 passportNoSmtRootIndex; // Only for passport, 0 for ID card + uint256 passportNoSmtRootIndex; // Only for passport, 99 for ID card } /** @@ -98,7 +98,7 @@ library CircuitConstantsV2 { nameyobSmtRootIndex: 18, scopeIndex: 19, userIdentifierIndex: 20, - passportNoSmtRootIndex: 0 // Not applicable for ID cards + passportNoSmtRootIndex: 99 }); } else { revert("Invalid attestation ID"); diff --git a/contracts/contracts/example/Airdrop.sol b/contracts/contracts/example/Airdrop.sol index 9f016878a..2b28f0e46 100644 --- a/contracts/contracts/example/Airdrop.sol +++ b/contracts/contracts/example/Airdrop.sol @@ -1,329 +1,329 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.28; - -import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; -import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; - -import {ISelfVerificationRoot} from "../interfaces/ISelfVerificationRoot.sol"; - -import {SelfVerificationRoot} from "../abstract/SelfVerificationRoot.sol"; - -/** - * @title Airdrop (Experimental) - * @notice This contract manages an airdrop campaign by verifying user registrations with zero‐knowledge proofs - * and distributing ERC20 tokens. It is provided for testing and demonstration purposes only. - * **WARNING:** This contract has not been audited and is NOT intended for production use. - * @dev Inherits from SelfVerificationRoot for registration logic and Ownable for administrative control. - */ -contract Airdrop is SelfVerificationRoot, Ownable { - using SafeERC20 for IERC20; - - // ==================================================== - // Storage Variables - // ==================================================== - - /// @notice ERC20 token to be airdropped. - IERC20 public immutable token; - /// @notice Merkle root used to validate airdrop claims. - bytes32 public merkleRoot; - /// @notice Tracks addresses that have claimed tokens. - mapping(address => bool) public claimed; - /// @notice Indicates whether the registration phase is active. - bool public isRegistrationOpen; - /// @notice Indicates whether the claim phase is active. - bool public isClaimOpen; - - /// @notice Maps nullifiers to user identifiers for registration tracking - mapping(uint256 nullifier => uint256 userIdentifier) internal _nullifierToUserIdentifier; - - /// @notice Maps user identifiers to registration status - mapping(uint256 userIdentifier => bool registered) internal _registeredUserIdentifiers; - - // ==================================================== - // Errors - // ==================================================== - - /// @notice Reverts when an invalid Merkle proof is provided. - error InvalidProof(); - /// @notice Reverts when a user attempts to claim tokens more than once. - error AlreadyClaimed(); - /// @notice Reverts when an unregistered address attempts to claim tokens. - error NotRegistered(address nonRegisteredAddress); - /// @notice Reverts when registration is attempted while the registration phase is closed. - error RegistrationNotOpen(); - /// @notice Reverts when a claim attempt is made while registration is still open. - error RegistrationNotClosed(); - /// @notice Reverts when a claim is attempted while claiming is not enabled. - error ClaimNotOpen(); - /// @notice Reverts when an invalid user identifier is provided. - error InvalidUserIdentifier(); - /// @notice Reverts when a user identifier has already been registered - error UserIdentifierAlreadyRegistered(); - /// @notice Reverts when a nullifier has already been registered - error RegisteredNullifier(); - - // ==================================================== - // Events - // ==================================================== - - /// @notice Emitted when a user successfully claims tokens. - /// @param index The index of the claim in the Merkle tree. - /// @param account The address that claimed tokens. - /// @param amount The amount of tokens claimed. - event Claimed(uint256 index, address account, uint256 amount); - /// @notice Emitted when the registration phase is opened. - event RegistrationOpen(); - /// @notice Emitted when the registration phase is closed. - event RegistrationClose(); - /// @notice Emitted when the claim phase is opened. - event ClaimOpen(); - /// @notice Emitted when the claim phase is closed. - event ClaimClose(); - - /// @notice Emitted when a user identifier is registered. - event UserIdentifierRegistered(uint256 indexed registeredUserIdentifier, uint256 indexed nullifier); - - /// @notice Emitted when the Merkle root is updated. - event MerkleRootUpdated(bytes32 newMerkleRoot); - - // ==================================================== - // Constructor - // ==================================================== - - /** - * @notice Constructor for the experimental Airdrop contract. - * @dev Initializes the airdrop parameters, zero-knowledge verification configuration, - * and sets the ERC20 token to be distributed. - * @param identityVerificationHubAddress The address of the Identity Verification Hub. - * @param scopeValue The expected proof scope for user registration. - * @param contractVersion The contract version for validation. - * @param attestationIds The expected attestation identifiers required in proofs. - * @param tokenAddress The address of the ERC20 token for airdrop. - */ - constructor( - address identityVerificationHubAddress, - uint256 scopeValue, - uint8 contractVersion, - bytes32[] memory attestationIds, - address tokenAddress - ) - SelfVerificationRoot(identityVerificationHubAddress, scopeValue, contractVersion, attestationIds) - Ownable(_msgSender()) - { - token = IERC20(tokenAddress); - } - - // ==================================================== - // External/Public Functions - // ==================================================== - - /** - * @notice Sets the Merkle root for claim validation. - * @dev Only callable by the contract owner. - * @param newMerkleRoot The new Merkle root. - */ - function setMerkleRoot(bytes32 newMerkleRoot) external onlyOwner { - merkleRoot = newMerkleRoot; - emit MerkleRootUpdated(newMerkleRoot); - } - - /** - * @notice Updates the verification configuration for address registration. - * @dev Only callable by the contract owner. - * @param newVerificationConfig The new verification configuration. - */ - function setVerificationConfig( - ISelfVerificationRoot.VerificationConfig memory newVerificationConfig - ) external onlyOwner { - _setVerificationConfig(newVerificationConfig); - } - - /** - * @notice Updates the scope used for verification. - * @dev Only callable by the contract owner. - * @param newScope The new scope to set. - */ - function setScope(uint256 newScope) external onlyOwner { - _setScope(newScope); - } - - /** - * @notice Adds a new attestation ID to the allowed list. - * @dev Only callable by the contract owner. - * @param attestationId The attestation ID to add. - */ - function addAttestationId(bytes32 attestationId) external onlyOwner { - _addAttestationId(attestationId); - } - - /** - * @notice Removes an attestation ID from the allowed list. - * @dev Only callable by the contract owner. - * @param attestationId The attestation ID to remove. - */ - function removeAttestationId(bytes32 attestationId) external onlyOwner { - _removeAttestationId(attestationId); - } - - /** - * @notice Opens the registration phase for users. - * @dev Only callable by the contract owner. - */ - function openRegistration() external onlyOwner { - isRegistrationOpen = true; - emit RegistrationOpen(); - } - - /** - * @notice Closes the registration phase. - * @dev Only callable by the contract owner. - */ - function closeRegistration() external onlyOwner { - isRegistrationOpen = false; - emit RegistrationClose(); - } - - /** - * @notice Opens the claim phase, allowing registered users to claim tokens. - * @dev Only callable by the contract owner. - */ - function openClaim() external onlyOwner { - isClaimOpen = true; - emit ClaimOpen(); - } - - /** - * @notice Closes the claim phase. - * @dev Only callable by the contract owner. - */ - function closeClaim() external onlyOwner { - isClaimOpen = false; - emit ClaimClose(); - } - - /** - * @notice Retrieves the expected proof scope. - * @return The scope value used for registration verification. - */ - function getScope() external view returns (uint256) { - return _scope; - } - - /** - * @notice Checks if the specified attestation ID is allowed. - * @param attestationId The attestation ID to check. - * @return True if the attestation ID is allowed, false otherwise. - */ - function isAttestationIdAllowed(bytes32 attestationId) external view returns (bool) { - return _attestationIdToEnabled[attestationId]; - } - - /** - * @notice Retrieves the current verification configuration. - * @return The verification configuration used for registration. - */ - function getVerificationConfig() external view returns (ISelfVerificationRoot.VerificationConfig memory) { - return _getVerificationConfig(); - } - - /** - * @notice Checks if a given address is registered. - * @param registeredAddress The address to check. - * @return True if the address is registered, false otherwise. - */ - function isRegistered(address registeredAddress) external view returns (bool) { - return _registeredUserIdentifiers[uint256(uint160(registeredAddress))]; - } - - /** - * @notice Allows a registered user to claim their tokens. - * @dev Reverts if registration is still open, if claiming is disabled, if already claimed, - * or if the sender is not registered. Also validates the claim using a Merkle proof. - * @param index The index of the claim in the Merkle tree. - * @param amount The amount of tokens to be claimed. - * @param merkleProof The Merkle proof verifying the claim. - */ - function claim(uint256 index, uint256 amount, bytes32[] memory merkleProof) external { - if (isRegistrationOpen) { - revert RegistrationNotClosed(); - } - if (!isClaimOpen) { - revert ClaimNotOpen(); - } - if (claimed[msg.sender]) { - revert AlreadyClaimed(); - } - if (!_registeredUserIdentifiers[uint256(uint160(msg.sender))]) { - revert NotRegistered(msg.sender); - } - - // Verify the Merkle proof. - bytes32 node = keccak256(abi.encodePacked(index, msg.sender, amount)); - if (!MerkleProof.verify(merkleProof, merkleRoot, node)) revert InvalidProof(); - - // Mark as claimed and transfer tokens. - _setClaimed(); - token.safeTransfer(msg.sender, amount); - - emit Claimed(index, msg.sender, amount); - } - - // ==================================================== - // Override Functions from SelfVerificationRoot - // ==================================================== - - /** - * @notice Hook called after successful verification - handles user registration - * @dev Validates registration conditions and registers the user - * @param userIdentifier The user identifier from the proof - * @param nullifier The nullifier from the proof - */ - function onBasicVerificationSuccess( - bytes32 /* attestationId */, - uint256 /* scope */, - uint256 userIdentifier, - uint256 nullifier, - uint256 /* identityCommitmentRoot */, - uint256[] memory /* revealedDataPacked */, - uint256[4] memory /* forbiddenCountriesListPacked */ - ) internal override { - // Check if registration is open - if (!isRegistrationOpen) { - revert RegistrationNotOpen(); - } - - // Check if nullifier has already been registered - if (_nullifierToUserIdentifier[nullifier] != 0) { - revert RegisteredNullifier(); - } - - // Check if user identifier is valid - if (userIdentifier == 0) { - revert InvalidUserIdentifier(); - } - - // Check if user identifier has already been registered - if (_registeredUserIdentifiers[userIdentifier]) { - revert UserIdentifierAlreadyRegistered(); - } - - _nullifierToUserIdentifier[nullifier] = userIdentifier; - _registeredUserIdentifiers[userIdentifier] = true; - - // Emit registration event - emit UserIdentifierRegistered(userIdentifier, nullifier); - } - - // ==================================================== - // Internal Functions - // ==================================================== - - /** - * @notice Internal function to mark the caller as having claimed their tokens. - * @dev Updates the claimed mapping. - */ - function _setClaimed() internal { - claimed[msg.sender] = true; - } -} + // // SPDX-License-Identifier: MIT +// pragma solidity 0.8.28; + +// import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +// import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; +// import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +// import {ISelfVerificationRoot} from "../interfaces/ISelfVerificationRoot.sol"; + +// import {SelfVerificationRoot} from "../abstract/SelfVerificationRoot.sol"; + +// /** +// * @title Airdrop (Experimental) +// * @notice This contract manages an airdrop campaign by verifying user registrations with zero‐knowledge proofs +// * and distributing ERC20 tokens. It is provided for testing and demonstration purposes only. +// * **WARNING:** This contract has not been audited and is NOT intended for production use. +// * @dev Inherits from SelfVerificationRoot for registration logic and Ownable for administrative control. +// */ +// contract Airdrop is SelfVerificationRoot, Ownable { +// using SafeERC20 for IERC20; + +// // ==================================================== +// // Storage Variables +// // ==================================================== + +// /// @notice ERC20 token to be airdropped. +// IERC20 public immutable token; +// /// @notice Merkle root used to validate airdrop claims. +// bytes32 public merkleRoot; +// /// @notice Tracks addresses that have claimed tokens. +// mapping(address => bool) public claimed; +// /// @notice Indicates whether the registration phase is active. +// bool public isRegistrationOpen; +// /// @notice Indicates whether the claim phase is active. +// bool public isClaimOpen; + +// /// @notice Maps nullifiers to user identifiers for registration tracking +// mapping(uint256 nullifier => uint256 userIdentifier) internal _nullifierToUserIdentifier; + +// /// @notice Maps user identifiers to registration status +// mapping(uint256 userIdentifier => bool registered) internal _registeredUserIdentifiers; + +// // ==================================================== +// // Errors +// // ==================================================== + +// /// @notice Reverts when an invalid Merkle proof is provided. +// error InvalidProof(); +// /// @notice Reverts when a user attempts to claim tokens more than once. +// error AlreadyClaimed(); +// /// @notice Reverts when an unregistered address attempts to claim tokens. +// error NotRegistered(address nonRegisteredAddress); +// /// @notice Reverts when registration is attempted while the registration phase is closed. +// error RegistrationNotOpen(); +// /// @notice Reverts when a claim attempt is made while registration is still open. +// error RegistrationNotClosed(); +// /// @notice Reverts when a claim is attempted while claiming is not enabled. +// error ClaimNotOpen(); +// /// @notice Reverts when an invalid user identifier is provided. +// error InvalidUserIdentifier(); +// /// @notice Reverts when a user identifier has already been registered +// error UserIdentifierAlreadyRegistered(); +// /// @notice Reverts when a nullifier has already been registered +// error RegisteredNullifier(); + +// // ==================================================== +// // Events +// // ==================================================== + +// /// @notice Emitted when a user successfully claims tokens. +// /// @param index The index of the claim in the Merkle tree. +// /// @param account The address that claimed tokens. +// /// @param amount The amount of tokens claimed. +// event Claimed(uint256 index, address account, uint256 amount); +// /// @notice Emitted when the registration phase is opened. +// event RegistrationOpen(); +// /// @notice Emitted when the registration phase is closed. +// event RegistrationClose(); +// /// @notice Emitted when the claim phase is opened. +// event ClaimOpen(); +// /// @notice Emitted when the claim phase is closed. +// event ClaimClose(); + +// /// @notice Emitted when a user identifier is registered. +// event UserIdentifierRegistered(uint256 indexed registeredUserIdentifier, uint256 indexed nullifier); + +// /// @notice Emitted when the Merkle root is updated. +// event MerkleRootUpdated(bytes32 newMerkleRoot); + +// // ==================================================== +// // Constructor +// // ==================================================== + +// /** +// * @notice Constructor for the experimental Airdrop contract. +// * @dev Initializes the airdrop parameters, zero-knowledge verification configuration, +// * and sets the ERC20 token to be distributed. +// * @param identityVerificationHubAddress The address of the Identity Verification Hub. +// * @param scopeValue The expected proof scope for user registration. +// * @param contractVersion The contract version for validation. +// * @param attestationIds The expected attestation identifiers required in proofs. +// * @param tokenAddress The address of the ERC20 token for airdrop. +// */ +// constructor( +// address identityVerificationHubAddress, +// uint256 scopeValue, +// uint8 contractVersion, +// bytes32[] memory attestationIds, +// address tokenAddress +// ) +// SelfVerificationRoot(identityVerificationHubAddress, scopeValue, contractVersion, attestationIds) +// Ownable(_msgSender()) +// { +// token = IERC20(tokenAddress); +// } + +// // ==================================================== +// // External/Public Functions +// // ==================================================== + +// /** +// * @notice Sets the Merkle root for claim validation. +// * @dev Only callable by the contract owner. +// * @param newMerkleRoot The new Merkle root. +// */ +// function setMerkleRoot(bytes32 newMerkleRoot) external onlyOwner { +// merkleRoot = newMerkleRoot; +// emit MerkleRootUpdated(newMerkleRoot); +// } + +// /** +// * @notice Updates the verification configuration for address registration. +// * @dev Only callable by the contract owner. +// * @param newVerificationConfig The new verification configuration. +// */ +// function setVerificationConfig( +// ISelfVerificationRoot.VerificationConfig memory newVerificationConfig +// ) external onlyOwner { +// _setVerificationConfig(newVerificationConfig); +// } + +// /** +// * @notice Updates the scope used for verification. +// * @dev Only callable by the contract owner. +// * @param newScope The new scope to set. +// */ +// function setScope(uint256 newScope) external onlyOwner { +// _setScope(newScope); +// } + +// /** +// * @notice Adds a new attestation ID to the allowed list. +// * @dev Only callable by the contract owner. +// * @param attestationId The attestation ID to add. +// */ +// function addAttestationId(bytes32 attestationId) external onlyOwner { +// _addAttestationId(attestationId); +// } + +// /** +// * @notice Removes an attestation ID from the allowed list. +// * @dev Only callable by the contract owner. +// * @param attestationId The attestation ID to remove. +// */ +// function removeAttestationId(bytes32 attestationId) external onlyOwner { +// _removeAttestationId(attestationId); +// } + +// /** +// * @notice Opens the registration phase for users. +// * @dev Only callable by the contract owner. +// */ +// function openRegistration() external onlyOwner { +// isRegistrationOpen = true; +// emit RegistrationOpen(); +// } + +// /** +// * @notice Closes the registration phase. +// * @dev Only callable by the contract owner. +// */ +// function closeRegistration() external onlyOwner { +// isRegistrationOpen = false; +// emit RegistrationClose(); +// } + +// /** +// * @notice Opens the claim phase, allowing registered users to claim tokens. +// * @dev Only callable by the contract owner. +// */ +// function openClaim() external onlyOwner { +// isClaimOpen = true; +// emit ClaimOpen(); +// } + +// /** +// * @notice Closes the claim phase. +// * @dev Only callable by the contract owner. +// */ +// function closeClaim() external onlyOwner { +// isClaimOpen = false; +// emit ClaimClose(); +// } + +// /** +// * @notice Retrieves the expected proof scope. +// * @return The scope value used for registration verification. +// */ +// function getScope() external view returns (uint256) { +// return _scope; +// } + +// /** +// * @notice Checks if the specified attestation ID is allowed. +// * @param attestationId The attestation ID to check. +// * @return True if the attestation ID is allowed, false otherwise. +// */ +// function isAttestationIdAllowed(bytes32 attestationId) external view returns (bool) { +// return _attestationIdToEnabled[attestationId]; +// } + +// /** +// * @notice Retrieves the current verification configuration. +// * @return The verification configuration used for registration. +// */ +// function getVerificationConfig() external view returns (ISelfVerificationRoot.VerificationConfig memory) { +// return _getVerificationConfig(); +// } + +// /** +// * @notice Checks if a given address is registered. +// * @param registeredAddress The address to check. +// * @return True if the address is registered, false otherwise. +// */ +// function isRegistered(address registeredAddress) external view returns (bool) { +// return _registeredUserIdentifiers[uint256(uint160(registeredAddress))]; +// } + +// /** +// * @notice Allows a registered user to claim their tokens. +// * @dev Reverts if registration is still open, if claiming is disabled, if already claimed, +// * or if the sender is not registered. Also validates the claim using a Merkle proof. +// * @param index The index of the claim in the Merkle tree. +// * @param amount The amount of tokens to be claimed. +// * @param merkleProof The Merkle proof verifying the claim. +// */ +// function claim(uint256 index, uint256 amount, bytes32[] memory merkleProof) external { +// if (isRegistrationOpen) { +// revert RegistrationNotClosed(); +// } +// if (!isClaimOpen) { +// revert ClaimNotOpen(); +// } +// if (claimed[msg.sender]) { +// revert AlreadyClaimed(); +// } +// if (!_registeredUserIdentifiers[uint256(uint160(msg.sender))]) { +// revert NotRegistered(msg.sender); +// } + +// // Verify the Merkle proof. +// bytes32 node = keccak256(abi.encodePacked(index, msg.sender, amount)); +// if (!MerkleProof.verify(merkleProof, merkleRoot, node)) revert InvalidProof(); + +// // Mark as claimed and transfer tokens. +// _setClaimed(); +// token.safeTransfer(msg.sender, amount); + +// emit Claimed(index, msg.sender, amount); +// } + +// // ==================================================== +// // Override Functions from SelfVerificationRoot +// // ==================================================== + +// /** +// * @notice Hook called after successful verification - handles user registration +// * @dev Validates registration conditions and registers the user +// * @param userIdentifier The user identifier from the proof +// * @param nullifier The nullifier from the proof +// */ +// function onBasicVerificationSuccess( +// bytes32 /* attestationId */, +// uint256 /* scope */, +// uint256 userIdentifier, +// uint256 nullifier, +// uint256 /* identityCommitmentRoot */, +// uint256[] memory /* revealedDataPacked */, +// uint256[4] memory /* forbiddenCountriesListPacked */ +// ) internal override { +// // Check if registration is open +// if (!isRegistrationOpen) { +// revert RegistrationNotOpen(); +// } + +// // Check if nullifier has already been registered +// if (_nullifierToUserIdentifier[nullifier] != 0) { +// revert RegisteredNullifier(); +// } + +// // Check if user identifier is valid +// if (userIdentifier == 0) { +// revert InvalidUserIdentifier(); +// } + +// // Check if user identifier has already been registered +// if (_registeredUserIdentifiers[userIdentifier]) { +// revert UserIdentifierAlreadyRegistered(); +// } + +// _nullifierToUserIdentifier[nullifier] = userIdentifier; +// _registeredUserIdentifiers[userIdentifier] = true; + +// // Emit registration event +// emit UserIdentifierRegistered(userIdentifier, nullifier); +// } + +// // ==================================================== +// // Internal Functions +// // ==================================================== + +// /** +// * @notice Internal function to mark the caller as having claimed their tokens. +// * @dev Updates the claimed mapping. +// */ +// function _setClaimed() internal { +// claimed[msg.sender] = true; +// } +// } diff --git a/contracts/contracts/example/HappyBirthday.sol b/contracts/contracts/example/HappyBirthday.sol index 14e6b23f3..9315d60db 100644 --- a/contracts/contracts/example/HappyBirthday.sol +++ b/contracts/contracts/example/HappyBirthday.sol @@ -1,201 +1,201 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.28; - -import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; -import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; - -import {ISelfVerificationRoot} from "../interfaces/ISelfVerificationRoot.sol"; - -import {SelfCircuitLibrary} from "../libraries/SelfCircuitLibrary.sol"; -import {SelfVerificationRoot} from "../abstract/SelfVerificationRoot.sol"; - -/** - * @title SelfHappyBirthday - * @notice A contract that gives out USDC to users on their birthday - * @dev Uses SelfVerificationRoot to handle verification with nullifier management for birthday claims - */ -contract SelfHappyBirthday is SelfVerificationRoot, Ownable { - using SafeERC20 for IERC20; - - // ==================================================== - // Storage Variables - // ==================================================== - - /// @notice USDC token contract - IERC20 public immutable usdc; - - /// @notice Default: 1 dollar (6 decimals for USDC) - uint256 public claimableAmount = 1e6; - - /// @notice Default: 1 day window around birthday - uint256 public claimableWindow = 1 days; - - /// @notice Tracks users who have claimed to prevent double claims - mapping(uint256 nullifier => bool hasClaimed) public hasClaimed; - - // ==================================================== - // Events - // ==================================================== - - event USDCClaimed(address indexed claimer, uint256 amount); - event ClaimableAmountUpdated(uint256 oldAmount, uint256 newAmount); - event ClaimableWindowUpdated(uint256 oldWindow, uint256 newWindow); - - // ==================================================== - // Errors - // ==================================================== - - error NotWithinBirthdayWindow(); - error AlreadyClaimed(); - - /** - * @notice Initializes the HappyBirthday contract - * @param identityVerificationHubAddress The address of the Identity Verification Hub - * @param scopeValue The expected proof scope for user registration - * @param contractVersion The contract version for validation - * @param attestationIds Array of allowed attestation identifiers - * @param token The USDC token address - */ - constructor( - address identityVerificationHubAddress, - uint256 scopeValue, - uint8 contractVersion, - bytes32[] memory attestationIds, - address token - ) - SelfVerificationRoot(identityVerificationHubAddress, scopeValue, contractVersion, attestationIds) - Ownable(_msgSender()) - { - usdc = IERC20(token); - } - - // ==================================================== - // External/Public Functions - // ==================================================== - - /** - * @notice Sets the verification configuration - * @param newVerificationConfig The new verification settings - */ - function setVerificationConfig( - ISelfVerificationRoot.VerificationConfig memory newVerificationConfig - ) external onlyOwner { - _setVerificationConfig(newVerificationConfig); - } - - /** - * @notice Sets the claimable USDC amount - * @param newAmount The new claimable amount - */ - function setClaimableAmount(uint256 newAmount) external onlyOwner { - uint256 oldAmount = claimableAmount; - claimableAmount = newAmount; - emit ClaimableAmountUpdated(oldAmount, newAmount); - } - - /** - * @notice Sets the claimable window around birthdays - * @param newWindow The new claimable window in seconds - */ - function setClaimableWindow(uint256 newWindow) external onlyOwner { - uint256 oldWindow = claimableWindow; - claimableWindow = newWindow; - emit ClaimableWindowUpdated(oldWindow, newWindow); - } - - /** - * @notice Allows the owner to withdraw USDC from the contract - * @param to The address to withdraw to - * @param amount The amount to withdraw - */ - function withdrawUSDC(address to, uint256 amount) external onlyOwner { - usdc.safeTransfer(to, amount); - } - - // ==================================================== - // Override Functions from SelfVerificationRoot - // ==================================================== - - /** - * @notice Hook called after successful verification - * @dev Checks user hasn't claimed, validates birthday window, and transfers USDC if eligible - * @param userIdentifier The user identifier from the proof - * @param nullifier The nullifier from the proof - * @param revealedDataPacked The packed revealed data from the proof - */ - function onBasicVerificationSuccess( - bytes32 /* attestationId */, - uint256 /* scope */, - uint256 userIdentifier, - uint256 nullifier, - uint256 /* identityCommitmentRoot */, - uint256[] memory revealedDataPacked, - uint256[4] memory /* forbiddenCountriesListPacked */ - ) internal override { - // Check if user has already claimed - if (hasClaimed[nullifier]) { - revert AlreadyClaimed(); - } - - // Check if within birthday window - only use first 3 elements for passport data - uint256[3] memory passportData; - for (uint256 i = 0; i < 3 && i < revealedDataPacked.length; i++) { - passportData[i] = revealedDataPacked[i]; - } - - if (_isWithinBirthdayWindow(passportData)) { - // Mark user as claimed - hasClaimed[nullifier] = true; - - address recipient = address(uint160(userIdentifier)); - - // Transfer USDC to the user - usdc.safeTransfer(recipient, claimableAmount); - - // Emit success event - emit USDCClaimed(recipient, claimableAmount); - } else { - revert NotWithinBirthdayWindow(); - } - } - - // ==================================================== - // Internal Functions - // ==================================================== - - /** - * @notice Checks if the current date is within the user's birthday window - * @param revealedDataPacked The packed revealed data containing DOB information - * @return isWithinWindow True if within the birthday window - */ - function _isWithinBirthdayWindow(uint256[3] memory revealedDataPacked) internal view returns (bool) { - string memory dob = SelfCircuitLibrary.getDateOfBirth(revealedDataPacked); - - bytes memory dobBytes = bytes(dob); - bytes memory dayBytes = new bytes(2); - bytes memory monthBytes = new bytes(2); - - dayBytes[0] = dobBytes[0]; - dayBytes[1] = dobBytes[1]; - - monthBytes[0] = dobBytes[3]; - monthBytes[1] = dobBytes[4]; - - string memory day = string(dayBytes); - string memory month = string(monthBytes); - string memory dobInThisYear = string(abi.encodePacked("25", month, day)); - - uint256 dobInThisYearTimestamp = SelfCircuitLibrary.dateToTimestamp(dobInThisYear); - - uint256 currentTime = block.timestamp; - uint256 timeDifference; - - if (currentTime > dobInThisYearTimestamp) { - timeDifference = currentTime - dobInThisYearTimestamp; - } else { - timeDifference = dobInThisYearTimestamp - currentTime; - } - - return timeDifference <= claimableWindow; - } -} + // // SPDX-License-Identifier: MIT +// pragma solidity 0.8.28; + +// import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +// import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +// import {ISelfVerificationRoot} from "../interfaces/ISelfVerificationRoot.sol"; + +// import {SelfCircuitLibrary} from "../libraries/SelfCircuitLibrary.sol"; +// import {SelfVerificationRoot} from "../abstract/SelfVerificationRoot.sol"; + +// /** +// * @title SelfHappyBirthday +// * @notice A contract that gives out USDC to users on their birthday +// * @dev Uses SelfVerificationRoot to handle verification with nullifier management for birthday claims +// */ +// contract SelfHappyBirthday is SelfVerificationRoot, Ownable { +// using SafeERC20 for IERC20; + +// // ==================================================== +// // Storage Variables +// // ==================================================== + +// /// @notice USDC token contract +// IERC20 public immutable usdc; + +// /// @notice Default: 1 dollar (6 decimals for USDC) +// uint256 public claimableAmount = 1e6; + +// /// @notice Default: 1 day window around birthday +// uint256 public claimableWindow = 1 days; + +// /// @notice Tracks users who have claimed to prevent double claims +// mapping(uint256 nullifier => bool hasClaimed) public hasClaimed; + +// // ==================================================== +// // Events +// // ==================================================== + +// event USDCClaimed(address indexed claimer, uint256 amount); +// event ClaimableAmountUpdated(uint256 oldAmount, uint256 newAmount); +// event ClaimableWindowUpdated(uint256 oldWindow, uint256 newWindow); + +// // ==================================================== +// // Errors +// // ==================================================== + +// error NotWithinBirthdayWindow(); +// error AlreadyClaimed(); + +// /** +// * @notice Initializes the HappyBirthday contract +// * @param identityVerificationHubAddress The address of the Identity Verification Hub +// * @param scopeValue The expected proof scope for user registration +// * @param contractVersion The contract version for validation +// * @param attestationIds Array of allowed attestation identifiers +// * @param token The USDC token address +// */ +// constructor( +// address identityVerificationHubAddress, +// uint256 scopeValue, +// uint8 contractVersion, +// bytes32[] memory attestationIds, +// address token +// ) +// SelfVerificationRoot(identityVerificationHubAddress, scopeValue, contractVersion, attestationIds) +// Ownable(_msgSender()) +// { +// usdc = IERC20(token); +// } + +// // ==================================================== +// // External/Public Functions +// // ==================================================== + +// /** +// * @notice Sets the verification configuration +// * @param newVerificationConfig The new verification settings +// */ +// function setVerificationConfig( +// ISelfVerificationRoot.VerificationConfig memory newVerificationConfig +// ) external onlyOwner { +// _setVerificationConfig(newVerificationConfig); +// } + +// /** +// * @notice Sets the claimable USDC amount +// * @param newAmount The new claimable amount +// */ +// function setClaimableAmount(uint256 newAmount) external onlyOwner { +// uint256 oldAmount = claimableAmount; +// claimableAmount = newAmount; +// emit ClaimableAmountUpdated(oldAmount, newAmount); +// } + +// /** +// * @notice Sets the claimable window around birthdays +// * @param newWindow The new claimable window in seconds +// */ +// function setClaimableWindow(uint256 newWindow) external onlyOwner { +// uint256 oldWindow = claimableWindow; +// claimableWindow = newWindow; +// emit ClaimableWindowUpdated(oldWindow, newWindow); +// } + +// /** +// * @notice Allows the owner to withdraw USDC from the contract +// * @param to The address to withdraw to +// * @param amount The amount to withdraw +// */ +// function withdrawUSDC(address to, uint256 amount) external onlyOwner { +// usdc.safeTransfer(to, amount); +// } + +// // ==================================================== +// // Override Functions from SelfVerificationRoot +// // ==================================================== + +// /** +// * @notice Hook called after successful verification +// * @dev Checks user hasn't claimed, validates birthday window, and transfers USDC if eligible +// * @param userIdentifier The user identifier from the proof +// * @param nullifier The nullifier from the proof +// * @param revealedDataPacked The packed revealed data from the proof +// */ +// function onBasicVerificationSuccess( +// bytes32 /* attestationId */, +// uint256 /* scope */, +// uint256 userIdentifier, +// uint256 nullifier, +// uint256 /* identityCommitmentRoot */, +// uint256[] memory revealedDataPacked, +// uint256[4] memory /* forbiddenCountriesListPacked */ +// ) internal override { +// // Check if user has already claimed +// if (hasClaimed[nullifier]) { +// revert AlreadyClaimed(); +// } + +// // Check if within birthday window - only use first 3 elements for passport data +// uint256[3] memory passportData; +// for (uint256 i = 0; i < 3 && i < revealedDataPacked.length; i++) { +// passportData[i] = revealedDataPacked[i]; +// } + +// if (_isWithinBirthdayWindow(passportData)) { +// // Mark user as claimed +// hasClaimed[nullifier] = true; + +// address recipient = address(uint160(userIdentifier)); + +// // Transfer USDC to the user +// usdc.safeTransfer(recipient, claimableAmount); + +// // Emit success event +// emit USDCClaimed(recipient, claimableAmount); +// } else { +// revert NotWithinBirthdayWindow(); +// } +// } + +// // ==================================================== +// // Internal Functions +// // ==================================================== + +// /** +// * @notice Checks if the current date is within the user's birthday window +// * @param revealedDataPacked The packed revealed data containing DOB information +// * @return isWithinWindow True if within the birthday window +// */ +// function _isWithinBirthdayWindow(uint256[3] memory revealedDataPacked) internal view returns (bool) { +// string memory dob = SelfCircuitLibrary.getDateOfBirth(revealedDataPacked); + +// bytes memory dobBytes = bytes(dob); +// bytes memory dayBytes = new bytes(2); +// bytes memory monthBytes = new bytes(2); + +// dayBytes[0] = dobBytes[0]; +// dayBytes[1] = dobBytes[1]; + +// monthBytes[0] = dobBytes[3]; +// monthBytes[1] = dobBytes[4]; + +// string memory day = string(dayBytes); +// string memory month = string(monthBytes); +// string memory dobInThisYear = string(abi.encodePacked("25", month, day)); + +// uint256 dobInThisYearTimestamp = SelfCircuitLibrary.dateToTimestamp(dobInThisYear); + +// uint256 currentTime = block.timestamp; +// uint256 timeDifference; + +// if (currentTime > dobInThisYearTimestamp) { +// timeDifference = currentTime - dobInThisYearTimestamp; +// } else { +// timeDifference = dobInThisYearTimestamp - currentTime; +// } + +// return timeDifference <= claimableWindow; +// } +// } diff --git a/contracts/contracts/example/SelfPassportERC721.sol b/contracts/contracts/example/SelfPassportERC721.sol index 6348106cc..7df8611d1 100644 --- a/contracts/contracts/example/SelfPassportERC721.sol +++ b/contracts/contracts/example/SelfPassportERC721.sol @@ -1,219 +1,219 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.28; - -import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; -import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; - -import {ISelfVerificationRoot} from "../interfaces/ISelfVerificationRoot.sol"; - -import {SelfCircuitLibrary} from "../libraries/SelfCircuitLibrary.sol"; -import {SelfVerificationRoot} from "../abstract/SelfVerificationRoot.sol"; - -/** - * @title SelfPassportERC721 - * @notice This contract issues ERC721 tokens based on verified passport credentials using self's verification infrastructure - * @dev Inherits from SelfVerificationRoot for verification logic and ERC721 for NFT functionality - */ -contract SelfPassportERC721 is SelfVerificationRoot, ERC721, Ownable { - using SelfCircuitLibrary for uint256[3]; - - // ==================================================== - // Storage Variables - // ==================================================== - - /// @notice Counter for token IDs - uint256 private _tokenIdCounter; - - /// @notice Mapping from token ID to passport attributes - mapping(uint256 tokenId => SelfCircuitLibrary.PassportData passportAttributes) private _passportAttributes; - - /// @notice Mapping to track minted user identifiers to prevent double minting - mapping(uint256 userIdentifier => bool minted) private _mintedUserIdentifiers; - - // ==================================================== - // Events - // ==================================================== - - event PassportNFTMinted(uint256 indexed tokenId, address indexed owner, SelfCircuitLibrary.PassportData attributes); - - // ==================================================== - // Errors - // ==================================================== - - error UserIdentifierAlreadyMinted(); - error InvalidUserIdentifier(); - - // ==================================================== - // Constructor - // ==================================================== - - /** - * @notice Constructor for the SelfPassportERC721 contract - * @param identityVerificationHubAddress The address of the Identity Verification Hub - * @param scopeValue The expected proof scope for user registration - * @param contractVersion The contract version for validation - * @param attestationIdsList The expected attestation identifiers required in proofs - * @param name The name of the NFT collection - * @param symbol The symbol of the NFT collection - */ - constructor( - address identityVerificationHubAddress, - uint256 scopeValue, - uint8 contractVersion, - bytes32[] memory attestationIdsList, - string memory name, - string memory symbol - ) - SelfVerificationRoot(identityVerificationHubAddress, scopeValue, contractVersion, attestationIdsList) - ERC721(name, symbol) - Ownable(_msgSender()) - {} - - // ==================================================== - // External/Public Functions - // ==================================================== - - /** - * @notice Updates the scope used for verification - * @dev Only callable by the contract owner - * @param newScope The new scope to set - */ - function setScope(uint256 newScope) external onlyOwner { - _setScope(newScope); - } - - /** - * @notice Adds a new attestation ID to the allowed list - * @dev Only callable by the contract owner - * @param attestationId The attestation ID to add - */ - function addAttestationId(bytes32 attestationId) external onlyOwner { - _addAttestationId(attestationId); - } - - /** - * @notice Removes an attestation ID from the allowed list - * @dev Only callable by the contract owner - * @param attestationId The attestation ID to remove - */ - function removeAttestationId(bytes32 attestationId) external onlyOwner { - _removeAttestationId(attestationId); - } - - /** - * @notice Updates the verification configuration - * @dev Only callable by the contract owner - * @param newVerificationConfig The new verification configuration - */ - function setVerificationConfig( - ISelfVerificationRoot.VerificationConfig memory newVerificationConfig - ) external onlyOwner { - _setVerificationConfig(newVerificationConfig); - } - - /** - * @notice Get passport attributes for a specific token ID - * @param tokenId The token ID to query - * @return The passport attributes associated with the token - */ - function getPassportAttributes(uint256 tokenId) external view returns (SelfCircuitLibrary.PassportData memory) { - require(_exists(tokenId), "Token does not exist"); - return _passportAttributes[tokenId]; - } - - /** - * @notice Check if a user identifier has already minted an NFT - * @param userIdentifier The user identifier to check - * @return True if the user identifier has already minted, false otherwise - */ - function isUserIdentifierMinted(uint256 userIdentifier) external view returns (bool) { - return _mintedUserIdentifiers[userIdentifier]; - } - - /** - * @notice Check if the specified attestation ID is allowed - * @param attestationId The attestation ID to check - * @return True if the attestation ID is allowed, false otherwise - */ - function isAttestationIdAllowed(bytes32 attestationId) external view returns (bool) { - return _attestationIdToEnabled[attestationId]; - } - - /** - * @notice Get the current scope value - * @return The current scope value - */ - function getScope() external view returns (uint256) { - return _scope; - } - - /** - * @notice Get the current verification configuration - * @return The current verification configuration - */ - function getVerificationConfig() external view returns (ISelfVerificationRoot.VerificationConfig memory) { - return _getVerificationConfig(); - } - - // ==================================================== - // Override Functions from SelfVerificationRoot - // ==================================================== - - /** - * @notice Hook called after successful verification - handles NFT minting - * @dev Validates user identifier and mints passport NFT with extracted attributes - * @param userIdentifier The user identifier from the proof - * @param revealedDataPacked The packed revealed data from the proof - */ - function onBasicVerificationSuccess( - bytes32 /* attestationId */, - uint256 /* scope */, - uint256 userIdentifier, - uint256 /* nullifier */, - uint256 /* identityCommitmentRoot */, - uint256[] memory revealedDataPacked, - uint256[4] memory /* forbiddenCountriesListPacked */ - ) internal override { - // Check if user identifier is valid - if (userIdentifier == 0) { - revert InvalidUserIdentifier(); - } - - // Check if user identifier has already minted an NFT - if (_mintedUserIdentifiers[userIdentifier]) { - revert UserIdentifierAlreadyMinted(); - } - - // Convert dynamic array to fixed-size array for passport data (first 3 elements) - uint256[3] memory passportRevealedData; - for (uint256 i = 0; i < 3 && i < revealedDataPacked.length; i++) { - passportRevealedData[i] = revealedDataPacked[i]; - } - - // Extract passport data using SelfCircuitLibrary - SelfCircuitLibrary.PassportData memory attributes = SelfCircuitLibrary.extractPassportData( - passportRevealedData - ); - - // Mint NFT - uint256 tokenId = _tokenIdCounter++; - _mint(msg.sender, tokenId); - _passportAttributes[tokenId] = attributes; - _mintedUserIdentifiers[userIdentifier] = true; - - emit PassportNFTMinted(tokenId, msg.sender, attributes); - } - - // ==================================================== - // Internal Functions - // ==================================================== - - /** - * @notice Check if a token exists - * @param tokenId The token ID to check - * @return True if the token exists, false otherwise - */ - function _exists(uint256 tokenId) internal view returns (bool) { - return _ownerOf(tokenId) != address(0); - } -} + // // SPDX-License-Identifier: MIT +// pragma solidity 0.8.28; + +// import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +// import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +// import {ISelfVerificationRoot} from "../interfaces/ISelfVerificationRoot.sol"; + +// import {SelfCircuitLibrary} from "../libraries/SelfCircuitLibrary.sol"; +// import {SelfVerificationRoot} from "../abstract/SelfVerificationRoot.sol"; + +// /** +// * @title SelfPassportERC721 +// * @notice This contract issues ERC721 tokens based on verified passport credentials using self's verification infrastructure +// * @dev Inherits from SelfVerificationRoot for verification logic and ERC721 for NFT functionality +// */ +// contract SelfPassportERC721 is SelfVerificationRoot, ERC721, Ownable { +// using SelfCircuitLibrary for uint256[3]; + +// // ==================================================== +// // Storage Variables +// // ==================================================== + +// /// @notice Counter for token IDs +// uint256 private _tokenIdCounter; + +// /// @notice Mapping from token ID to passport attributes +// mapping(uint256 tokenId => SelfCircuitLibrary.PassportData passportAttributes) private _passportAttributes; + +// /// @notice Mapping to track minted user identifiers to prevent double minting +// mapping(uint256 userIdentifier => bool minted) private _mintedUserIdentifiers; + +// // ==================================================== +// // Events +// // ==================================================== + +// event PassportNFTMinted(uint256 indexed tokenId, address indexed owner, SelfCircuitLibrary.PassportData attributes); + +// // ==================================================== +// // Errors +// // ==================================================== + +// error UserIdentifierAlreadyMinted(); +// error InvalidUserIdentifier(); + +// // ==================================================== +// // Constructor +// // ==================================================== + +// /** +// * @notice Constructor for the SelfPassportERC721 contract +// * @param identityVerificationHubAddress The address of the Identity Verification Hub +// * @param scopeValue The expected proof scope for user registration +// * @param contractVersion The contract version for validation +// * @param attestationIdsList The expected attestation identifiers required in proofs +// * @param name The name of the NFT collection +// * @param symbol The symbol of the NFT collection +// */ +// constructor( +// address identityVerificationHubAddress, +// uint256 scopeValue, +// uint8 contractVersion, +// bytes32[] memory attestationIdsList, +// string memory name, +// string memory symbol +// ) +// SelfVerificationRoot(identityVerificationHubAddress, scopeValue, contractVersion, attestationIdsList) +// ERC721(name, symbol) +// Ownable(_msgSender()) +// {} + +// // ==================================================== +// // External/Public Functions +// // ==================================================== + +// /** +// * @notice Updates the scope used for verification +// * @dev Only callable by the contract owner +// * @param newScope The new scope to set +// */ +// function setScope(uint256 newScope) external onlyOwner { +// _setScope(newScope); +// } + +// /** +// * @notice Adds a new attestation ID to the allowed list +// * @dev Only callable by the contract owner +// * @param attestationId The attestation ID to add +// */ +// function addAttestationId(bytes32 attestationId) external onlyOwner { +// _addAttestationId(attestationId); +// } + +// /** +// * @notice Removes an attestation ID from the allowed list +// * @dev Only callable by the contract owner +// * @param attestationId The attestation ID to remove +// */ +// function removeAttestationId(bytes32 attestationId) external onlyOwner { +// _removeAttestationId(attestationId); +// } + +// /** +// * @notice Updates the verification configuration +// * @dev Only callable by the contract owner +// * @param newVerificationConfig The new verification configuration +// */ +// function setVerificationConfig( +// ISelfVerificationRoot.VerificationConfig memory newVerificationConfig +// ) external onlyOwner { +// _setVerificationConfig(newVerificationConfig); +// } + +// /** +// * @notice Get passport attributes for a specific token ID +// * @param tokenId The token ID to query +// * @return The passport attributes associated with the token +// */ +// function getPassportAttributes(uint256 tokenId) external view returns (SelfCircuitLibrary.PassportData memory) { +// require(_exists(tokenId), "Token does not exist"); +// return _passportAttributes[tokenId]; +// } + +// /** +// * @notice Check if a user identifier has already minted an NFT +// * @param userIdentifier The user identifier to check +// * @return True if the user identifier has already minted, false otherwise +// */ +// function isUserIdentifierMinted(uint256 userIdentifier) external view returns (bool) { +// return _mintedUserIdentifiers[userIdentifier]; +// } + +// /** +// * @notice Check if the specified attestation ID is allowed +// * @param attestationId The attestation ID to check +// * @return True if the attestation ID is allowed, false otherwise +// */ +// function isAttestationIdAllowed(bytes32 attestationId) external view returns (bool) { +// return _attestationIdToEnabled[attestationId]; +// } + +// /** +// * @notice Get the current scope value +// * @return The current scope value +// */ +// function getScope() external view returns (uint256) { +// return _scope; +// } + +// /** +// * @notice Get the current verification configuration +// * @return The current verification configuration +// */ +// function getVerificationConfig() external view returns (ISelfVerificationRoot.VerificationConfig memory) { +// return _getVerificationConfig(); +// } + +// // ==================================================== +// // Override Functions from SelfVerificationRoot +// // ==================================================== + +// /** +// * @notice Hook called after successful verification - handles NFT minting +// * @dev Validates user identifier and mints passport NFT with extracted attributes +// * @param userIdentifier The user identifier from the proof +// * @param revealedDataPacked The packed revealed data from the proof +// */ +// function onBasicVerificationSuccess( +// bytes32 /* attestationId */, +// uint256 /* scope */, +// uint256 userIdentifier, +// uint256 /* nullifier */, +// uint256 /* identityCommitmentRoot */, +// uint256[] memory revealedDataPacked, +// uint256[4] memory /* forbiddenCountriesListPacked */ +// ) internal override { +// // Check if user identifier is valid +// if (userIdentifier == 0) { +// revert InvalidUserIdentifier(); +// } + +// // Check if user identifier has already minted an NFT +// if (_mintedUserIdentifiers[userIdentifier]) { +// revert UserIdentifierAlreadyMinted(); +// } + +// // Convert dynamic array to fixed-size array for passport data (first 3 elements) +// uint256[3] memory passportRevealedData; +// for (uint256 i = 0; i < 3 && i < revealedDataPacked.length; i++) { +// passportRevealedData[i] = revealedDataPacked[i]; +// } + +// // Extract passport data using SelfCircuitLibrary +// SelfCircuitLibrary.PassportData memory attributes = SelfCircuitLibrary.extractPassportData( +// passportRevealedData +// ); + +// // Mint NFT +// uint256 tokenId = _tokenIdCounter++; +// _mint(msg.sender, tokenId); +// _passportAttributes[tokenId] = attributes; +// _mintedUserIdentifiers[userIdentifier] = true; + +// emit PassportNFTMinted(tokenId, msg.sender, attributes); +// } + +// // ==================================================== +// // Internal Functions +// // ==================================================== + +// /** +// * @notice Check if a token exists +// * @param tokenId The token ID to check +// * @return True if the token exists, false otherwise +// */ +// function _exists(uint256 tokenId) internal view returns (bool) { +// return _ownerOf(tokenId) != address(0); +// } +// } diff --git a/contracts/contracts/interfaces/IIdentityVerificationHubV2.sol b/contracts/contracts/interfaces/IIdentityVerificationHubV2.sol index 72ff5c324..cb566af36 100644 --- a/contracts/contracts/interfaces/IIdentityVerificationHubV2.sol +++ b/contracts/contracts/interfaces/IIdentityVerificationHubV2.sol @@ -3,101 +3,22 @@ pragma solidity 0.8.28; import {IRegisterCircuitVerifier} from "./IRegisterCircuitVerifier.sol"; import {IDscCircuitVerifier} from "./IDscCircuitVerifier.sol"; -import {IVcAndDiscloseCircuitVerifier} from "./IVcAndDiscloseCircuitVerifier.sol"; -import {CircuitConstants} from "../constants/CircuitConstants.sol"; +import {SelfStructs} from "../libraries/SelfStructs.sol"; /** * @title IIdentityVerificationHubV2 - * @notice Interface for the Identity Verification Hub for verifying zero-knowledge proofs using VC and Disclose circuits. - * @dev Defines data structures and external functions for verifying proofs and recovering human-readable data. + * @notice Interface for the Identity Verification Hub V2 for verifying zero-knowledge proofs. + * @dev Defines all external and public functions from IdentityVerificationHubImplV2. */ interface IIdentityVerificationHubV2 { + // ==================================================== + // External Functions + // ==================================================== + /** - * @notice Enum representing types of data that may be revealed. - */ - enum RevealedDataType { - ISSUING_STATE, // The issuing state of the passport. - NAME, // The full name of the passport holder. - PASSPORT_NUMBER, // The passport number. - NATIONALITY, // The nationality. - DATE_OF_BIRTH, // The date of birth. - GENDER, // The gender. - EXPIRY_DATE, // The passport expiry date. - OLDER_THAN, // The "older than" age verification value. - PASSPORT_NO_OFAC, // The passport number OFAC status. - NAME_AND_DOB_OFAC, // The name and date of birth OFAC verification result. - NAME_AND_YOB_OFAC // The name and year of birth OFAC verification result. - } - - /** - * @notice Structure representing the verification result of a VC and Disclose proof. - * @param attestationId The attestation identifier from the proof. - * @param scope The scope of the verification. - * @param userIdentifier Unique identifier for the user. - * @param nullifier A value used to prevent double registration. - * @param identityCommitmentRoot The root of the identity commitment. - * @param revealedDataPacked Packed revealed data. - * @param forbiddenCountriesListPacked Packed forbidden countries list. - */ - struct VcAndDiscloseVerificationResult { - uint256 attestationId; - uint256 scope; - uint256 userIdentifier; - uint256 nullifier; - uint256 identityCommitmentRoot; - uint256[3] revealedDataPacked; - uint256[4] forbiddenCountriesListPacked; - } - - struct IdCardVcAndDiscloseVerificationResult { - uint256 attestationId; - uint256 scope; - uint256 userIdentifier; - uint256 nullifier; - uint256 identityCommitmentRoot; - uint256[4] revealedDataPacked; - uint256[4] forbiddenCountriesListPacked; - } - - /** - * @notice Structure representing a hub proof for VC and Disclose verification. - * @param olderThanEnabled Flag indicating if the 'olderThan' check is required. - * @param olderThan Threshold age for verification. - * @param forbiddenCountriesEnabled Flag indicating if forbidden countries verification is required. - * @param forbiddenCountriesListPacked Packed forbidden countries list. - * @param ofacEnabled Array of flags indicating which OFAC checks are enabled. [passportNo, nameAndDob, nameAndYob] - * @param vcAndDiscloseProof The underlying VC and Disclose proof. - */ - struct VcAndDiscloseHubProof { - bool olderThanEnabled; - uint256 olderThan; - bool forbiddenCountriesEnabled; - uint256[4] forbiddenCountriesListPacked; - bool[3] ofacEnabled; - IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof vcAndDiscloseProof; - } - - struct IdCardVcAndDiscloseHubProof { - bool olderThanEnabled; - uint256 olderThan; - bool forbiddenCountriesEnabled; - uint256[4] forbiddenCountriesListPacked; - bool[2] ofacEnabled; - IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof vcAndDiscloseProof; - } - - /** - * @notice Verifies a VC and Disclose proof using unified bytes interface. - * @dev Supports both passport and ID card proofs through a unified interface. - * @param proofData Encoded proof data containing all necessary verification parameters. - * @return result Encoded verification result containing all relevant data. - */ - function verifyVcAndDisclose(bytes calldata proofData) external view returns (bytes memory result); - - /** - * @notice Registers a passport commitment using a register circuit proof. - * @dev Verifies the proof and then calls the Identity Registry to register the commitment. - * @param attestationId The attestation identifier. + * @notice Registers a commitment using a register circuit proof. + * @dev Verifies the register circuit proof and then calls the Identity Registry to register the commitment. + * @param attestationId The attestation ID. * @param registerCircuitVerifierId The identifier for the register circuit verifier to use. * @param registerCircuitProof The register circuit proof data. */ @@ -109,10 +30,10 @@ interface IIdentityVerificationHubV2 { /** * @notice Registers a DSC key commitment using a DSC circuit proof. - * @dev Verifies the DSC circuit proof before registering the DSC key commitment. - * @param attestationId The attestation identifier. - * @param dscCircuitVerifierId The identifier for the DSC circuit verifier to be used. - * @param dscCircuitProof The proof data for the DSC circuit. + * @dev Verifies the DSC proof and then calls the Identity Registry to register the dsc key commitment. + * @param attestationId The attestation ID. + * @param dscCircuitVerifierId The identifier for the DSC circuit verifier to use. + * @param dscCircuitProof The DSC circuit proof data. */ function registerDscKeyCommitment( bytes32 attestationId, @@ -121,75 +42,140 @@ interface IIdentityVerificationHubV2 { ) external; /** - * @notice Returns the address of the Identity Registry for a specific attestation type. - * @param attestationId The attestation identifier. - * @return registryAddr The address of the Identity Registry contract. - */ - function registry(bytes32 attestationId) external view returns (address registryAddr); - - /** - * @notice Returns the address of the VC and Disclose circuit verifier for a specific attestation type. - * @param attestationId The attestation identifier. - * @return verifierAddr The address of the VC and Disclose circuit verifier. + * @notice Sets verification config in V2 storage (owner only) + * @dev The configId is automatically generated from the config content using sha256(abi.encode(config)) + * @param config The verification configuration + * @return configId The generated config ID */ - function vcAndDiscloseCircuitVerifier(bytes32 attestationId) external view returns (address verifierAddr); + function setVerificationConfigV2( + SelfStructs.VerificationConfigV2 memory config + ) external returns (bytes32 configId); /** - * @notice Retrieves the register circuit verifier for a given signature type. - * @param typeId The signature type identifier. - * @return verifier The address of the register circuit verifier. + * @notice Main verification function with new structured input format + * @param baseVerificationInput The base verification input data + * @param userContextData The user context data */ - function sigTypeToRegisterCircuitVerifiers(uint256 typeId) external view returns (address verifier); - - /** - * @notice Retrieves the DSC circuit verifier for a given signature type. - * @param typeId The signature type identifier. - * @return verifier The address of the DSC circuit verifier. - */ - function sigTypeToDscCircuitVerifiers(uint256 typeId) external view returns (address verifier); + function verify(bytes calldata baseVerificationInput, bytes calldata userContextData) external; /** * @notice Updates the registry address. - * @param attestationId The attestation identifier. + * @param attestationId The attestation ID. * @param registryAddress The new registry address. */ function updateRegistry(bytes32 attestationId, address registryAddress) external; /** * @notice Updates the VC and Disclose circuit verifier address. - * @param attestationId The attestation identifier. + * @param attestationId The attestation ID. * @param vcAndDiscloseCircuitVerifierAddress The new VC and Disclose circuit verifier address. */ function updateVcAndDiscloseCircuit(bytes32 attestationId, address vcAndDiscloseCircuitVerifierAddress) external; /** * @notice Updates the register circuit verifier for a specific signature type. + * @param attestationId The attestation identifier. * @param typeId The signature type identifier. * @param verifierAddress The new register circuit verifier address. */ - function updateRegisterCircuitVerifier(uint256 typeId, address verifierAddress) external; + function updateRegisterCircuitVerifier(bytes32 attestationId, uint256 typeId, address verifierAddress) external; /** * @notice Updates the DSC circuit verifier for a specific signature type. + * @param attestationId The attestation identifier. * @param typeId The signature type identifier. * @param verifierAddress The new DSC circuit verifier address. */ - function updateDscVerifier(uint256 typeId, address verifierAddress) external; + function updateDscVerifier(bytes32 attestationId, uint256 typeId, address verifierAddress) external; /** * @notice Batch updates register circuit verifiers. + * @param attestationIds An array of attestation identifiers. * @param typeIds An array of signature type identifiers. * @param verifierAddresses An array of new register circuit verifier addresses. */ function batchUpdateRegisterCircuitVerifiers( + bytes32[] calldata attestationIds, uint256[] calldata typeIds, address[] calldata verifierAddresses ) external; /** * @notice Batch updates DSC circuit verifiers. + * @param attestationIds An array of attestation identifiers. * @param typeIds An array of signature type identifiers. * @param verifierAddresses An array of new DSC circuit verifier addresses. */ - function batchUpdateDscCircuitVerifiers(uint256[] calldata typeIds, address[] calldata verifierAddresses) external; + function batchUpdateDscCircuitVerifiers( + bytes32[] calldata attestationIds, + uint256[] calldata typeIds, + address[] calldata verifierAddresses + ) external; + + // ==================================================== + // External View Functions + // ==================================================== + + /** + * @notice Returns the registry address for a given attestation ID. + * @param attestationId The attestation ID to query. + * @return The registry address associated with the attestation ID. + */ + function registry(bytes32 attestationId) external view returns (address); + + /** + * @notice Returns the disclose verifier address for a given attestation ID. + * @param attestationId The attestation ID to query. + * @return The disclose verifier address associated with the attestation ID. + */ + function discloseVerifier(bytes32 attestationId) external view returns (address); + + /** + * @notice Returns the register circuit verifier address for a given attestation ID and type ID. + * @param attestationId The attestation ID to query. + * @param typeId The type ID to query. + * @return The register circuit verifier address associated with the attestation ID and type ID. + */ + function registerCircuitVerifiers(bytes32 attestationId, uint256 typeId) external view returns (address); + + /** + * @notice Returns the DSC circuit verifier address for a given attestation ID and type ID. + * @param attestationId The attestation ID to query. + * @param typeId The type ID to query. + * @return The DSC circuit verifier address associated with the attestation ID and type ID. + */ + function dscCircuitVerifiers(bytes32 attestationId, uint256 typeId) external view returns (address); + + /** + * @notice Returns the merkle root timestamp for a given attestation ID and root. + * @param attestationId The attestation ID to query. + * @param root The merkle root to query. + * @return The merkle root timestamp associated with the attestation ID and root. + */ + function rootTimestamp(bytes32 attestationId, uint256 root) external view returns (uint256); + + /** + * @notice Returns the identity commitment merkle root for a given attestation ID. + * @param attestationId The attestation ID to query. + * @return The identity commitment merkle root associated with the attestation ID. + */ + function getIdentityCommitmentMerkleRoot(bytes32 attestationId) external view returns (uint256); + + /** + * @notice Checks if a verification config exists + * @param configId The configuration identifier + * @return exists Whether the config exists + */ + function verificationConfigV2Exists(bytes32 configId) external view returns (bool exists); + + // ==================================================== + // Public Functions + // ==================================================== + + /** + * @notice Generates a config ID from a verification config + * @param config The verification configuration + * @return The generated config ID (sha256 hash of encoded config) + */ + function generateConfigId(SelfStructs.VerificationConfigV2 memory config) external pure returns (bytes32); } diff --git a/contracts/contracts/interfaces/ISelfVerificationRoot.sol b/contracts/contracts/interfaces/ISelfVerificationRoot.sol index b7b2cee01..9fa75bb47 100644 --- a/contracts/contracts/interfaces/ISelfVerificationRoot.sol +++ b/contracts/contracts/interfaces/ISelfVerificationRoot.sol @@ -1,15 +1,20 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.28; +/** + * @title ISelfVerificationRoot + * @notice Interface for self-verification infrastructure integration + * @dev Provides base functionality for verifying and disclosing identity credentials + */ interface ISelfVerificationRoot { - struct VerificationConfig { - bool olderThanEnabled; - uint256 olderThan; - bool forbiddenCountriesEnabled; - uint256[4] forbiddenCountriesListPacked; - bool[3] ofacEnabled; - } - + /** + * @notice Structure containing proof data for disclose circuits + * @dev Contains the proof elements required for zero-knowledge verification + * @param a First proof element + * @param b Second proof element (2x2 matrix) + * @param c Third proof element + * @param pubSignals Array of 21 public signals for the circuit + */ struct DiscloseCircuitProof { uint256[2] a; uint256[2][2] b; @@ -18,8 +23,51 @@ interface ISelfVerificationRoot { } /** - * @notice Verifies a self-proof using bytes-based relayer data - * @param relayerData Packed data from relayer in format: | 1 byte circuitVersion | 1 byte contractVersion | 30 bytes buffer | 32 bytes attestationId | 32 bytes scope | proof data | + * @notice Structure containing verified identity disclosure output data + * @dev Contains all disclosed identity information after successful verification + * @param attestationId Unique identifier for the identity documents + * @param userIdentifier Unique identifier for the user + * @param nullifier Unique nullifier to prevent double-spending + * @param forbiddenCountriesListPacked Packed representation of forbidden countries list + * @param issuingState The state/country that issued the identity document + * @param name Array of name components + * @param idNumber The identity document number + * @param nationality The nationality of the document holder + * @param dateOfBirth Date of birth in string format + * @param gender Gender of the document holder + * @param expiryDate Expiry date of the identity document + * @param olderThan Verified age threshold (e.g., 18 for adult verification) + * @param ofac Array of OFAC (Office of Foreign Assets Control) compliance flags + */ + struct GenericDiscloseOutputV2 { + bytes32 attestationId; + uint256 userIdentifier; + uint256 nullifier; + uint256[4] forbiddenCountriesListPacked; + string issuingState; + string[] name; + string idNumber; + string nationality; + string dateOfBirth; + string gender; + string expiryDate; + uint256 olderThan; + bool[3] ofac; + } + + /** + * @notice Verifies a self-proof using the bytes-based interface + * @dev Parses relayer data format and validates against contract settings before calling hub V2 + * @param proofPayload Packed data from relayer in format: | 32 bytes attestationId | proof data | + * @param userContextData User-defined data in format: | 32 bytes configId | 32 bytes destChainId | 32 bytes userIdentifier | data | + */ + function verifySelfProof(bytes calldata proofPayload, bytes calldata userContextData) external; + + /** + * @notice Callback function called upon successful verification + * @dev Only the identity verification hub V2 contract should call this function + * @param output The verification output data containing disclosed identity information + * @param userData The user-defined data passed through the verification process */ - function verifySelfProof(bytes calldata relayerData) external; + function onVerificationSuccess(bytes memory output, bytes memory userData) external; } diff --git a/contracts/contracts/libraries/CircuitAttributeHandler.sol b/contracts/contracts/libraries/CircuitAttributeHandler.sol index 88696e503..6f1429b3f 100644 --- a/contracts/contracts/libraries/CircuitAttributeHandler.sol +++ b/contracts/contracts/libraries/CircuitAttributeHandler.sol @@ -12,7 +12,7 @@ library CircuitAttributeHandler { /** * @dev Reverts when the provided character codes array does not contain enough data to extract an attribute. */ - error INSUFFICIENT_CHARCODE_LEN(); + error InsufficientCharcodeLen(); // Define constant start and end positions for each attribute uint256 private constant ISSUING_STATE_START = 2; @@ -179,7 +179,7 @@ library CircuitAttributeHandler { /** * @notice Extracts a substring from a specified range in the byte array. - * @dev Reverts with INSUFFICIENT_CHARCODE_LEN if the byte array's length is insufficient. + * @dev Reverts with InsufficientCharcodeLen if the byte array's length is insufficient. * @param charcodes The byte array containing the encoded passport attribute. * @param start The starting index (inclusive) of the attribute in the byte array. * @param end The ending index (inclusive) of the attribute in the byte array. @@ -191,7 +191,7 @@ library CircuitAttributeHandler { uint256 end ) internal pure returns (string memory) { if (charcodes.length <= end) { - revert INSUFFICIENT_CHARCODE_LEN(); + revert InsufficientCharcodeLen(); } bytes memory attributeBytes = new bytes(end - start + 1); for (uint256 i = start; i <= end; i++) { diff --git a/contracts/contracts/libraries/CircuitAttributeHandlerV2.sol b/contracts/contracts/libraries/CircuitAttributeHandlerV2.sol index 32d31ab99..5cdcd9433 100644 --- a/contracts/contracts/libraries/CircuitAttributeHandlerV2.sol +++ b/contracts/contracts/libraries/CircuitAttributeHandlerV2.sol @@ -3,6 +3,7 @@ pragma solidity 0.8.28; import {Formatter} from "./Formatter.sol"; import {AttestationId} from "../constants/AttestationId.sol"; +import {SelfStructs} from "./SelfStructs.sol"; /** * @title UnifiedAttributeHandler Library @@ -13,7 +14,7 @@ library CircuitAttributeHandlerV2 { /** * @dev Reverts when the provided character codes array does not contain enough data to extract an attribute. */ - error INSUFFICIENT_CHARCODE_LEN(); + error InsufficientCharcodeLen(); /** * @notice Structure containing field positions for a specific attestation type. @@ -195,9 +196,9 @@ library CircuitAttributeHandlerV2 { * @param charcodes The byte array containing attribute data. * @return The OFAC status for document number check as a uint256. */ - function getDocumentNoOfac(bytes32 attestationId, bytes memory charcodes) internal pure returns (uint256) { + function getDocumentNoOfac(bytes32 attestationId, bytes memory charcodes) internal pure returns (bool) { FieldPositions memory positions = getFieldPositions(attestationId); - return uint8(charcodes[positions.ofacStart]); + return uint8(charcodes[positions.ofacStart]) == 1; } /** @@ -206,12 +207,12 @@ library CircuitAttributeHandlerV2 { * @param charcodes The byte array containing attribute data. * @return The OFAC status for name and DOB check as a uint256. */ - function getNameAndDobOfac(bytes32 attestationId, bytes memory charcodes) internal pure returns (uint256) { + function getNameAndDobOfac(bytes32 attestationId, bytes memory charcodes) internal pure returns (bool) { FieldPositions memory positions = getFieldPositions(attestationId); if (attestationId == AttestationId.E_PASSPORT) { - return uint8(charcodes[positions.ofacStart + 1]); + return uint8(charcodes[positions.ofacStart + 1]) == 1; } else { - return uint8(charcodes[positions.ofacStart]); + return uint8(charcodes[positions.ofacStart]) == 1; } } @@ -221,12 +222,12 @@ library CircuitAttributeHandlerV2 { * @param charcodes The byte array containing attribute data. * @return The OFAC status for name and YOB check as a uint256. */ - function getNameAndYobOfac(bytes32 attestationId, bytes memory charcodes) internal pure returns (uint256) { + function getNameAndYobOfac(bytes32 attestationId, bytes memory charcodes) internal pure returns (bool) { FieldPositions memory positions = getFieldPositions(attestationId); if (attestationId == AttestationId.E_PASSPORT) { - return uint8(charcodes[positions.ofacStart + 2]); + return uint8(charcodes[positions.ofacStart + 2]) == 1; } else { - return uint8(charcodes[positions.ofacStart + 1]); + return uint8(charcodes[positions.ofacStart + 1]) == 1; } } @@ -246,22 +247,23 @@ library CircuitAttributeHandlerV2 { bool checkNameAndDob, bool checkNameAndYob ) internal pure returns (bool) { - bool documentNoResult = true; - bool nameAndDobResult = true; - bool nameAndYobResult = true; + bool documentNoResult = true; // Default to true (no violation) if not checking + bool nameAndDobResult = true; // Default to true (no violation) if not checking + bool nameAndYobResult = true; // Default to true (no violation) if not checking if (checkDocumentNo && attestationId == AttestationId.E_PASSPORT) { - documentNoResult = getDocumentNoOfac(attestationId, charcodes) == 1; + documentNoResult = getDocumentNoOfac(attestationId, charcodes); } if (checkNameAndDob) { - nameAndDobResult = getNameAndDobOfac(attestationId, charcodes) == 1; + nameAndDobResult = getNameAndDobOfac(attestationId, charcodes); } if (checkNameAndYob) { - nameAndYobResult = getNameAndYobOfac(attestationId, charcodes) == 1; + nameAndYobResult = getNameAndYobOfac(attestationId, charcodes); } + // Return true if all enabled checks indicate no OFAC violations (all return true) return documentNoResult && nameAndDobResult && nameAndYobResult; } @@ -293,7 +295,7 @@ library CircuitAttributeHandlerV2 { uint256 end ) internal pure returns (string memory) { if (charcodes.length <= end) { - revert INSUFFICIENT_CHARCODE_LEN(); + revert InsufficientCharcodeLen(); } bytes memory attributeBytes = new bytes(end - start + 1); for (uint256 i = start; i <= end; i++) { @@ -319,6 +321,6 @@ library CircuitAttributeHandlerV2 { * @dev Maintained for backward compatibility. Use getDocumentNoOfac instead. */ function getPassportNoOfac(bytes memory charcodes) internal pure returns (uint256) { - return getDocumentNoOfac(AttestationId.E_PASSPORT, charcodes); + return getDocumentNoOfac(AttestationId.E_PASSPORT, charcodes) ? 1 : 0; } } diff --git a/contracts/contracts/libraries/CustomVerifier.sol b/contracts/contracts/libraries/CustomVerifier.sol new file mode 100644 index 000000000..e94d829eb --- /dev/null +++ b/contracts/contracts/libraries/CustomVerifier.sol @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; +import {CircuitAttributeHandlerV2} from "./CircuitAttributeHandlerV2.sol"; +import {AttestationId} from "../constants/AttestationId.sol"; +import {SelfStructs} from "./SelfStructs.sol"; +import {CircuitAttributeHandlerV2} from "./CircuitAttributeHandlerV2.sol"; +import {Formatter} from "./Formatter.sol"; +import {GenericFormatter} from "./GenericFormatter.sol"; + +library CustomVerifier { + error InvalidAttestationId(); + error InvalidOfacCheck(); + error InvalidForbiddenCountries(); + error InvalidOlderThan(); + + /** + * @notice Verifies the configuration of the custom verifier. + * @param attestationId The attestation ID. + * @param config The verification config of the custom verifier. + * @param proofOutput The proof output of the custom verifier. + * @return genericDiscloseOutput The generic disclose output. + */ + function customVerify( + bytes32 attestationId, + bytes calldata config, + bytes calldata proofOutput + ) external pure returns (SelfStructs.GenericDiscloseOutputV2 memory) { + SelfStructs.VerificationConfigV2 memory verificationConfig = GenericFormatter.verificationConfigFromBytes( + config + ); + + if (attestationId == AttestationId.E_PASSPORT) { + SelfStructs.PassportOutput memory passportOutput = abi.decode(proofOutput, (SelfStructs.PassportOutput)); + return CustomVerifier.verifyPassport(verificationConfig, passportOutput); + } else if (attestationId == AttestationId.EU_ID_CARD) { + SelfStructs.EuIdOutput memory idCardOutput = abi.decode(proofOutput, (SelfStructs.EuIdOutput)); + return CustomVerifier.verifyIdCard(verificationConfig, idCardOutput); + } else { + revert InvalidAttestationId(); + } + } + + /** + * @notice Verifies a passport output. + * @param verificationConfig The verification configuration. + * @param passportOutput The passport output from the circuit. + * @return genericDiscloseOutput The generic disclose output. + */ + function verifyPassport( + SelfStructs.VerificationConfigV2 memory verificationConfig, + SelfStructs.PassportOutput memory passportOutput + ) internal pure returns (SelfStructs.GenericDiscloseOutputV2 memory) { + if ( + verificationConfig.ofacEnabled[0] || verificationConfig.ofacEnabled[1] || verificationConfig.ofacEnabled[2] + ) { + if ( + !CircuitAttributeHandlerV2.compareOfac( + AttestationId.E_PASSPORT, + passportOutput.revealedDataPacked, + verificationConfig.ofacEnabled[0], + verificationConfig.ofacEnabled[1], + verificationConfig.ofacEnabled[2] + ) + ) { + revert InvalidOfacCheck(); + } + } + if (verificationConfig.forbiddenCountriesEnabled) { + for (uint256 i = 0; i < 4; i++) { + if ( + passportOutput.forbiddenCountriesListPacked[i] != verificationConfig.forbiddenCountriesListPacked[i] + ) { + revert InvalidForbiddenCountries(); + } + } + } + + if (verificationConfig.olderThanEnabled) { + if ( + !CircuitAttributeHandlerV2.compareOlderThan( + AttestationId.E_PASSPORT, + passportOutput.revealedDataPacked, + verificationConfig.olderThan + ) + ) { + revert InvalidOlderThan(); + } + } + + SelfStructs.GenericDiscloseOutputV2 memory genericDiscloseOutput = SelfStructs.GenericDiscloseOutputV2({ + attestationId: AttestationId.E_PASSPORT, + userIdentifier: passportOutput.userIdentifier, + nullifier: passportOutput.nullifier, + forbiddenCountriesListPacked: passportOutput.forbiddenCountriesListPacked, + issuingState: CircuitAttributeHandlerV2.getIssuingState( + AttestationId.E_PASSPORT, + passportOutput.revealedDataPacked + ), + name: CircuitAttributeHandlerV2.getName(AttestationId.E_PASSPORT, passportOutput.revealedDataPacked), + idNumber: CircuitAttributeHandlerV2.getDocumentNumber( + AttestationId.E_PASSPORT, + passportOutput.revealedDataPacked + ), + nationality: CircuitAttributeHandlerV2.getNationality( + AttestationId.E_PASSPORT, + passportOutput.revealedDataPacked + ), + dateOfBirth: CircuitAttributeHandlerV2.getDateOfBirth( + AttestationId.E_PASSPORT, + passportOutput.revealedDataPacked + ), + gender: CircuitAttributeHandlerV2.getGender(AttestationId.E_PASSPORT, passportOutput.revealedDataPacked), + expiryDate: CircuitAttributeHandlerV2.getExpiryDate( + AttestationId.E_PASSPORT, + passportOutput.revealedDataPacked + ), + olderThan: verificationConfig.olderThan, + ofac: [ + CircuitAttributeHandlerV2.getDocumentNoOfac( + AttestationId.E_PASSPORT, + passportOutput.revealedDataPacked + ), + CircuitAttributeHandlerV2.getNameAndDobOfac( + AttestationId.E_PASSPORT, + passportOutput.revealedDataPacked + ), + CircuitAttributeHandlerV2.getNameAndYobOfac(AttestationId.E_PASSPORT, passportOutput.revealedDataPacked) + ] + }); + + return genericDiscloseOutput; + } + + /** + * @notice Verifies an ID card output. + * @param verificationConfig The verification configuration. + * @param idCardOutput The ID card output from the circuit. + * @return genericDiscloseOutput The generic disclose output. + */ + function verifyIdCard( + SelfStructs.VerificationConfigV2 memory verificationConfig, + SelfStructs.EuIdOutput memory idCardOutput + ) internal pure returns (SelfStructs.GenericDiscloseOutputV2 memory) { + if (verificationConfig.ofacEnabled[0] || verificationConfig.ofacEnabled[1]) { + if ( + !CircuitAttributeHandlerV2.compareOfac( + AttestationId.EU_ID_CARD, + idCardOutput.revealedDataPacked, + false, + verificationConfig.ofacEnabled[0], + verificationConfig.ofacEnabled[1] + ) + ) { + revert InvalidOfacCheck(); + } + } + + if (verificationConfig.forbiddenCountriesEnabled) { + for (uint256 i = 0; i < 4; i++) { + if ( + idCardOutput.forbiddenCountriesListPacked[i] != verificationConfig.forbiddenCountriesListPacked[i] + ) { + revert InvalidForbiddenCountries(); + } + } + } + + if (verificationConfig.olderThanEnabled) { + if ( + !CircuitAttributeHandlerV2.compareOlderThan( + AttestationId.EU_ID_CARD, + idCardOutput.revealedDataPacked, + verificationConfig.olderThan + ) + ) { + revert InvalidOlderThan(); + } + } + + SelfStructs.GenericDiscloseOutputV2 memory genericDiscloseOutput = SelfStructs.GenericDiscloseOutputV2({ + attestationId: AttestationId.EU_ID_CARD, + userIdentifier: idCardOutput.userIdentifier, + nullifier: idCardOutput.nullifier, + forbiddenCountriesListPacked: idCardOutput.forbiddenCountriesListPacked, + issuingState: CircuitAttributeHandlerV2.getIssuingState( + AttestationId.EU_ID_CARD, + idCardOutput.revealedDataPacked + ), + name: CircuitAttributeHandlerV2.getName(AttestationId.EU_ID_CARD, idCardOutput.revealedDataPacked), + idNumber: CircuitAttributeHandlerV2.getDocumentNumber( + AttestationId.EU_ID_CARD, + idCardOutput.revealedDataPacked + ), + nationality: CircuitAttributeHandlerV2.getNationality( + AttestationId.EU_ID_CARD, + idCardOutput.revealedDataPacked + ), + dateOfBirth: CircuitAttributeHandlerV2.getDateOfBirth( + AttestationId.EU_ID_CARD, + idCardOutput.revealedDataPacked + ), + gender: CircuitAttributeHandlerV2.getGender(AttestationId.EU_ID_CARD, idCardOutput.revealedDataPacked), + expiryDate: CircuitAttributeHandlerV2.getExpiryDate( + AttestationId.EU_ID_CARD, + idCardOutput.revealedDataPacked + ), + olderThan: verificationConfig.olderThan, + ofac: [ + false, + CircuitAttributeHandlerV2.getNameAndDobOfac(AttestationId.EU_ID_CARD, idCardOutput.revealedDataPacked), + CircuitAttributeHandlerV2.getNameAndYobOfac(AttestationId.EU_ID_CARD, idCardOutput.revealedDataPacked) + ] + }); + + return genericDiscloseOutput; + } +} diff --git a/contracts/contracts/libraries/Formatter.sol b/contracts/contracts/libraries/Formatter.sol index a39947f3d..7c5a8d96c 100644 --- a/contracts/contracts/libraries/Formatter.sol +++ b/contracts/contracts/libraries/Formatter.sol @@ -154,6 +154,7 @@ library Formatter { * @param publicSignals A packed uint256 containing encoded forbidden country data. * @return forbiddenCountries An array of strings representing the forbidden country codes. */ + // TODO: look at this function a bit function extractForbiddenCountriesFromPacked( uint256[4] memory publicSignals ) internal pure returns (string[MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH] memory forbiddenCountries) { @@ -164,33 +165,47 @@ library Formatter { } for (uint256 j = 0; j < MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH; j++) { - uint256 byteIndex = j * 3; + uint256 byteIndex = (j * 3) % 93; + uint256 index = j / 31; - if (byteIndex + 2 < 32) { + if (byteIndex + 2 < 31) { uint256 shift = byteIndex * 8; uint256 mask = 0xFFFFFF; - uint256 packedData = (publicSignals[0] >> shift) & mask; - forbiddenCountries[j] = string(abi.encodePacked(uint24(packedData))); - } else if (byteIndex < 32) { - uint256 bytesFrom0 = 32 - byteIndex; - uint256 bytesTo1 = 3 - bytesFrom0; - - uint256 shift0 = byteIndex * 8; - uint256 mask0 = (1 << (bytesFrom0 * 8)) - 1; - uint256 part0 = (publicSignals[0] >> shift0) & mask0; - - uint256 shift1 = 0; - uint256 mask1 = (1 << (bytesTo1 * 8)) - 1; - uint256 part1 = (publicSignals[1] >> shift1) & mask1; - - uint256 combined = (part1 << (bytesFrom0 * 8)) | part0; + uint256 packedData = (publicSignals[index * 3] >> shift) & mask; + uint256 reversedPackedData = ((packedData & 0xff) << 16) | + ((packedData & 0xff00)) | + ((packedData & 0xff0000) >> 16); + forbiddenCountries[j] = string(abi.encodePacked(uint24(reversedPackedData))); + } else if (byteIndex < 31) { + uint256 part0 = (publicSignals[0] >> (byteIndex * 8)); + uint256 part1 = publicSignals[1] & 0x00ffff; + uint256 reversedPart1 = ((part1 & 0xff) << 8) | ((part1 & 0xff00) >> 8); + uint256 combined = reversedPart1 | (part0 << 16); forbiddenCountries[j] = string(abi.encodePacked(uint24(combined))); - } else { - uint256 byteIndexIn1 = byteIndex - 32; + } else if (byteIndex + 2 < 62) { + uint256 byteIndexIn1 = byteIndex - 31; uint256 shift = byteIndexIn1 * 8; uint256 mask = 0xFFFFFF; uint256 packedData = (publicSignals[1] >> shift) & mask; - forbiddenCountries[j] = string(abi.encodePacked(uint24(packedData))); + uint256 reversedPackedData = ((packedData & 0xff) << 16) | + ((packedData & 0xff00)) | + ((packedData & 0xff0000) >> 16); + forbiddenCountries[j] = string(abi.encodePacked(uint24(reversedPackedData))); + } else if (byteIndex < 62) { + uint256 part0 = (publicSignals[1] >> ((byteIndex - 31) * 8)) & 0x00ffff; + uint256 reversedPart0 = ((part0 & 0xff) << 8) | ((part0 & 0xff00) >> 8); + uint256 part1 = publicSignals[2] & 0x0000ff; + uint256 combined = part1 | (reversedPart0 << 8); + forbiddenCountries[j] = string(abi.encodePacked(uint24(combined))); + } else if (byteIndex < 93) { + uint256 byteIndexIn1 = byteIndex - 62; + uint256 shift = byteIndexIn1 * 8; + uint256 mask = 0xFFFFFF; + uint256 packedData = (publicSignals[2] >> shift) & mask; + uint256 reversedPackedData = ((packedData & 0xff) << 16) | + ((packedData & 0xff00)) | + ((packedData & 0xff0000) >> 16); + forbiddenCountries[j] = string(abi.encodePacked(uint24(reversedPackedData))); } } diff --git a/contracts/contracts/libraries/GenericFormatter.sol b/contracts/contracts/libraries/GenericFormatter.sol new file mode 100644 index 000000000..da16da46c --- /dev/null +++ b/contracts/contracts/libraries/GenericFormatter.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {SelfStructs} from "./SelfStructs.sol"; + +struct GenericVerificationStruct { + uint8 attestationId; + bytes verificationConfig; +} + +library GenericFormatter { + /** + * @notice Converts a VerificationConfigV1 struct to a VerificationConfigV2 struct. + * @param verificationConfigV1 The VerificationConfigV1 struct to convert. + * @return verificationConfig The converted VerificationConfigV2 struct. + */ + function fromV1Config( + SelfStructs.VerificationConfigV1 memory verificationConfigV1 + ) internal pure returns (SelfStructs.VerificationConfigV2 memory verificationConfig) { + verificationConfig = SelfStructs.VerificationConfigV2({ + olderThanEnabled: verificationConfigV1.olderThanEnabled, + olderThan: verificationConfigV1.olderThan, + forbiddenCountriesEnabled: verificationConfigV1.forbiddenCountriesEnabled, + forbiddenCountriesListPacked: verificationConfigV1.forbiddenCountriesListPacked, + ofacEnabled: verificationConfigV1.ofacEnabled + }); + } + + /** + * @notice Converts a bytes array to the latest VerificationConfig struct. + * @param verificationConfig The bytes array to convert. + * @return verificationConfigV2 The converted VerificationConfig struct. + */ + function verificationConfigFromBytes( + bytes memory verificationConfig + ) internal pure returns (SelfStructs.VerificationConfigV2 memory verificationConfigV2) { + return abi.decode(verificationConfig, (SelfStructs.VerificationConfigV2)); + } + + /** + * @notice Formats a VerificationConfigV1 struct to the latest verification config bytes array. + * @param verificationConfigV1 The VerificationConfigV1 struct to format. + * @return v1ConfigBytes The latest verification config formatted bytes array. + */ + function formatV1Config( + SelfStructs.VerificationConfigV1 memory verificationConfigV1 + ) internal pure returns (bytes memory v1ConfigBytes) { + SelfStructs.VerificationConfigV2 memory verificationConfigV2 = fromV1Config(verificationConfigV1); + return abi.encode(verificationConfigV2); + } + + /** + * @notice Formats a VerificationConfigV2 struct to the latest verification config bytes array. + * @param verificationConfigV2 The VerificationConfigV2 struct to format. + * @return v2ConfigBytes The latest verification config formatted bytes array. + */ + function formatV2Config( + SelfStructs.VerificationConfigV2 memory verificationConfigV2 + ) internal pure returns (bytes memory v2ConfigBytes) { + return abi.encode(verificationConfigV2); + } + + /** + * @notice Formats a GenericDiscloseOutputV2 struct to the latest generic disclose output bytes array. + * @param genericDiscloseOutput The GenericDiscloseOutputV2 struct to format. + * @return v2StructBytes The latest generic disclose output formatted bytes array. + */ + function toV2Struct( + SelfStructs.GenericDiscloseOutputV2 memory genericDiscloseOutput + ) internal pure returns (bytes memory v2StructBytes) { + v2StructBytes = abi.encode(genericDiscloseOutput); + } +} diff --git a/contracts/contracts/libraries/IdCardAttributeHandler.sol b/contracts/contracts/libraries/IdCardAttributeHandler.sol index 9207b439d..03c587a87 100644 --- a/contracts/contracts/libraries/IdCardAttributeHandler.sol +++ b/contracts/contracts/libraries/IdCardAttributeHandler.sol @@ -13,7 +13,7 @@ library IdCardAttributeHandler { /** * @dev Reverts when the provided character codes array does not contain enough data to extract an attribute. */ - error INSUFFICIENT_CHARCODE_LEN(); + error InsufficientCharcodeLen(); // Define constant start and end positions for each attribute uint256 private constant ISSUING_STATE_START = 2; @@ -177,7 +177,7 @@ library IdCardAttributeHandler { /** * @notice Extracts a substring from a specified range in the byte array. - * @dev Reverts with INSUFFICIENT_CHARCODE_LEN if the byte array's length is insufficient. + * @dev Reverts with InsufficientCharcodeLen if the byte array's length is insufficient. * @param charcodes The byte array containing the encoded passport attribute. * @param start The starting index (inclusive) of the attribute in the byte array. * @param end The ending index (inclusive) of the attribute in the byte array. @@ -189,7 +189,7 @@ library IdCardAttributeHandler { uint256 end ) internal pure returns (string memory) { if (charcodes.length <= end) { - revert INSUFFICIENT_CHARCODE_LEN(); + revert InsufficientCharcodeLen(); } bytes memory attributeBytes = new bytes(end - start + 1); for (uint256 i = start; i <= end; i++) { diff --git a/contracts/contracts/libraries/SelfStructs.sol b/contracts/contracts/libraries/SelfStructs.sol new file mode 100644 index 000000000..14b1fbb99 --- /dev/null +++ b/contracts/contracts/libraries/SelfStructs.sol @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +/** + * @title SelfStructs + * @dev Library containing data structures for Self protocol identity verification + * @notice Defines structs for passport verification, EU ID verification, and generic disclosure outputs + */ +library SelfStructs { + /** + * @dev Header structure for Hub input containing contract version and scope information + * @param contractVersion Version of the contract being used + * @param scope Scope identifier for the verification request + * @param attestationId Unique identifier for the attestation + */ + struct HubInputHeader { + uint8 contractVersion; + uint256 scope; + bytes32 attestationId; + } + + /** + * @dev Output structure for passport verification results + * @param attestationId Unique identifier for the attestation + * @param revealedDataPacked Packed binary data of revealed information + * @param userIdentifier Unique identifier for the user + * @param nullifier Cryptographic nullifier to prevent double-spending + * @param forbiddenCountriesListPacked Packed list of forbidden countries (4 uint256 array) + */ + struct PassportOutput { + uint256 attestationId; + bytes revealedDataPacked; + uint256 userIdentifier; + uint256 nullifier; + uint256[4] forbiddenCountriesListPacked; + } + + /** + * @dev Output structure for EU ID verification results + * @param attestationId Unique identifier for the attestation + * @param revealedDataPacked Packed binary data of revealed information + * @param userIdentifier Unique identifier for the user + * @param nullifier Cryptographic nullifier to prevent double-spending + * @param forbiddenCountriesListPacked Packed list of forbidden countries (4 uint256 array) + */ + struct EuIdOutput { + uint256 attestationId; + bytes revealedDataPacked; + uint256 userIdentifier; + uint256 nullifier; + uint256[4] forbiddenCountriesListPacked; + } + + /// @dev OFAC verification mode: Passport number only + uint256 constant passportNoOfac = 0; + /// @dev OFAC verification mode: Name and date of birth + uint256 constant nameAndDobOfac = 1; + /// @dev OFAC verification mode: Name and year of birth + uint256 constant nameAndYobOfac = 2; + + /** + * @dev Generic disclosure output structure (Version 2) with detailed personal information + * @param attestationId Unique identifier for the attestation + * @param userIdentifier Unique identifier for the user + * @param nullifier Cryptographic nullifier to prevent double-spending + * @param forbiddenCountriesListPacked Packed list of forbidden countries (4 uint256 array) + * @param issuingState Country or state that issued the document + * @param name Array of name components (first, middle, last names) + * @param idNumber Government-issued identification number + * @param nationality Nationality of the document holder + * @param dateOfBirth Date of birth in string format + * @param gender Gender of the document holder + * @param expiryDate Document expiration date in string format + * @param olderThan Minimum age verification result + * @param ofac Array of OFAC (Office of Foreign Assets Control) verification results for different modes + */ + struct GenericDiscloseOutputV2 { + bytes32 attestationId; + uint256 userIdentifier; + uint256 nullifier; + uint256[4] forbiddenCountriesListPacked; + string issuingState; + string[] name; + string idNumber; + string nationality; + string dateOfBirth; + string gender; + string expiryDate; + uint256 olderThan; + bool[3] ofac; + } + + /** + * @dev Verification configuration structure (Version 1) + * @param olderThanEnabled Whether minimum age verification is enabled + * @param olderThan Minimum age requirement + * @param forbiddenCountriesEnabled Whether forbidden countries check is enabled + * @param forbiddenCountriesListPacked Packed list of forbidden countries (4 uint256 array) + * @param ofacEnabled Array of boolean flags for different OFAC verification modes + */ + struct VerificationConfigV1 { + bool olderThanEnabled; + uint256 olderThan; + bool forbiddenCountriesEnabled; + uint256[4] forbiddenCountriesListPacked; + bool[3] ofacEnabled; + } + + /** + * @dev Verification configuration structure (Version 2) + * @param olderThanEnabled Whether minimum age verification is enabled + * @param olderThan Minimum age requirement + * @param forbiddenCountriesEnabled Whether forbidden countries check is enabled + * @param forbiddenCountriesListPacked Packed list of forbidden countries (4 uint256 array) + * @param ofacEnabled Array of boolean flags for different OFAC verification modes + */ + struct VerificationConfigV2 { + bool olderThanEnabled; + uint256 olderThan; + bool forbiddenCountriesEnabled; + uint256[4] forbiddenCountriesListPacked; + bool[3] ofacEnabled; + } +} diff --git a/contracts/contracts/registry/IdentityRegistryIdCard.sol b/contracts/contracts/registry/IdentityRegistryIdCard.sol deleted file mode 100644 index e41dfda66..000000000 --- a/contracts/contracts/registry/IdentityRegistryIdCard.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.28; - -import {ProxyRoot} from "../upgradeable/ProxyRoot.sol"; - -/** - * @title IdentityRegistry - * @notice Acts as an upgradeable proxy for the identity registry. - * @dev Inherits from ProxyRoot to delegate calls to an implementation contract. - * The constructor initializes the proxy using the provided implementation address and initialization data. - */ -contract IdentityRegistryIdCard is ProxyRoot { - /** - * @notice Creates a new instance of the IdentityRegistry proxy. - * @param _logic The address of the initial implementation contract that contains the registry logic. - * @param _data The initialization data passed to the implementation during deployment. - */ - constructor(address _logic, bytes memory _data) ProxyRoot(_logic, _data) {} -} diff --git a/contracts/contracts/registry/IdentityRegistryIdCardImplV1.sol b/contracts/contracts/registry/IdentityRegistryIdCardImplV1.sol index 270270716..068ef2e63 100644 --- a/contracts/contracts/registry/IdentityRegistryIdCardImplV1.sol +++ b/contracts/contracts/registry/IdentityRegistryIdCardImplV1.sol @@ -2,11 +2,8 @@ pragma solidity 0.8.28; import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; -import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; -import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {InternalLeanIMT, LeanIMTData} from "@zk-kit/imt.sol/internal/InternalLeanIMT.sol"; import {IIdentityRegistryIdCardV1} from "../interfaces/IIdentityRegistryIdCardV1.sol"; -import {IIdentityVerificationHubV1} from "../interfaces/IIdentityVerificationHubV1.sol"; import {ImplRoot} from "../upgradeable/ImplRoot.sol"; /** * @notice ⚠️ CRITICAL STORAGE LAYOUT WARNING ⚠️ diff --git a/contracts/contracts/tests/TestCustomVerifier.sol b/contracts/contracts/tests/TestCustomVerifier.sol new file mode 100644 index 000000000..077233905 --- /dev/null +++ b/contracts/contracts/tests/TestCustomVerifier.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {CustomVerifier} from "../libraries/CustomVerifier.sol"; +import {SelfStructs} from "../libraries/SelfStructs.sol"; + +contract TestCustomVerifier { + function testCustomVerify( + bytes32 attestationId, + bytes calldata config, + bytes calldata proofOutput + ) external pure returns (SelfStructs.GenericDiscloseOutputV2 memory) { + return CustomVerifier.customVerify(attestationId, config, proofOutput); + } +} diff --git a/contracts/contracts/tests/TestSelfVerificationRoot.sol b/contracts/contracts/tests/TestSelfVerificationRoot.sol new file mode 100644 index 000000000..ee136363a --- /dev/null +++ b/contracts/contracts/tests/TestSelfVerificationRoot.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import {SelfVerificationRoot} from "../abstract/SelfVerificationRoot.sol"; +import {ISelfVerificationRoot} from "../interfaces/ISelfVerificationRoot.sol"; + +/** + * @title TestSelfVerificationRoot + * @notice Test implementation of SelfVerificationRoot for testing purposes + * @dev This contract provides a concrete implementation of the abstract SelfVerificationRoot + */ +contract TestSelfVerificationRoot is SelfVerificationRoot { + // Storage for testing purposes + bool public verificationSuccessful; + ISelfVerificationRoot.GenericDiscloseOutputV2 public lastOutput; + bytes public lastUserData; + + // Events for testing + event VerificationCompleted(ISelfVerificationRoot.GenericDiscloseOutputV2 output, bytes userData); + + /** + * @notice Constructor for the test contract + * @param identityVerificationHubV2Address The address of the Identity Verification Hub V2 + * @param scopeValue The expected proof scope for user registration + */ + constructor( + address identityVerificationHubV2Address, + uint256 scopeValue + ) SelfVerificationRoot(identityVerificationHubV2Address, scopeValue) {} + + /** + * @notice Implementation of customVerificationHook for testing + * @dev This function is called by onVerificationSuccess after hub address validation + * @param output The verification output from the hub + * @param userData The user data passed through verification + */ + function customVerificationHook( + ISelfVerificationRoot.GenericDiscloseOutputV2 memory output, + bytes memory userData + ) internal override { + verificationSuccessful = true; + lastOutput = output; + lastUserData = userData; + + emit VerificationCompleted(output, userData); + } + + /** + * @notice Reset the test state + */ + function resetTestState() external { + verificationSuccessful = false; + lastOutput = ISelfVerificationRoot.GenericDiscloseOutputV2({ + attestationId: bytes32(0), + userIdentifier: 0, + nullifier: 0, + forbiddenCountriesListPacked: [uint256(0), uint256(0), uint256(0), uint256(0)], + issuingState: "", + name: new string[](3), + idNumber: "", + nationality: "", + dateOfBirth: "", + gender: "", + expiryDate: "", + olderThan: 0, + ofac: [false, false, false] + }); + lastUserData = ""; + } + + /** + * @notice Expose the internal _setScope function for testing + * @param newScope The new scope value to set + */ + function setScope(uint256 newScope) external { + _setScope(newScope); + } + + /** + * @notice Test function to simulate calling onVerificationSuccess from hub + * @dev This function is only for testing purposes to verify access control + * @param output The verification output + * @param userData The user data + */ + function testOnVerificationSuccess(bytes memory output, bytes memory userData) external { + // This should fail if called by anyone other than the hub + onVerificationSuccess(output, userData); + } +} diff --git a/contracts/contracts/tests/testGenericFormatter.sol b/contracts/contracts/tests/testGenericFormatter.sol new file mode 100644 index 000000000..3f563a321 --- /dev/null +++ b/contracts/contracts/tests/testGenericFormatter.sol @@ -0,0 +1,34 @@ +import {GenericFormatter} from "../libraries/GenericFormatter.sol"; +import {SelfStructs} from "../libraries/SelfStructs.sol"; + +contract TestGenericFormatter { + function testFromV1Config( + SelfStructs.VerificationConfigV1 memory verificationConfigV1 + ) public pure returns (SelfStructs.VerificationConfigV2 memory verificationConfigV2) { + verificationConfigV2 = GenericFormatter.fromV1Config(verificationConfigV1); + } + + function testVerificationConfigFromBytes( + bytes memory verificationConfig + ) public pure returns (SelfStructs.VerificationConfigV2 memory verificationConfigV2) { + verificationConfigV2 = GenericFormatter.verificationConfigFromBytes(verificationConfig); + } + + function testFormatV1Config( + SelfStructs.VerificationConfigV1 memory verificationConfigV1 + ) public pure returns (bytes memory v1ConfigBytes) { + v1ConfigBytes = GenericFormatter.formatV1Config(verificationConfigV1); + } + + function testFormatV2Config( + SelfStructs.VerificationConfigV2 memory verificationConfigV2 + ) public pure returns (bytes memory v2ConfigBytes) { + v2ConfigBytes = GenericFormatter.formatV2Config(verificationConfigV2); + } + + function testToV2Struct( + SelfStructs.GenericDiscloseOutputV2 memory genericDiscloseOutput + ) public pure returns (bytes memory v2StructBytes) { + v2StructBytes = GenericFormatter.toV2Struct(genericDiscloseOutput); + } +} diff --git a/contracts/contracts/verifiers/disclose/Verifier_vc_and_disclose_id.sol b/contracts/contracts/verifiers/disclose/Verifier_vc_and_disclose_id.sol new file mode 100644 index 000000000..598366bc6 --- /dev/null +++ b/contracts/contracts/verifiers/disclose/Verifier_vc_and_disclose_id.sol @@ -0,0 +1,307 @@ +// SPDX-License-Identifier: GPL-3.0 +/* + Copyright 2021 0KIMS association. + + This file is generated with [snarkJS](https://github.com/iden3/snarkjs). + + snarkJS is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + snarkJS is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with snarkJS. If not, see . +*/ + +pragma solidity >=0.7.0 <0.9.0; + +contract Verifier_vc_and_disclose_id { + // Scalar field size + uint256 constant r = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + // Base field size + uint256 constant q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + + // Verification Key data + uint256 constant alphax = 20491192805390485299153009773594534940189261866228447918068658471970481763042; + uint256 constant alphay = 9383485363053290200918347156157836566562967994039712273449902621266178545958; + uint256 constant betax1 = 4252822878758300859123897981450591353533073413197771768651442665752259397132; + uint256 constant betax2 = 6375614351688725206403948262868962793625744043794305715222011528459656738731; + uint256 constant betay1 = 21847035105528745403288232691147584728191162732299865338377159692350059136679; + uint256 constant betay2 = 10505242626370262277552901082094356697409835680220590971873171140371331206856; + uint256 constant gammax1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634; + uint256 constant gammax2 = 10857046999023057135944570762232829481370756359578518086990519993285655852781; + uint256 constant gammay1 = 4082367875863433681332203403145435568316851327593401208105741076214120093531; + uint256 constant gammay2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930; + uint256 constant deltax1 = 2570683437117593959871249718321087344182581865653762639494656774741884774451; + uint256 constant deltax2 = 10791937519136459850121173854513919670439026432248975480520108456769523413706; + uint256 constant deltay1 = 7697803293347511746398205466597805067891748159831340108443169903730430911531; + uint256 constant deltay2 = 18135141573537061188590013042324734692899788683249633264832904379088420521347; + + uint256 constant IC0x = 5856920506801943179747940431507261587545690354191837904074746625856713057019; + uint256 constant IC0y = 19124539120756340306225201952668471579555384876400327849356328019845881097562; + + uint256 constant IC1x = 3907275788156399155726133032274445611289536322362606696599801283854580295437; + uint256 constant IC1y = 8451119154682439762054395905067543035497291620054904162598329277934126172016; + + uint256 constant IC2x = 20530143257595175213619797207279919184153764911566159122843961254673243634293; + uint256 constant IC2y = 18418107796075636508766997478881789861884175034155105905934657000306915821371; + + uint256 constant IC3x = 14368654893588239986356440315957545435792265903841511372331944472664329358460; + uint256 constant IC3y = 12284629478683204119754717091716141149657267016652380030058008792997116131875; + + uint256 constant IC4x = 9578716983925369516022217522731093507962466534359837901987460531141004851058; + uint256 constant IC4y = 11546230489007268978353544383968439771367148945013199458278541261408798518042; + + uint256 constant IC5x = 20186291580274548265191299475582935526688657371386630094736889868165148343049; + uint256 constant IC5y = 7066081396404019076294461314754121975461942238116236506003634245369912659348; + + uint256 constant IC6x = 7223725756527208741423329209765674164138947999927552108248321109787428330576; + uint256 constant IC6y = 7090893321878038809726547992284174238790568751222590654054815492845205850020; + + uint256 constant IC7x = 3508039657302366273723082871441943167324729420192561664273405366370025413334; + uint256 constant IC7y = 16077897542007852149081275458028106372577804015189016149401990661491415919989; + + uint256 constant IC8x = 7157834980199389511778623097557341082580034352641045942337042309147987264745; + uint256 constant IC8y = 17810088059705235516956644702714110398594370075197014246657966746880992708168; + + uint256 constant IC9x = 19990085150526235401122450579432100767788242749821689359772693208891467804622; + uint256 constant IC9y = 11875741660249391520213283913162030612995484283095257075118031592533202953731; + + uint256 constant IC10x = 565576411533726770996320843760026133874517147039816053645457725776038253277; + uint256 constant IC10y = 6930421180986466104206189528520482999522362852059930498501019935177194699565; + + uint256 constant IC11x = 9687304248878239799475267106341943076035784248337790140346422230644442528821; + uint256 constant IC11y = 8718390928981091008213508300667652242975655218883879916045519674874973495651; + + uint256 constant IC12x = 13400562939760543038178200762869273415986171711360997974863414188041195677804; + uint256 constant IC12y = 19454142021037427981814241940238985741634162007055597028328858197655005999592; + + uint256 constant IC13x = 5304642595939683424612415509804552638020604037251875803456909825635793998553; + uint256 constant IC13y = 5306882009576422477327808720898870532843294871978759595546305216807124752880; + + uint256 constant IC14x = 14031793532934637725744550192616647697277176739864804433516834701426772096040; + uint256 constant IC14y = 13997965923135752232663850400013330288274429042096588718589372655870427909076; + + uint256 constant IC15x = 6857315285146692182841362377259336559693847336499456322687817740418786750593; + uint256 constant IC15y = 7773075738364850482446135825145951942474724287022442267891210024402400169358; + + uint256 constant IC16x = 7350867218242766859946239631839980088884228896188196079908494306313085242757; + uint256 constant IC16y = 16585312954662800633717122107305570207242746661443177600922110732010586303604; + + uint256 constant IC17x = 12371794706813431625295862613989653271433404490947256703099159689503429758617; + uint256 constant IC17y = 16874395293051993576135801684114190330547607587787157588928779976192005582901; + + uint256 constant IC18x = 18408185524203075886684659649084141997263054479485752795420181339411166689531; + uint256 constant IC18y = 16243204335737707642434624849163560305778796389979434010995242909912410681115; + + uint256 constant IC19x = 12827474512217515366731958666602059443683014227879101851822634933350038305567; + uint256 constant IC19y = 12103285317170015797205692728698593084779876459612203243369112597137507623396; + + uint256 constant IC20x = 21871607573936419852307486960157754714579931787264995102940433544145315016287; + uint256 constant IC20y = 3793515164944941168720752793034269182533154487955578472737823429132294441082; + + uint256 constant IC21x = 694085742582167480921564969992368553233272238548053666297768861621687596406; + uint256 constant IC21y = 19146278969945936933324725088253247909700597465969498560427768702663925772917; + + // Memory data + uint16 constant pVk = 0; + uint16 constant pPairing = 128; + + uint16 constant pLastMem = 896; + + function verifyProof( + uint[2] calldata _pA, + uint[2][2] calldata _pB, + uint[2] calldata _pC, + uint[21] calldata _pubSignals + ) public view returns (bool) { + assembly { + function checkField(v) { + if iszero(lt(v, r)) { + mstore(0, 0) + return(0, 0x20) + } + } + + // G1 function to multiply a G1 value(x,y) to value in an address + function g1_mulAccC(pR, x, y, s) { + let success + let mIn := mload(0x40) + mstore(mIn, x) + mstore(add(mIn, 32), y) + mstore(add(mIn, 64), s) + + success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + + mstore(add(mIn, 64), mload(pR)) + mstore(add(mIn, 96), mload(add(pR, 32))) + + success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + } + + function checkPairing(pA, pB, pC, pubSignals, pMem) -> isOk { + let _pPairing := add(pMem, pPairing) + let _pVk := add(pMem, pVk) + + mstore(_pVk, IC0x) + mstore(add(_pVk, 32), IC0y) + + // Compute the linear combination vk_x + + g1_mulAccC(_pVk, IC1x, IC1y, calldataload(add(pubSignals, 0))) + + g1_mulAccC(_pVk, IC2x, IC2y, calldataload(add(pubSignals, 32))) + + g1_mulAccC(_pVk, IC3x, IC3y, calldataload(add(pubSignals, 64))) + + g1_mulAccC(_pVk, IC4x, IC4y, calldataload(add(pubSignals, 96))) + + g1_mulAccC(_pVk, IC5x, IC5y, calldataload(add(pubSignals, 128))) + + g1_mulAccC(_pVk, IC6x, IC6y, calldataload(add(pubSignals, 160))) + + g1_mulAccC(_pVk, IC7x, IC7y, calldataload(add(pubSignals, 192))) + + g1_mulAccC(_pVk, IC8x, IC8y, calldataload(add(pubSignals, 224))) + + g1_mulAccC(_pVk, IC9x, IC9y, calldataload(add(pubSignals, 256))) + + g1_mulAccC(_pVk, IC10x, IC10y, calldataload(add(pubSignals, 288))) + + g1_mulAccC(_pVk, IC11x, IC11y, calldataload(add(pubSignals, 320))) + + g1_mulAccC(_pVk, IC12x, IC12y, calldataload(add(pubSignals, 352))) + + g1_mulAccC(_pVk, IC13x, IC13y, calldataload(add(pubSignals, 384))) + + g1_mulAccC(_pVk, IC14x, IC14y, calldataload(add(pubSignals, 416))) + + g1_mulAccC(_pVk, IC15x, IC15y, calldataload(add(pubSignals, 448))) + + g1_mulAccC(_pVk, IC16x, IC16y, calldataload(add(pubSignals, 480))) + + g1_mulAccC(_pVk, IC17x, IC17y, calldataload(add(pubSignals, 512))) + + g1_mulAccC(_pVk, IC18x, IC18y, calldataload(add(pubSignals, 544))) + + g1_mulAccC(_pVk, IC19x, IC19y, calldataload(add(pubSignals, 576))) + + g1_mulAccC(_pVk, IC20x, IC20y, calldataload(add(pubSignals, 608))) + + g1_mulAccC(_pVk, IC21x, IC21y, calldataload(add(pubSignals, 640))) + + // -A + mstore(_pPairing, calldataload(pA)) + mstore(add(_pPairing, 32), mod(sub(q, calldataload(add(pA, 32))), q)) + + // B + mstore(add(_pPairing, 64), calldataload(pB)) + mstore(add(_pPairing, 96), calldataload(add(pB, 32))) + mstore(add(_pPairing, 128), calldataload(add(pB, 64))) + mstore(add(_pPairing, 160), calldataload(add(pB, 96))) + + // alpha1 + mstore(add(_pPairing, 192), alphax) + mstore(add(_pPairing, 224), alphay) + + // beta2 + mstore(add(_pPairing, 256), betax1) + mstore(add(_pPairing, 288), betax2) + mstore(add(_pPairing, 320), betay1) + mstore(add(_pPairing, 352), betay2) + + // vk_x + mstore(add(_pPairing, 384), mload(add(pMem, pVk))) + mstore(add(_pPairing, 416), mload(add(pMem, add(pVk, 32)))) + + // gamma2 + mstore(add(_pPairing, 448), gammax1) + mstore(add(_pPairing, 480), gammax2) + mstore(add(_pPairing, 512), gammay1) + mstore(add(_pPairing, 544), gammay2) + + // C + mstore(add(_pPairing, 576), calldataload(pC)) + mstore(add(_pPairing, 608), calldataload(add(pC, 32))) + + // delta2 + mstore(add(_pPairing, 640), deltax1) + mstore(add(_pPairing, 672), deltax2) + mstore(add(_pPairing, 704), deltay1) + mstore(add(_pPairing, 736), deltay2) + + let success := staticcall(sub(gas(), 2000), 8, _pPairing, 768, _pPairing, 0x20) + + isOk := and(success, mload(_pPairing)) + } + + let pMem := mload(0x40) + mstore(0x40, add(pMem, pLastMem)) + + // Validate that all evaluations ∈ F + + checkField(calldataload(add(_pubSignals, 0))) + + checkField(calldataload(add(_pubSignals, 32))) + + checkField(calldataload(add(_pubSignals, 64))) + + checkField(calldataload(add(_pubSignals, 96))) + + checkField(calldataload(add(_pubSignals, 128))) + + checkField(calldataload(add(_pubSignals, 160))) + + checkField(calldataload(add(_pubSignals, 192))) + + checkField(calldataload(add(_pubSignals, 224))) + + checkField(calldataload(add(_pubSignals, 256))) + + checkField(calldataload(add(_pubSignals, 288))) + + checkField(calldataload(add(_pubSignals, 320))) + + checkField(calldataload(add(_pubSignals, 352))) + + checkField(calldataload(add(_pubSignals, 384))) + + checkField(calldataload(add(_pubSignals, 416))) + + checkField(calldataload(add(_pubSignals, 448))) + + checkField(calldataload(add(_pubSignals, 480))) + + checkField(calldataload(add(_pubSignals, 512))) + + checkField(calldataload(add(_pubSignals, 544))) + + checkField(calldataload(add(_pubSignals, 576))) + + checkField(calldataload(add(_pubSignals, 608))) + + checkField(calldataload(add(_pubSignals, 640))) + + // Validate all evaluations + let isValid := checkPairing(_pA, _pB, _pC, _pubSignals, pMem) + + mstore(0, isValid) + return(0, 0x20) + } + } +} diff --git a/contracts/contracts/verifiers/register_id/Verifier_register_id_sha256_sha256_sha256_rsa_65537_4096.sol b/contracts/contracts/verifiers/register_id/Verifier_register_id_sha256_sha256_sha256_rsa_65537_4096.sol index 37e0e0026..50d7b9f92 100644 --- a/contracts/contracts/verifiers/register_id/Verifier_register_id_sha256_sha256_sha256_rsa_65537_4096.sol +++ b/contracts/contracts/verifiers/register_id/Verifier_register_id_sha256_sha256_sha256_rsa_65537_4096.sol @@ -22,17 +22,17 @@ pragma solidity >=0.7.0 <0.9.0; contract Verifier_register_id_sha256_sha256_sha256_rsa_65537_4096 { // Scalar field size - uint256 constant r = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + uint256 constant r = 21888242871839275222246405745257275088548364400416034343698204186575808495617; // Base field size - uint256 constant q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + uint256 constant q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; // Verification Key data - uint256 constant alphax = 20491192805390485299153009773594534940189261866228447918068658471970481763042; - uint256 constant alphay = 9383485363053290200918347156157836566562967994039712273449902621266178545958; - uint256 constant betax1 = 4252822878758300859123897981450591353533073413197771768651442665752259397132; - uint256 constant betax2 = 6375614351688725206403948262868962793625744043794305715222011528459656738731; - uint256 constant betay1 = 21847035105528745403288232691147584728191162732299865338377159692350059136679; - uint256 constant betay2 = 10505242626370262277552901082094356697409835680220590971873171140371331206856; + uint256 constant alphax = 20491192805390485299153009773594534940189261866228447918068658471970481763042; + uint256 constant alphay = 9383485363053290200918347156157836566562967994039712273449902621266178545958; + uint256 constant betax1 = 4252822878758300859123897981450591353533073413197771768651442665752259397132; + uint256 constant betax2 = 6375614351688725206403948262868962793625744043794305715222011528459656738731; + uint256 constant betay1 = 21847035105528745403288232691147584728191162732299865338377159692350059136679; + uint256 constant betay2 = 10505242626370262277552901082094356697409835680220590971873171140371331206856; uint256 constant gammax1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634; uint256 constant gammax2 = 10857046999023057135944570762232829481370756359578518086990519993285655852781; uint256 constant gammay1 = 4082367875863433681332203403145435568316851327593401208105741076214120093531; @@ -42,27 +42,30 @@ contract Verifier_register_id_sha256_sha256_sha256_rsa_65537_4096 { uint256 constant deltay1 = 17093903636529404715977441649383548797208493053670591927268936136905628890632; uint256 constant deltay2 = 4972965029582644081071578284460620299080512423640837516215418184958287485742; - uint256 constant IC0x = 10355093401382030671225395655869217898600304666279529568537338332467402365304; uint256 constant IC0y = 4965486376320532678254373789150183805614443765077280090063627634214290673841; - + uint256 constant IC1x = 15499415295419376168702866885907180620949913073936284071089537160198730049399; uint256 constant IC1y = 9281988302763410034273237781396743554700695834575740098855226007996985888530; - + uint256 constant IC2x = 14098031970434182418452511377672297745474345532972352145312731453903292311930; uint256 constant IC2y = 5496357494362502413877905425401698232434560336945612609023708765434745421701; - + uint256 constant IC3x = 6540495825150439480926083011463382216384205445522489211977434270583326380648; uint256 constant IC3y = 4164688383627561794431395614711252825194458846441353030452544157419373614848; - - + // Memory data uint16 constant pVk = 0; uint16 constant pPairing = 128; uint16 constant pLastMem = 896; - function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[3] calldata _pubSignals) public view returns (bool) { + function verifyProof( + uint[2] calldata _pA, + uint[2][2] calldata _pB, + uint[2] calldata _pC, + uint[3] calldata _pubSignals + ) public view returns (bool) { assembly { function checkField(v) { if iszero(lt(v, r)) { @@ -70,7 +73,7 @@ contract Verifier_register_id_sha256_sha256_sha256_rsa_65537_4096 { return(0, 0x20) } } - + // G1 function to multiply a G1 value(x,y) to value in an address function g1_mulAccC(pR, x, y, s) { let success @@ -105,13 +108,12 @@ contract Verifier_register_id_sha256_sha256_sha256_rsa_65537_4096 { mstore(add(_pVk, 32), IC0y) // Compute the linear combination vk_x - + g1_mulAccC(_pVk, IC1x, IC1y, calldataload(add(pubSignals, 0))) - + g1_mulAccC(_pVk, IC2x, IC2y, calldataload(add(pubSignals, 32))) - + g1_mulAccC(_pVk, IC3x, IC3y, calldataload(add(pubSignals, 64))) - // -A mstore(_pPairing, calldataload(pA)) @@ -137,7 +139,6 @@ contract Verifier_register_id_sha256_sha256_sha256_rsa_65537_4096 { mstore(add(_pPairing, 384), mload(add(pMem, pVk))) mstore(add(_pPairing, 416), mload(add(pMem, add(pVk, 32)))) - // gamma2 mstore(add(_pPairing, 448), gammax1) mstore(add(_pPairing, 480), gammax2) @@ -154,7 +155,6 @@ contract Verifier_register_id_sha256_sha256_sha256_rsa_65537_4096 { mstore(add(_pPairing, 704), deltay1) mstore(add(_pPairing, 736), deltay2) - let success := staticcall(sub(gas(), 2000), 8, _pPairing, 768, _pPairing, 0x20) isOk := and(success, mload(_pPairing)) @@ -164,19 +164,18 @@ contract Verifier_register_id_sha256_sha256_sha256_rsa_65537_4096 { mstore(0x40, add(pMem, pLastMem)) // Validate that all evaluations ∈ F - + checkField(calldataload(add(_pubSignals, 0))) - + checkField(calldataload(add(_pubSignals, 32))) - + checkField(calldataload(add(_pubSignals, 64))) - // Validate all evaluations let isValid := checkPairing(_pA, _pB, _pC, _pubSignals, pMem) mstore(0, isValid) - return(0, 0x20) - } - } - } + return(0, 0x20) + } + } +} diff --git a/contracts/hardhat.config.ts b/contracts/hardhat.config.ts index 9f50c7802..fd6c97d2c 100644 --- a/contracts/hardhat.config.ts +++ b/contracts/hardhat.config.ts @@ -1,7 +1,7 @@ import { HardhatUserConfig } from "hardhat/config"; import "@nomicfoundation/hardhat-toolbox"; require("dotenv").config({ - path: process.env.CI ? ".env.test" : ".env" + path: process.env.CI ? ".env.test" : ".env", }); import "hardhat-contract-sizer"; import "@nomicfoundation/hardhat-ignition-ethers"; @@ -16,14 +16,10 @@ const config: HardhatUserConfig = { optimizer: { enabled: true, runs: 200, - details: { - yul: true, - }, }, metadata: { bytecodeHash: "none", }, - viaIR: false, }, }, contractSizer: { diff --git a/contracts/ignition/modules/hub/deployHub.ts b/contracts/ignition/modules/hub/deployHub.ts index b8747d6e4..cbdee499c 100644 --- a/contracts/ignition/modules/hub/deployHub.ts +++ b/contracts/ignition/modules/hub/deployHub.ts @@ -18,14 +18,7 @@ export default buildModule("DeployHubV1", (m) => { const identityVerificationHubImplV1 = m.contract("IdentityVerificationHubImplV1"); const hubInterface = getHubInitializeData(); - const initializeData = hubInterface.encodeFunctionData("initialize", [ - "", - "", - [], - [], - [], - [], - ]); + const initializeData = hubInterface.encodeFunctionData("initialize", ["", "", [], [], [], []]); // Deploy proxy with V1 implementation const hubV1 = m.contract("IdentityVerificationHub", [identityVerificationHubImplV1, initializeData]); diff --git a/contracts/ignition/modules/verifiers/deployAllVerifiers.ts b/contracts/ignition/modules/verifiers/deployAllVerifiers.ts index 1cca736a7..cae65f8f3 100644 --- a/contracts/ignition/modules/verifiers/deployAllVerifiers.ts +++ b/contracts/ignition/modules/verifiers/deployAllVerifiers.ts @@ -7,7 +7,7 @@ import * as path from "path"; * Get enum keys (circuit names) excluding numeric values */ function getEnumKeys>(enumObject: T): string[] { - return Object.keys(enumObject).filter(key => isNaN(Number(key))); + return Object.keys(enumObject).filter((key) => isNaN(Number(key))); } /** @@ -22,7 +22,7 @@ function contractExists(contractName: string): boolean { path.join(contractsDir, "verifiers", `${contractName}.sol`), ]; - return possiblePaths.some(filePath => fs.existsSync(filePath)); + return possiblePaths.some((filePath) => fs.existsSync(filePath)); } export default buildModule("DeployAllVerifiers", (m) => { @@ -64,8 +64,12 @@ export default buildModule("DeployAllVerifiers", (m) => { console.log(`Total verifiers deployment summary:`); console.log(` - VC and Disclose: 1`); - console.log(` - Register: ${successfulRegisterDeployments}/${registerCircuits.length} (${registerCircuits.length - successfulRegisterDeployments} skipped)`); - console.log(` - DSC: ${successfulDscDeployments}/${dscCircuits.length} (${dscCircuits.length - successfulDscDeployments} skipped)`); + console.log( + ` - Register: ${successfulRegisterDeployments}/${registerCircuits.length} (${registerCircuits.length - successfulRegisterDeployments} skipped)`, + ); + console.log( + ` - DSC: ${successfulDscDeployments}/${dscCircuits.length} (${dscCircuits.length - successfulDscDeployments} skipped)`, + ); console.log(` - Total successful deployments: ${1 + successfulRegisterDeployments + successfulDscDeployments}`); return deployedContracts; diff --git a/contracts/package.json b/contracts/package.json index 255232583..80d35f2b0 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -15,15 +15,15 @@ "contracts/abstract/*" ], "scripts": { - "build": "npx hardhat clean && npx hardhat compile", + "build": "yarn hardhat clean && yarn hardhat compile", "deploy:all": "npm run deploy:verifiers:all && npm run deploy:registry && npm run deploy:registry:idcard && npm run deploy:hub:v2", - "deploy:hub": "npx dotenv-cli -- bash -c 'npx hardhat ignition deploy ignition/modules/hub/deployHub.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'", - "deploy:hub:v2": "npx dotenv-cli -- bash -c 'npx hardhat ignition deploy ignition/modules/hub/deployHubV2.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'", - "deploy:pcr0": "npx dotenv-cli -- bash -c 'npx hardhat ignition deploy ignition/modules/utils/deployPCR0.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'", - "deploy:registry": "npx dotenv-cli -- bash -c 'npx hardhat ignition deploy ignition/modules/registry/deployRegistry.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'", - "deploy:registry:idcard": "npx dotenv-cli -- bash -c 'npx hardhat ignition deploy ignition/modules/registry/deployIdCardRegistry.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'", - "deploy:verifiers": "npx dotenv-cli -- bash -c 'npx hardhat ignition deploy ignition/modules/verifiers/deployVerifiers.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'", - "deploy:verifiers:all": "npx dotenv-cli -- bash -c 'npx hardhat ignition deploy ignition/modules/verifiers/deployAllVerifiers.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'", + "deploy:hub": "npx dotenv-cli -- bash -c 'yarn hardhat ignition deploy ignition/modules/hub/deployHub.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'", + "deploy:hub:v2": "npx dotenv-cli -- bash -c 'yarn hardhat ignition deploy ignition/modules/hub/deployHubV2.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'", + "deploy:pcr0": "npx dotenv-cli -- bash -c 'yarn hardhat ignition deploy ignition/modules/utils/deployPCR0.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'", + "deploy:registry": "npx dotenv-cli -- bash -c 'yarn hardhat ignition deploy ignition/modules/registry/deployRegistry.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'", + "deploy:registry:idcard": "npx dotenv-cli -- bash -c 'yarn hardhat ignition deploy ignition/modules/registry/deployIdCardRegistry.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'", + "deploy:verifiers": "npx dotenv-cli -- bash -c 'yarn hardhat ignition deploy ignition/modules/verifiers/deployVerifiers.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'", + "deploy:verifiers:all": "npx dotenv-cli -- bash -c 'yarn hardhat ignition deploy ignition/modules/verifiers/deployAllVerifiers.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'", "export-prod": "bash ./scripts/prod.sh", "prettier:check": "prettier --list-different '**/*.{json,md,yml,sol,ts}'", "prettier:write": "prettier --write '**/*.{json,md,yml,sol,ts}'", @@ -31,32 +31,33 @@ "set:hub:v2": "npx dotenv-cli -- bash -c 'NETWORK=${NETWORK:-staging} npx ts-node scripts/setHubV2.ts'", "set:registry": "npx dotenv-cli -- bash -c 'NETWORK=${NETWORK:-staging} npx ts-node scripts/setRegistry.ts'", "set:registry:idcard": "npx dotenv-cli -- bash -c 'NETWORK=${NETWORK:-staging} npx ts-node scripts/setRegistryId.ts'", - "test": "npx hardhat test", + "test": "yarn hardhat test", "test:airdrop": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} npx hardhat test test/example/airdrop.test.ts'", "test:attribute": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} npx hardhat test test/unit/CircuitAttributeHandler.test.ts'", - "test:coverage": "npx hardhat coverage", - "test:coverage:local": "TEST_ENV=local npx hardhat coverage", - "test:disclose": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} npx hardhat test test/integration/vcAndDisclose.test.ts'", - "test:endtoend": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} npx hardhat test test/Integration/endToEnd.test.ts'", - "test:example": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} npx hardhat test test/example/*'", - "test:formatter": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} npx hardhat test test/unit/formatter.test.ts'", - "test:hub": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} npx hardhat test test/unit/IdentityVerificationHub.test.ts'", - "test:integration": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} npx hardhat test test/integration/*'", - "test:local": "TEST_ENV=local npx hardhat test", - "test:pcr": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} npx hardhat test test/unit/PCR0Manager.test.ts'", - "test:register": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} npx hardhat test test/integration/commitmentRegistration.test.ts'", - "test:registry": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} npx hardhat test test/unit/IdentityRegistry.test.ts'", - "test:sdkcore": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} npx hardhat test test/sdk/sdkCore.test.ts --network localhost'", - "test:unit": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} npx hardhat test test/unit/*'", - "test:verifyall": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} npx hardhat test test/integration/verifyAll.test.ts'", - "test:view": "npx hardhat test test/view.ts", + "test:coverage": "yarn hardhat coverage", + "test:coverage:local": "TEST_ENV=local yarn hardhat coverage", + "test:disclose": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} yarn hardhat test test/integration/vcAndDisclose.test.ts'", + "test:endtoend": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} yarn hardhat test test/Integration/endToEnd.test.ts'", + "test:example": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} yarn hardhat test test/example/*'", + "test:formatter": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} yarn hardhat test test/unit/formatter.test.ts'", + "test:hub": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} yarn hardhat test test/unit/IdentityVerificationHub.test.ts'", + "test:integration": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} yarn hardhat test test/integration/*'", + "test:local": "TEST_ENV=local yarn hardhat test", + "test:pcr": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} yarn hardhat test test/unit/PCR0Manager.test.ts'", + "test:register": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} yarn hardhat test test/integration/commitmentRegistration.test.ts'", + "test:registry": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} yarn hardhat test test/unit/IdentityRegistry.test.ts'", + "test:sdkcore": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} yarn hardhat test test/sdk/sdkCore.test.ts --network localhost'", + "test:unit": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} yarn hardhat test test/unit/*'", + "test:verifyall": "npx dotenv-cli -- bash -c 'TEST_ENV=${TEST_ENV:-local} yarn hardhat test test/integration/verifyAll.test.ts'", + "test:view": "yarn hardhat test test/view.ts", + "test:v2": "npx hardhat test test/v2/selfVerificationFlow.test.ts --network localhost", "types": "tsc -noEmit", - "update:cscaroot": "npx dotenv-cli -- bash -c 'npx hardhat ignition deploy ignition/modules/scripts/updateRegistryCscaRoot.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'", + "update:cscaroot": "npx dotenv-cli -- bash -c 'yarn hardhat ignition deploy ignition/modules/scripts/updateRegistryCscaRoot.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'", "update:hub": "npx dotenv-cli -- bash -c 'NETWORK=${NETWORK:-staging} npx ts-node scripts/setRegistry.ts'", - "update:ofacroot": "npx dotenv-cli -- bash -c 'npx hardhat ignition deploy ignition/modules/scripts/updateRegistryOfacRoot.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'", - "update:pcr0": "npx dotenv-cli -- bash -c 'PCR0_ACTION=${PCR0_ACTION:-add} PCR0_KEY=${PCR0_KEY} npx hardhat ignition deploy ignition/modules/scripts/updatePCR0.ts --network ${NETWORK:-localhost} --reset'", - "upgrade:hub": "npx dotenv-cli -- bash -c 'npx hardhat ignition deploy ignition/modules/upgrade/deployNewHubAndUpgrade.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'", - "upgrade:registry": "npx dotenv-cli -- bash -c 'npx hardhat ignition deploy ignition/modules/upgrade/deployNewRegistryAndUpgrade.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'" + "update:ofacroot": "npx dotenv-cli -- bash -c 'yarn hardhat ignition deploy ignition/modules/scripts/updateRegistryOfacRoot.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'", + "update:pcr0": "npx dotenv-cli -- bash -c 'PCR0_ACTION=${PCR0_ACTION:-add} PCR0_KEY=${PCR0_KEY} yarn hardhat ignition deploy ignition/modules/scripts/updatePCR0.ts --network ${NETWORK:-localhost} --reset'", + "upgrade:hub": "npx dotenv-cli -- bash -c 'yarn hardhat ignition deploy ignition/modules/upgrade/deployNewHubAndUpgrade.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'", + "upgrade:registry": "npx dotenv-cli -- bash -c 'yarn hardhat ignition deploy ignition/modules/upgrade/deployNewRegistryAndUpgrade.ts --network ${NETWORK:-localhost} ${VERIFY:+--verify}'" }, "dependencies": { "@ashpect/smt": "https://github.com/ashpect/smt#main", @@ -108,5 +109,6 @@ "ts-node": "^10.9.1", "typechain": "^8.3.2", "typescript": "^5.1.6" - } + }, + "packageManager": "yarn@4.5.3" } diff --git a/contracts/scripts/README.md b/contracts/scripts/README.md new file mode 100644 index 000000000..603ee45ab --- /dev/null +++ b/contracts/scripts/README.md @@ -0,0 +1,153 @@ +# Scripts Directory + +This directory contains utility scripts for the Self contracts project. + +## Available Scripts + +### Test Scripts (`test.sh`) + +Run various types of tests for the contracts. + +```bash +# Show all available test commands +./scripts/test.sh help + +# Run V2 verification flow tests +./scripts/test.sh v2 + +# Run all contract tests +./scripts/test.sh all + +# Run unit tests +./scripts/test.sh unit + +# Run integration tests +./scripts/test.sh integration + +# Run test coverage +./scripts/test.sh coverage + +# Run specific test types +./scripts/test.sh airdrop +./scripts/test.sh attribute +./scripts/test.sh formatter +./scripts/test.sh hub +./scripts/test.sh registry +./scripts/test.sh sdk + +# Clean test artifacts +./scripts/test.sh clean +``` + +### Development Scripts (`dev.sh`) + +Development and deployment utilities. + +```bash +# Show all available development commands +./scripts/dev.sh help + +# Start local Hardhat node +./scripts/dev.sh node + +# Compile contracts +./scripts/dev.sh build + +# Clean build artifacts +./scripts/dev.sh clean + +# Check contract sizes +./scripts/dev.sh size + +# Deploy contracts +./scripts/dev.sh deploy +./scripts/dev.sh deploy:hub +./scripts/dev.sh deploy:hub:v2 +./scripts/dev.sh deploy:registry + +# Open Hardhat console +./scripts/dev.sh console +``` + +## Usage Examples + +### Quick Test Workflow + +```bash +# Navigate to contracts directory +cd contracts + +# Run V2 tests +./scripts/test.sh v2 + +# If tests fail, check build +./scripts/dev.sh build + +# Run coverage to see test completeness +./scripts/test.sh coverage +``` + +### Development Workflow + +```bash +# Start local development node (in terminal 1) +./scripts/dev.sh node + +# In another terminal, deploy contracts +./scripts/dev.sh deploy:hub:v2 + +# Run tests against local node +./scripts/test.sh integration +``` + +## Script Features + +- **Colored Output**: Scripts provide colored status messages for better readability +- **Error Handling**: Scripts will exit on errors and provide meaningful error messages +- **Path Detection**: Scripts automatically detect if you're running from `contracts/` or `contracts/scripts/` +- **Environment Variables**: Test scripts automatically set appropriate environment variables + +## Running from Different Directories + +The scripts are smart about directory detection: + +```bash +# From contracts directory +./scripts/test.sh v2 + +# From contracts/scripts directory +./test.sh v2 + +# Both will work correctly +``` + +## Troubleshooting + +### Script Permission Issues + +If you get permission denied errors: + +```bash +chmod +x scripts/test.sh scripts/dev.sh +``` + +### "hardhat.config.ts not found" Error + +This means the script couldn't find the Hardhat configuration. Make sure you're running from: + +- The `contracts/` directory, or +- The `contracts/scripts/` directory + +### Yarn 4 Workspace Issues + +If you encounter Yarn workspace issues, these scripts are designed to work directly with `npx hardhat` to avoid the +workspace complexities. + +## Integration with Package.json + +The scripts complement the existing `package.json` scripts: + +- Package.json scripts: Can be run from anywhere using `yarn` commands +- Shell scripts: Run directly from contracts directory, providing more control and better output + +Choose the approach that works best for your workflow! diff --git a/contracts/scripts/dev.sh b/contracts/scripts/dev.sh new file mode 100755 index 000000000..2d4271ef9 --- /dev/null +++ b/contracts/scripts/dev.sh @@ -0,0 +1,140 @@ +#!/bin/bash + +# Development script for Self contracts +# Usage: ./scripts/dev.sh [command] + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Function to print colored output +print_status() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Function to show help +show_help() { + echo "Self Contracts Development Tools" + echo "" + echo "Usage: ./scripts/dev.sh [command]" + echo "" + echo "Commands:" + echo " node Start local Hardhat node" + echo " build Compile contracts" + echo " clean Clean build artifacts" + echo " size Check contract sizes" + echo " deploy Deploy all contracts" + echo " deploy:hub Deploy hub contracts" + echo " deploy:hub:v2 Deploy hub V2 contracts" + echo " deploy:registry Deploy registry contracts" + echo " console Open Hardhat console" + echo " help Show this help message" + echo "" + echo "Examples:" + echo " ./scripts/dev.sh node" + echo " ./scripts/dev.sh build" + echo " ./scripts/dev.sh deploy:hub:v2" + echo "" +} + +# Function to run development commands +run_dev_command() { + local command=$1 + + case $command in + "node") + print_status "Starting Hardhat node..." + npx hardhat node + ;; + "build") + print_status "Compiling contracts..." + npx hardhat clean + npx hardhat compile + print_success "Contracts compiled successfully" + ;; + "clean") + print_status "Cleaning build artifacts..." + npx hardhat clean + rm -rf cache/ + rm -rf artifacts/ + rm -rf typechain-types/ + print_success "Build artifacts cleaned" + ;; + "size") + print_status "Checking contract sizes..." + npx hardhat compile + npx hardhat size-contracts + ;; + "deploy") + print_status "Deploying all contracts..." + npm run deploy:all + print_success "All contracts deployed" + ;; + "deploy:hub") + print_status "Deploying hub contracts..." + npm run deploy:hub + print_success "Hub contracts deployed" + ;; + "deploy:hub:v2") + print_status "Deploying hub V2 contracts..." + npm run deploy:hub:v2 + print_success "Hub V2 contracts deployed" + ;; + "deploy:registry") + print_status "Deploying registry contracts..." + npm run deploy:registry + print_success "Registry contracts deployed" + ;; + "console") + print_status "Opening Hardhat console..." + npx hardhat console + ;; + *) + print_error "Unknown command: $command" + show_help + exit 1 + ;; + esac +} + +# Main execution +main() { + # Change to contracts directory if not already there + if [[ ! -f "hardhat.config.ts" ]]; then + if [[ -f "../hardhat.config.ts" ]]; then + cd .. + else + print_error "Cannot find hardhat.config.ts. Please run from contracts directory or contracts/scripts directory." + exit 1 + fi + fi + + case ${1:-help} in + "help"|"--help"|"-h") + show_help + ;; + *) + run_dev_command $1 + ;; + esac +} + +# Run main function with all arguments +main "$@" diff --git a/contracts/scripts/setHubV2.ts b/contracts/scripts/setHubV2.ts index e35e32b56..1138da559 100644 --- a/contracts/scripts/setHubV2.ts +++ b/contracts/scripts/setHubV2.ts @@ -13,9 +13,9 @@ const PRIVATE_KEY = process.env.CELO_KEY; // Network to Chain ID mapping const NETWORK_TO_CHAIN_ID: Record = { - "localhost": "31337", - "celoAlfajores": "44787", - "celo": "42220", + localhost: "31337", + celoAlfajores: "44787", + celo: "42220", }; // Get chain ID from network name @@ -34,7 +34,10 @@ const AttestationId = { // Dynamic paths based on chain ID const deployedAddressesPath = path.join(__dirname, `../ignition/deployments/chain-${CHAIN_ID}/deployed_addresses.json`); -const contractAbiPath = path.join(__dirname, `../ignition/deployments/chain-${CHAIN_ID}/artifacts/DeployHubV2#IdentityVerificationHubImplV2.json`); +const contractAbiPath = path.join( + __dirname, + `../ignition/deployments/chain-${CHAIN_ID}/artifacts/DeployHubV2#IdentityVerificationHubImplV2.json`, +); // Debug logs for paths and files console.log("Network:", NETWORK); @@ -222,7 +225,7 @@ try { } } -main().catch((error) => { + main().catch((error) => { console.error("Execution error:", error); process.exitCode = 1; }); diff --git a/contracts/scripts/setRegistry.ts b/contracts/scripts/setRegistry.ts index 821883524..ebddb0b79 100644 --- a/contracts/scripts/setRegistry.ts +++ b/contracts/scripts/setRegistry.ts @@ -16,9 +16,9 @@ const CSCA_ROOT = process.env.CSCA_ROOT; // Allow manual CSCA root setting // Network to Chain ID mapping const NETWORK_TO_CHAIN_ID: Record = { - "localhost": "31337", - "celoAlfajores": "44787", - "celo": "42220", + localhost: "31337", + celoAlfajores: "44787", + celo: "42220", }; // Get chain ID from network name @@ -30,7 +30,10 @@ const CHAIN_ID = getChainId(NETWORK); // Dynamic paths based on chain ID const deployedAddressesPath = path.join(__dirname, `../ignition/deployments/chain-${CHAIN_ID}/deployed_addresses.json`); -const contractAbiPath = path.join(__dirname, `../ignition/deployments/chain-${CHAIN_ID}/artifacts/DeployRegistryModule#IdentityRegistryImplV1.json`); +const contractAbiPath = path.join( + __dirname, + `../ignition/deployments/chain-${CHAIN_ID}/artifacts/DeployRegistryModule#IdentityRegistryImplV1.json`, +); // Debug logs for paths and files console.log("Network:", NETWORK); diff --git a/contracts/scripts/setRegistryId.ts b/contracts/scripts/setRegistryId.ts index bc7d9d295..47193e7ca 100644 --- a/contracts/scripts/setRegistryId.ts +++ b/contracts/scripts/setRegistryId.ts @@ -16,9 +16,9 @@ const CSCA_ROOT = process.env.CSCA_ROOT; // Allow manual CSCA root setting // Network to Chain ID mapping const NETWORK_TO_CHAIN_ID: Record = { - "localhost": "31337", - "celoAlfajores": "44787", - "celo": "42220", + localhost: "31337", + celoAlfajores: "44787", + celo: "42220", }; // Get chain ID from network name @@ -30,7 +30,10 @@ const CHAIN_ID = getChainId(NETWORK); // Dynamic paths based on chain ID const deployedAddressesPath = path.join(__dirname, `../ignition/deployments/chain-${CHAIN_ID}/deployed_addresses.json`); -const contractAbiPath = path.join(__dirname, `../ignition/deployments/chain-${CHAIN_ID}/artifacts/DeployIdCardRegistryModule#IdentityRegistryIdCardImplV1.json`); +const contractAbiPath = path.join( + __dirname, + `../ignition/deployments/chain-${CHAIN_ID}/artifacts/DeployIdCardRegistryModule#IdentityRegistryIdCardImplV1.json`, +); // Debug logs for paths and files console.log("Network:", NETWORK); @@ -83,7 +86,11 @@ try { throw new Error("Hub address not found in deployed_addresses.json"); } - const identityRegistryIdCard = new ethers.Contract(registryIdCardAddress as string, identityRegistryIdCardAbi, wallet); + const identityRegistryIdCard = new ethers.Contract( + registryIdCardAddress as string, + identityRegistryIdCardAbi, + wallet, + ); console.log("Registry ID Card contract instance created"); // Update hub address diff --git a/contracts/scripts/test.sh b/contracts/scripts/test.sh new file mode 100755 index 000000000..29c89066a --- /dev/null +++ b/contracts/scripts/test.sh @@ -0,0 +1,185 @@ +#!/bin/bash + +# Test execution script for Self contracts +# Usage: ./scripts/test.sh [test-type] + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Function to print colored output +print_status() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Function to show help +show_help() { + echo "Self Contracts Test Runner" + echo "" + echo "Usage: ./scripts/test.sh [command]" + echo "" + echo "Commands:" + echo " all Run all contract tests" + echo "" + echo "V2 Tests (Individual):" + echo " v2-disclose-passport Run V2 passport disclosure tests" + echo " v2-disclose-id Run V2 ID disclosure tests" + echo " v2-register-id Run V2 ID registration tests" + echo " v2-register-passport Run V2 passport registration tests" + echo " v2-hub-other Run V2 hub other functionality tests" + echo "" + echo "V2 Tests (Groups):" + echo " v2-disclose Run all V2 disclosure tests" + echo " v2-register Run all V2 registration tests" + echo " v2-all Run all V2 tests" + echo "" + echo "Legacy Tests:" + echo " unit Run unit tests" + echo " integration Run integration tests" + echo " coverage Run test coverage" + echo " airdrop Run airdrop tests" + echo " attribute Run attribute handler tests" + echo " formatter Run formatter tests" + echo " hub Run hub tests" + echo " registry Run registry tests" + echo " sdk Run SDK core tests" + echo "" + echo "Utilities:" + echo " clean Clean test artifacts" + echo " help Show this help message" + echo "" + echo "Examples:" + echo " ./scripts/test.sh v2-disclose-passport" + echo " ./scripts/test.sh v2-register-id" + echo " ./scripts/test.sh v2-all" + echo " ./scripts/test.sh coverage" + echo "" +} + +# Function to run tests +run_test() { + local test_type=$1 + print_status "Running $test_type tests..." + + case $test_type in + "all") + npx hardhat test + ;; + # V2 Individual Tests + "v2-disclose-passport") + npx hardhat test test/v2/disclosePassport.test.ts --network localhost + ;; + "v2-disclose-id") + npx hardhat test test/v2/discloseId.test.ts --network localhost + ;; + "v2-register-id") + npx hardhat test test/v2/registerId.test.ts --network localhost + ;; + "v2-register-passport") + npx hardhat test test/v2/registerPassport.test.ts --network localhost + ;; + "v2-hub-other") + npx hardhat test test/v2/hubOther.test.ts --network localhost + ;; + # V2 Group Tests + "v2-disclose") + npx hardhat test test/v2/disclosePassport.test.ts test/v2/discloseId.test.ts --network localhost + ;; + "v2-register") + npx hardhat test test/v2/registerId.test.ts test/v2/registerPassport.test.ts --network localhost + ;; + "v2-all") + npx hardhat test test/v2/ --network localhost + ;; + # Legacy Tests + "unit") + TEST_ENV=local npx hardhat test test/unit/* + ;; + "integration") + TEST_ENV=local npx hardhat test test/integration/* + ;; + "coverage") + npx hardhat coverage + ;; + "airdrop") + TEST_ENV=local npx hardhat test test/example/airdrop.test.ts + ;; + "attribute") + TEST_ENV=local npx hardhat test test/unit/CircuitAttributeHandler.test.ts + ;; + "formatter") + TEST_ENV=local npx hardhat test test/unit/formatter.test.ts + ;; + "hub") + TEST_ENV=local npx hardhat test test/unit/IdentityVerificationHub.test.ts + ;; + "registry") + TEST_ENV=local npx hardhat test test/unit/IdentityRegistry.test.ts + ;; + "sdk") + TEST_ENV=local npx hardhat test test/sdk/sdkCore.test.ts --network localhost + ;; + *) + print_error "Unknown test type: $test_type" + show_help + exit 1 + ;; + esac +} + +# Function to clean test artifacts +clean_tests() { + print_status "Cleaning test artifacts..." + rm -rf cache/ + rm -rf artifacts/ + rm -rf typechain-types/ + rm -rf coverage/ + rm -rf coverage.json + print_success "Test artifacts cleaned" +} + +# Main execution +main() { + # Change to contracts directory if not already there + if [[ ! -f "hardhat.config.ts" ]]; then + if [[ -f "../hardhat.config.ts" ]]; then + cd .. + else + print_error "Cannot find hardhat.config.ts. Please run from contracts directory or contracts/scripts directory." + exit 1 + fi + fi + + case ${1:-help} in + "clean") + clean_tests + ;; + "help"|"--help"|"-h") + show_help + ;; + *) + run_test $1 + print_success "$1 tests completed" + ;; + esac +} + +# Run main function with all arguments +main "$@" diff --git a/contracts/test/example/airdrop.test.ts b/contracts/test/example/airdrop.test.ts index f9685f87f..3ef303a20 100644 --- a/contracts/test/example/airdrop.test.ts +++ b/contracts/test/example/airdrop.test.ts @@ -32,7 +32,7 @@ describe("Airdrop", () => { before(async () => { deployedActors = await deploySystemFixtures(); // must be imported dynamic since @openpassport/zk-kit-lean-imt is exclusively esm and hardhat does not support esm with typescript until verison 3 - const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then(mod => mod.LeanIMT); + const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then((mod) => mod.LeanIMT); registerSecret = generateRandomFieldElement(); nullifier = generateRandomFieldElement(); attestationIds = [BigInt(ATTESTATION_ID.E_PASSPORT)]; @@ -74,15 +74,13 @@ describe("Airdrop", () => { ); const airdropFactory = await ethers.getContractFactory("Airdrop"); - airdrop = await airdropFactory - .connect(deployedActors.owner) - .deploy( - deployedActors.hub.target, - hashEndpointWithScope("https://test.com", "test-scope"), - 0, // the types show we need a contract version here - attestationIds, - token.target, - ); + airdrop = await airdropFactory.connect(deployedActors.owner).deploy( + deployedActors.hub.target, + hashEndpointWithScope("https://test.com", "test-scope"), + 0, // the types show we need a contract version here + attestationIds, + token.target, + ); await airdrop.waitForDeployment(); const verificationConfig = { @@ -275,7 +273,6 @@ describe("Airdrop", () => { }); it("should not able to register address by user if attestation id is invalid", async () => { - const { registry, owner, user1 } = deployedActors; const invalidCommitment = generateCommitment( @@ -290,7 +287,7 @@ describe("Airdrop", () => { const hashFunction = (a: bigint, b: bigint) => poseidon2([a, b]); // must be imported dynamic since @openpassport/zk-kit-lean-imt is exclusively esm and hardhat does not support esm with typescript until verison 3 - const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then(mod => mod.LeanIMT); + const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then((mod) => mod.LeanIMT); const invalidImt = new LeanIMT(hashFunction); await invalidImt.insert(BigInt(commitment)); await invalidImt.insert(BigInt(invalidCommitment)); @@ -352,7 +349,7 @@ describe("Airdrop", () => { const airdropFactory = await ethers.getContractFactory("Airdrop"); const newAirdrop = await airdropFactory .connect(owner) - .deploy(hub.target, hashEndpointWithScope("https://test.com", "test-scope"),0, attestationIds, token.target); + .deploy(hub.target, hashEndpointWithScope("https://test.com", "test-scope"), 0, attestationIds, token.target); await newAirdrop.waitForDeployment(); const verificationConfig = { diff --git a/contracts/test/integration/commitmentRegistration.test.ts b/contracts/test/integration/commitmentRegistration.test.ts index 975c57131..1301bb8ed 100644 --- a/contracts/test/integration/commitmentRegistration.test.ts +++ b/contracts/test/integration/commitmentRegistration.test.ts @@ -5,8 +5,8 @@ import { poseidon2 } from "poseidon-lite"; import { CIRCUIT_CONSTANTS, DscVerifierId, RegisterVerifierId } from "@selfxyz/common/constants/constants"; import { ATTESTATION_ID } from "../utils/constants"; import { deploySystemFixtures } from "../utils/deployment"; -import { generateDscProof, generateRegisterProof } from "../utils/generateProof.js"; -import serialized_dsc_tree from "../utils/pubkeys/serialized_dsc_tree.json"; +import { generateDscProof, generateRegisterProof } from "../utils/generateProof"; +import serialized_dsc_tree from "../../../common/pubkeys/serialized_dsc_tree.json"; import { DeployedActors } from "../utils/types"; import { generateRandomFieldElement } from "../utils/utils"; @@ -59,7 +59,7 @@ describe("Commitment Registration Tests", function () { const hashFunction = (a: bigint, b: bigint) => poseidon2([a, b]); // must be imported dynamic since @openpassport/zk-kit-lean-imt is exclusively esm and hardhat does not support esm with typescript until verison 3 - const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then(mod => mod.LeanIMT); + const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then((mod) => mod.LeanIMT); const imt = new LeanIMT(hashFunction); await imt.insert(BigInt(dscProof.pubSignals[CIRCUIT_CONSTANTS.DSC_TREE_LEAF_INDEX])); @@ -243,7 +243,7 @@ describe("Commitment Registration Tests", function () { const hashFunction = (a: bigint, b: bigint) => poseidon2([a, b]); // must be imported dynamic since @openpassport/zk-kit-lean-imt is exclusively esm and hardhat does not support esm with typescript until verison 3 - const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then(mod => mod.LeanIMT); + const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then((mod) => mod.LeanIMT); const imt = new LeanIMT(hashFunction); await imt.insert(BigInt(registerProof.pubSignals[CIRCUIT_CONSTANTS.REGISTER_COMMITMENT_INDEX])); diff --git a/contracts/test/integration/endToEnd.test.ts b/contracts/test/integration/endToEnd.test.ts index 4985125fc..7cf10c1f3 100644 --- a/contracts/test/integration/endToEnd.test.ts +++ b/contracts/test/integration/endToEnd.test.ts @@ -1,4 +1,3 @@ - import { expect } from "chai"; import { BigNumberish, TransactionReceipt } from "ethers"; import { ethers } from "hardhat"; @@ -10,8 +9,9 @@ import { ATTESTATION_ID } from "../utils/constants"; import { deploySystemFixtures } from "../utils/deployment"; import BalanceTree from "../utils/example/balance-tree"; import { Formatter } from "../utils/formatter"; -import { generateDscProof, generateRegisterProof, generateVcAndDiscloseProof } from "../utils/generateProof.js"; -import serialized_dsc_tree from "../utils/pubkeys/serialized_dsc_tree.json"; +import { generateDscProof, generateRegisterProof, generateVcAndDiscloseProof } from "../utils/generateProof"; +import { LeanIMT } from "@openpassport/zk-kit-lean-imt"; +import serialized_dsc_tree from "../../../common/pubkeys/serialized_dsc_tree.json"; import { DeployedActors, VcAndDiscloseHubProof } from "../utils/types"; import { generateRandomFieldElement, splitHexFromBack } from "../utils/utils"; @@ -86,7 +86,7 @@ describe("End to End Tests", function () { const hashFunction = (a: bigint, b: bigint) => poseidon2([a, b]); // must be imported dynamic since @openpassport/zk-kit-lean-imt is exclusively esm and hardhat does not support esm with typescript until verison 3 - const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then(mod => mod.LeanIMT); + const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then((mod) => mod.LeanIMT); const imt = new LeanIMT(hashFunction); await imt.insert(BigInt(registerProof.pubSignals[CIRCUIT_CONSTANTS.REGISTER_COMMITMENT_INDEX])); @@ -183,20 +183,18 @@ describe("End to End Tests", function () { await token.waitForDeployment(); const airdropFactory = await ethers.getContractFactory("Airdrop"); - const airdrop = await airdropFactory - .connect(owner) - .deploy( - hub.target, - castFromScope("test-scope"), - ATTESTATION_ID.E_PASSPORT, - token.target, - true, - 20, - // @ts-expect-error - true, - countriesListPacked as [BigNumberish, BigNumberish, BigNumberish, BigNumberish], - [true, true, true], - ); + const airdrop = await airdropFactory.connect(owner).deploy( + hub.target, + castFromScope("test-scope"), + ATTESTATION_ID.E_PASSPORT, + token.target, + true, + 20, + // @ts-expect-error + true, + countriesListPacked as [BigNumberish, BigNumberish, BigNumberish, BigNumberish], + [true, true, true], + ); await airdrop.waitForDeployment(); await token.connect(owner).mint(airdrop.target, BigInt(1000000000000000000)); diff --git a/contracts/test/integration/vcAndDisclose.test.ts b/contracts/test/integration/vcAndDisclose.test.ts index dc6591d39..c15d799c8 100644 --- a/contracts/test/integration/vcAndDisclose.test.ts +++ b/contracts/test/integration/vcAndDisclose.test.ts @@ -10,11 +10,7 @@ import { generateCommitment } from "@selfxyz/common/utils/passports/passport"; import { BigNumberish } from "ethers"; import { generateRandomFieldElement, getStartOfDayTimestamp, splitHexFromBack } from "../utils/utils"; import { Formatter, CircuitAttributeHandler } from "../utils/formatter"; -import { - formatCountriesList, - reverseBytes, - reverseCountryBytes, -} from "@selfxyz/common/utils/circuits/formatInputs"; +import { formatCountriesList, reverseBytes, reverseCountryBytes } from "@selfxyz/common/utils/circuits/formatInputs"; import { getPackedForbiddenCountries } from "@selfxyz/common/utils/contracts/forbiddenCountries"; import { countries, Country3LetterCode } from "@selfxyz/common/constants/countries"; import fs from "fs"; @@ -47,7 +43,7 @@ describe("VC and Disclose", () => { const hashFunction = (a: bigint, b: bigint) => poseidon2([a, b]); // must be imported dynamic since @openpassport/zk-kit-lean-imt is exclusively esm and hardhat does not support esm with typescript until verison 3 - const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then(mod => mod.LeanIMT); + const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then((mod) => mod.LeanIMT); imt = new LeanIMT(hashFunction); await imt.insert(BigInt(commitment)); @@ -93,7 +89,7 @@ describe("VC and Disclose", () => { "ABC", "CBA", ] as Country3LetterCode[]; - forbiddenCountriesListPacked = getPackedForbiddenCountries(forbiddenCountriesList) + forbiddenCountriesListPacked = getPackedForbiddenCountries(forbiddenCountriesList); invalidForbiddenCountriesList = ["AAA", "ABC", "CBA", "CBA"]; // const invalidWholePacked = reverseBytes(Formatter.bytesToHexString(new Uint8Array(formatCountriesList(invalidForbiddenCountriesList)))); @@ -133,11 +129,16 @@ describe("VC and Disclose", () => { it("should verify and get result successfully", async () => { const { hub, registry, owner } = deployedActors; - const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { + const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { olderThanEnabled: true, olderThan: "20", forbiddenCountriesEnabled: true, - forbiddenCountriesListPacked: forbiddenCountriesListPacked, + forbiddenCountriesListPacked: forbiddenCountriesListPacked.slice(0, 4) as [ + BigNumberish, + BigNumberish, + BigNumberish, + BigNumberish, + ], ofacEnabled: [true, true, true] as [boolean, boolean, boolean], vcAndDiscloseProof: vcAndDiscloseProof, }; diff --git a/contracts/test/integration/verifyAll.test.ts b/contracts/test/integration/verifyAll.test.ts index 3562311b7..6fe782c73 100644 --- a/contracts/test/integration/verifyAll.test.ts +++ b/contracts/test/integration/verifyAll.test.ts @@ -41,7 +41,7 @@ describe("VerifyAll", () => { const hashFunction = (a: bigint, b: bigint) => poseidon2([a, b]); // must be imported dynamic since @openpassport/zk-kit-lean-imt is exclusively esm and hardhat does not support esm with typescript until verison 3 - const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then(mod => mod.LeanIMT); + const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then((mod) => mod.LeanIMT); imt = new LeanIMT(hashFunction); await imt.insert(BigInt(commitment)); @@ -178,7 +178,7 @@ describe("VerifyAll", () => { await registry.connect(owner).devAddIdentityCommitment(ATTESTATION_ID.E_PASSPORT, nullifier, commitment); vcAndDiscloseProof.pubSignals[CIRCUIT_CONSTANTS.VC_AND_DISCLOSE_MERKLE_ROOT_INDEX] = generateRandomFieldElement(); - const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { + const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { olderThanEnabled: true, olderThan: "20", forbiddenCountriesEnabled: true, @@ -199,7 +199,7 @@ describe("VerifyAll", () => { await registry.connect(owner).devAddIdentityCommitment(ATTESTATION_ID.E_PASSPORT, nullifier, commitment); - const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { + const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { olderThanEnabled: true, olderThan: "20", forbiddenCountriesEnabled: true, @@ -222,7 +222,7 @@ describe("VerifyAll", () => { vcAndDiscloseProof.a[0] = generateRandomFieldElement(); - const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { + const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { olderThanEnabled: false, olderThan: "20", forbiddenCountriesEnabled: false, @@ -245,7 +245,7 @@ describe("VerifyAll", () => { vcAndDiscloseProof.pubSignals[CIRCUIT_CONSTANTS.VC_AND_DISCLOSE_CURRENT_DATE_INDEX] = 0; - const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { + const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { olderThanEnabled: true, olderThan: "20", forbiddenCountriesEnabled: true, @@ -266,7 +266,7 @@ describe("VerifyAll", () => { const { registry, owner } = deployedActors; await registry.connect(owner).devAddIdentityCommitment(ATTESTATION_ID.E_PASSPORT, nullifier, commitment); - const vcAndDiscloseHubProof : VcAndDiscloseHubProof = { + const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { olderThanEnabled: true, olderThan: "21", // Higher than the age in proof forbiddenCountriesEnabled: false, @@ -304,7 +304,7 @@ describe("VerifyAll", () => { "0", ); - const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { + const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { olderThanEnabled: true, olderThan: "20", forbiddenCountriesEnabled: false, @@ -329,7 +329,7 @@ describe("VerifyAll", () => { const { registry, owner } = deployedActors; await registry.connect(owner).devAddIdentityCommitment(ATTESTATION_ID.E_PASSPORT, nullifier, commitment); - const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { + const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { olderThanEnabled: true, olderThan: "20", forbiddenCountriesEnabled: true, @@ -350,7 +350,7 @@ describe("VerifyAll", () => { const { registry, owner } = deployedActors; await registry.connect(owner).devAddIdentityCommitment(ATTESTATION_ID.E_PASSPORT, nullifier, commitment); - const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { + const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { olderThanEnabled: true, olderThan: "20", forbiddenCountriesEnabled: true, @@ -378,7 +378,7 @@ describe("VerifyAll", () => { vcAndDiscloseProof.pubSignals[CIRCUIT_CONSTANTS.VC_AND_DISCLOSE_PASSPORT_NO_SMT_ROOT_INDEX] = generateRandomFieldElement(); - const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { + const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { olderThanEnabled: true, olderThan: "20", forbiddenCountriesEnabled: true, @@ -402,7 +402,7 @@ describe("VerifyAll", () => { vcAndDiscloseProof.pubSignals[CIRCUIT_CONSTANTS.VC_AND_DISCLOSE_NAME_DOB_SMT_ROOT_INDEX] = generateRandomFieldElement(); - const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { + const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { olderThanEnabled: true, olderThan: "20", forbiddenCountriesEnabled: true, @@ -426,7 +426,7 @@ describe("VerifyAll", () => { vcAndDiscloseProof.pubSignals[CIRCUIT_CONSTANTS.VC_AND_DISCLOSE_NAME_YOB_SMT_ROOT_INDEX] = generateRandomFieldElement(); - const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { + const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { olderThanEnabled: true, olderThan: "20", forbiddenCountriesEnabled: true, @@ -479,7 +479,7 @@ describe("VerifyAll", () => { vcAndDiscloseProof.a[0] = generateRandomFieldElement(); - const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { + const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { olderThanEnabled: true, olderThan: "20", forbiddenCountriesEnabled: true, @@ -502,7 +502,7 @@ describe("VerifyAll", () => { vcAndDiscloseProof.pubSignals[CIRCUIT_CONSTANTS.VC_AND_DISCLOSE_CURRENT_DATE_INDEX] = 0; - const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { + const vcAndDiscloseHubProof: VcAndDiscloseHubProof = { olderThanEnabled: true, olderThan: "20", forbiddenCountriesEnabled: true, diff --git a/contracts/test/unit/CustomVerifier.test.ts b/contracts/test/unit/CustomVerifier.test.ts new file mode 100644 index 000000000..ab168b0c5 --- /dev/null +++ b/contracts/test/unit/CustomVerifier.test.ts @@ -0,0 +1,411 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { TestCustomVerifier, CustomVerifier } from "../../typechain-types"; + +export const AttestationId = { + E_PASSPORT: "0x0000000000000000000000000000000000000000000000000000000000000001", + EU_ID_CARD: "0x0000000000000000000000000000000000000000000000000000000000000002", +} as const; + +describe("CustomVerifier", function () { + let testVerifier: TestCustomVerifier; + let customVerifier: CustomVerifier; + + before(async function () { + const CustomVerifierFactory = await ethers.getContractFactory("CustomVerifier"); + customVerifier = await CustomVerifierFactory.deploy(); + await customVerifier.waitForDeployment(); + + const TestVerifierFactory = await ethers.getContractFactory("TestCustomVerifier", { + libraries: { + CustomVerifier: await customVerifier.getAddress(), + }, + }); + testVerifier = await TestVerifierFactory.deploy(); + await testVerifier.waitForDeployment(); + }); + + describe("Passport Verification", function () { + const mrz = ethers.toUtf8Bytes( + "P + await testVerifier.testCustomVerify( + AttestationId.E_PASSPORT, + ethers.AbiCoder.defaultAbiCoder().encode(["tuple(bool,uint256,bool,uint256[4],bool[3])"], [config]), + ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256,bytes,uint256,uint256,uint256[4])"], + [samplePassportOutput], + ), + ), + ).to.be.revertedWithCustomError(customVerifier, "INVALID_OFAC"); + }); + + it("should return proper OFAC results", async function () { + const config = [ + false, + 0, + false, + [ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0)], + [false, false, false], + ]; + + const result = await testVerifier.testCustomVerify( + AttestationId.E_PASSPORT, + ethers.AbiCoder.defaultAbiCoder().encode(["tuple(bool,uint256,bool,uint256[4],bool[3])"], [config]), + ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256,bytes,uint256,uint256,uint256[4])"], + [samplePassportOutput], + ), + ); + + expect(result.attestationId).to.equal(AttestationId.E_PASSPORT); + expect(result.ofac[0]).to.equal(true); + expect(result.ofac[1]).to.equal(false); + expect(result.ofac[2]).to.equal(true); + }); + + it("should verify passport with forbidden countries check", async function () { + const config = [ + false, + 0, + true, + [ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0)], + [false, false, false], + ]; + + const result = await testVerifier.testCustomVerify( + AttestationId.E_PASSPORT, + ethers.AbiCoder.defaultAbiCoder().encode(["tuple(bool,uint256,bool,uint256[4],bool[3])"], [config]), + ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256,bytes,uint256,uint256,uint256[4])"], + [samplePassportOutput], + ), + ); + + expect(result.attestationId).to.equal(AttestationId.E_PASSPORT); + }); + + it("should throw an error if age is not valid", async function () { + const config = [ + true, + 19, + false, + [ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0)], + [false, false, false], + ]; + + expect( + async () => + await testVerifier.testCustomVerify( + AttestationId.E_PASSPORT, + ethers.AbiCoder.defaultAbiCoder().encode(["tuple(bool,uint256,bool,uint256[4],bool[3])"], [config]), + ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256,bytes,uint256,uint256,uint256[4])"], + [samplePassportOutput], + ), + ), + ).to.be.revertedWithCustomError(customVerifier, "INVALID_OLDER_THAN"); + }); + + it("should not throw an error if older than is not enabled", async function () { + const config = [ + false, + 19, + false, + [ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0)], + [false, false, false], + ]; + + const result = await testVerifier.testCustomVerify( + AttestationId.E_PASSPORT, + ethers.AbiCoder.defaultAbiCoder().encode(["tuple(bool,uint256,bool,uint256[4],bool[3])"], [config]), + ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256,bytes,uint256,uint256,uint256[4])"], + [samplePassportOutput], + ), + ); + + expect(result.attestationId).to.equal(AttestationId.E_PASSPORT); + }); + + it("should not throw an error if age is valid", async function () { + const config = [ + true, + 18, + false, + [ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0)], + [false, false, false], + ]; + + const result = await testVerifier.testCustomVerify( + AttestationId.E_PASSPORT, + ethers.AbiCoder.defaultAbiCoder().encode(["tuple(bool,uint256,bool,uint256[4],bool[3])"], [config]), + ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256,bytes,uint256,uint256,uint256[4])"], + [samplePassportOutput], + ), + ); + + expect(result.attestationId).to.equal(AttestationId.E_PASSPORT); + expect(result.olderThan).to.equal(18); + }); + }); + + describe("ID Card Verification", function () { + let mrz = "I + await testVerifier.testCustomVerify( + AttestationId.EU_ID_CARD, + ethers.AbiCoder.defaultAbiCoder().encode(["tuple(bool,uint256,bool,uint256[4],bool[3])"], [config]), + ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256,bytes,uint256,uint256,uint256[4])"], + [sampleIdCardOutput], + ), + ), + ).to.be.revertedWithCustomError(customVerifier, "INVALID_OFAC"); + }); + + it("should return proper OFAC results", async function () { + const config = [ + false, + 0, + false, + [ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0)], + [false, false, false], + ]; + + const result = await testVerifier.testCustomVerify( + AttestationId.EU_ID_CARD, + ethers.AbiCoder.defaultAbiCoder().encode(["tuple(bool,uint256,bool,uint256[4],bool[3])"], [config]), + ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256,bytes,uint256,uint256,uint256[4])"], + [sampleIdCardOutput], + ), + ); + + expect(result.attestationId).to.equal(AttestationId.EU_ID_CARD); + expect(result.ofac[0]).to.equal(false); + expect(result.ofac[1]).to.equal(true); + expect(result.ofac[2]).to.equal(false); + }); + + it("should verify ID card with OFAC checks", async function () { + const config = [ + false, + 0, + false, + [ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0)], + [false, false, false], + ]; + + const result = await testVerifier.testCustomVerify( + AttestationId.EU_ID_CARD, + ethers.AbiCoder.defaultAbiCoder().encode(["tuple(bool,uint256,bool,uint256[4],bool[3])"], [config]), + ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256,bytes,uint256,uint256,uint256[4])"], + [sampleIdCardOutput], + ), + ); + + expect(result.attestationId).to.equal(AttestationId.EU_ID_CARD); + }); + + it("should verify ID card with forbidden countries check", async function () { + const config = [ + false, + 0, + true, + [ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0)], + [false, false, false], + ]; + + const result = await testVerifier.testCustomVerify( + AttestationId.EU_ID_CARD, + ethers.AbiCoder.defaultAbiCoder().encode(["tuple(bool,uint256,bool,uint256[4],bool[3])"], [config]), + ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256,bytes,uint256,uint256,uint256[4])"], + [sampleIdCardOutput], + ), + ); + + expect(result.attestationId).to.equal(AttestationId.EU_ID_CARD); + }); + + it("should throw an error if age is not valid", async function () { + const config = [ + true, + 19, + false, + [ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0)], + [false, false, false], + ]; + + expect( + async () => + await testVerifier.testCustomVerify( + AttestationId.EU_ID_CARD, + ethers.AbiCoder.defaultAbiCoder().encode(["tuple(bool,uint256,bool,uint256[4],bool[3])"], [config]), + ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256,bytes,uint256,uint256,uint256[4])"], + [sampleIdCardOutput], + ), + ), + ).to.be.revertedWithCustomError(customVerifier, "INVALID_OLDER_THAN"); + }); + + it("should not throw an error if older than is not enabled", async function () { + const config = [ + false, + 19, + false, + [ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0)], + [false, false, false], + ]; + + const result = await testVerifier.testCustomVerify( + AttestationId.EU_ID_CARD, + ethers.AbiCoder.defaultAbiCoder().encode(["tuple(bool,uint256,bool,uint256[4],bool[3])"], [config]), + ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256,bytes,uint256,uint256,uint256[4])"], + [sampleIdCardOutput], + ), + ); + + expect(result.attestationId).to.equal(AttestationId.EU_ID_CARD); + }); + + it("should verify ID card with age check", async function () { + const config = [ + true, + 18, + false, + [ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0)], + [false, false, false], + ]; + + const result = await testVerifier.testCustomVerify( + AttestationId.EU_ID_CARD, + ethers.AbiCoder.defaultAbiCoder().encode(["tuple(bool,uint256,bool,uint256[4],bool[3])"], [config]), + ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256,bytes,uint256,uint256,uint256[4])"], + [sampleIdCardOutput], + ), + ); + + expect(result.attestationId).to.equal(AttestationId.EU_ID_CARD); + expect(result.olderThan).to.equal(18); + }); + }); + + it("should revert with invalid attestation ID", async function () { + const config = [ + false, + 0, + false, + [ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0)], + [false, false, false], + ]; + + const invalidAttestationId = ethers.zeroPadValue(ethers.toBeHex(999), 32); + + await expect( + testVerifier.testCustomVerify( + invalidAttestationId, + ethers.AbiCoder.defaultAbiCoder().encode(["tuple(bool,uint256,bool,uint256[4],bool[3])"], [config]), + ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256,bytes,uint256,uint256,uint256[4])"], + [ + [ + ethers.getBigInt(ethers.hexlify(ethers.randomBytes(32))), // attestationId (uint256) + ethers.randomBytes(88), // revealedDataPacked (bytes) + ethers.getBigInt(ethers.hexlify(ethers.randomBytes(32))), // userIdentifier (uint256) + ethers.getBigInt(ethers.hexlify(ethers.randomBytes(32))), // nullifier (uint256) + [ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0), ethers.getBigInt(0)], // forbiddenCountriesListPacked + ], + ], + ), + ), + ).to.be.revertedWithCustomError(customVerifier, "INVALID_ATTESTATION_ID"); + }); +}); diff --git a/contracts/test/unit/GenericFormatter.test.ts b/contracts/test/unit/GenericFormatter.test.ts new file mode 100644 index 000000000..4e84a601a --- /dev/null +++ b/contracts/test/unit/GenericFormatter.test.ts @@ -0,0 +1,165 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { TestGenericFormatter } from "../../typechain-types"; +import type { SelfStructs } from "../../typechain-types/contracts/tests/testGenericFormatter.sol/TestGenericFormatter"; + +describe("GenericFormatter", function () { + let testGenericFormatter: TestGenericFormatter; + + before(async function () { + const TestGenericFormatterFactory = await ethers.getContractFactory("TestGenericFormatter"); + testGenericFormatter = await TestGenericFormatterFactory.deploy(); + await testGenericFormatter.waitForDeployment(); + }); + + it("should convert from v1 to the latest config struct", async function () { + // Create a sample VerificationConfigV1 struct + const verificationConfigV1: SelfStructs.VerificationConfigV1Struct = { + olderThanEnabled: true, + olderThan: 18, + forbiddenCountriesEnabled: false, + forbiddenCountriesListPacked: [0n, 0n, 0n, 0n], + ofacEnabled: [false, false, false], + }; + + const verificationConfigV2 = await testGenericFormatter.testFromV1Config(verificationConfigV1); + + // Add your assertions here + expect(verificationConfigV2.olderThanEnabled).to.equal(verificationConfigV1.olderThanEnabled); + expect(verificationConfigV2.olderThan).to.equal(verificationConfigV1.olderThan); + expect(verificationConfigV2.forbiddenCountriesEnabled).to.equal(verificationConfigV1.forbiddenCountriesEnabled); + expect(verificationConfigV2.forbiddenCountriesListPacked).to.deep.equal( + verificationConfigV1.forbiddenCountriesListPacked, + ); + expect(verificationConfigV2.ofacEnabled).to.deep.equal(verificationConfigV1.ofacEnabled); + }); + + it("should convert from bytes to the latest config struct", async function () { + // Create a sample VerificationConfigV2 struct + const verificationConfigV2: SelfStructs.VerificationConfigV2Struct = { + olderThanEnabled: true, + olderThan: 18, + forbiddenCountriesEnabled: false, + forbiddenCountriesListPacked: [0n, 0n, 0n, 0n], + ofacEnabled: [false, false, false], + }; + + //abi encode the verificationConfigV2 struct + const verificationConfigV2Bytes = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(bool,uint256,bool,uint256[4],bool[3])"], + [ + [ + verificationConfigV2.olderThanEnabled, + verificationConfigV2.olderThan, + verificationConfigV2.forbiddenCountriesEnabled, + verificationConfigV2.forbiddenCountriesListPacked, + verificationConfigV2.ofacEnabled, + ], + ], + ); + + const verificationConfigV2BytesDecoded = + await testGenericFormatter.testVerificationConfigFromBytes(verificationConfigV2Bytes); + + // Add your assertions here + expect(verificationConfigV2BytesDecoded.olderThanEnabled).to.equal(verificationConfigV2.olderThanEnabled); + expect(verificationConfigV2BytesDecoded.olderThan).to.equal(verificationConfigV2.olderThan); + expect(verificationConfigV2BytesDecoded.forbiddenCountriesEnabled).to.equal( + verificationConfigV2.forbiddenCountriesEnabled, + ); + expect(verificationConfigV2BytesDecoded.forbiddenCountriesListPacked).to.deep.equal( + verificationConfigV2.forbiddenCountriesListPacked, + ); + expect(verificationConfigV2BytesDecoded.ofacEnabled).to.deep.equal(verificationConfigV2.ofacEnabled); + }); + + it("should convert v1 config to bytes of the latest config struct", async function () { + // Create a sample VerificationConfigV1 struct + const verificationConfigV1: SelfStructs.VerificationConfigV1Struct = { + olderThanEnabled: true, + olderThan: 18, + forbiddenCountriesEnabled: false, + forbiddenCountriesListPacked: [0n, 0n, 0n, 0n], + ofacEnabled: [false, false, false], + }; + + const verificationConfigLatest = await testGenericFormatter.testFormatV1Config(verificationConfigV1); + + const verificationConfigLatestDecoded = ethers.AbiCoder.defaultAbiCoder().decode( + ["tuple(bool,uint256,bool,uint256[4],bool[3])"], + verificationConfigLatest, + ); + + // Add your assertions here + expect(verificationConfigLatestDecoded[0][0]).to.equal(verificationConfigV1.olderThanEnabled); + expect(verificationConfigLatestDecoded[0][1]).to.equal(verificationConfigV1.olderThan); + expect(verificationConfigLatestDecoded[0][2]).to.equal(verificationConfigV1.forbiddenCountriesEnabled); + expect(verificationConfigLatestDecoded[0][3]).to.deep.equal(verificationConfigV1.forbiddenCountriesListPacked); + expect(verificationConfigLatestDecoded[0][4]).to.deep.equal(verificationConfigV1.ofacEnabled); + }); + + it("should convert v2 config to bytes of the latest config struct", async function () { + // Create a sample VerificationConfigV2 struct + const verificationConfigV2: SelfStructs.VerificationConfigV2Struct = { + olderThanEnabled: true, + olderThan: 18, + forbiddenCountriesEnabled: false, + forbiddenCountriesListPacked: [0n, 0n, 0n, 0n], + ofacEnabled: [false, false, false], + }; + + const verificationConfigV2Bytes = await testGenericFormatter.testFormatV2Config(verificationConfigV2); + + const verificationConfigLatest = ethers.AbiCoder.defaultAbiCoder().decode( + ["tuple(bool,uint256,bool,uint256[4],bool[3])"], + verificationConfigV2Bytes, + ); + + // Add your assertions here + expect(verificationConfigLatest[0][0]).to.equal(verificationConfigV2.olderThanEnabled); + expect(verificationConfigLatest[0][1]).to.equal(verificationConfigV2.olderThan); + expect(verificationConfigLatest[0][2]).to.equal(verificationConfigV2.forbiddenCountriesEnabled); + expect(verificationConfigLatest[0][3]).to.deep.equal(verificationConfigV2.forbiddenCountriesListPacked); + expect(verificationConfigLatest[0][4]).to.deep.equal(verificationConfigV2.ofacEnabled); + }); + + it("should convert v2 struct to bytes of the latest config struct", async function () { + // Create a sample GenericDiscloseOutputV2 struct + const genericDiscloseOutputV2: SelfStructs.GenericDiscloseOutputV2Struct = { + attestationId: "0x0000000000000000000000000000000000000000000000000000000000000001", + userIdentifier: 1, + nullifier: 1, + forbiddenCountriesListPacked: [0n, 0n, 0n, 0n], + issuingState: "US", + name: ["John", "Doe"], + idNumber: "1234567890", + nationality: "US", + dateOfBirth: "1990-01-01", + gender: "Male", + expiryDate: "2025-01-01", + olderThan: 18, + ofac: [false, false, false], + }; + + const genericDiscloseOutputV2Bytes = await testGenericFormatter.testToV2Struct(genericDiscloseOutputV2); + + const genericDiscloseOutputLatest = ethers.AbiCoder.defaultAbiCoder().decode( + ["tuple(bytes32,uint256,uint256,uint256[4],string,string[],string,string,string,string,string,uint256,bool[3])"], + genericDiscloseOutputV2Bytes, + ); + + expect(genericDiscloseOutputV2.attestationId.toString()).to.equal(genericDiscloseOutputV2.attestationId); + expect(genericDiscloseOutputLatest[0][1]).to.equal(genericDiscloseOutputV2.userIdentifier); + expect(genericDiscloseOutputLatest[0][2]).to.equal(genericDiscloseOutputV2.nullifier); + expect(genericDiscloseOutputLatest[0][3]).to.deep.equal(genericDiscloseOutputV2.forbiddenCountriesListPacked); + expect(genericDiscloseOutputLatest[0][4]).to.equal(genericDiscloseOutputV2.issuingState); + expect(genericDiscloseOutputLatest[0][5]).to.deep.equal(genericDiscloseOutputV2.name); + expect(genericDiscloseOutputLatest[0][6]).to.equal(genericDiscloseOutputV2.idNumber); + expect(genericDiscloseOutputLatest[0][7]).to.equal(genericDiscloseOutputV2.nationality); + expect(genericDiscloseOutputLatest[0][8]).to.equal(genericDiscloseOutputV2.dateOfBirth); + expect(genericDiscloseOutputLatest[0][9]).to.equal(genericDiscloseOutputV2.gender); + expect(genericDiscloseOutputLatest[0][10]).to.equal(genericDiscloseOutputV2.expiryDate); + expect(genericDiscloseOutputLatest[0][11]).to.equal(genericDiscloseOutputV2.olderThan); + expect(genericDiscloseOutputLatest[0][12]).to.deep.equal(genericDiscloseOutputV2.ofac); + }); +}); diff --git a/contracts/test/unit/IdentityRegistry.test.ts b/contracts/test/unit/IdentityRegistry.test.ts index cd6738e33..8a387762b 100644 --- a/contracts/test/unit/IdentityRegistry.test.ts +++ b/contracts/test/unit/IdentityRegistry.test.ts @@ -192,7 +192,7 @@ describe("Unit Tests for IdentityRegistry", () => { const hashFunction = (a: bigint, b: bigint) => poseidon2([a, b]); // must be imported dynamic since @openpassport/zk-kit-lean-imt is exclusively esm and hardhat does not support esm with typescript until verison 3 - const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then(mod => mod.LeanIMT); + const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then((mod) => mod.LeanIMT); const imt = new LeanIMT(hashFunction); imt.insert(BigInt(commitment)); expect(imt.root).to.equal(root); diff --git a/contracts/test/unit/formatter.test.ts b/contracts/test/unit/formatter.test.ts index fbbfa94e4..568ce8bdd 100644 --- a/contracts/test/unit/formatter.test.ts +++ b/contracts/test/unit/formatter.test.ts @@ -150,13 +150,26 @@ describe("Formatter", function () { describe("extractForbiddenCountriesFromPacked", function () { it("should match contract and ts implementation", async function () { - const input = "0x414141424242434343"; - const contractResult = await testFormatter.testExtractForbiddenCountriesFromPacked([input, 0n, 0n, 0n]); - const tsResult = Formatter.extractForbiddenCountriesFromPacked(BigInt(input)); - expect(contractResult).to.deep.equal(tsResult); - expect(contractResult[0]).to.equal("CCC"); - expect(contractResult[1]).to.equal("BBB"); - expect(contractResult[2]).to.equal("AAA"); + const input1 = "0x414754414154414149414f4741444e414d5341415a44424c41414c41474641"; + const input2 = "0x4542524c42425242444742524842534842455a415355415742414d52414752"; + const input3 = "0x4e41434d484b5650434e52424c4f424e5442554d424e45425a4c42554d424c"; + const input4 = "0x4853454d4559424d5a45575a5455564b4e445453454e4843564943"; + const contractResult = await testFormatter.testExtractForbiddenCountriesFromPacked([ + input1, + input2, + input3, + input4, + ]); + const tsResult: string[] = Formatter.extractForbiddenCountriesFromPacked([input1, input2, input3, input4], "id"); + let formattedTsResult = tsResult + .map((item: string, index: number) => { + if (index % 3 === 0) { + return item + tsResult[index + 1] + tsResult[index + 2]; + } + return undefined; + }) + .filter(Boolean); + expect(contractResult).to.deep.equal(formattedTsResult); }); it("should revert when field element is out of range", async function () { diff --git a/contracts/test/utils/constants.ts b/contracts/test/utils/constants.ts index e9c37b753..3ac0134f9 100644 --- a/contracts/test/utils/constants.ts +++ b/contracts/test/utils/constants.ts @@ -1,6 +1,7 @@ export const ATTESTATION_ID = { INVALID_ATTESTATION_ID: "0x0000000000000000000000000000000000000000000000000000000000000000", E_PASSPORT: "0x0000000000000000000000000000000000000000000000000000000000000001", + EU_ID_CARD: "0x0000000000000000000000000000000000000000000000000000000000000002", }; export const FIELD_PRIME = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); diff --git a/contracts/test/utils/deploymentV2.ts b/contracts/test/utils/deploymentV2.ts new file mode 100644 index 000000000..5c1fdf935 --- /dev/null +++ b/contracts/test/utils/deploymentV2.ts @@ -0,0 +1,239 @@ +import { ethers } from "hardhat"; +import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; +import { Signer } from "ethers"; +import { DscVerifierId, RegisterVerifierId } from "@selfxyz/common/constants/constants"; +import { genAndInitMockPassportData } from "@selfxyz/common/utils/passports/genMockPassportData"; +import { getCscaTreeRoot } from "@selfxyz/common/utils/trees"; +import { PassportData } from "@selfxyz/common/utils/types"; +import { getSMTs } from "./generateProof"; +import serialized_csca_tree from "../../../common/pubkeys/serialized_csca_tree.json"; +import { DeployedActorsV2 } from "./types"; +import { hashEndpointWithScope } from "@selfxyz/common/utils/scope"; + +// Verifier artifacts (local staging) +import VcAndDiscloseVerifierArtifactLocal from "../../artifacts/contracts/verifiers/local/staging/disclose/Verifier_vc_and_disclose_staging.sol/Verifier_vc_and_disclose_staging.json"; +import VcAndDiscloseIdVerifierArtifactLocal from "../../artifacts/contracts/verifiers/local/staging/disclose/Verifier_vc_and_disclose_id_staging.sol/Verifier_vc_and_disclose_id_staging.json"; +import RegisterVerifierArtifactLocal from "../../artifacts/contracts/verifiers/local/staging/register/Verifier_register_sha256_sha256_sha256_rsa_65537_4096_staging.sol/Verifier_register_sha256_sha256_sha256_rsa_65537_4096_staging.json"; +import RegisterIdVerifierArtifactLocal from "../../artifacts/contracts/verifiers/local/staging/register_id/Verifier_register_id_sha256_sha256_sha256_rsa_65537_4096_staging.sol/Verifier_register_id_sha256_sha256_sha256_rsa_65537_4096_staging.json"; +import DscVerifierArtifactLocal from "../../artifacts/contracts/verifiers/local/staging/dsc/Verifier_dsc_sha256_rsa_65537_4096_staging.sol/Verifier_dsc_sha256_rsa_65537_4096_staging.json"; +import { PoseidonT3 } from "poseidon-solidity"; + +export async function deploySystemFixturesV2(): Promise { + let identityVerificationHubV2: any; + let identityVerificationHubImplV2: any; + let identityRegistryProxy: any; + let identityRegistryImpl: any; + let identityRegistryIdProxy: any; + let identityRegistryIdImpl: any; + let vcAndDiscloseVerifier: any; + let vcAndDiscloseIdVerifier: any; + let registerVerifier: any; + let registerIdVerifier: any; + let dscVerifier: any; + let testSelfVerificationRoot: any; + let owner: HardhatEthersSigner; + let user1: HardhatEthersSigner; + let user2: HardhatEthersSigner; + let mockPassport: PassportData; + + [owner, user1, user2] = await ethers.getSigners(); + + const newBalance = "0x" + ethers.parseEther("10000").toString(16); + + await ethers.provider.send("hardhat_setBalance", [await owner.getAddress(), newBalance]); + await ethers.provider.send("hardhat_setBalance", [await user1.getAddress(), newBalance]); + await ethers.provider.send("hardhat_setBalance", [await user2.getAddress(), newBalance]); + + mockPassport = genAndInitMockPassportData("sha256", "sha256", "rsa_sha256_65537_4096", "FRA", "940131", "401031"); + + // Deploy verifiers using artifacts + const vcAndDiscloseVerifierArtifact = VcAndDiscloseVerifierArtifactLocal; + const vcAndDiscloseVerifierFactory = await ethers.getContractFactory( + vcAndDiscloseVerifierArtifact.abi, + vcAndDiscloseVerifierArtifact.bytecode, + ); + vcAndDiscloseVerifier = await vcAndDiscloseVerifierFactory.connect(owner).deploy(); + await vcAndDiscloseVerifier.waitForDeployment(); + + // Deploy VC and Disclose ID verifier + const vcAndDiscloseIdVerifierArtifact = VcAndDiscloseIdVerifierArtifactLocal; + const vcAndDiscloseIdVerifierFactory = await ethers.getContractFactory( + vcAndDiscloseIdVerifierArtifact.abi, + vcAndDiscloseIdVerifierArtifact.bytecode, + ); + vcAndDiscloseIdVerifier = await vcAndDiscloseIdVerifierFactory.connect(owner).deploy(); + await vcAndDiscloseIdVerifier.waitForDeployment(); + + // Deploy register verifier + const registerVerifierArtifact = RegisterVerifierArtifactLocal; + const registerVerifierFactory = await ethers.getContractFactory( + registerVerifierArtifact.abi, + registerVerifierArtifact.bytecode, + ); + registerVerifier = await registerVerifierFactory.connect(owner).deploy(); + await registerVerifier.waitForDeployment(); + + // Deploy register ID verifier + const registerIdVerifierArtifact = RegisterIdVerifierArtifactLocal; + const registerIdVerifierFactory = await ethers.getContractFactory( + registerIdVerifierArtifact.abi, + registerIdVerifierArtifact.bytecode, + ); + registerIdVerifier = await registerIdVerifierFactory.connect(owner).deploy(); + await registerIdVerifier.waitForDeployment(); + + // Deploy dsc verifier + const dscVerifierArtifact = DscVerifierArtifactLocal; + const dscVerifierFactory = await ethers.getContractFactory(dscVerifierArtifact.abi, dscVerifierArtifact.bytecode); + dscVerifier = await dscVerifierFactory.connect(owner).deploy(); + await dscVerifier.waitForDeployment(); + + // Deploy PoseidonT3 + const PoseidonT3Factory = await ethers.getContractFactory("PoseidonT3"); + const poseidonT3 = await PoseidonT3Factory.connect(owner).deploy(); + await poseidonT3.waitForDeployment(); + + // Deploy CustomVerifier library + const CustomVerifierFactory = await ethers.getContractFactory("CustomVerifier"); + const customVerifier = await CustomVerifierFactory.connect(owner).deploy(); + await customVerifier.waitForDeployment(); + + // Deploy GenericFormatter library + const GenericFormatterFactory = await ethers.getContractFactory("GenericFormatter"); + const genericFormatter = await GenericFormatterFactory.connect(owner).deploy(); + await genericFormatter.waitForDeployment(); + + // Deploy IdentityRegistryImplV1 (same registry as V1) + const IdentityRegistryImplFactory = await ethers.getContractFactory("IdentityRegistryImplV1", { + libraries: { + PoseidonT3: poseidonT3.target, + }, + }); + identityRegistryImpl = await IdentityRegistryImplFactory.connect(owner).deploy(); + await identityRegistryImpl.waitForDeployment(); + + // Deploy IdentityRegistryIdCardImplV1 for ID cards + const IdentityRegistryIdImplFactory = await ethers.getContractFactory("IdentityRegistryIdCardImplV1", { + libraries: { + PoseidonT3: poseidonT3.target, + }, + }); + identityRegistryIdImpl = await IdentityRegistryIdImplFactory.connect(owner).deploy(); + await identityRegistryIdImpl.waitForDeployment(); + // Deploy IdentityVerificationHubImplV2 + const IdentityVerificationHubImplV2Factory = await ethers.getContractFactory("IdentityVerificationHubImplV2", { + libraries: { + CustomVerifier: customVerifier.target, + }, + }); + identityVerificationHubImplV2 = await IdentityVerificationHubImplV2Factory.connect(owner).deploy(); + await identityVerificationHubImplV2.waitForDeployment(); + + // Deploy registry with temporary hub address + const temporaryHubAddress = "0x0000000000000000000000000000000000000000"; + const registryInitData = identityRegistryImpl.interface.encodeFunctionData("initialize", [temporaryHubAddress]); + const registryProxyFactory = await ethers.getContractFactory("IdentityRegistry"); + identityRegistryProxy = await registryProxyFactory + .connect(owner) + .deploy(identityRegistryImpl.target, registryInitData); + await identityRegistryProxy.waitForDeployment(); + + // Deploy ID card registry with temporary hub address + const registryIdInitData = identityRegistryIdImpl.interface.encodeFunctionData("initialize", [temporaryHubAddress]); + const registryIdProxyFactory = await ethers.getContractFactory("IdentityRegistry"); + identityRegistryIdProxy = await registryIdProxyFactory + .connect(owner) + .deploy(identityRegistryIdImpl.target, registryIdInitData); + await identityRegistryIdProxy.waitForDeployment(); + + // Deploy hub V2 with simple initialization (V2 has different initialization) + const initializeDataV2 = identityVerificationHubImplV2.interface.encodeFunctionData("initialize"); + const hubFactory = await ethers.getContractFactory("IdentityVerificationHub"); + identityVerificationHubV2 = await hubFactory + .connect(owner) + .deploy(identityVerificationHubImplV2.target, initializeDataV2); + await identityVerificationHubV2.waitForDeployment(); + + // Get contracts with implementation ABI and update hub address + const registryContract = await ethers.getContractAt("IdentityRegistryImplV1", identityRegistryProxy.target); + const updateHubTx = await registryContract.updateHub(identityVerificationHubV2.target); + await updateHubTx.wait(); + + const registryIdContract = await ethers.getContractAt("IdentityRegistryIdCardImplV1", identityRegistryIdProxy.target); + const updateIdHubTx = await registryIdContract.updateHub(identityVerificationHubV2.target); + await updateIdHubTx.wait(); + + const hubContract = (await ethers.getContractAt( + "IdentityVerificationHubImplV2", + identityVerificationHubV2.target, + )) as any; + + // Initialize roots + const csca_root = getCscaTreeRoot(serialized_csca_tree); + await registryContract.updateCscaRoot(csca_root, { from: owner }); + await registryIdContract.updateCscaRoot(csca_root, { from: owner }); + + const { passportNo_smt, nameAndDob_smt, nameAndYob_smt } = getSMTs(); + + await registryContract.updatePassportNoOfacRoot(passportNo_smt.root, { from: owner }); + await registryContract.updateNameAndDobOfacRoot(nameAndDob_smt.root, { from: owner }); + await registryIdContract.updateNameAndDobOfacRoot(nameAndDob_smt.root, { from: owner }); + await registryContract.updateNameAndYobOfacRoot(nameAndYob_smt.root, { from: owner }); + await registryIdContract.updateNameAndYobOfacRoot(nameAndYob_smt.root, { from: owner }); + + // Register verifiers with the hub + const E_PASSPORT = ethers.hexlify(ethers.zeroPadValue(ethers.toBeHex(1), 32)); + const EU_ID_CARD = ethers.hexlify(ethers.zeroPadValue(ethers.toBeHex(2), 32)); + + // Update registries in the hub + await hubContract.updateRegistry(E_PASSPORT, identityRegistryProxy.target); + await hubContract.updateRegistry(EU_ID_CARD, identityRegistryIdProxy.target); + + // Update VC and Disclose verifiers + await hubContract.updateVcAndDiscloseCircuit(E_PASSPORT, vcAndDiscloseVerifier.target); + await hubContract.updateVcAndDiscloseCircuit(EU_ID_CARD, vcAndDiscloseIdVerifier.target); + + // Update register verifiers + await hubContract.updateRegisterCircuitVerifier( + E_PASSPORT, + RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096, + registerVerifier.target, + ); + await hubContract.updateRegisterCircuitVerifier( + EU_ID_CARD, + RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096, + registerIdVerifier.target, + ); + + // Update DSC verifiers + await hubContract.updateDscVerifier(E_PASSPORT, DscVerifierId.dsc_sha256_rsa_65537_4096, dscVerifier.target); + // Add DSC verifier for EU_ID_CARD as well + await hubContract.updateDscVerifier(EU_ID_CARD, DscVerifierId.dsc_sha256_rsa_65537_4096, dscVerifier.target); + + // Deploy TestSelfVerificationRoot + const testScope = hashEndpointWithScope("example.com", "test-scope"); + const testRootFactory = await ethers.getContractFactory("TestSelfVerificationRoot"); + testSelfVerificationRoot = await testRootFactory.deploy(identityVerificationHubV2.target, testScope); + await testSelfVerificationRoot.waitForDeployment(); + + return { + hubImplV2: identityVerificationHubImplV2, + hub: hubContract, + registryImpl: identityRegistryImpl, + registry: registryContract, + registryIdImpl: identityRegistryIdImpl, + registryId: registryIdContract, + vcAndDisclose: vcAndDiscloseVerifier, + vcAndDiscloseId: vcAndDiscloseIdVerifier, + register: registerVerifier, + registerId: RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096, + dsc: dscVerifier, + dscId: DscVerifierId.dsc_sha256_rsa_65537_4096, + testSelfVerificationRoot: testSelfVerificationRoot, + customVerifier: customVerifier, + owner: owner as any, + user1: user1 as any, + user2: user2 as any, + mockPassport: mockPassport, + }; +} diff --git a/contracts/test/utils/formatter.ts b/contracts/test/utils/formatter.ts index aa6822f9b..a74ef9fe5 100644 --- a/contracts/test/utils/formatter.ts +++ b/contracts/test/utils/formatter.ts @@ -88,19 +88,25 @@ export class Formatter { ); } - static extractForbiddenCountriesFromPacked(publicSignal: bigint): string[] { - const forbiddenCountries: string[] = new Array(Formatter.MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH); - for (let j = 0; j < Formatter.MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH; j++) { - const byteIndex = BigInt(j * 3); - const shift = byteIndex * 8n; - const mask = 0xffffffn; - const packedData = (publicSignal >> shift) & mask; - const char1 = String.fromCharCode(Number((packedData >> 16n) & 0xffn)); - const char2 = String.fromCharCode(Number((packedData >> 8n) & 0xffn)); - const char3 = String.fromCharCode(Number(packedData & 0xffn)); - forbiddenCountries[j] = char1 + char2 + char3; - } - return forbiddenCountries; + static extractForbiddenCountriesFromPacked( + revealedData_packed: string | string[], + id_type: "passport" | "id", + ): string[] { + // If revealedData_packed is not an array, convert it to an array + const packedArray = Array.isArray(revealedData_packed) ? revealedData_packed : [revealedData_packed]; + + const bytesCount = id_type === "passport" ? [31, 31, 31] : [31, 31, 31, 27]; // nb of bytes in each of the first three field elements + const bytesArray = packedArray.flatMap((element: string, index: number) => { + const bytes = bytesCount[index] || 31; // Use 31 as default if index is out of range + const elementBigInt = BigInt(element); + const byteMask = BigInt(255); // 0xFF + const bytesOfElement = [...Array(bytes)].map((_, byteIndex) => { + return (elementBigInt >> (BigInt(byteIndex) * BigInt(8))) & byteMask; + }); + return bytesOfElement; + }); + + return bytesArray.map((byte: bigint) => String.fromCharCode(Number(byte))); } static proofDateToUnixTimestamp(dateNum: number[]): number { diff --git a/contracts/test/utils/generateProof.ts b/contracts/test/utils/generateProof.ts index cef65bf0d..52520a578 100644 --- a/contracts/test/utils/generateProof.ts +++ b/contracts/test/utils/generateProof.ts @@ -1,10 +1,5 @@ -const CYAN = "\x1b[36m"; -const YELLOW = "\x1b[33m"; -const GREEN = "\x1b[32m"; -const RESET = "\x1b[0m"; - -import { LeanIMT } from "@openpassport/zk-kit-lean-imt" -import { ChildNodes, SMT } from "@openpassport/zk-kit-smt" +import { LeanIMT } from "@openpassport/zk-kit-lean-imt"; +import { ChildNodes, SMT } from "@openpassport/zk-kit-smt"; import fs from "fs"; import path from "path"; import { poseidon2, poseidon3 } from "poseidon-lite"; @@ -19,8 +14,9 @@ import { generateCircuitInputsRegister, generateCircuitInputsVCandDisclose, } from "@selfxyz/common/utils/circuits/generateInputs"; -import serialized_csca_tree from "./pubkeys/serialized_csca_tree.json"; -import serialized_dsc_tree from "./pubkeys/serialized_dsc_tree.json"; +import { getCircuitNameFromPassportData } from "@selfxyz/common/utils/circuits/circuitsName"; +import serialized_csca_tree from "../../../common/pubkeys/serialized_csca_tree.json"; +import serialized_dsc_tree from "../../../common/pubkeys/serialized_dsc_tree.json"; const registerCircuits: CircuitArtifacts = { register_sha256_sha256_sha256_rsa_65537_4096: { @@ -29,6 +25,13 @@ const registerCircuits: CircuitArtifacts = { vkey: "../circuits/build/register/register_sha256_sha256_sha256_rsa_65537_4096/register_sha256_sha256_sha256_rsa_65537_4096_vkey.json", }, }; +const registerCircuitsId: CircuitArtifacts = { + register_id_sha256_sha256_sha256_rsa_65537_4096: { + wasm: "../circuits/build/register_id/register_id_sha256_sha256_sha256_rsa_65537_4096/register_id_sha256_sha256_sha256_rsa_65537_4096_js/register_id_sha256_sha256_sha256_rsa_65537_4096.wasm", + zkey: "../circuits/build/register_id/register_id_sha256_sha256_sha256_rsa_65537_4096/register_id_sha256_sha256_sha256_rsa_65537_4096_final.zkey", + vkey: "../circuits/build/register_id/register_id_sha256_sha256_sha256_rsa_65537_4096/register_id_sha256_sha256_sha256_rsa_65537_4096_vkey.json", + }, +}; const dscCircuits: CircuitArtifacts = { dsc_sha256_rsa_65537_4096: { wasm: "../circuits/build/dsc/dsc_sha256_rsa_65537_4096/dsc_sha256_rsa_65537_4096_js/dsc_sha256_rsa_65537_4096.wasm", @@ -43,10 +46,15 @@ const vcAndDiscloseCircuits: CircuitArtifacts = { vkey: "../circuits/build/disclose/vc_and_disclose/vc_and_disclose_vkey.json", }, }; +const vcAndDiscloseIdCircuits: CircuitArtifacts = { + vc_and_disclose_id: { + wasm: "../circuits/build/disclose/vc_and_disclose_id/vc_and_disclose_id_js/vc_and_disclose_id.wasm", + zkey: "../circuits/build/disclose/vc_and_disclose_id/vc_and_disclose_id_final.zkey", + vkey: "../circuits/build/disclose/vc_and_disclose_id/vc_and_disclose_id_vkey.json", + }, +}; export async function generateRegisterProof(secret: string, passportData: PassportData): Promise { - console.log(CYAN, "=== Start generateRegisterProof ===", RESET); - // Get the circuit inputs const registerCircuitInputs: CircuitSignals = await generateCircuitInputsRegister( secret, @@ -55,8 +63,6 @@ export async function generateRegisterProof(secret: string, passportData: Passpo ); // Generate the proof - const startTime = performance.now(); - const registerProof: { proof: Groth16Proof; publicSignals: PublicSignals; @@ -66,9 +72,6 @@ export async function generateRegisterProof(secret: string, passportData: Passpo registerCircuits["register_sha256_sha256_sha256_rsa_65537_4096"].zkey, ); - const endTime = performance.now(); - console.log(GREEN, `groth16.fullProve execution time: ${((endTime - startTime) / 1000).toFixed(2)} seconds`, RESET); - // Verify the proof const vKey = JSON.parse( fs.readFileSync(registerCircuits["register_sha256_sha256_sha256_rsa_65537_4096"].vkey, "utf8"), @@ -77,28 +80,72 @@ export async function generateRegisterProof(secret: string, passportData: Passpo if (!isValid) { throw new Error("Generated register proof verification failed"); } - console.log(GREEN, "Register proof verified successfully", RESET); const rawCallData = await groth16.exportSolidityCallData(registerProof.proof, registerProof.publicSignals); const fixedProof = parseSolidityCalldata(rawCallData, {} as RegisterCircuitProof); - console.log(CYAN, "=== End generateRegisterProof ===", RESET); return fixedProof; } -export async function generateDscProof(passportData: PassportData): Promise { - console.log(CYAN, "=== Start generateDscProof ===", RESET); +export async function generateRegisterIdProof( + secret: string, + passportData: PassportData, +): Promise { + // Get the correct circuit name based on passport data + const circuitName = getCircuitNameFromPassportData(passportData, "register"); + + // Get the circuit inputs for ID card - passportData should already be parsed from genMockIdDocAndInitDataParsing + const registerCircuitInputs: CircuitSignals = await generateCircuitInputsRegister( + secret, + passportData, + serialized_dsc_tree as string, + ); + + // Use the correct circuit artifacts based on the generated circuit name + let circuitArtifacts; + let artifactKey; + + // Check if this is an ID circuit + if (circuitName.startsWith("register_id_")) { + circuitArtifacts = registerCircuitsId; + // Use the actual circuit name as the key + artifactKey = circuitName; + } else { + circuitArtifacts = registerCircuits; + artifactKey = "register_sha256_sha256_sha256_rsa_65537_4096"; + } + + // Generate the proof + const registerProof: { + proof: Groth16Proof; + publicSignals: PublicSignals; + } = await groth16.fullProve( + registerCircuitInputs, + circuitArtifacts[artifactKey].wasm, + circuitArtifacts[artifactKey].zkey, + ); + + // Verify the proof + const vKey = JSON.parse(fs.readFileSync(circuitArtifacts[artifactKey].vkey, "utf8")); + const isValid = await groth16.verify(vKey, registerProof.publicSignals, registerProof.proof); + if (!isValid) { + throw new Error("Generated register ID proof verification failed"); + } + + const rawCallData = await groth16.exportSolidityCallData(registerProof.proof, registerProof.publicSignals); + const fixedProof = parseSolidityCalldata(rawCallData, {} as RegisterCircuitProof); + return fixedProof; +} + +export async function generateDscProof(passportData: PassportData): Promise { const dscCircuitInputs: CircuitSignals = await generateCircuitInputsDSC(passportData, serialized_csca_tree); - const startTime = performance.now(); const dscProof = await groth16.fullProve( dscCircuitInputs, dscCircuits["dsc_sha256_rsa_65537_4096"].wasm, dscCircuits["dsc_sha256_rsa_65537_4096"].zkey, ); - const endTime = performance.now(); - console.log(GREEN, `groth16.fullProve execution time: ${((endTime - startTime) / 1000).toFixed(2)} seconds`, RESET); // Verify the proof const vKey = JSON.parse(fs.readFileSync(dscCircuits["dsc_sha256_rsa_65537_4096"].vkey, "utf8")); @@ -106,12 +153,10 @@ export async function generateDscProof(passportData: PassportData): Promise, + majority: string = "20", + passportNo_smt?: SMT, + nameAndDob_smt?: SMT, + nameAndYob_smt?: SMT, + selectorOfac: string | number = "1", + forbiddenCountriesList: string[] = [ + "AAA", + "000", + "000", + "000", + "000", + "000", + "000", + "000", + "000", + "000", + "AAA", + "000", + "000", + "000", + "000", + "000", + "000", + "000", + "000", + "000", + "AAA", + "000", + "000", + "000", + "000", + "000", + "000", + "000", + "000", + "000", + "AAA", + "000", + "000", + "000", + "000", + "000", + "000", + "000", + "000", + "000", + ], + userIdentifier: string = "0000000000000000000000000000000000000000", +): Promise { + // Initialize all three SMTs if not provided + if (!passportNo_smt || !nameAndDob_smt || !nameAndYob_smt) { + const smts = getSMTs(); + passportNo_smt = smts.passportNo_smt; + nameAndDob_smt = smts.nameAndDob_smt; + nameAndYob_smt = smts.nameAndYob_smt; + } + + const idCardPassportData = { + ...passportData, + documentType: passportData.documentType.includes("id") ? passportData.documentType : "id_card", + documentCategory: "id_card" as const, + }; + + const vcAndDiscloseCircuitInputs: CircuitSignals = generateCircuitInputsVCandDisclose( + secret, + attestationId, + idCardPassportData, + scope, + selectorDg1, + selectorOlderThan, + merkletree, + majority, + passportNo_smt, + nameAndDob_smt, + nameAndYob_smt, + selectorOfac, + forbiddenCountriesList, + userIdentifier, + ); + + const vcAndDiscloseProof = await groth16.fullProve( + vcAndDiscloseCircuitInputs, + vcAndDiscloseIdCircuits["vc_and_disclose_id"].wasm, + vcAndDiscloseIdCircuits["vc_and_disclose_id"].zkey, + ); + + // Verify the proof + const vKey = JSON.parse(fs.readFileSync(vcAndDiscloseIdCircuits["vc_and_disclose_id"].vkey, "utf8")); + const isValid = await groth16.verify(vKey, vcAndDiscloseProof.publicSignals, vcAndDiscloseProof.proof); + if (!isValid) { + throw new Error("Generated VC and Disclose ID proof verification failed"); + } + + const rawCallData = await groth16.exportSolidityCallData(vcAndDiscloseProof.proof, vcAndDiscloseProof.publicSignals); + const fixedProof = parseSolidityCalldata(rawCallData, {} as VcAndDiscloseProof); + + return fixedProof; +} + export function parseSolidityCalldata(rawCallData: string, _type: T): T { const parsed = JSON.parse("[" + rawCallData + "]"); @@ -272,7 +417,14 @@ export function parseSolidityCalldata(rawCallData: string, _type: T): T { [BigNumberish, BigNumberish], ], c: parsed[2].map((x: string) => x.replace(/"/g, "")) as [BigNumberish, BigNumberish], - pubSignals: parsed[3].map((x: string) => x.replace(/"/g, "")) as BigNumberish[], + pubSignals: parsed[3].map((x: string) => { + const cleaned = x.replace(/"/g, ""); + // Convert hex strings to decimal strings for Solidity compatibility + if (cleaned.startsWith("0x")) { + return BigInt(cleaned).toString(); + } + return cleaned; + }) as BigNumberish[], } as T; } @@ -300,7 +452,6 @@ function importSMTFromJsonFile(filePath?: string): SMT | null { return smt; } catch (error) { - console.error("Failed to import SMT from JSON file:", error); return null; } } diff --git a/contracts/test/utils/pubkeys/serialized_csca_tree.json b/contracts/test/utils/pubkeys/serialized_csca_tree.json deleted file mode 100644 index 5139722da..000000000 --- a/contracts/test/utils/pubkeys/serialized_csca_tree.json +++ /dev/null @@ -1,90 +0,0 @@ -[ - [ - "6302746167612040169287204224641965049119379670159808996613022200426959969278", - "21737912865216631366336567244260032647310946375673351181140174093591714702999", - "7881627741362630218419203394369410748786507764316669620068500512816306974393", - "8442633355440465296842644318461346259324083140085137778501389055937910431110", - "494385956299168270408334656570463268819757224023693256178124768603625095689", - "11109705732184239012583404749930109480114669765649070936031155493622876369432", - "9074991679283645951358641479142018086508433068636738897852818247691550887353", - "10472104103456953748165921858843921722705273802507936987918628317450502368318", - "20465532314290048641249890589020580844800312880610998262795900425795687925759", - "5768994172638224755740597462572068991220057867415414997645244086458792645415", - "17252018052637913533753543738759416074689182570352156984838315665730273174771", - "344641985496327935255151802075808884620413685031595062530048227920050721780", - "12136951745768356780790830952320550859256567348204838329686829291956271851018", - "13156935969312787083658542670212591426438912414983737359002368687207144158384", - "18390019689329531194486865663275817993149098196912806933141622083576329149060", - "1481242557340385890029242958318001323542042109291864424212505135403557049174", - "8212379972296569224239707053291801266656219357105654879157065434106153446780", - "7259130865988598378063439736597905343524876834653292276109931166452499429748", - "9121308753649396222680496889506939509201230922178179924059434299141020697403", - "285292161892340475671724520102600999462489619312686773735450615184611138494", - "17039352924793721634937165985544670409252882635692632479205349210469115588765", - "13502358060740841171380532205068310953416088597412723446166411697331808464867", - "17340560759412667275187297637986710225182012906580596771637656874104617617955", - "8161679470983166059226129385619085265731972285960057248143860608525733203270", - "14871986472052100593919450740854089518175775672170855933096343961866149319949", - "1024796798868617073580401107121867347946885220866292564654180021134775438463", - "21314659513316629128269900118046844671368217281573948618189189184438357521850", - "14333285970232052794263361289909650744651387298949229098454892979931317772146", - "16041205263585308774562352509747184978808349452049402919724529400974025427436", - "8087267757933126132764313502987988617372965137423098839133763536652762365681", - "7962106263240616478489255388356842229007064058701247603002333884146997650489", - "3623426348190205637422491853880154438593931070755716928634661523298474873370", - "14890281186129558220608231498920908810133225689204820445535572821472349664447" - ], - [ - "4799972325846543794225228491143787399389885942417063987224237164999385319062", - "17050236804818394861130974609766586541491094962728898163841781451223822854686", - "1684095988446507706929542511950029896329456076438958417914434742534053808377", - "13030822995128201263800907485086206983654704449426873876221363197647850166314", - "20387868117709928393743787975391876407731857373450679028712293718320824421501", - "20648800321790649263930241990062778433044036026899293567267368546697502978404", - "5558822243190898430854422659247277485120763541538425901094235849734898971547", - "9648977827828540671109446184233701627175773049876679003145259446306367526913", - "19587958295993125277460383800858337068930180629959346593667253473373677697838", - "10766098235994178632473997874302736133480358322525035521842128765122396106753", - "3280132879539287366527818935691748975940933587498820629810825597324185825847", - "16042507993949674348775016509851234008694527541085892473255432193590272155228", - "9861886961854997054898644300025435424974733812770562105962523420323474270014", - "19963900440588427317645840967905315109665755922636714102274837921808725924490", - "14560929249637716209472399173281335447881032559475124155250089695314652709191", - "8793029054134443177154661146037690681847213703147023923126117330651746975093", - "6925999197894078032454979151597762706585652495739163647097172857061948107548" - ], - [ - "15437505910104448767291373721892514134533670716520577686244116418756186347964", - "9662712081254759511361246703401148719683866951663061909834810685640445739155", - "20383431234416469352301291449238452506080771017490889548224583250446902949522", - "17761227464350859107613675961034420867642506074271853781885405739945665021951", - "10107612039899335485435001531034291183382103402117414413277201288890819890175", - "21676120760606796382962041245156922927516003007606533210349079976883427407876", - "3959481944782480427438878998268686710659856580112036162216134326047024223619", - "13995366414942085322718873409710308506843557459098667415203661966308146712276", - "12396189675521664477208213044494994395570714180213788407180369449372794337406" - ], - [ - "17536551248416856833253545290007826015310552834679591084728236812275380736581", - "21178262016621282270578676828655596120453358323099758552458721672074592774466", - "12983142270089439210893516110450393549941947745609655791579563598275214147990", - "11138438821067972642938006246604783995156242377512994534882399065269415238242", - "14367141578614776950464394914864658179440566498674064519890241555879050349273" - ], - [ - "4746628767395628818871695814217923898815372663453343963780833567597879413422", - "6217935900653585035630246253466782187759116959924419206414312068302028006200", - "1712622252469401905020836297393811034367718131168934306349084470952949672370" - ], - [ - "9591986692462415575100546764405459060632901984266333538073859143124986153857", - "16005335605576341683358111497065243375958891362902160878740195332217005325867" - ], - ["10058083772386987881503691291273436622272886362704429356343750534180295442877"], - ["948496844530378519444411419272223562136844993455458676689351273655202389660"], - ["6104686411816540186205486815934621935504228294686310666920439592650163266817"], - ["8785911549693694407543433563052767959786709016516642293679450790050523979623"], - ["7409592596312085101815420137623073822216578588711762918861029979315261400521"], - ["21777804325204060904854919426171461175668073322071471253268661582106674611134"], - ["13859398115974385161464830211947258005860166431741677064758266112192747818198"] -] diff --git a/contracts/test/utils/pubkeys/serialized_dsc_tree.json b/contracts/test/utils/pubkeys/serialized_dsc_tree.json deleted file mode 100644 index fbf51fc8c..000000000 --- a/contracts/test/utils/pubkeys/serialized_dsc_tree.json +++ /dev/null @@ -1 +0,0 @@ -"[[\"8474170120361574158328936749210134677109057903005360945237099789945718842442\",\"19025861045901247405057316482734230273999651461753587376586889481054653237298\",\"20875820196105056284418196645437121025521090457969915100313025042226816593058\",\"7981401722738051151242865671764881670381691410051713896829121611466467295296\",\"12686075888445000028034879614337002534166281820554518240319859431277458776808\",\"14407479994300627796369211860752956065461957169462957624471349543175814297361\",\"12876099927862331079950419893066049696538807114168859906501896216679946602822\",\"5034430740274171017815797630858587451285547946739275122278422412563124952340\",\"124908299050395035311905641407789814479238558810338620545288553719611907579\",\"2220350286514662949665617433093307231741026918951518572442081261648362984066\",\"21054071841429471407849176541802267087608621767405046215729266220057231321239\",\"18615459511690451805285056890862312778437329715516723596790967668107849472332\",\"11005834873878236310149874426944776526137242691148625759790072174524730632293\",\"7750466501575524692208442425341714971523444376628469247291115085823741362258\",\"2825614199585564216616864222833372928389506766845048349547149599270041996580\",\"20178939917842893412863622473123830356625340961044353255941385554773117435807\",\"15457105913874757357155517217216962392853062937896722147907639311387695489612\",\"5769570513706963538956166571458035734925811338270969027092827256594315896305\",\"6944618873207772930654947866168069208208574383743967671528812057261674809023\",\"481787392403338571656555722870122978065125892949434958835001773033712625191\",\"629022117628670814916597453011668822767584986875266116143558377822126606210\",\"3477506405023338639718612883193130086582505996283986141234891023161625314400\",\"10391239348681537631698595933529223926008268217047488115607852208836329547314\",\"17714411760364866672536495662484312224393687256599208863125247267615177780962\",\"8235397798041831527134655625941532067772455314854641402993505266475178259142\",\"15400445794279992494417489709867566126537687907753955918275441261129856435204\",\"18390538379285507212129312705208118101486722955290795425636438098737923067560\",\"15884158870062763074209623120979824036430500099471957276287699843774740810060\",\"9761474784835077830881823851138622604776507060902897946796201272804305644780\",\"10691342730033436831098118713873643843887824911850191956325145412899736489783\",\"5383646477412575449009401478396232205746537027068927954390800800393113212132\",\"11221442935955024550310715250831163771206851175519681722264731998826151062912\",\"5908215522026944047821144963285306601790999208803054898792188809472216445547\",\"19125477641235279033749474384585292663869320556945218215852551798484901700632\",\"21131596906673841534294586137917770250418344721734587506304435102735580889655\",\"5546854205853827616610180972262457239247839686812479293725221982292586246857\",\"765319165068330175794491754566055878846660871087781618280248834367406785408\",\"9065563084454046530671534818701959328556136219713201237904842104821385096277\",\"11685470115846281888274197814651339961028617777494077059927246879793227459012\",\"2276790636588619756427393596069501098393513502175223999114797598139979501715\"],[\"18261435412082991275184532065290531009107742677653928657546608300990409875179\",\"9319096001557865141309312824962941754323190215020661725351078769489865210042\",\"19426464515945862948128564234105343408552273980845098594209919356069483229628\",\"4821438189762812946550415462056480603193509374059280985662653954928168448767\",\"5172906179275109031852701363533115355308886025681591977544612584826814597738\",\"3030902410998504999074059222657043445867065651115237138539258929106073952351\",\"14984550843964273185801085401106206042254593799102067736545138712711200363110\",\"4913017693235246056337618677701835414584892336316530224150731143499438377822\",\"20331547282693860184739325401078246632991653782842932001956973617899699067126\",\"7600383600608310101623426738393844905406553598472129359788500052979517101086\",\"21052687276768682440237728714031588951028862448534763565173935420275983308030\",\"8624573291232390725167327242752231606002232362298782976538648069452315809692\",\"8822425521071097948786926466502634257594788443097595142360595191654091518800\",\"19870347064194260309549332912586515029667844641153191360540616815967059032631\",\"20465460310501582547409465331218341819661912832562849210077024323229630431309\",\"8822852684497325396969645265731037061910702688625880340802544167587243049164\",\"4478528672717298316804099458930548551969390361723990676862003909749451604942\",\"17325287090866702355475285665146878940121103201057390207999938983310817624720\",\"19625874220796709797520370627316734190983871032135923532916997267931941944017\",\"4971210922480782538363635536321057597816923124821190325639868004751176123095\"],[\"4116500508658592197045562123902818266144060908634297057533152651751621275415\",\"6279942219928883797763183575386930078658513224739644044432142134698996392345\",\"17873714886463212348626929321462768984929311072311394677407846329308137071177\",\"1780903854488782716523110881333093026159313079337979149518816941412656424372\",\"20050373159836077479057811893536206817195523291436452658040605882811525003132\",\"5410620983195375911090727814270361454832036795917695206544043001420960637777\",\"11266551165651302260349077780564641889328703387362942837789171445336788206333\",\"3608626782139895235764576982540708534353226535204704760149123479387449221471\",\"3145665689117343568678004953880446893036465022181894889004516583481449637793\",\"8073537774997617083133123196297054007342256527983221664627563913756598041137\"],[\"16950176155260599508276620633155897140104757247891462208942656524243675299741\",\"4384637840548698893518161520012906111962786493558848227457354530627659879521\",\"5124677781615023074976959243179487140944992271935523984403489366636038434778\",\"12988207380549681248970615897816015977834414112005771449262709089864569444208\",\"4960783735404364608985140352905530473941590990406201882678348579000881422078\"],[\"20387009608350563521735170556423317268483084337333204688511143658578884542027\",\"19972334535313243417117998358484532425461333194385844246074835217244635372928\",\"4960783735404364608985140352905530473941590990406201882678348579000881422078\"],[\"1003947683617565493626440885069112088208918036484637499642204220769104979880\",\"4960783735404364608985140352905530473941590990406201882678348579000881422078\"],[\"17493683025876340868978454534142017149014501237522261427894104407551129583657\"]]" diff --git a/contracts/test/utils/types.ts b/contracts/test/utils/types.ts index f5482ff81..3f1ef2539 100644 --- a/contracts/test/utils/types.ts +++ b/contracts/test/utils/types.ts @@ -3,20 +3,34 @@ import type { PassportData } from "@selfxyz/common/utils/types"; import type { PublicSignals, Groth16Proof } from "snarkjs"; -// Contract imports import { IdentityVerificationHub, IdentityVerificationHubImplV1, + IdentityVerificationHubImplV2, IdentityRegistry, IdentityRegistryImplV1, -} from "../../typechain-types"; - -import type { + IdentityRegistryIdCardImplV1, + TestSelfVerificationRoot, + Verifier_vc_and_disclose_staging as LocalVerifier, + Verifier_vc_and_disclose_id_staging as LocalIdCardVerifier, + Verifier_vc_and_disclose as ProdVerifier, + Verifier_vc_and_disclose_id as ProdIdCardVerifier, + Verifier_register_sha256_sha256_sha256_rsa_65537_4096 as ProdRegisterVerifier, + Verifier_register_sha256_sha256_sha256_rsa_65537_4096_staging as LocalRegisterVerifier, + Verifier_register_id_sha256_sha256_sha256_rsa_65537_4096 as ProdIdCardRegisterVerifier, + Verifier_register_id_sha256_sha256_sha256_rsa_65537_4096_staging as LocalIdCardRegisterVerifier, + Verifier_dsc_sha256_rsa_65537_4096 as ProdDscVerifier, + Verifier_dsc_sha256_rsa_65537_4096_staging as LocalDscVerifier, IIdentityVerificationHubV1, + IIdentityVerificationHubV2, + IIdentityRegistryIdCardV1, + IIdentityRegistryV1, IRegisterCircuitVerifier, IDscCircuitVerifier, IVcAndDiscloseCircuitVerifier, -} from "../../typechain-types/contracts/IdentityVerificationHubImplV1"; +} from "../../typechain-types"; + +import { DscVerifierId, RegisterVerifierId } from "@selfxyz/common"; export type PassportProof = IIdentityVerificationHubV1.PassportProofStruct; export type RegisterCircuitProof = IRegisterCircuitVerifier.RegisterCircuitProofStruct; @@ -24,19 +38,17 @@ export type DscCircuitProof = IDscCircuitVerifier.DscCircuitProofStruct; export type VcAndDiscloseHubProof = IIdentityVerificationHubV1.VcAndDiscloseHubProofStruct; export type VcAndDiscloseProof = IVcAndDiscloseCircuitVerifier.VcAndDiscloseProofStruct; -// Verifier type imports -import type { Verifier_vc_and_disclose as ProdVerifier } from "../../typechain-types/contracts/verifiers/disclose/Verifier_vc_and_disclose"; -import type { Verifier_vc_and_disclose as LocalVerifier } from "../../typechain-types/contracts/verifiers/local/disclose/Verifier_vc_and_disclose"; -import type { Verifier_register_rsa_65537_sha256_sha256_sha256_rsa_65537_4096 as ProdRegisterVerifier } from "../../typechain-types/contracts/verifiers/register/Verifier_register_rsa_65537_sha256_sha256_sha256_rsa_65537_4096"; -import type { Verifier_register_sha256_sha256_sha256_rsa_65537_4096 as LocalRegisterVerifier } from "../../typechain-types/contracts/verifiers/local/register/Verifier_register_sha256_sha256_sha256_rsa_65537_4096"; -import type { Verifier_dsc_rsa_65537_sha256_4096 as ProdDscVerifier } from "../../typechain-types/contracts/verifiers/dsc/Verifier_dsc_rsa_65537_sha256_4096"; -import type { Verifier_dsc_rsa_sha256_65537_4096 as LocalDscVerifier } from "../../typechain-types/contracts/verifiers/local/dsc/Verifier_dsc_rsa_sha256_65537_4096"; - // Type definitions export type VcAndDiscloseVerifier = typeof process.env.TEST_ENV extends "local" ? LocalVerifier : ProdVerifier; +export type VcAndDiscloseIdVerifier = typeof process.env.TEST_ENV extends "local" + ? LocalIdCardVerifier + : ProdIdCardVerifier; export type RegisterVerifier = typeof process.env.TEST_ENV extends "local" ? LocalRegisterVerifier : ProdRegisterVerifier; +export type IdCardRegisterVerifier = typeof process.env.TEST_ENV extends "local" + ? LocalIdCardRegisterVerifier + : ProdIdCardRegisterVerifier; export type DscVerifier = typeof process.env.TEST_ENV extends "local" ? LocalDscVerifier : ProdDscVerifier; export interface DeployedActors { @@ -53,12 +65,36 @@ export interface DeployedActors { mockPassport: PassportData; } +export interface DeployedActorsV2 { + hubImplV2: IdentityVerificationHubImplV2; + hub: IdentityVerificationHubImplV2; + registryImpl: IdentityRegistryImplV1; + registry: IdentityRegistryImplV1; + registryIdImpl: IdentityRegistryIdCardImplV1; + registryId: IdentityRegistryIdCardImplV1; + vcAndDisclose: VcAndDiscloseVerifier; + vcAndDiscloseId: VcAndDiscloseIdVerifier; + register: RegisterVerifier; + registerId: RegisterVerifierId; + dsc: DscVerifier; + dscId: DscVerifierId; + testSelfVerificationRoot: TestSelfVerificationRoot; + customVerifier: any; + owner: Signer; + user1: Signer; + user2: Signer; + mockPassport: PassportData; +} + // Contract type exports export type { IdentityVerificationHub, IdentityVerificationHubImplV1, + IdentityVerificationHubImplV2, IdentityRegistry, IdentityRegistryImplV1, + IdentityRegistryIdCardImplV1, + TestSelfVerificationRoot, Groth16Proof, PublicSignals, }; diff --git a/contracts/test/v2/discloseId.test.ts b/contracts/test/v2/discloseId.test.ts new file mode 100644 index 000000000..35c3a09f2 --- /dev/null +++ b/contracts/test/v2/discloseId.test.ts @@ -0,0 +1,903 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { generateVcAndDiscloseIdProof, getSMTs } from "../utils/generateProof"; +import { poseidon2 } from "poseidon-lite"; +import { generateCommitment } from "@selfxyz/common/utils/passports/passport"; +import { BigNumberish } from "ethers"; +import { generateRandomFieldElement, getStartOfDayTimestamp } from "../utils/utils"; +import { getPackedForbiddenCountries } from "@selfxyz/common/utils/contracts/forbiddenCountries"; +import { countries } from "@selfxyz/common/constants/countries"; +import { deploySystemFixturesV2 } from "../utils/deploymentV2"; +import { DeployedActorsV2 } from "../utils/types"; +import { Country3LetterCode } from "@selfxyz/common/constants/countries"; +import { hashEndpointWithScope } from "@selfxyz/common/utils/scope"; +import { createHash } from "crypto"; +import { ID_CARD_ATTESTATION_ID } from "@selfxyz/common/constants/constants"; +import { genMockIdDocAndInitDataParsing } from "@selfxyz/common/utils/passports/genMockIdDoc"; + +// Helper function to calculate user identifier hash (same as passport test) +function calculateUserIdentifierHash(userContextData: string): string { + const sha256Hash = createHash("sha256") + .update(Buffer.from(userContextData.slice(2), "hex")) + .digest(); + const ripemdHash = createHash("ripemd160").update(sha256Hash).digest(); + return "0x" + ripemdHash.toString("hex").padStart(40, "0"); +} + +describe("Self Verification Flow V2 - ID Card", () => { + let deployedActors: DeployedActorsV2; + let snapshotId: string; + let baseVcAndDiscloseProof: any; + let pristineBaseVcAndDiscloseProof: any; + let vcAndDiscloseProof: any; + let registerSecret: any; + let imt: any; + let commitment: any; + let nullifier: any; + let mockIdCardData: any; + + let forbiddenCountriesList: Country3LetterCode[]; + let forbiddenCountriesListPacked: string[]; + let verificationConfigV2: any; + let configId: string; + + before(async () => { + deployedActors = await deploySystemFixturesV2(); + + // Generate mock ID card data + mockIdCardData = genMockIdDocAndInitDataParsing({ + idType: "mock_id_card", + dgHashAlgo: "sha256", + eContentHashAlgo: "sha256", + signatureType: "rsa_sha256_65537_2048", + nationality: "USA", + birthDate: "920315", + expiryDate: "321231", + }); + + registerSecret = generateRandomFieldElement(); + nullifier = generateRandomFieldElement(); + commitment = generateCommitment(registerSecret, ID_CARD_ATTESTATION_ID.toString(), mockIdCardData); + + const attestationIdBytes32 = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); + await deployedActors.registry + .connect(deployedActors.owner) + .devAddIdentityCommitment(attestationIdBytes32, nullifier, commitment); + + await deployedActors.registryId + .connect(deployedActors.owner) + .devAddIdentityCommitment(attestationIdBytes32, nullifier, commitment); + + const hashFunction = (a: bigint, b: bigint) => poseidon2([a, b]); + // must be imported dynamic since @openpassport/zk-kit-lean-imt is exclusively esm and hardhat does not support esm with typescript until version 3 + const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then((mod) => mod.LeanIMT); + imt = new LeanIMT(hashFunction); + await imt.insert(BigInt(commitment)); + + forbiddenCountriesList = [countries.AFGHANISTAN, "ABC", "CBA", "AAA"] as Country3LetterCode[]; + forbiddenCountriesListPacked = getPackedForbiddenCountries(forbiddenCountriesList); + + verificationConfigV2 = { + olderThanEnabled: true, + olderThan: "20", + forbiddenCountriesEnabled: true, + forbiddenCountriesListPacked: forbiddenCountriesListPacked as [ + BigNumberish, + BigNumberish, + BigNumberish, + BigNumberish, + ], + ofacEnabled: [false, false, false] as [boolean, boolean, boolean], + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const tempUserContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const userIdentifierHash = calculateUserIdentifierHash(tempUserContextData); + const userIdentifierBigInt = BigInt(userIdentifierHash); + + const expectedScopeFromHash = hashEndpointWithScope("example.com", "test-scope"); + const scopeAsBigInt = BigInt(expectedScopeFromHash); + const scopeAsBigIntString = scopeAsBigInt.toString(); + + baseVcAndDiscloseProof = await generateVcAndDiscloseIdProof( + registerSecret, + ID_CARD_ATTESTATION_ID.toString(), + mockIdCardData, + scopeAsBigIntString, + new Array(90).fill("1"), + "1", + imt, + "20", + undefined, + undefined, + undefined, + undefined, + forbiddenCountriesList, + userIdentifierBigInt.toString(16).padStart(64, "0"), + ); + + pristineBaseVcAndDiscloseProof = structuredClone(baseVcAndDiscloseProof); + snapshotId = await ethers.provider.send("evm_snapshot", []); + }); + + beforeEach(async () => { + baseVcAndDiscloseProof = structuredClone(pristineBaseVcAndDiscloseProof); + vcAndDiscloseProof = structuredClone(pristineBaseVcAndDiscloseProof); + + // Re-register the commitment after snapshot revert to ensure registry state is consistent + // Check if commitment already exists to avoid LeafAlreadyExists error + const currentRoot = await deployedActors.hub.getIdentityCommitmentMerkleRoot( + ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32), + ); + + if (currentRoot.toString() === "0") { + const attestationIdBytes32 = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); + await deployedActors.registry + .connect(deployedActors.owner) + .devAddIdentityCommitment(attestationIdBytes32, nullifier, commitment); + + await deployedActors.registryId + .connect(deployedActors.owner) + .devAddIdentityCommitment(attestationIdBytes32, nullifier, commitment); + } + }); + + afterEach(async () => { + await ethers.provider.send("evm_revert", [snapshotId]); + snapshotId = await ethers.provider.send("evm_snapshot", []); + }); + + describe("Complete V2 Verification Flow - ID Card", () => { + it("should complete full ID card verification flow with proper proof encoding", async () => { + // Use the already configured verificationConfigV2 and configId from before hook + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[vcAndDiscloseProof.a, vcAndDiscloseProof.b, vcAndDiscloseProof.c, vcAndDiscloseProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + await deployedActors.testSelfVerificationRoot.resetTestState(); + + const tx = await deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData); + + await expect(tx).to.emit(deployedActors.testSelfVerificationRoot, "VerificationCompleted"); + + expect(await deployedActors.testSelfVerificationRoot.verificationSuccessful()).to.be.true; + + const lastOutput = await deployedActors.testSelfVerificationRoot.lastOutput(); + expect(lastOutput).to.not.equal("0x"); + + const expectedUserData = ethers.solidityPacked(["bytes"], [userData]); + const actualUserData = await deployedActors.testSelfVerificationRoot.lastUserData(); + expect(actualUserData).to.equal(expectedUserData); + }); + + it("should fail verification with invalid length of proofData", async () => { + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + // Create proofData with less than 32 bytes (invalid) + const invalidProofData = ethers.toUtf8Bytes("short"); // Only 5 bytes + + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(invalidProofData, userContextData), + ).to.be.revertedWithCustomError(deployedActors.testSelfVerificationRoot, "InvalidDataFormat"); + }); + + it("should fail verification with invalid length of userContextData", async () => { + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[vcAndDiscloseProof.a, vcAndDiscloseProof.b, vcAndDiscloseProof.c, vcAndDiscloseProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + // Create userContextData with less than 96 bytes (invalid) + const invalidUserContextData = ethers.toUtf8Bytes("short_data"); // Only 10 bytes + + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, invalidUserContextData), + ).to.be.revertedWithCustomError(deployedActors.testSelfVerificationRoot, "InvalidDataFormat"); + }); + + it("should fail verification with invalid scope", async () => { + const verificationConfigV2 = { + olderThanEnabled: true, + olderThan: "20", + forbiddenCountriesEnabled: true, + forbiddenCountriesListPacked: forbiddenCountriesListPacked as [ + BigNumberish, + BigNumberish, + BigNumberish, + BigNumberish, + ], + ofacEnabled: [false, false, false] as [boolean, boolean, boolean], + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); + + // Create a separate commitment and register it + const scopeRegisterSecret = generateRandomFieldElement(); + const scopeNullifier = generateRandomFieldElement(); + const scopeCommitment = generateCommitment( + scopeRegisterSecret, + ID_CARD_ATTESTATION_ID.toString(), + mockIdCardData, + ); + + const attestationIdBytes32 = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); + await deployedActors.registryId + .connect(deployedActors.owner) + .devAddIdentityCommitment(attestationIdBytes32, scopeNullifier, scopeCommitment); + + // Create IMT for this specific commitment + const hashFunction = (a: bigint, b: bigint) => poseidon2([a, b]); + const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then((mod) => mod.LeanIMT); + const scopeIMT = new LeanIMT(hashFunction); + await scopeIMT.insert(BigInt(scopeCommitment)); + + const userIdentifierHash = calculateUserIdentifierHash(userContextData); + const userIdentifierBigInt = BigInt(userIdentifierHash); + + // Generate proof with a different scope (this will create a valid proof but with wrong scope) + const differentScopeFromHash = hashEndpointWithScope("different.com", "different-scope"); + const differentScopeAsBigInt = BigInt(differentScopeFromHash); + const differentScopeAsBigIntString = differentScopeAsBigInt.toString(); + + const differentScopeProof = await generateVcAndDiscloseIdProof( + scopeRegisterSecret, + ID_CARD_ATTESTATION_ID.toString(), + mockIdCardData, + differentScopeAsBigIntString, // Different scope + new Array(90).fill("1"), + "1", + scopeIMT, + "20", + undefined, + undefined, + undefined, + undefined, + forbiddenCountriesList, + userIdentifierBigInt.toString(16).padStart(64, "0"), + ); + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[differentScopeProof.a, differentScopeProof.b, differentScopeProof.c, differentScopeProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + // This should fail with ScopeMismatch because the proof has a different scope + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData), + ).to.be.revertedWithCustomError(deployedActors.hub, "ScopeMismatch"); + }); + + it("should fail verification with invalid user identifier", async () => { + const verificationConfigV2 = { + olderThanEnabled: false, + olderThan: "20", + forbiddenCountriesEnabled: false, + forbiddenCountriesListPacked: [0n, 0n, 0n, 0n] as [BigNumberish, BigNumberish, BigNumberish, BigNumberish], + ofacEnabled: [false, false, false] as [boolean, boolean, boolean], + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + // Create invalid userContextData by changing the user address to a different value + const invalidUserAddress = await deployedActors.user2.getAddress(); + const invalidUserContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(invalidUserAddress, 32), userData], + ); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); + + // Use the original valid proof without modification + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[vcAndDiscloseProof.a, vcAndDiscloseProof.b, vcAndDiscloseProof.c, vcAndDiscloseProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + // This should fail with InvalidUserIdentifierInProof because the userContextData doesn't match the proof + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, invalidUserContextData), + ).to.be.revertedWithCustomError(deployedActors.hub, "InvalidUserIdentifierInProof"); + }); + + it("should fail verification with invalid root", async () => { + const verificationConfigV2 = { + olderThanEnabled: true, + olderThan: "20", + forbiddenCountriesEnabled: true, + forbiddenCountriesListPacked: forbiddenCountriesListPacked as [ + BigNumberish, + BigNumberish, + BigNumberish, + BigNumberish, + ], + ofacEnabled: [false, false, false] as [boolean, boolean, boolean], + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); + + // Create proof with invalid merkle root - for ID card, merkle root is at index 10 + const modifiedVcAndDiscloseProof = { ...vcAndDiscloseProof }; + modifiedVcAndDiscloseProof.pubSignals[10] = "999999999"; // ID card merkle root index is 10 + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [ + [ + modifiedVcAndDiscloseProof.a, + modifiedVcAndDiscloseProof.b, + modifiedVcAndDiscloseProof.c, + modifiedVcAndDiscloseProof.pubSignals, + ], + ], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData), + ).to.be.revertedWithCustomError(deployedActors.hub, "InvalidIdentityCommitmentRoot"); + }); + + it("should fail verification with invalid current date + 1 day", async () => { + const verificationConfigV2 = { + olderThanEnabled: true, + olderThan: "20", + forbiddenCountriesEnabled: true, + forbiddenCountriesListPacked: forbiddenCountriesListPacked as [ + BigNumberish, + BigNumberish, + BigNumberish, + BigNumberish, + ], + ofacEnabled: [false, false, false] as [boolean, boolean, boolean], + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); + + // Get current block timestamp and calculate future date + const currentBlock = await ethers.provider.getBlock("latest"); + const oneDayAfter = getStartOfDayTimestamp(currentBlock!.timestamp) + 24 * 60 * 60; + + const date = new Date(oneDayAfter * 1000); + const dateComponents = [ + Math.floor((date.getUTCFullYear() % 100) / 10), + date.getUTCFullYear() % 10, + Math.floor((date.getUTCMonth() + 1) / 10), + (date.getUTCMonth() + 1) % 10, + Math.floor(date.getUTCDate() / 10), + date.getUTCDate() % 10, + ]; + + // Modify the current date fields in the proof (index 11-16 for ID card) + for (let i = 0; i < 6; i++) { + vcAndDiscloseProof.pubSignals[11 + i] = dateComponents[i].toString(); + } + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[vcAndDiscloseProof.a, vcAndDiscloseProof.b, vcAndDiscloseProof.c, vcAndDiscloseProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + // This should fail with CurrentDateNotInValidRange because the date is in the future + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData), + ).to.be.revertedWithCustomError(deployedActors.hub, "CurrentDateNotInValidRange"); + }); + + it("should fail verification with invalid current date - 1 day", async () => { + const verificationConfigV2 = { + olderThanEnabled: true, + olderThan: "20", + forbiddenCountriesEnabled: true, + forbiddenCountriesListPacked: forbiddenCountriesListPacked as [ + BigNumberish, + BigNumberish, + BigNumberish, + BigNumberish, + ], + ofacEnabled: [false, false, false] as [boolean, boolean, boolean], + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); + + // Get current block timestamp and calculate past date + const currentBlock = await ethers.provider.getBlock("latest"); + const oneDayBefore = getStartOfDayTimestamp(currentBlock!.timestamp) - 1; + + const date = new Date(oneDayBefore * 1000); + const dateComponents = [ + Math.floor((date.getUTCFullYear() % 100) / 10), + date.getUTCFullYear() % 10, + Math.floor((date.getUTCMonth() + 1) / 10), + (date.getUTCMonth() + 1) % 10, + Math.floor(date.getUTCDate() / 10), + date.getUTCDate() % 10, + ]; + + // Modify the current date fields in the proof (index 11-16 for ID card) + for (let i = 0; i < 6; i++) { + vcAndDiscloseProof.pubSignals[11 + i] = dateComponents[i].toString(); + } + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[vcAndDiscloseProof.a, vcAndDiscloseProof.b, vcAndDiscloseProof.c, vcAndDiscloseProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + // This should fail with CurrentDateNotInValidRange because the date is in the past + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData), + ).to.be.revertedWithCustomError(deployedActors.hub, "CurrentDateNotInValidRange"); + }); + + it("should fail verification with invalid groth16 proof", async () => { + const verificationConfigV2 = { + olderThanEnabled: true, + olderThan: "20", + forbiddenCountriesEnabled: true, + forbiddenCountriesListPacked: forbiddenCountriesListPacked as [ + BigNumberish, + BigNumberish, + BigNumberish, + BigNumberish, + ], + ofacEnabled: [false, false, false] as [boolean, boolean, boolean], + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); + + // Use the valid proof but modify only the groth16 proof components + // but keep the pubSignals valid so it doesn't fail at earlier checks + const invalidGrothProof = { ...vcAndDiscloseProof }; + invalidGrothProof.a = ["999999999", "888888888"]; // Invalid proof components + invalidGrothProof.b = [ + ["777777777", "666666666"], + ["555555555", "444444444"], + ]; + invalidGrothProof.c = ["333333333", "222222222"]; + // Keep pubSignals unchanged so other validations pass + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[invalidGrothProof.a, invalidGrothProof.b, invalidGrothProof.c, invalidGrothProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + // This should fail with InvalidVcAndDiscloseProof because the groth16 proof is invalid + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData), + ).to.be.revertedWithCustomError(deployedActors.hub, "InvalidVcAndDiscloseProof"); + }); + + it("should fail verification with invalid attestation Id", async () => { + const verificationConfigV2 = { + olderThanEnabled: true, + olderThan: "20", + forbiddenCountriesEnabled: true, + forbiddenCountriesListPacked: forbiddenCountriesListPacked as [ + BigNumberish, + BigNumberish, + BigNumberish, + BigNumberish, + ], + ofacEnabled: [false, false, false] as [boolean, boolean, boolean], + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + // Use invalid attestation ID + const invalidAttestationId = ethers.zeroPadValue(ethers.toBeHex(999999), 32); + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[vcAndDiscloseProof.a, vcAndDiscloseProof.b, vcAndDiscloseProof.c, vcAndDiscloseProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [invalidAttestationId, encodedProof]); + + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData), + ).to.be.revertedWith("Invalid attestation ID"); + }); + + it("should fail verification with invalid ofac check", async () => { + // Create a completely separate proof and setup for OFAC failure + const verificationConfigV2 = { + olderThanEnabled: false, + olderThan: "20", + forbiddenCountriesEnabled: false, + forbiddenCountriesListPacked: [0n, 0n, 0n, 0n] as [BigNumberish, BigNumberish, BigNumberish, BigNumberish], + ofacEnabled: [false, true, false] as [boolean, boolean, boolean], // ID card: [passport_no: false, name_dob: true, name_yob: false] + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const userIdentifierHash = calculateUserIdentifierHash(userContextData); + const userIdentifierBigInt = BigInt(userIdentifierHash); + + const expectedScopeFromHash = hashEndpointWithScope("example.com", "test-scope"); + const scopeAsBigInt = BigInt(expectedScopeFromHash); + const scopeAsBigIntString = scopeAsBigInt.toString(); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); + + // Use the existing commitment and merkle root instead of creating new ones + // Get OFAC SMTs that will cause validation failure + const { passportNo_smt, nameAndDob_smt, nameAndYob_smt } = getSMTs(); + + // Generate proof that will fail OFAC verification (with ofacCheck = "0") using existing IMT + const ofacFailingProof = await generateVcAndDiscloseIdProof( + registerSecret, // Use existing registerSecret + ID_CARD_ATTESTATION_ID.toString(), + mockIdCardData, + scopeAsBigIntString, + new Array(90).fill("1"), + "1", + imt, // Use existing IMT + "20", + passportNo_smt, + nameAndDob_smt, + nameAndYob_smt, + "0", // This will make OFAC verification fail + forbiddenCountriesList, + userIdentifierBigInt.toString(16).padStart(64, "0"), + ); + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[ofacFailingProof.a, ofacFailingProof.b, ofacFailingProof.c, ofacFailingProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData), + ).to.be.revertedWithCustomError(deployedActors.customVerifier, "InvalidOfacCheck"); + }); + + it("should fail verification with invalid forbidden countries check", async () => { + // Create a completely separate proof and setup for forbidden countries failure + const verificationConfigV2 = { + olderThanEnabled: false, + olderThan: "20", + forbiddenCountriesEnabled: true, + forbiddenCountriesListPacked: [0n, 0n, 0n, 0n] as [BigNumberish, BigNumberish, BigNumberish, BigNumberish], // Empty forbidden countries list + ofacEnabled: [false, false, false] as [boolean, boolean, boolean], // All OFAC checks disabled + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const userIdentifierHash = calculateUserIdentifierHash(userContextData); + const userIdentifierBigInt = BigInt(userIdentifierHash); + + const expectedScopeFromHash = hashEndpointWithScope("example.com", "test-scope"); + const scopeAsBigInt = BigInt(expectedScopeFromHash); + const scopeAsBigIntString = scopeAsBigInt.toString(); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); + + // Use the existing commitment and merkle root instead of creating new ones + // Get OFAC SMTs + const { passportNo_smt, nameAndDob_smt, nameAndYob_smt } = getSMTs(); + + // Generate proof with the original forbidden countries list (this will create a mismatch) using existing commitment + const forbiddenCountryProof = await generateVcAndDiscloseIdProof( + registerSecret, // Use existing registerSecret + ID_CARD_ATTESTATION_ID.toString(), + mockIdCardData, + scopeAsBigIntString, + new Array(90).fill("1"), + "1", + imt, // Use existing IMT + "20", + passportNo_smt, + nameAndDob_smt, + nameAndYob_smt, + "1", + forbiddenCountriesList, // Use the original forbidden countries list (different from config) + userIdentifierBigInt.toString(16).padStart(64, "0"), + ); + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[forbiddenCountryProof.a, forbiddenCountryProof.b, forbiddenCountryProof.c, forbiddenCountryProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + // This should fail because the forbidden countries list in the proof doesn't match the config + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData), + ).to.be.revertedWithCustomError(deployedActors.customVerifier, "InvalidForbiddenCountries"); + }); + + it("should fail verification with invalid older than check", async () => { + // Create a verification config that requires age > 25, but generate proof with age 20 + const verificationConfigV2 = { + olderThanEnabled: true, + olderThan: "25", // Require age > 25 (our proof will have age 20) + forbiddenCountriesEnabled: false, + forbiddenCountriesListPacked: [0n, 0n, 0n, 0n] as [BigNumberish, BigNumberish, BigNumberish, BigNumberish], + ofacEnabled: [false, false, false] as [boolean, boolean, boolean], // All OFAC checks disabled + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const userIdentifierHash = calculateUserIdentifierHash(userContextData); + const userIdentifierBigInt = BigInt(userIdentifierHash); + + const expectedScopeFromHash = hashEndpointWithScope("example.com", "test-scope"); + const scopeAsBigInt = BigInt(expectedScopeFromHash); + const scopeAsBigIntString = scopeAsBigInt.toString(); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); + + // Use the existing commitment and merkle root instead of creating new ones + // Get OFAC SMTs + const { passportNo_smt, nameAndDob_smt, nameAndYob_smt } = getSMTs(); + + // Generate proof with age 20 (which is less than required 25) using existing commitment + const youngerAgeProof = await generateVcAndDiscloseIdProof( + registerSecret, // Use existing registerSecret + ID_CARD_ATTESTATION_ID.toString(), + mockIdCardData, + scopeAsBigIntString, + new Array(90).fill("1"), + "1", + imt, // Use existing IMT + "20", // Age 20, which is less than required 25 + passportNo_smt, + nameAndDob_smt, + nameAndYob_smt, + "1", + forbiddenCountriesList, + userIdentifierBigInt.toString(16).padStart(64, "0"), + ); + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[youngerAgeProof.a, youngerAgeProof.b, youngerAgeProof.c, youngerAgeProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + // This should fail because age 20 is less than required 25 + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData), + ).to.be.revertedWithCustomError(deployedActors.customVerifier, "InvalidOlderThan"); + }); + + it("should fail verification with invalid dest chain Id", async () => { + const verificationConfigV2 = { + olderThanEnabled: false, + olderThan: "20", + forbiddenCountriesEnabled: false, + forbiddenCountriesListPacked: [0n, 0n, 0n, 0n] as [BigNumberish, BigNumberish, BigNumberish, BigNumberish], + ofacEnabled: [false, false, false] as [boolean, boolean, boolean], // All OFAC checks disabled + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + // Use an invalid destination chain ID that's different from current chain (31337) + const invalidDestChainId = ethers.zeroPadValue(ethers.toBeHex(999999), 32); + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, invalidDestChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const userIdentifierHash = calculateUserIdentifierHash(userContextData); + const userIdentifierBigInt = BigInt(userIdentifierHash); + + const expectedScopeFromHash = hashEndpointWithScope("example.com", "test-scope"); + const scopeAsBigInt = BigInt(expectedScopeFromHash); + const scopeAsBigIntString = scopeAsBigInt.toString(); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); + + // Use the existing commitment and merkle root instead of creating new ones + // Get OFAC SMTs + const { passportNo_smt, nameAndDob_smt, nameAndYob_smt } = getSMTs(); + + // Generate proof with the correct user identifier that matches the userContextData using existing commitment + const validProof = await generateVcAndDiscloseIdProof( + registerSecret, // Use existing registerSecret + ID_CARD_ATTESTATION_ID.toString(), + mockIdCardData, + scopeAsBigIntString, + new Array(90).fill("1"), + "1", + imt, // Use existing IMT + "20", + passportNo_smt, + nameAndDob_smt, + nameAndYob_smt, + "1", + forbiddenCountriesList, + userIdentifierBigInt.toString(16).padStart(64, "0"), + ); + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[validProof.a, validProof.b, validProof.c, validProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + // This should fail with CrossChainIsNotSupportedYet because destChainId (999999) != block.chainid (31337) + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData), + ).to.be.revertedWithCustomError(deployedActors.hub, "CrossChainIsNotSupportedYet"); + }); + + it("should fail verification with invalid msg sender to call onVerificationSuccess", async () => { + const mockOutput = ethers.toUtf8Bytes("mock-verification-output"); + const mockUserData = ethers.toUtf8Bytes("mock-user-data"); + + // Try to call onVerificationSuccess directly from a non-hub address + await expect( + deployedActors.testSelfVerificationRoot + .connect(deployedActors.user1) + .onVerificationSuccess(mockOutput, mockUserData), + ).to.be.revertedWithCustomError(deployedActors.testSelfVerificationRoot, "UnauthorizedCaller"); + + // Also test with owner account (should still fail) + await expect( + deployedActors.testSelfVerificationRoot + .connect(deployedActors.owner) + .onVerificationSuccess(mockOutput, mockUserData), + ).to.be.revertedWithCustomError(deployedActors.testSelfVerificationRoot, "UnauthorizedCaller"); + }); + }); +}); diff --git a/contracts/test/v2/disclosePassport.test.ts b/contracts/test/v2/disclosePassport.test.ts new file mode 100644 index 000000000..f32e803d1 --- /dev/null +++ b/contracts/test/v2/disclosePassport.test.ts @@ -0,0 +1,924 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { ATTESTATION_ID } from "../utils/constants"; +import { generateVcAndDiscloseProof, getSMTs } from "../utils/generateProof"; +import { poseidon2 } from "poseidon-lite"; +import { generateCommitment } from "@selfxyz/common/utils/passports/passport"; +import { BigNumberish } from "ethers"; +import { generateRandomFieldElement, getStartOfDayTimestamp } from "../utils/utils"; +import { getPackedForbiddenCountries } from "@selfxyz/common/utils/contracts/forbiddenCountries"; +import { countries } from "@selfxyz/common/constants/countries"; +import { deploySystemFixturesV2 } from "../utils/deploymentV2"; +import { DeployedActorsV2 } from "../utils/types"; +import { Country3LetterCode } from "@selfxyz/common/constants/countries"; +import { hashEndpointWithScope } from "@selfxyz/common/utils/scope"; +import { createHash } from "crypto"; + +// Helper function to format date for passport (YYMMDD format) +function formatDateForPassport(date: Date): string { + const year = date.getUTCFullYear().toString().slice(-2); // Get last 2 digits of year + const month = (date.getUTCMonth() + 1).toString().padStart(2, "0"); // Month is 0-indexed + const day = date.getUTCDate().toString().padStart(2, "0"); + return year + month + day; +} + +describe("Self Verification Flow V2", () => { + let deployedActors: DeployedActorsV2; + let snapshotId: string; + let baseVcAndDiscloseProof: any; + let pristineBaseVcAndDiscloseProof: any; + let vcAndDiscloseProof: any; + let registerSecret: any; + let imt: any; + let commitment: any; + let nullifier: any; + + let forbiddenCountriesList: Country3LetterCode[]; + let forbiddenCountriesListPacked: string[]; + let verificationConfigV2: any; + let configId: string; + + function calculateUserIdentifierHash(userContextData: string): string { + const sha256Hash = createHash("sha256") + .update(Buffer.from(userContextData.slice(2), "hex")) + .digest(); + const ripemdHash = createHash("ripemd160").update(sha256Hash).digest(); + return "0x" + ripemdHash.toString("hex").padStart(40, "0"); + } + + before(async () => { + deployedActors = await deploySystemFixturesV2(); + + // Take snapshot after deployment and balance setting + snapshotId = await ethers.provider.send("evm_snapshot", []); + + registerSecret = generateRandomFieldElement(); + nullifier = generateRandomFieldElement(); + commitment = generateCommitment(registerSecret, ATTESTATION_ID.E_PASSPORT, deployedActors.mockPassport); + + await deployedActors.registry + .connect(deployedActors.owner) + .devAddIdentityCommitment(ATTESTATION_ID.E_PASSPORT, nullifier, commitment); + + await deployedActors.registryId + .connect(deployedActors.owner) + .devAddIdentityCommitment(ATTESTATION_ID.E_PASSPORT, nullifier, commitment); + + const hashFunction = (a: bigint, b: bigint) => poseidon2([a, b]); + const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then((mod) => mod.LeanIMT); + imt = new LeanIMT(hashFunction); + await imt.insert(BigInt(commitment)); + + forbiddenCountriesList = [countries.AFGHANISTAN, "ABC", "CBA", "AAA"] as Country3LetterCode[]; + forbiddenCountriesListPacked = getPackedForbiddenCountries(forbiddenCountriesList); + + verificationConfigV2 = { + olderThanEnabled: true, + olderThan: "20", + forbiddenCountriesEnabled: true, + forbiddenCountriesListPacked: forbiddenCountriesListPacked as [ + BigNumberish, + BigNumberish, + BigNumberish, + BigNumberish, + ], + ofacEnabled: [true, true, true] as [boolean, boolean, boolean], + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const tempUserContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const userIdentifierHash = calculateUserIdentifierHash(tempUserContextData); + const userIdentifierBigInt = BigInt(userIdentifierHash); + + const expectedScopeFromHash = hashEndpointWithScope("example.com", "test-scope"); + const scopeAsBigInt = BigInt(expectedScopeFromHash); + const scopeAsBigIntString = scopeAsBigInt.toString(); + + baseVcAndDiscloseProof = await generateVcAndDiscloseProof( + registerSecret, + BigInt(ATTESTATION_ID.E_PASSPORT).toString(), + deployedActors.mockPassport, + scopeAsBigIntString, + new Array(88).fill("1"), + "1", + imt, + "20", + undefined, + undefined, + undefined, + undefined, + forbiddenCountriesList, + userIdentifierBigInt.toString(16).padStart(64, "0"), + ); + + pristineBaseVcAndDiscloseProof = structuredClone(baseVcAndDiscloseProof); + }); + + beforeEach(async () => { + baseVcAndDiscloseProof = structuredClone(pristineBaseVcAndDiscloseProof); + vcAndDiscloseProof = structuredClone(pristineBaseVcAndDiscloseProof); + + // Re-register the commitment after snapshot revert to ensure registry state is consistent + // Check if commitment already exists to avoid LeafAlreadyExists error + const currentRoot = await deployedActors.hub.getIdentityCommitmentMerkleRoot(ATTESTATION_ID.E_PASSPORT); + + if (currentRoot.toString() === "0") { + await deployedActors.registry + .connect(deployedActors.owner) + .devAddIdentityCommitment(ATTESTATION_ID.E_PASSPORT, nullifier, commitment); + + await deployedActors.registryId + .connect(deployedActors.owner) + .devAddIdentityCommitment(ATTESTATION_ID.E_PASSPORT, nullifier, commitment); + } + }); + + afterEach(async () => { + await ethers.provider.send("evm_revert", [snapshotId]); + snapshotId = await ethers.provider.send("evm_snapshot", []); + }); + + describe("Complete V2 Verification Flow", () => { + it("should complete full verification flow with proper proof encoding", async () => { + // Use the already configured verificationConfigV2 and configId from before hook + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ATTESTATION_ID.E_PASSPORT)), 32); + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[vcAndDiscloseProof.a, vcAndDiscloseProof.b, vcAndDiscloseProof.c, vcAndDiscloseProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + await deployedActors.testSelfVerificationRoot.resetTestState(); + + const tx = await deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData); + + await expect(tx).to.emit(deployedActors.testSelfVerificationRoot, "VerificationCompleted"); + + expect(await deployedActors.testSelfVerificationRoot.verificationSuccessful()).to.be.true; + + const lastOutput = await deployedActors.testSelfVerificationRoot.lastOutput(); + expect(lastOutput).to.not.equal("0x"); + + const expectedUserData = ethers.solidityPacked(["bytes"], [userData]); + const actualUserData = await deployedActors.testSelfVerificationRoot.lastUserData(); + expect(actualUserData).to.equal(expectedUserData); + }); + + it("should fail verification with invalid length of proofData", async () => { + // Use the already configured verificationConfigV2 and configId from before hook + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + // Create proofData with less than 32 bytes (invalid) + const invalidProofData = ethers.toUtf8Bytes("short"); // Only 5 bytes + + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(invalidProofData, userContextData), + ).to.be.revertedWithCustomError(deployedActors.testSelfVerificationRoot, "InvalidDataFormat"); + }); + + it("should fail verification with invalid length of userContextData", async () => { + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ATTESTATION_ID.E_PASSPORT)), 32); + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[vcAndDiscloseProof.a, vcAndDiscloseProof.b, vcAndDiscloseProof.c, vcAndDiscloseProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + // Create userContextData with less than 96 bytes (invalid) + const invalidUserContextData = ethers.toUtf8Bytes("short_data"); // Only 10 bytes + + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, invalidUserContextData), + ).to.be.revertedWithCustomError(deployedActors.testSelfVerificationRoot, "InvalidDataFormat"); + }); + + it("should fail verification with invalid scope", async () => { + const verificationConfigV2 = { + olderThanEnabled: true, + olderThan: "20", + forbiddenCountriesEnabled: true, + forbiddenCountriesListPacked: forbiddenCountriesListPacked as [ + BigNumberish, + BigNumberish, + BigNumberish, + BigNumberish, + ], + ofacEnabled: [true, true, true] as [boolean, boolean, boolean], + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ATTESTATION_ID.E_PASSPORT)), 32); + + // Create a separate commitment and register it + const scopeRegisterSecret = generateRandomFieldElement(); + const scopeNullifier = generateRandomFieldElement(); + const scopeCommitment = generateCommitment( + scopeRegisterSecret, + ATTESTATION_ID.E_PASSPORT, + deployedActors.mockPassport, + ); + + await deployedActors.registry + .connect(deployedActors.owner) + .devAddIdentityCommitment(ATTESTATION_ID.E_PASSPORT, scopeNullifier, scopeCommitment); + + // Create IMT for this specific commitment + const hashFunction = (a: bigint, b: bigint) => poseidon2([a, b]); + const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then((mod) => mod.LeanIMT); + const scopeIMT = new LeanIMT(hashFunction); + await scopeIMT.insert(BigInt(scopeCommitment)); + + const userIdentifierHash = calculateUserIdentifierHash(userContextData); + const userIdentifierBigInt = BigInt(userIdentifierHash); + + // Generate proof with a different scope (this will create a valid proof but with wrong scope) + const differentScopeFromHash = hashEndpointWithScope("different.com", "different-scope"); + const differentScopeAsBigInt = BigInt(differentScopeFromHash); + const differentScopeAsBigIntString = differentScopeAsBigInt.toString(); + + const differentScopeProof = await generateVcAndDiscloseProof( + scopeRegisterSecret, + BigInt(ATTESTATION_ID.E_PASSPORT).toString(), + deployedActors.mockPassport, + differentScopeAsBigIntString, // Different scope + new Array(88).fill("1"), + "1", + scopeIMT, + "20", + undefined, + undefined, + undefined, + undefined, + forbiddenCountriesList, + userIdentifierBigInt.toString(16).padStart(64, "0"), + ); + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[differentScopeProof.a, differentScopeProof.b, differentScopeProof.c, differentScopeProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + // This should fail with ScopeMismatch because the proof has a different scope + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData), + ).to.be.revertedWithCustomError(deployedActors.hub, "ScopeMismatch"); + }); + + it("should fail verification with invalid user identifier", async () => { + const verificationConfigV2 = { + olderThanEnabled: false, + olderThan: "20", + forbiddenCountriesEnabled: false, + forbiddenCountriesListPacked: [0n, 0n, 0n, 0n] as [BigNumberish, BigNumberish, BigNumberish, BigNumberish], + ofacEnabled: [false, false, false] as [boolean, boolean, boolean], + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + // Create invalid userContextData by changing the user address to a different value + const invalidUserAddress = await deployedActors.user2.getAddress(); + const invalidUserContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(invalidUserAddress, 32), userData], + ); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ATTESTATION_ID.E_PASSPORT)), 32); + + // Use the original valid proof without modification + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[vcAndDiscloseProof.a, vcAndDiscloseProof.b, vcAndDiscloseProof.c, vcAndDiscloseProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + // This should fail with InvalidUserIdentifierInProof because the userContextData doesn't match the proof + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, invalidUserContextData), + ).to.be.revertedWithCustomError(deployedActors.hub, "InvalidUserIdentifierInProof"); + }); + + it("should fail verification with invalid root", async () => { + const verificationConfigV2 = { + olderThanEnabled: true, + olderThan: "20", + forbiddenCountriesEnabled: true, + forbiddenCountriesListPacked: forbiddenCountriesListPacked as [ + BigNumberish, + BigNumberish, + BigNumberish, + BigNumberish, + ], + ofacEnabled: [true, true, true] as [boolean, boolean, boolean], + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const userIdentifierHash = calculateUserIdentifierHash(userContextData); + const userIdentifierBigInt = BigInt(userIdentifierHash); + + const expectedScopeFromHash = hashEndpointWithScope("example.com", "test-scope"); + const scopeAsBigInt = BigInt(expectedScopeFromHash); + const scopeAsBigIntString = scopeAsBigInt.toString(); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ATTESTATION_ID.E_PASSPORT)), 32); + + // Create a separate commitment with a different secret to generate a different merkle root + const differentRegisterSecret = generateRandomFieldElement(); + const differentNullifier = generateRandomFieldElement(); + const differentCommitment = generateCommitment( + differentRegisterSecret, + ATTESTATION_ID.E_PASSPORT, + deployedActors.mockPassport, + ); + + // Create a new IMT with different commitment (different root) + const hashFunction = (a: bigint, b: bigint) => poseidon2([a, b]); + const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then((mod) => mod.LeanIMT); + const differentIMT = new LeanIMT(hashFunction); + await differentIMT.insert(BigInt(differentCommitment)); + + // Generate proof with different merkle root + const differentRootProof = await generateVcAndDiscloseProof( + differentRegisterSecret, + BigInt(ATTESTATION_ID.E_PASSPORT).toString(), + deployedActors.mockPassport, + scopeAsBigIntString, + new Array(88).fill("1"), + "1", + differentIMT, // Different IMT = different root + "20", + undefined, + undefined, + undefined, + undefined, + forbiddenCountriesList, + userIdentifierBigInt.toString(16).padStart(64, "0"), + ); + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[differentRootProof.a, differentRootProof.b, differentRootProof.c, differentRootProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData), + ).to.be.revertedWithCustomError(deployedActors.hub, "InvalidIdentityCommitmentRoot"); + }); + + it("should fail verification with invalid current date + 1 day", async () => { + const verificationConfigV2 = { + olderThanEnabled: true, + olderThan: "20", + forbiddenCountriesEnabled: true, + forbiddenCountriesListPacked: forbiddenCountriesListPacked as [ + BigNumberish, + BigNumberish, + BigNumberish, + BigNumberish, + ], + ofacEnabled: [true, true, true] as [boolean, boolean, boolean], + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ATTESTATION_ID.E_PASSPORT)), 32); + + // Get current block timestamp and calculate future date + const currentBlock = await ethers.provider.getBlock("latest"); + const oneDayAfter = getStartOfDayTimestamp(currentBlock!.timestamp) + 24 * 60 * 60; + + const date = new Date(oneDayAfter * 1000); + const dateComponents = [ + Math.floor((date.getUTCFullYear() % 100) / 10), + date.getUTCFullYear() % 10, + Math.floor((date.getUTCMonth() + 1) / 10), + (date.getUTCMonth() + 1) % 10, + Math.floor(date.getUTCDate() / 10), + date.getUTCDate() % 10, + ]; + + // Modify the current date fields directly in the proof signals (index 10-15 for E_PASSPORT) + for (let i = 0; i < 6; i++) { + vcAndDiscloseProof.pubSignals[10 + i] = dateComponents[i].toString(); + } + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[vcAndDiscloseProof.a, vcAndDiscloseProof.b, vcAndDiscloseProof.c, vcAndDiscloseProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + // This should fail with CurrentDateNotInValidRange because the date is in the future + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData), + ).to.be.revertedWithCustomError(deployedActors.hub, "CurrentDateNotInValidRange"); + }); + + it("should fail verification with invalid current date - 1 day", async () => { + const verificationConfigV2 = { + olderThanEnabled: true, + olderThan: "20", + forbiddenCountriesEnabled: true, + forbiddenCountriesListPacked: forbiddenCountriesListPacked as [ + BigNumberish, + BigNumberish, + BigNumberish, + BigNumberish, + ], + ofacEnabled: [true, true, true] as [boolean, boolean, boolean], + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ATTESTATION_ID.E_PASSPORT)), 32); + + // Get current block timestamp and calculate past date + const currentBlock = await ethers.provider.getBlock("latest"); + const oneDayBefore = getStartOfDayTimestamp(currentBlock!.timestamp) - 1; + + const date = new Date(oneDayBefore * 1000); + const dateComponents = [ + Math.floor((date.getUTCFullYear() % 100) / 10), + date.getUTCFullYear() % 10, + Math.floor((date.getUTCMonth() + 1) / 10), + (date.getUTCMonth() + 1) % 10, + Math.floor(date.getUTCDate() / 10), + date.getUTCDate() % 10, + ]; + + // Modify the current date fields directly in the proof signals (index 10-15 for E_PASSPORT) + for (let i = 0; i < 6; i++) { + vcAndDiscloseProof.pubSignals[10 + i] = dateComponents[i].toString(); + } + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[vcAndDiscloseProof.a, vcAndDiscloseProof.b, vcAndDiscloseProof.c, vcAndDiscloseProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + // This should fail with CurrentDateNotInValidRange because the date is in the past + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData), + ).to.be.revertedWithCustomError(deployedActors.hub, "CurrentDateNotInValidRange"); + }); + + it("should fail verification with invalid groth16 proof", async () => { + const verificationConfigV2 = { + olderThanEnabled: true, + olderThan: "20", + forbiddenCountriesEnabled: true, + forbiddenCountriesListPacked: forbiddenCountriesListPacked as [ + BigNumberish, + BigNumberish, + BigNumberish, + BigNumberish, + ], + ofacEnabled: [true, true, true] as [boolean, boolean, boolean], + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ATTESTATION_ID.E_PASSPORT)), 32); + + // Use the valid proof but modify only the groth16 proof components to make it fail verification + // but keep the pubSignals valid so it doesn't fail at earlier checks + const invalidGrothProof = structuredClone(vcAndDiscloseProof); + invalidGrothProof.a = ["999999999", "888888888"]; // Invalid proof components + invalidGrothProof.b = [ + ["777777777", "666666666"], + ["555555555", "444444444"], + ]; + invalidGrothProof.c = ["333333333", "222222222"]; + // Keep pubSignals unchanged so other validations pass + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[invalidGrothProof.a, invalidGrothProof.b, invalidGrothProof.c, invalidGrothProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + // This should fail with InvalidVcAndDiscloseProof because the groth16 proof is invalid + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData), + ).to.be.revertedWithCustomError(deployedActors.hub, "InvalidVcAndDiscloseProof"); + }); + + it("should fail verification with invalid attestation Id", async () => { + const verificationConfigV2 = { + olderThanEnabled: true, + olderThan: "20", + forbiddenCountriesEnabled: true, + forbiddenCountriesListPacked: forbiddenCountriesListPacked as [ + BigNumberish, + BigNumberish, + BigNumberish, + BigNumberish, + ], + ofacEnabled: [true, true, true] as [boolean, boolean, boolean], + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + // Use invalid attestation ID + const invalidAttestationId = ethers.zeroPadValue(ethers.toBeHex(999999), 32); + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[vcAndDiscloseProof.a, vcAndDiscloseProof.b, vcAndDiscloseProof.c, vcAndDiscloseProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [invalidAttestationId, encodedProof]); + + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData), + ).to.be.revertedWith("Invalid attestation ID"); + }); + + it("should fail verification with invalid ofac check", async () => { + // Create a completely separate proof and setup for OFAC failure + const verificationConfigV2 = { + olderThanEnabled: false, + olderThan: "20", + forbiddenCountriesEnabled: false, + forbiddenCountriesListPacked: [0n, 0n, 0n, 0n] as [BigNumberish, BigNumberish, BigNumberish, BigNumberish], + ofacEnabled: [true, true, true] as [boolean, boolean, boolean], // Enable OFAC checks + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const userIdentifierHash = calculateUserIdentifierHash(userContextData); + const userIdentifierBigInt = BigInt(userIdentifierHash); + + const expectedScopeFromHash = hashEndpointWithScope("example.com", "test-scope"); + const scopeAsBigInt = BigInt(expectedScopeFromHash); + const scopeAsBigIntString = scopeAsBigInt.toString(); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ATTESTATION_ID.E_PASSPORT)), 32); + + // Use the existing commitment and merkle root instead of creating new ones + // Get OFAC SMTs that will cause validation failure + const { passportNo_smt, nameAndDob_smt, nameAndYob_smt } = getSMTs(); + + // Generate proof that will fail OFAC verification (with ofacCheck = "0") using existing IMT + const ofacFailingProof = await generateVcAndDiscloseProof( + registerSecret, // Use existing registerSecret + BigInt(ATTESTATION_ID.E_PASSPORT).toString(), + deployedActors.mockPassport, + scopeAsBigIntString, + new Array(88).fill("1"), + "1", + imt, // Use existing IMT + "20", + passportNo_smt, + nameAndDob_smt, + nameAndYob_smt, + "0", // This will make OFAC verification fail + forbiddenCountriesList, + userIdentifierBigInt.toString(16).padStart(64, "0"), + ); + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[ofacFailingProof.a, ofacFailingProof.b, ofacFailingProof.c, ofacFailingProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData), + ).to.be.revertedWithCustomError(deployedActors.customVerifier, "InvalidOfacCheck"); + }); + + it("should fail verification with invalid forbidden countries check", async () => { + // Create a forbidden countries list that should NOT match the proof + const mismatchedForbiddenCountriesList = [ + countries.IRAN, // This should NOT match what's in the passport/proof + "ABC", + "CBA", + "AAA", + ] as Country3LetterCode[]; + const mismatchedForbiddenCountriesListPacked = getPackedForbiddenCountries(mismatchedForbiddenCountriesList); + + const verificationConfigV2 = { + olderThanEnabled: false, + olderThan: "20", + forbiddenCountriesEnabled: true, + forbiddenCountriesListPacked: mismatchedForbiddenCountriesListPacked as [ + BigNumberish, + BigNumberish, + BigNumberish, + BigNumberish, + ], + ofacEnabled: [false, false, false] as [boolean, boolean, boolean], + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const userIdentifierHash = calculateUserIdentifierHash(userContextData); + const userIdentifierBigInt = BigInt(userIdentifierHash); + + const expectedScopeFromHash = hashEndpointWithScope("example.com", "test-scope"); + const scopeAsBigInt = BigInt(expectedScopeFromHash); + const scopeAsBigIntString = scopeAsBigInt.toString(); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ATTESTATION_ID.E_PASSPORT)), 32); + + // Generate proof with the original forbidden countries list (this will create a mismatch) using existing commitment + const forbiddenCountryProof = await generateVcAndDiscloseProof( + registerSecret, // Use existing registerSecret + BigInt(ATTESTATION_ID.E_PASSPORT).toString(), + deployedActors.mockPassport, + scopeAsBigIntString, + new Array(88).fill("1"), + "1", + imt, // Use existing IMT + "20", + undefined, + undefined, + undefined, + undefined, + forbiddenCountriesList, // Use the original forbidden countries list (different from config) + userIdentifierBigInt.toString(16).padStart(64, "0"), + ); + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[forbiddenCountryProof.a, forbiddenCountryProof.b, forbiddenCountryProof.c, forbiddenCountryProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + // This should fail because the forbidden countries list in the proof doesn't match the config + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData), + ).to.be.revertedWithCustomError(deployedActors.customVerifier, "InvalidForbiddenCountries"); + }); + + it("should fail verification with invalid older than check", async () => { + // Create a verification config that requires age > 25, but generate proof with age 20 + const verificationConfigV2 = { + olderThanEnabled: true, + olderThan: "25", // Require age > 25 (our proof will have age 20) + forbiddenCountriesEnabled: false, + forbiddenCountriesListPacked: [0n, 0n, 0n, 0n] as [BigNumberish, BigNumberish, BigNumberish, BigNumberish], + ofacEnabled: [false, false, false] as [boolean, boolean, boolean], + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const userIdentifierHash = calculateUserIdentifierHash(userContextData); + const userIdentifierBigInt = BigInt(userIdentifierHash); + + const expectedScopeFromHash = hashEndpointWithScope("example.com", "test-scope"); + const scopeAsBigInt = BigInt(expectedScopeFromHash); + const scopeAsBigIntString = scopeAsBigInt.toString(); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ATTESTATION_ID.E_PASSPORT)), 32); + + // Generate proof with age 20 (which is less than required 25) using existing commitment + const youngerAgeProof = await generateVcAndDiscloseProof( + registerSecret, // Use existing registerSecret + BigInt(ATTESTATION_ID.E_PASSPORT).toString(), + deployedActors.mockPassport, + scopeAsBigIntString, + new Array(88).fill("1"), + "1", + imt, // Use existing IMT + "20", // Age 20, which is less than required 25 + undefined, + undefined, + undefined, + undefined, + forbiddenCountriesList, + userIdentifierBigInt.toString(16).padStart(64, "0"), + ); + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[youngerAgeProof.a, youngerAgeProof.b, youngerAgeProof.c, youngerAgeProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + // This should fail because age 20 is less than required 25 + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData), + ).to.be.revertedWithCustomError(deployedActors.customVerifier, "InvalidOlderThan"); + }); + + it("should fail verification with invalid dest chain Id", async () => { + const verificationConfigV2 = { + olderThanEnabled: false, + olderThan: "20", + forbiddenCountriesEnabled: false, + forbiddenCountriesListPacked: [0n, 0n, 0n, 0n] as [BigNumberish, BigNumberish, BigNumberish, BigNumberish], + ofacEnabled: [false, false, false] as [boolean, boolean, boolean], + }; + + await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + + const user1Address = await deployedActors.user1.getAddress(); + const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); + + // Use an invalid destination chain ID that's different from current chain (31337) + const invalidDestChainId = ethers.zeroPadValue(ethers.toBeHex(999999), 32); + const userContextData = ethers.solidityPacked( + ["bytes32", "bytes32", "bytes32", "bytes"], + [configId, invalidDestChainId, ethers.zeroPadValue(user1Address, 32), userData], + ); + + const userIdentifierHash = calculateUserIdentifierHash(userContextData); + const userIdentifierBigInt = BigInt(userIdentifierHash); + + const expectedScopeFromHash = hashEndpointWithScope("example.com", "test-scope"); + const scopeAsBigInt = BigInt(expectedScopeFromHash); + const scopeAsBigIntString = scopeAsBigInt.toString(); + + const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ATTESTATION_ID.E_PASSPORT)), 32); + + // Generate proof with the correct user identifier that matches the userContextData using existing commitment + const validProof = await generateVcAndDiscloseProof( + registerSecret, // Use existing registerSecret + BigInt(ATTESTATION_ID.E_PASSPORT).toString(), + deployedActors.mockPassport, + scopeAsBigIntString, + new Array(88).fill("1"), + "1", + imt, // Use existing IMT + "20", + undefined, + undefined, + undefined, + undefined, + forbiddenCountriesList, + userIdentifierBigInt.toString(16).padStart(64, "0"), + ); + + const encodedProof = ethers.AbiCoder.defaultAbiCoder().encode( + ["tuple(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[21] pubSignals)"], + [[validProof.a, validProof.b, validProof.c, validProof.pubSignals]], + ); + + const proofData = ethers.solidityPacked(["bytes32", "bytes"], [attestationId, encodedProof]); + + // This should fail with CrossChainIsNotSupportedYet because destChainId (999999) != block.chainid (31337) + await expect( + deployedActors.testSelfVerificationRoot.verifySelfProof(proofData, userContextData), + ).to.be.revertedWithCustomError(deployedActors.hub, "CrossChainIsNotSupportedYet"); + }); + + it("should fail verification with invalid msg sender to call onVerificationSuccess", async () => { + const mockOutput = ethers.toUtf8Bytes("mock-verification-output"); + const mockUserData = ethers.toUtf8Bytes("mock-user-data"); + + // Try to call onVerificationSuccess directly from a non-hub address + await expect( + deployedActors.testSelfVerificationRoot + .connect(deployedActors.user1) + .onVerificationSuccess(mockOutput, mockUserData), + ).to.be.revertedWithCustomError(deployedActors.testSelfVerificationRoot, "UnauthorizedCaller"); + + // Also test with owner account (should still fail) + await expect( + deployedActors.testSelfVerificationRoot + .connect(deployedActors.owner) + .onVerificationSuccess(mockOutput, mockUserData), + ).to.be.revertedWithCustomError(deployedActors.testSelfVerificationRoot, "UnauthorizedCaller"); + }); + }); +}); diff --git a/contracts/test/v2/hubOther.test.ts b/contracts/test/v2/hubOther.test.ts new file mode 100644 index 000000000..b9ee2a38d --- /dev/null +++ b/contracts/test/v2/hubOther.test.ts @@ -0,0 +1,186 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { deploySystemFixturesV2 } from "../utils/deploymentV2"; +import { DeployedActorsV2 } from "../utils/types"; +import { DscVerifierId, RegisterVerifierId } from "@selfxyz/common/constants/constants"; +import { ID_CARD_ATTESTATION_ID, PASSPORT_ATTESTATION_ID } from "@selfxyz/common/constants/constants"; + +describe("Hub Other Functions Test", function () { + this.timeout(0); + + let deployedActors: DeployedActorsV2; + let snapshotId: string; + let attestationIdBytes32: string; + let ePassportAttestationIdBytes32: string; + + before(async () => { + // Deploy contracts and setup initial state + deployedActors = await deploySystemFixturesV2(); + attestationIdBytes32 = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); + ePassportAttestationIdBytes32 = ethers.zeroPadValue(ethers.toBeHex(BigInt(PASSPORT_ATTESTATION_ID)), 32); + + console.log("🎉 System deployment and initial setup completed!"); + }); + + beforeEach(async () => { + // Take snapshot before each test + snapshotId = await ethers.provider.send("evm_snapshot", []); + }); + + afterEach(async () => { + // Revert to snapshot after each test + await ethers.provider.send("evm_revert", [snapshotId]); + }); + + describe("Batch Update Functions Error Tests", () => { + it("should fail with LengthMismatch when arrays have different lengths in batchUpdateRegisterCircuitVerifiers", async () => { + const attestationIds = [attestationIdBytes32, ePassportAttestationIdBytes32]; + const typeIds = [1]; // Different length + const verifierAddresses = [ethers.ZeroAddress, ethers.ZeroAddress]; + + await expect( + deployedActors.hub.batchUpdateRegisterCircuitVerifiers(attestationIds, typeIds, verifierAddresses), + ).to.be.revertedWithCustomError(deployedActors.hub, "LengthMismatch"); + }); + + it("should fail with LengthMismatch when arrays have different lengths in batchUpdateDscCircuitVerifiers", async () => { + const attestationIds = [attestationIdBytes32]; + const typeIds = [1, 2]; // Different length + const verifierAddresses = [ethers.ZeroAddress]; + + await expect( + deployedActors.hub.batchUpdateDscCircuitVerifiers(attestationIds, typeIds, verifierAddresses), + ).to.be.revertedWithCustomError(deployedActors.hub, "LengthMismatch"); + }); + + it("should successfully batch update register circuit verifiers with matching array lengths", async () => { + const attestationIds = [attestationIdBytes32, ePassportAttestationIdBytes32]; + const typeIds = [1, 2]; + const verifierAddresses = [ethers.ZeroAddress, ethers.ZeroAddress]; + + await expect(deployedActors.hub.batchUpdateRegisterCircuitVerifiers(attestationIds, typeIds, verifierAddresses)) + .to.not.be.reverted; + }); + + it("should successfully batch update DSC circuit verifiers with matching array lengths", async () => { + const attestationIds = [attestationIdBytes32, ePassportAttestationIdBytes32]; + const typeIds = [1, 2]; + const verifierAddresses = [ethers.ZeroAddress, ethers.ZeroAddress]; + + await expect(deployedActors.hub.batchUpdateDscCircuitVerifiers(attestationIds, typeIds, verifierAddresses)).to.not + .be.reverted; + }); + }); + + describe("Access Control Tests", () => { + it("should fail when non-owner tries to call onlyOwner functions", async () => { + const nonOwnerHub = deployedActors.hub.connect(deployedActors.user1); + + await expect(nonOwnerHub.updateRegistry(attestationIdBytes32, ethers.ZeroAddress)).to.be.reverted; // Should revert due to onlyOwner modifier + + await expect(nonOwnerHub.updateVcAndDiscloseCircuit(attestationIdBytes32, ethers.ZeroAddress)).to.be.reverted; // Should revert due to onlyOwner modifier + + await expect(nonOwnerHub.updateRegisterCircuitVerifier(attestationIdBytes32, 1, ethers.ZeroAddress)).to.be + .reverted; // Should revert due to onlyOwner modifier + + await expect(nonOwnerHub.updateDscVerifier(attestationIdBytes32, 1, ethers.ZeroAddress)).to.be.reverted; // Should revert due to onlyOwner modifier + }); + }); + + describe("View Functions Tests", () => { + it("should return correct registry address", async () => { + const registryAddress = await deployedActors.hub.registry(attestationIdBytes32); + expect(registryAddress).to.equal(await deployedActors.registryId.getAddress()); + }); + + it("should return correct disclose verifier address", async () => { + const discloseVerifierAddress = await deployedActors.hub.discloseVerifier(attestationIdBytes32); + expect(discloseVerifierAddress).to.not.equal(ethers.ZeroAddress); + }); + + it("should return correct register circuit verifier address", async () => { + const registerVerifierAddress = await deployedActors.hub.registerCircuitVerifiers( + attestationIdBytes32, + RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096, + ); + expect(registerVerifierAddress).to.not.equal(ethers.ZeroAddress); + }); + + it("should return correct DSC circuit verifier address", async () => { + const dscVerifierAddress = await deployedActors.hub.dscCircuitVerifiers( + attestationIdBytes32, + DscVerifierId.dsc_sha256_rsa_65537_4096, + ); + expect(dscVerifierAddress).to.not.equal(ethers.ZeroAddress); + }); + + it("should return correct identity commitment merkle root", async () => { + const merkleRoot = await deployedActors.hub.getIdentityCommitmentMerkleRoot(attestationIdBytes32); + expect(merkleRoot).to.be.a("bigint"); + }); + + it("should fail getIdentityCommitmentMerkleRoot with InvalidAttestationId", async () => { + const invalidAttestationId = ethers.zeroPadValue(ethers.toBeHex(999), 32); + + await expect( + deployedActors.hub.getIdentityCommitmentMerkleRoot(invalidAttestationId), + ).to.be.revertedWithCustomError(deployedActors.hub, "InvalidAttestationId"); + }); + + it("should fail rootTimestamp with InvalidAttestationId", async () => { + const invalidAttestationId = ethers.zeroPadValue(ethers.toBeHex(999), 32); + + await expect(deployedActors.hub.rootTimestamp(invalidAttestationId, 123)).to.be.revertedWithCustomError( + deployedActors.hub, + "InvalidAttestationId", + ); + }); + }); + + describe("Verification Config V2 Tests", () => { + it("should successfully set and retrieve verification config V2", async () => { + const config = { + olderThanEnabled: true, + olderThan: 18, + forbiddenCountriesEnabled: true, + forbiddenCountriesListPacked: [840, 156, 0, 0] as [number, number, number, number], // USA, China + ofacEnabled: [true, false, false] as [boolean, boolean, boolean], + }; + + const configId = await deployedActors.hub.setVerificationConfigV2.staticCall(config); + await expect(deployedActors.hub.setVerificationConfigV2(config)) + .to.emit(deployedActors.hub, "VerificationConfigV2Set") + .withArgs(configId, [ + config.olderThanEnabled, + config.olderThan, + config.forbiddenCountriesEnabled, + config.forbiddenCountriesListPacked, + config.ofacEnabled, + ]); + + const exists = await deployedActors.hub.verificationConfigV2Exists(configId); + expect(exists).to.be.true; + }); + + it("should generate consistent config IDs for the same config", async () => { + const config = { + olderThanEnabled: false, + olderThan: 21, + forbiddenCountriesEnabled: false, + forbiddenCountriesListPacked: [392, 0, 0, 0] as [number, number, number, number], // Japan + ofacEnabled: [false, false, false] as [boolean, boolean, boolean], + }; + + const generatedId = await deployedActors.hub.generateConfigId(config); + const staticCallId = await deployedActors.hub.setVerificationConfigV2.staticCall(config); + + expect(generatedId).to.equal(staticCallId); + }); + + it("should return false for non-existent config", async () => { + const nonExistentConfigId = ethers.randomBytes(32); + const exists = await deployedActors.hub.verificationConfigV2Exists(nonExistentConfigId); + expect(exists).to.be.false; + }); + }); +}); diff --git a/contracts/test/v2/registerId.test.ts b/contracts/test/v2/registerId.test.ts new file mode 100644 index 000000000..1d43c6d06 --- /dev/null +++ b/contracts/test/v2/registerId.test.ts @@ -0,0 +1,266 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { generateRandomFieldElement } from "../utils/utils"; +import { deploySystemFixturesV2 } from "../utils/deploymentV2"; +import { DeployedActorsV2 } from "../utils/types"; +import { generateDscProof, generateRegisterIdProof } from "../utils/generateProof"; +import { DscVerifierId, RegisterVerifierId } from "@selfxyz/common/constants/constants"; +import serialized_dsc_tree from "@selfxyz/common/pubkeys/serialized_dsc_tree.json"; +import { + CIRCUIT_CONSTANTS, + ID_CARD_ATTESTATION_ID, + PASSPORT_ATTESTATION_ID, +} from "@selfxyz/common/constants/constants"; +import { genMockIdDocAndInitDataParsing } from "@selfxyz/common/utils/passports/genMockIdDoc"; + +describe("ID Registration test", function () { + this.timeout(0); + + let deployedActors: DeployedActorsV2; + let snapshotId: string; + let attestationIdBytes32: string; + let ePassportAttestationIdBytes32: string; + + before(async () => { + // Deploy contracts and setup initial state + deployedActors = await deploySystemFixturesV2(); + attestationIdBytes32 = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); + ePassportAttestationIdBytes32 = ethers.zeroPadValue(ethers.toBeHex(BigInt(PASSPORT_ATTESTATION_ID)), 32); + + console.log("🎉 System deployment and initial setup completed!"); + }); + + beforeEach(async () => { + // Take snapshot before each test + snapshotId = await ethers.provider.send("evm_snapshot", []); + }); + + afterEach(async () => { + // Revert to snapshot after each test + await ethers.provider.send("evm_revert", [snapshotId]); + }); + + describe("DSC Commitment Registration", () => { + let dscProof: any; + let idCardData: any; + + before(async () => { + // Generate DSC proof once for all tests in this describe block + idCardData = genMockIdDocAndInitDataParsing({ + idType: "mock_id_card", + dgHashAlgo: "sha256", + eContentHashAlgo: "sha256", + signatureType: "rsa_sha256_65537_2048", + nationality: "USA", + birthDate: "900101", + expiryDate: "301231", + }); + + dscProof = await generateDscProof(idCardData); + console.log("✅ DSC proof generated for DSC commitment tests"); + }); + + it("should successfully register DSC key commitment", async () => { + const dscCircuitVerifierId = DscVerifierId.dsc_sha256_rsa_65537_4096; + const initialDscRoot = await deployedActors.registryId.getDscKeyCommitmentMerkleRoot(); + const initialTreeSize = await deployedActors.registryId.getDscKeyCommitmentTreeSize(); + + // Register the DSC key commitment + await expect( + deployedActors.hub.registerDscKeyCommitment(attestationIdBytes32, dscCircuitVerifierId, dscProof), + ).to.emit(deployedActors.registryId, "DscKeyCommitmentRegistered"); + + // Verify DSC was added to tree + const updatedDscRoot = await deployedActors.registryId.getDscKeyCommitmentMerkleRoot(); + const updatedTreeSize = await deployedActors.registryId.getDscKeyCommitmentTreeSize(); + + expect(updatedDscRoot).to.not.equal(initialDscRoot); + expect(updatedTreeSize).to.equal(initialTreeSize + 1n); + + // Verify the commitment is registered + const isRegistered = await deployedActors.registryId.isRegisteredDscKeyCommitment( + dscProof.pubSignals[CIRCUIT_CONSTANTS.DSC_TREE_LEAF_INDEX], + ); + expect(isRegistered).to.be.true; + }); + + it("should fail with NoVerifierSet when using non-existent verifier ID", async () => { + const nonExistentVerifierId = 999999; // Non-existent verifier ID + + await expect( + deployedActors.hub.registerDscKeyCommitment(attestationIdBytes32, nonExistentVerifierId, dscProof), + ).to.be.revertedWithCustomError(deployedActors.hub, "NoVerifierSet"); + }); + + it("should fail with NoVerifierSet when using invalid attestation ID (no verifier configured)", async () => { + const invalidAttestationId = ethers.zeroPadValue(ethers.toBeHex(999), 32); + const dscCircuitVerifierId = DscVerifierId.dsc_sha256_rsa_65537_4096; + + await expect( + deployedActors.hub.registerDscKeyCommitment(invalidAttestationId, dscCircuitVerifierId, dscProof), + ).to.be.revertedWithCustomError(deployedActors.hub, "NoVerifierSet"); + }); + + it("should fail with InvalidAttestationId when verifier exists but attestation ID is invalid", async () => { + const invalidAttestationId = ethers.zeroPadValue(ethers.toBeHex(999), 32); + const dscCircuitVerifierId = DscVerifierId.dsc_sha256_rsa_65537_4096; + + // First, set up a verifier for the invalid attestation ID + await deployedActors.hub.updateDscVerifier( + invalidAttestationId, + dscCircuitVerifierId, + await deployedActors.dsc.getAddress(), + ); + + // Now the call should fail with InvalidAttestationId since verifier exists but attestation ID is not valid + await expect( + deployedActors.hub.registerDscKeyCommitment(invalidAttestationId, dscCircuitVerifierId, dscProof), + ).to.be.revertedWithCustomError(deployedActors.hub, "InvalidAttestationId"); + }); + + it("should fail with InvalidDscProof when providing invalid proof", async () => { + const dscCircuitVerifierId = DscVerifierId.dsc_sha256_rsa_65537_4096; + + // Create invalid proof by modifying the original + const invalidDscProof = { + ...dscProof, + a: ["0x1", "0x2"], // Invalid proof values + b: [ + ["0x1", "0x2"], + ["0x3", "0x4"], + ], + c: ["0x1", "0x2"], + }; + + await expect( + deployedActors.hub.registerDscKeyCommitment(attestationIdBytes32, dscCircuitVerifierId, invalidDscProof), + ).to.be.revertedWithCustomError(deployedActors.hub, "InvalidDscProof"); + }); + + it("should fail with InvalidCscaRoot when CSCA root doesn't match", async () => { + const dscCircuitVerifierId = DscVerifierId.dsc_sha256_rsa_65537_4096; + + // Manipulate the CSCA root in the registry to make it invalid + await deployedActors.registryId.updateCscaRoot(12345); // Invalid CSCA root + + await expect( + deployedActors.hub.registerDscKeyCommitment(attestationIdBytes32, dscCircuitVerifierId, dscProof), + ).to.be.revertedWithCustomError(deployedActors.hub, "InvalidCscaRoot"); + }); + }); + + describe("Identity Commitment Registration", () => { + let registerProof: any; + let registerSecret: string; + let idCardData: any; + + before(async () => { + const dscKeys = JSON.parse(serialized_dsc_tree); + for (let i = 0; i < dscKeys[0].length; i++) { + await deployedActors.registryId.devAddDscKeyCommitment(BigInt(dscKeys[0][i])); + } + + // Generate identity commitment proof + idCardData = genMockIdDocAndInitDataParsing({ + idType: "mock_id_card", + dgHashAlgo: "sha256", + eContentHashAlgo: "sha256", + signatureType: "rsa_sha256_65537_2048", + nationality: "GBR", + birthDate: "920315", + expiryDate: "321231", + }); + + registerSecret = generateRandomFieldElement(); + registerProof = await generateRegisterIdProof(registerSecret, idCardData); + console.log("✅ Identity commitment proof generated for identity tests"); + }); + + it("should successfully register identity commitment", async () => { + const registerCircuitVerifierId = RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096; + + // Register the identity commitment + await expect( + deployedActors.hub.registerCommitment(attestationIdBytes32, registerCircuitVerifierId, registerProof), + ).to.emit(deployedActors.registryId, "CommitmentRegistered"); + + // Verify the commitment is registered by checking the nullifier + const isRegistered = await deployedActors.registryId.nullifiers( + attestationIdBytes32, + registerProof.pubSignals[CIRCUIT_CONSTANTS.REGISTER_NULLIFIER_INDEX], + ); + expect(isRegistered).to.be.true; + }); + + it("should fail with NoVerifierSet when using non-existent register verifier ID", async () => { + const nonExistentVerifierId = 999999; // Non-existent verifier ID + + await expect( + deployedActors.hub.registerCommitment(attestationIdBytes32, nonExistentVerifierId, registerProof), + ).to.be.revertedWithCustomError(deployedActors.hub, "NoVerifierSet"); + }); + + it("should fail with NoVerifierSet when using invalid attestation ID for register (no verifier configured)", async () => { + const invalidAttestationId = ethers.zeroPadValue(ethers.toBeHex(999), 32); + const registerCircuitVerifierId = RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096; + + await expect( + deployedActors.hub.registerCommitment(invalidAttestationId, registerCircuitVerifierId, registerProof), + ).to.be.revertedWithCustomError(deployedActors.hub, "NoVerifierSet"); + }); + + it("should fail with InvalidAttestationId when register verifier exists but attestation ID is invalid", async () => { + const invalidAttestationId = ethers.zeroPadValue(ethers.toBeHex(999), 32); + const registerCircuitVerifierId = RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096; + + // First, set up a verifier for the invalid attestation ID + await deployedActors.hub.updateRegisterCircuitVerifier( + invalidAttestationId, + registerCircuitVerifierId, + await deployedActors.register.getAddress(), + ); + + // Now the call should fail with InvalidAttestationId since verifier exists but attestation ID is not valid + await expect( + deployedActors.hub.registerCommitment(invalidAttestationId, registerCircuitVerifierId, registerProof), + ).to.be.revertedWithCustomError(deployedActors.hub, "InvalidAttestationId"); + }); + + it("should fail with InvalidRegisterProof when providing invalid register proof", async () => { + const registerCircuitVerifierId = RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096; + + // Create invalid proof by modifying the original + const invalidRegisterProof = { + ...registerProof, + a: ["0x1", "0x2"], // Invalid proof values + b: [ + ["0x1", "0x2"], + ["0x3", "0x4"], + ], + c: ["0x1", "0x2"], + }; + + await expect( + deployedActors.hub.registerCommitment(attestationIdBytes32, registerCircuitVerifierId, invalidRegisterProof), + ).to.be.revertedWithCustomError(deployedActors.hub, "InvalidRegisterProof"); + }); + + it("should fail with InvalidDscCommitmentRoot when DSC commitment root doesn't match", async () => { + const registerCircuitVerifierId = RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096; + + // Create a new registry snapshot to restore later + const tempSnapshot = await ethers.provider.send("evm_snapshot", []); + + // Add an invalid DSC key commitment to change the root + await deployedActors.registryId.devAddDscKeyCommitment(BigInt(999999)); + + // The proof was generated with the original root, so it should fail + await expect( + deployedActors.hub.registerCommitment(attestationIdBytes32, registerCircuitVerifierId, registerProof), + ).to.be.revertedWithCustomError(deployedActors.hub, "InvalidDscCommitmentRoot"); + + // Restore the snapshot + await ethers.provider.send("evm_revert", [tempSnapshot]); + }); + }); +}); diff --git a/contracts/test/v2/registerPassport.test.ts b/contracts/test/v2/registerPassport.test.ts new file mode 100644 index 000000000..88d5b62b2 --- /dev/null +++ b/contracts/test/v2/registerPassport.test.ts @@ -0,0 +1,268 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { generateRandomFieldElement } from "../utils/utils"; +import { deploySystemFixturesV2 } from "../utils/deploymentV2"; +import { DeployedActorsV2 } from "../utils/types"; +import { generateDscProof, generateRegisterProof } from "../utils/generateProof"; +import { DscVerifierId, RegisterVerifierId } from "@selfxyz/common/constants/constants"; +import serialized_dsc_tree from "@selfxyz/common/pubkeys/serialized_dsc_tree.json"; +import { CIRCUIT_CONSTANTS, PASSPORT_ATTESTATION_ID } from "@selfxyz/common/constants/constants"; +import { genMockIdDocAndInitDataParsing } from "@selfxyz/common/utils/passports/genMockIdDoc"; + +describe("Passport Registration test", function () { + this.timeout(0); + + let deployedActors: DeployedActorsV2; + let snapshotId: string; + let ePassportAttestationIdBytes32: string; + + before(async () => { + // Deploy contracts and setup initial state + deployedActors = await deploySystemFixturesV2(); + ePassportAttestationIdBytes32 = ethers.zeroPadValue(ethers.toBeHex(BigInt(PASSPORT_ATTESTATION_ID)), 32); + + console.log("🎉 System deployment and initial setup completed!"); + }); + + beforeEach(async () => { + // Take snapshot before each test + snapshotId = await ethers.provider.send("evm_snapshot", []); + }); + + afterEach(async () => { + // Revert to snapshot after each test + await ethers.provider.send("evm_revert", [snapshotId]); + }); + + describe("DSC Commitment Registration for Passport", () => { + let dscProof: any; + let passportData: any; + + before(async () => { + // Generate DSC proof once for all tests in this describe block + passportData = genMockIdDocAndInitDataParsing({ + idType: "mock_passport", + dgHashAlgo: "sha256", + eContentHashAlgo: "sha256", + signatureType: "rsa_sha256_65537_2048", + nationality: "USA", + birthDate: "900101", + expiryDate: "301231", + }); + + dscProof = await generateDscProof(passportData); + console.log("✅ DSC proof generated for passport DSC commitment tests"); + }); + + it("should successfully register DSC key commitment for passport", async () => { + const dscCircuitVerifierId = DscVerifierId.dsc_sha256_rsa_65537_4096; + const initialDscRoot = await deployedActors.registry.getDscKeyCommitmentMerkleRoot(); + const initialTreeSize = await deployedActors.registry.getDscKeyCommitmentTreeSize(); + + // Register the DSC key commitment + await expect( + deployedActors.hub.registerDscKeyCommitment(ePassportAttestationIdBytes32, dscCircuitVerifierId, dscProof), + ).to.emit(deployedActors.registry, "DscKeyCommitmentRegistered"); + + // Verify DSC was added to tree + const updatedDscRoot = await deployedActors.registry.getDscKeyCommitmentMerkleRoot(); + const updatedTreeSize = await deployedActors.registry.getDscKeyCommitmentTreeSize(); + + expect(updatedDscRoot).to.not.equal(initialDscRoot); + expect(updatedTreeSize).to.equal(initialTreeSize + 1n); + + // Verify the commitment is registered + const isRegistered = await deployedActors.registry.isRegisteredDscKeyCommitment( + dscProof.pubSignals[CIRCUIT_CONSTANTS.DSC_TREE_LEAF_INDEX], + ); + expect(isRegistered).to.be.true; + }); + + it("should fail with NoVerifierSet when using non-existent verifier ID for passport", async () => { + const nonExistentVerifierId = 999999; // Non-existent verifier ID + + await expect( + deployedActors.hub.registerDscKeyCommitment(ePassportAttestationIdBytes32, nonExistentVerifierId, dscProof), + ).to.be.revertedWithCustomError(deployedActors.hub, "NoVerifierSet"); + }); + + it("should fail with NoVerifierSet when using invalid attestation ID for passport (no verifier configured)", async () => { + const invalidAttestationId = ethers.zeroPadValue(ethers.toBeHex(999), 32); + const dscCircuitVerifierId = DscVerifierId.dsc_sha256_rsa_65537_4096; + + await expect( + deployedActors.hub.registerDscKeyCommitment(invalidAttestationId, dscCircuitVerifierId, dscProof), + ).to.be.revertedWithCustomError(deployedActors.hub, "NoVerifierSet"); + }); + + it("should fail with InvalidAttestationId when verifier exists but attestation ID is invalid for passport", async () => { + const invalidAttestationId = ethers.zeroPadValue(ethers.toBeHex(999), 32); + const dscCircuitVerifierId = DscVerifierId.dsc_sha256_rsa_65537_4096; + + // First, set up a verifier for the invalid attestation ID + await deployedActors.hub.updateDscVerifier( + invalidAttestationId, + dscCircuitVerifierId, + await deployedActors.dsc.getAddress(), + ); + + // Now the call should fail with InvalidAttestationId since verifier exists but attestation ID is not valid + await expect( + deployedActors.hub.registerDscKeyCommitment(invalidAttestationId, dscCircuitVerifierId, dscProof), + ).to.be.revertedWithCustomError(deployedActors.hub, "InvalidAttestationId"); + }); + + it("should fail with InvalidDscProof when providing invalid proof for passport", async () => { + const dscCircuitVerifierId = DscVerifierId.dsc_sha256_rsa_65537_4096; + + // Create invalid proof by modifying the original + const invalidDscProof = { + ...dscProof, + a: ["0x1", "0x2"], // Invalid proof values + b: [ + ["0x1", "0x2"], + ["0x3", "0x4"], + ], + c: ["0x1", "0x2"], + }; + + await expect( + deployedActors.hub.registerDscKeyCommitment( + ePassportAttestationIdBytes32, + dscCircuitVerifierId, + invalidDscProof, + ), + ).to.be.revertedWithCustomError(deployedActors.hub, "InvalidDscProof"); + }); + + it("should fail with InvalidCscaRoot when CSCA root doesn't match for passport", async () => { + const dscCircuitVerifierId = DscVerifierId.dsc_sha256_rsa_65537_4096; + + // Manipulate the CSCA root in the registry to make it invalid + await deployedActors.registry.updateCscaRoot(12345); // Invalid CSCA root + + await expect( + deployedActors.hub.registerDscKeyCommitment(ePassportAttestationIdBytes32, dscCircuitVerifierId, dscProof), + ).to.be.revertedWithCustomError(deployedActors.hub, "InvalidCscaRoot"); + }); + }); + + describe("Passport Identity Commitment Registration", () => { + let registerProof: any; + let registerSecret: string; + let passportData: any; + + before(async () => { + const dscKeys = JSON.parse(serialized_dsc_tree); + for (let i = 0; i < dscKeys[0].length; i++) { + await deployedActors.registry.devAddDscKeyCommitment(BigInt(dscKeys[0][i])); + } + + // Generate passport identity commitment proof using passport-specific function + passportData = genMockIdDocAndInitDataParsing({ + idType: "mock_passport", + dgHashAlgo: "sha256", + eContentHashAlgo: "sha256", + signatureType: "rsa_sha256_65537_2048", + nationality: "GBR", + birthDate: "920315", + expiryDate: "321231", + }); + + registerSecret = generateRandomFieldElement(); + registerProof = await generateRegisterProof(registerSecret, passportData); + console.log("✅ Passport identity commitment proof generated for passport identity tests"); + }); + + it("should successfully register passport identity commitment", async () => { + const registerCircuitVerifierId = RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096; + + // Register the passport identity commitment + await expect( + deployedActors.hub.registerCommitment(ePassportAttestationIdBytes32, registerCircuitVerifierId, registerProof), + ).to.emit(deployedActors.registry, "CommitmentRegistered"); + + // Verify the commitment is registered by checking the nullifier + const isRegistered = await deployedActors.registry.nullifiers( + ePassportAttestationIdBytes32, + registerProof.pubSignals[CIRCUIT_CONSTANTS.REGISTER_NULLIFIER_INDEX], + ); + expect(isRegistered).to.be.true; + }); + + it("should fail with NoVerifierSet when using non-existent passport register verifier ID", async () => { + const nonExistentVerifierId = 999999; // Non-existent verifier ID + + await expect( + deployedActors.hub.registerCommitment(ePassportAttestationIdBytes32, nonExistentVerifierId, registerProof), + ).to.be.revertedWithCustomError(deployedActors.hub, "NoVerifierSet"); + }); + + it("should fail with NoVerifierSet when using invalid attestation ID for passport register (no verifier configured)", async () => { + const invalidAttestationId = ethers.zeroPadValue(ethers.toBeHex(999), 32); + const registerCircuitVerifierId = RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096; + + await expect( + deployedActors.hub.registerCommitment(invalidAttestationId, registerCircuitVerifierId, registerProof), + ).to.be.revertedWithCustomError(deployedActors.hub, "NoVerifierSet"); + }); + + it("should fail with InvalidAttestationId when passport register verifier exists but attestation ID is invalid", async () => { + const invalidAttestationId = ethers.zeroPadValue(ethers.toBeHex(999), 32); + const registerCircuitVerifierId = RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096; + + // First, set up a verifier for the invalid attestation ID + await deployedActors.hub.updateRegisterCircuitVerifier( + invalidAttestationId, + registerCircuitVerifierId, + await deployedActors.register.getAddress(), + ); + + // Now the call should fail with InvalidAttestationId since verifier exists but attestation ID is not valid + await expect( + deployedActors.hub.registerCommitment(invalidAttestationId, registerCircuitVerifierId, registerProof), + ).to.be.revertedWithCustomError(deployedActors.hub, "InvalidAttestationId"); + }); + + it("should fail with InvalidRegisterProof when providing invalid passport register proof", async () => { + const registerCircuitVerifierId = RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096; + + // Create invalid proof by modifying the original + const invalidRegisterProof = { + ...registerProof, + a: ["0x1", "0x2"], // Invalid proof values + b: [ + ["0x1", "0x2"], + ["0x3", "0x4"], + ], + c: ["0x1", "0x2"], + }; + + await expect( + deployedActors.hub.registerCommitment( + ePassportAttestationIdBytes32, + registerCircuitVerifierId, + invalidRegisterProof, + ), + ).to.be.revertedWithCustomError(deployedActors.hub, "InvalidRegisterProof"); + }); + + it("should fail with InvalidDscCommitmentRoot when DSC commitment root doesn't match for passport", async () => { + const registerCircuitVerifierId = RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096; + + // Create a new registry snapshot to restore later + const tempSnapshot = await ethers.provider.send("evm_snapshot", []); + + // Add an invalid DSC key commitment to change the root + await deployedActors.registry.devAddDscKeyCommitment(BigInt(999999)); + + // The proof was generated with the original root, so it should fail + await expect( + deployedActors.hub.registerCommitment(ePassportAttestationIdBytes32, registerCircuitVerifierId, registerProof), + ).to.be.revertedWithCustomError(deployedActors.hub, "InvalidDscCommitmentRoot"); + + // Restore the snapshot + await ethers.provider.send("evm_revert", [tempSnapshot]); + }); + }); +}); diff --git a/contracts/yarnrc.yml b/contracts/yarnrc.yml new file mode 100644 index 000000000..3186f3f07 --- /dev/null +++ b/contracts/yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: node-modules From bf8cf6c0bc64b2f13fa4877196c15d750c4e8d71 Mon Sep 17 00:00:00 2001 From: Vishalkulkarni45 <109329073+Vishalkulkarni45@users.noreply.github.com> Date: Wed, 18 Jun 2025 16:33:50 +0530 Subject: [PATCH 3/5] fix: vc_and_disclose_id test (#640) * fix: vc_and_disclose_id test * chore: yarn prettier --- .../utils/passport/disclose/disclose_id.circom | 10 +++++----- circuits/tests/disclose/vc_and_disclose_id.test.ts | 14 +++++--------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/circuits/circuits/utils/passport/disclose/disclose_id.circom b/circuits/circuits/utils/passport/disclose/disclose_id.circom index 7335fc22b..3c8868167 100644 --- a/circuits/circuits/utils/passport/disclose/disclose_id.circom +++ b/circuits/circuits/utils/passport/disclose/disclose_id.circom @@ -42,9 +42,9 @@ template DISCLOSE_ID( signal input ofac_nameyob_smt_leaf_key; signal input ofac_nameyob_smt_root; signal input ofac_nameyob_smt_siblings[nameyobTreeLevels]; - + signal input selector_ofac; - + // assert selectors are 0 or 1 for (var i = 0; i < 90; i++) { selector_dg1[i] * (selector_dg1[i] - 1) === 0; @@ -64,11 +64,11 @@ template DISCLOSE_ID( older_than_verified[0] <== isOlderThan.out * majority[0]; older_than_verified[1] <== isOlderThan.out * majority[1]; - signal revealedData[94]; // mrz: 88 bytes | older_than: 2 bytes | ofac: 3 byte + signal revealedData[94]; // mrz: 90 bytes | older_than: 2 bytes | ofac: 2 byte for (var i = 0; i < 90; i++) { revealedData[i] <== dg1[5+i] * selector_dg1[i]; } - + revealedData[90] <== older_than_verified[0] * selector_older_than; revealedData[91] <== older_than_verified[1] * selector_older_than; @@ -91,4 +91,4 @@ template DISCLOSE_ID( var chunkLength = computeIntChunkLength(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH * 3); signal output forbidden_countries_list_packed[chunkLength] <== ProveCountryIsNotInList_ID(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH)(dg1, forbidden_countries_list); -} \ No newline at end of file +} diff --git a/circuits/tests/disclose/vc_and_disclose_id.test.ts b/circuits/tests/disclose/vc_and_disclose_id.test.ts index 8814cf0d2..f64201875 100644 --- a/circuits/tests/disclose/vc_and_disclose_id.test.ts +++ b/circuits/tests/disclose/vc_and_disclose_id.test.ts @@ -13,7 +13,6 @@ import crypto from 'crypto'; import { SMT } from '@openpassport/zk-kit-smt'; import nameAndDobjson from '@selfxyz/common/ofacdata/outputs/nameAndDobSMT_ID.json' with { type: 'json' }; import nameAndYobjson from '@selfxyz/common/ofacdata/outputs/nameAndYobSMT_ID.json' with { type: 'json' }; -import passportNojson from '@selfxyz/common/ofacdata/outputs/passportNoAndNationalitySMT.json' with { type: 'json' }; import { formatAndUnpackForbiddenCountriesList, formatAndUnpackReveal, @@ -53,9 +52,6 @@ describe('Disclose', function () { const tree: any = new LeanIMT((a, b) => poseidon2([a, b]), []); tree.insert(BigInt(commitment)); - const passportNo_smt = new SMT(poseidon2, true); - passportNo_smt.import(passportNojson); - const nameAndDob_smt = new SMT(poseidon2, true); nameAndDob_smt.import(nameAndDobjson); @@ -85,7 +81,7 @@ describe('Disclose', function () { selector_older_than, tree, majority, - passportNo_smt, + null, nameAndDob_smt, nameAndYob_smt, selector_ofac, @@ -141,7 +137,7 @@ describe('Disclose', function () { const revealedData_packed = await circuit.getOutput(w, ['revealedData_packed[4]']); const reveal_unpacked = formatAndUnpackReveal(revealedData_packed, 'id'); - for (let i = 0; i < 88; i++) { + for (let i = 0; i < 90; i++) { if (selector_dg1[i] == '1') { const char = String.fromCharCode(Number(inputs.dg1[i + 5])); assert(reveal_unpacked[i] == char, 'Should reveal the right character'); @@ -187,8 +183,8 @@ describe('Disclose', function () { const revealedData_packed = await circuit.getOutput(w, ['revealedData_packed[4]']); const reveal_unpacked = formatAndUnpackReveal(revealedData_packed, 'id'); - expect(reveal_unpacked[88]).to.equal('\x00'); - expect(reveal_unpacked[89]).to.equal('\x00'); + expect(reveal_unpacked[90]).to.equal('\x00'); + expect(reveal_unpacked[91]).to.equal('\x00'); }); describe('OFAC disclosure', function () { @@ -269,7 +265,7 @@ describe('Disclose', function () { selector_older_than, tree, majority, - passportNo_smt, + null, nameAndDob_smt, nameAndYob_smt, '1', // selector_ofac From a9f6207227fe25935aa24d5e23884370c79d6a74 Mon Sep 17 00:00:00 2001 From: Nesopie <87437291+Nesopie@users.noreply.github.com> Date: Fri, 20 Jun 2025 18:05:33 +0530 Subject: [PATCH 4/5] feat: add getConfigId function in SelfVerificationRoot (#650) * feat: add getConfigId function in SelfVerificationRoot * update comment --------- Co-authored-by: motemotech --- .../IdentityVerificationHubImplV2.sol | 5 +- .../abstract/SelfVerificationRoot.sol | 33 +++++++-- .../tests/TestSelfVerificationRoot.sol | 11 +++ contracts/test/v2/discloseId.test.ts | 70 +++++++++--------- contracts/test/v2/disclosePassport.test.ts | 71 +++++++++---------- 5 files changed, 108 insertions(+), 82 deletions(-) diff --git a/contracts/contracts/IdentityVerificationHubImplV2.sol b/contracts/contracts/IdentityVerificationHubImplV2.sol index 37c4be1bd..f18c2aed6 100644 --- a/contracts/contracts/IdentityVerificationHubImplV2.sol +++ b/contracts/contracts/IdentityVerificationHubImplV2.sol @@ -263,7 +263,7 @@ contract IdentityVerificationHubImplV2 is ImplRoot { */ function setVerificationConfigV2( SelfStructs.VerificationConfigV2 memory config - ) external virtual onlyProxy onlyOwner returns (bytes32 configId) { + ) external virtual onlyProxy returns (bytes32 configId) { configId = generateConfigId(config); IdentityVerificationHubV2Storage storage $v2 = _getIdentityVerificationHubV2Storage(); $v2._v2VerificationConfigs[configId] = config; @@ -1025,7 +1025,8 @@ contract IdentityVerificationHubImplV2 is ImplRoot { // Get the user identifier index for this attestation type uint256 proofUserIdentifier = vcAndDiscloseProof.pubSignals[indices.userIdentifierIndex]; - bytes32 sha256Hash = sha256(userContextData); + bytes memory userContextDataWithoutConfigId = userContextData[32:]; + bytes32 sha256Hash = sha256(userContextDataWithoutConfigId); bytes20 ripemdHash = ripemd160(abi.encodePacked(sha256Hash)); uint256 hashedValue = uint256(uint160(ripemdHash)); diff --git a/contracts/contracts/abstract/SelfVerificationRoot.sol b/contracts/contracts/abstract/SelfVerificationRoot.sol index c242c4f04..4e9254043 100644 --- a/contracts/contracts/abstract/SelfVerificationRoot.sol +++ b/contracts/contracts/abstract/SelfVerificationRoot.sol @@ -87,9 +87,9 @@ abstract contract SelfVerificationRoot is ISelfVerificationRoot { * @notice Verifies a self-proof using the bytes-based interface * @dev Parses relayer data format and validates against contract settings before calling hub V2 * @param proofPayload Packed data from relayer in format: | 32 bytes attestationId | proof data | - * @param userContextData User-defined data in format: | 32 bytes configId | 32 bytes destChainId | 32 bytes userIdentifier | data | + * @param userContextData User-defined data in format: | 32 bytes destChainId | 32 bytes userIdentifier | data | * @custom:data-format proofPayload = | 32 bytes attestationId | proofData | - * @custom:data-format userContextData = | 32 bytes configId | 32 bytes destChainId | 32 bytes userIdentifier | data | + * @custom:data-format userContextData = | 32 bytes destChainId | 32 bytes userIdentifier | data | * @custom:data-format hubData = | 1 bytes contract version | 31 bytes buffer | 32 bytes scope | 32 bytes attestationId | proofData | */ function verifySelfProof(bytes calldata proofPayload, bytes calldata userContextData) public { @@ -98,8 +98,8 @@ abstract contract SelfVerificationRoot is ISelfVerificationRoot { revert InvalidDataFormat(); } - // Minimum userDefinedData length: 32 (configId) + 32 (destChainId) + 32 (userIdentifier) = 96 bytes - if (userContextData.length < 96) { + // Minimum userDefinedData length: 32 (destChainId) + 32 (userIdentifier) + 0 (userDefinedData) = 64 bytes + if (userContextData.length < 64) { revert InvalidDataFormat(); } @@ -109,6 +109,12 @@ abstract contract SelfVerificationRoot is ISelfVerificationRoot { attestationId := calldataload(proofPayload.offset) } + bytes32 destinationChainId = bytes32(userContextData[0:32]); + bytes32 userIdentifier = bytes32(userContextData[32:64]); + bytes memory userDefinedData = userContextData[64:]; + + bytes32 configId = getConfigId(destinationChainId, userIdentifier, userDefinedData); + // Hub data should be | 1 byte contractVersion | 31 bytes buffer | 32 bytes scope | 32 bytes attestationId | proof data bytes memory baseVerificationInput = abi.encodePacked( // 1 byte contractVersion @@ -124,7 +130,7 @@ abstract contract SelfVerificationRoot is ISelfVerificationRoot { ); // Call hub V2 verification - _identityVerificationHubV2.verify(baseVerificationInput, userContextData); + _identityVerificationHubV2.verify(baseVerificationInput, bytes.concat(configId, userContextData)); } /** @@ -150,6 +156,23 @@ abstract contract SelfVerificationRoot is ISelfVerificationRoot { customVerificationHook(genericDiscloseOutput, userData); } + /** + * @notice Generates a configId for the user + * @dev This function should be overridden by the implementing contract to provide custom configId logic + * @param destinationChainId The destination chain ID + * @param userIdentifier The user identifier + * @param userDefinedData The user defined data + * @return The configId + */ + function getConfigId( + bytes32 destinationChainId, + bytes32 userIdentifier, + bytes memory userDefinedData + ) public view virtual returns (bytes32) { + // Default implementation reverts; must be overridden in derived contract + revert("SelfVerificationRoot: getConfigId must be overridden"); + } + /** * @notice Custom verification hook that can be overridden by implementing contracts * @dev This function is called after successful verification and hub address validation diff --git a/contracts/contracts/tests/TestSelfVerificationRoot.sol b/contracts/contracts/tests/TestSelfVerificationRoot.sol index ee136363a..1c8cf713f 100644 --- a/contracts/contracts/tests/TestSelfVerificationRoot.sol +++ b/contracts/contracts/tests/TestSelfVerificationRoot.sol @@ -3,6 +3,7 @@ pragma solidity 0.8.28; import {SelfVerificationRoot} from "../abstract/SelfVerificationRoot.sol"; import {ISelfVerificationRoot} from "../interfaces/ISelfVerificationRoot.sol"; +import {SelfStructs} from "../libraries/SelfStructs.sol"; /** * @title TestSelfVerificationRoot @@ -14,6 +15,7 @@ contract TestSelfVerificationRoot is SelfVerificationRoot { bool public verificationSuccessful; ISelfVerificationRoot.GenericDiscloseOutputV2 public lastOutput; bytes public lastUserData; + SelfStructs.VerificationConfigV2 public verificationConfig; // Events for testing event VerificationCompleted(ISelfVerificationRoot.GenericDiscloseOutputV2 output, bytes userData); @@ -76,6 +78,15 @@ contract TestSelfVerificationRoot is SelfVerificationRoot { _setScope(newScope); } + function setVerificationConfig(SelfStructs.VerificationConfigV2 memory config) external { + verificationConfig = config; + _identityVerificationHubV2.setVerificationConfigV2(verificationConfig); + } + + function getConfigId(bytes32 destinationChainId, bytes32 userIdentifier, bytes memory userDefinedData) public view override returns (bytes32) { + return _identityVerificationHubV2.generateConfigId(verificationConfig); + } + /** * @notice Test function to simulate calling onVerificationSuccess from hub * @dev This function is only for testing purposes to verify access control diff --git a/contracts/test/v2/discloseId.test.ts b/contracts/test/v2/discloseId.test.ts index 35c3a09f2..de9237e66 100644 --- a/contracts/test/v2/discloseId.test.ts +++ b/contracts/test/v2/discloseId.test.ts @@ -90,7 +90,7 @@ describe("Self Verification Flow V2 - ID Card", () => { ofacEnabled: [false, false, false] as [boolean, boolean, boolean], }; - await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); + await deployedActors.testSelfVerificationRoot.setVerificationConfig(verificationConfigV2); configId = await deployedActors.hub.generateConfigId(verificationConfigV2); const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); @@ -98,8 +98,8 @@ describe("Self Verification Flow V2 - ID Card", () => { const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const tempUserContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const userIdentifierHash = calculateUserIdentifierHash(tempUserContextData); @@ -165,8 +165,8 @@ describe("Self Verification Flow V2 - ID Card", () => { const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); @@ -200,8 +200,8 @@ describe("Self Verification Flow V2 - ID Card", () => { const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); // Create proofData with less than 32 bytes (invalid) @@ -251,8 +251,8 @@ describe("Self Verification Flow V2 - ID Card", () => { const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); @@ -334,8 +334,8 @@ describe("Self Verification Flow V2 - ID Card", () => { // Create invalid userContextData by changing the user address to a different value const invalidUserAddress = await deployedActors.user2.getAddress(); const invalidUserContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(invalidUserAddress, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(invalidUserAddress, 32), userData], ); const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); @@ -376,8 +376,8 @@ describe("Self Verification Flow V2 - ID Card", () => { const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); @@ -427,8 +427,8 @@ describe("Self Verification Flow V2 - ID Card", () => { const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); @@ -487,8 +487,8 @@ describe("Self Verification Flow V2 - ID Card", () => { const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); @@ -547,8 +547,8 @@ describe("Self Verification Flow V2 - ID Card", () => { const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ID_CARD_ATTESTATION_ID)), 32); @@ -599,8 +599,8 @@ describe("Self Verification Flow V2 - ID Card", () => { const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); // Use invalid attestation ID @@ -628,16 +628,15 @@ describe("Self Verification Flow V2 - ID Card", () => { ofacEnabled: [false, true, false] as [boolean, boolean, boolean], // ID card: [passport_no: false, name_dob: true, name_yob: false] }; - await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); - const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + await deployedActors.testSelfVerificationRoot.setVerificationConfig(verificationConfigV2); const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); const user1Address = await deployedActors.user1.getAddress(); const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const userIdentifierHash = calculateUserIdentifierHash(userContextData); @@ -693,16 +692,15 @@ describe("Self Verification Flow V2 - ID Card", () => { ofacEnabled: [false, false, false] as [boolean, boolean, boolean], // All OFAC checks disabled }; - await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); - const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + await deployedActors.testSelfVerificationRoot.setVerificationConfig(verificationConfigV2); const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); const user1Address = await deployedActors.user1.getAddress(); const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const userIdentifierHash = calculateUserIdentifierHash(userContextData); @@ -759,16 +757,15 @@ describe("Self Verification Flow V2 - ID Card", () => { ofacEnabled: [false, false, false] as [boolean, boolean, boolean], // All OFAC checks disabled }; - await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); - const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + await deployedActors.testSelfVerificationRoot.setVerificationConfig(verificationConfigV2); const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); const user1Address = await deployedActors.user1.getAddress(); const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const userIdentifierHash = calculateUserIdentifierHash(userContextData); @@ -824,8 +821,7 @@ describe("Self Verification Flow V2 - ID Card", () => { ofacEnabled: [false, false, false] as [boolean, boolean, boolean], // All OFAC checks disabled }; - await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); - const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + await deployedActors.testSelfVerificationRoot.setVerificationConfig(verificationConfigV2); const user1Address = await deployedActors.user1.getAddress(); const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); @@ -833,8 +829,8 @@ describe("Self Verification Flow V2 - ID Card", () => { // Use an invalid destination chain ID that's different from current chain (31337) const invalidDestChainId = ethers.zeroPadValue(ethers.toBeHex(999999), 32); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, invalidDestChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [invalidDestChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const userIdentifierHash = calculateUserIdentifierHash(userContextData); diff --git a/contracts/test/v2/disclosePassport.test.ts b/contracts/test/v2/disclosePassport.test.ts index f32e803d1..5082488e9 100644 --- a/contracts/test/v2/disclosePassport.test.ts +++ b/contracts/test/v2/disclosePassport.test.ts @@ -85,16 +85,15 @@ describe("Self Verification Flow V2", () => { ofacEnabled: [true, true, true] as [boolean, boolean, boolean], }; - await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); - configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + await deployedActors.testSelfVerificationRoot.setVerificationConfig(verificationConfigV2); const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); const user1Address = await deployedActors.user1.getAddress(); const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const tempUserContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const userIdentifierHash = calculateUserIdentifierHash(tempUserContextData); @@ -156,8 +155,8 @@ describe("Self Verification Flow V2", () => { const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ATTESTATION_ID.E_PASSPORT)), 32); @@ -192,8 +191,8 @@ describe("Self Verification Flow V2", () => { const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); // Create proofData with less than 32 bytes (invalid) @@ -243,8 +242,8 @@ describe("Self Verification Flow V2", () => { const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ATTESTATION_ID.E_PASSPORT)), 32); @@ -325,8 +324,8 @@ describe("Self Verification Flow V2", () => { // Create invalid userContextData by changing the user address to a different value const invalidUserAddress = await deployedActors.user2.getAddress(); const invalidUserContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(invalidUserAddress, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(invalidUserAddress, 32), userData], ); const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ATTESTATION_ID.E_PASSPORT)), 32); @@ -367,8 +366,8 @@ describe("Self Verification Flow V2", () => { const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const userIdentifierHash = calculateUserIdentifierHash(userContextData); @@ -447,8 +446,8 @@ describe("Self Verification Flow V2", () => { const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ATTESTATION_ID.E_PASSPORT)), 32); @@ -507,8 +506,8 @@ describe("Self Verification Flow V2", () => { const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ATTESTATION_ID.E_PASSPORT)), 32); @@ -567,8 +566,8 @@ describe("Self Verification Flow V2", () => { const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const attestationId = ethers.zeroPadValue(ethers.toBeHex(BigInt(ATTESTATION_ID.E_PASSPORT)), 32); @@ -619,8 +618,8 @@ describe("Self Verification Flow V2", () => { const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); // Use invalid attestation ID @@ -648,16 +647,15 @@ describe("Self Verification Flow V2", () => { ofacEnabled: [true, true, true] as [boolean, boolean, boolean], // Enable OFAC checks }; - await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); - const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + await deployedActors.testSelfVerificationRoot.setVerificationConfig(verificationConfigV2); const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); const user1Address = await deployedActors.user1.getAddress(); const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const userIdentifierHash = calculateUserIdentifierHash(userContextData); @@ -726,16 +724,15 @@ describe("Self Verification Flow V2", () => { ofacEnabled: [false, false, false] as [boolean, boolean, boolean], }; - await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); - const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + await deployedActors.testSelfVerificationRoot.setVerificationConfig(verificationConfigV2); const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); const user1Address = await deployedActors.user1.getAddress(); const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const userIdentifierHash = calculateUserIdentifierHash(userContextData); @@ -788,16 +785,15 @@ describe("Self Verification Flow V2", () => { ofacEnabled: [false, false, false] as [boolean, boolean, boolean], }; - await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); - const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + await deployedActors.testSelfVerificationRoot.setVerificationConfig(verificationConfigV2); const destChainId = ethers.zeroPadValue(ethers.toBeHex(31337), 32); const user1Address = await deployedActors.user1.getAddress(); const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, destChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [destChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const userIdentifierHash = calculateUserIdentifierHash(userContextData); @@ -849,8 +845,7 @@ describe("Self Verification Flow V2", () => { ofacEnabled: [false, false, false] as [boolean, boolean, boolean], }; - await deployedActors.hub.setVerificationConfigV2(verificationConfigV2); - const configId = await deployedActors.hub.generateConfigId(verificationConfigV2); + await deployedActors.testSelfVerificationRoot.setVerificationConfig(verificationConfigV2); const user1Address = await deployedActors.user1.getAddress(); const userData = ethers.toUtf8Bytes("test-user-data-for-verification"); @@ -858,8 +853,8 @@ describe("Self Verification Flow V2", () => { // Use an invalid destination chain ID that's different from current chain (31337) const invalidDestChainId = ethers.zeroPadValue(ethers.toBeHex(999999), 32); const userContextData = ethers.solidityPacked( - ["bytes32", "bytes32", "bytes32", "bytes"], - [configId, invalidDestChainId, ethers.zeroPadValue(user1Address, 32), userData], + ["bytes32", "bytes32", "bytes"], + [invalidDestChainId, ethers.zeroPadValue(user1Address, 32), userData], ); const userIdentifierHash = calculateUserIdentifierHash(userContextData); From 6e694993f68432f84aefa2244500488e9120b859 Mon Sep 17 00:00:00 2001 From: kevinsslin Date: Sat, 21 Jun 2025 18:21:31 +0200 Subject: [PATCH 5/5] feat: update Hardhat configuration and add TestSelfVerificationRoot deployment module * Change account key reference from CELO_KEY to PRIVATE_KEY in Hardhat config. * Rename celoAlfajores to alfajores in the config. * Add custom chain configuration for alfajores with updated API URLs. * Introduce a new deployment module for TestSelfVerificationRoot contract, including usage and verification instructions. --- .../tests/TestSelfVerificationRoot.sol | 6 +++- contracts/hardhat.config.ts | 22 +++++++----- .../modules/deployTestSelfVerificationRoot.ts | 34 +++++++++++++++++++ 3 files changed, 52 insertions(+), 10 deletions(-) create mode 100644 contracts/ignition/modules/deployTestSelfVerificationRoot.ts diff --git a/contracts/contracts/tests/TestSelfVerificationRoot.sol b/contracts/contracts/tests/TestSelfVerificationRoot.sol index 1c8cf713f..59cfb6bc8 100644 --- a/contracts/contracts/tests/TestSelfVerificationRoot.sol +++ b/contracts/contracts/tests/TestSelfVerificationRoot.sol @@ -83,7 +83,11 @@ contract TestSelfVerificationRoot is SelfVerificationRoot { _identityVerificationHubV2.setVerificationConfigV2(verificationConfig); } - function getConfigId(bytes32 destinationChainId, bytes32 userIdentifier, bytes memory userDefinedData) public view override returns (bytes32) { + function getConfigId( + bytes32 destinationChainId, + bytes32 userIdentifier, + bytes memory userDefinedData + ) public view override returns (bytes32) { return _identityVerificationHubV2.generateConfigId(verificationConfig); } diff --git a/contracts/hardhat.config.ts b/contracts/hardhat.config.ts index fd6c97d2c..d28342d2f 100644 --- a/contracts/hardhat.config.ts +++ b/contracts/hardhat.config.ts @@ -54,32 +54,36 @@ const config: HardhatUserConfig = { celo: { chainId: 42220, url: process.env.CELO_RPC_URL || "https://forno.celo.org", - accounts: [process.env.CELO_KEY as string], + accounts: [process.env.PRIVATE_KEY as string], }, - celoAlfajores: { + alfajores: { chainId: 44787, url: process.env.CELO_ALFAJORES_RPC_URL || "https://alfajores-forno.celo-testnet.org", accounts: [process.env.PRIVATE_KEY as string], }, - celoBaklava: { - chainId: 62320, - url: process.env.CELO_BAKLAVA_RPC_URL || "https://baklava-forno.celo-testnet.org", - accounts: [process.env.PRIVATE_KEY as string], - }, }, etherscan: { apiKey: { sepolia: process.env.ETHERSCAN_API_KEY as string, ethereum: process.env.ETHERSCAN_API_KEY as string, celo: process.env.CELOSCAN_API_KEY as string, + alfajores: process.env.CELOSCAN_API_KEY as string, }, customChains: [ { network: "celo", chainId: 42220, urls: { - apiURL: "https://api.celoscan.io/api", - browserURL: "https://celoscan.io", + apiURL: "https://api.etherscan.io/v2/api?chainid=42220", + browserURL: "https://celoscan.io/", + }, + }, + { + network: "alfajores", + chainId: 44787, + urls: { + apiURL: "https://api.etherscan.io/v2/api?chainid=44787", + browserURL: "https://alfajores.celoscan.io", }, }, ], diff --git a/contracts/ignition/modules/deployTestSelfVerificationRoot.ts b/contracts/ignition/modules/deployTestSelfVerificationRoot.ts new file mode 100644 index 000000000..61d0cf753 --- /dev/null +++ b/contracts/ignition/modules/deployTestSelfVerificationRoot.ts @@ -0,0 +1,34 @@ +import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; + +/** + * TestSelfVerificationRoot Deployment Module + * + * Deploys the TestSelfVerificationRoot contract for testing self-verification functionality. + * + * USAGE: + * npx hardhat ignition deploy ignition/modules/deployTestSelfVerificationRoot.ts --network alfajores --verify + * + * VERIFICATION: + * npx hardhat verify 0x3e2487a250e2A7b56c7ef5307Fb591Cc8C83623D 12345 --network alfajores + * + * PARAMETERS: + * - identityVerificationHubV2Address: Hub V2 contract address (default: 0x3e2487a250e2A7b56c7ef5307Fb591Cc8C83623D) + * - scopeValue: Proof scope value (default: 12345 - TEMPORARY VALUE, you have to calculate it yourself after getting the address and called setScopeValue) + */ + +export default buildModule("DeployTestSelfVerificationRoot", (m) => { + const identityVerificationHubV2Address = m.getParameter( + "identityVerificationHubV2Address", + "0x3e2487a250e2A7b56c7ef5307Fb591Cc8C83623D", + ); + const scopeValue = m.getParameter("scopeValue", 12345); + + const testSelfVerificationRoot = m.contract("TestSelfVerificationRoot", [ + identityVerificationHubV2Address, + scopeValue, + ]); + + return { + testSelfVerificationRoot, + }; +});