diff --git a/.env b/.env index c49fd72..37eb90c 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -CELO_PRIVATE_KEY=0xc518ebb1d856a629d691457769c71b31a98ac833c1222e9adde8e4bec70b190f \ No newline at end of file +CELO_PRIVATE_KEY=0x87904685d468b4f8920b30df9bcc073122aa4064ce6ee0ca48224134fa61aea0 \ No newline at end of file diff --git a/.env.local b/.env.local new file mode 100644 index 0000000..8e95ccf --- /dev/null +++ b/.env.local @@ -0,0 +1,18 @@ + +CELO_PRIVATE_KEY=0x87904685d468b4f8920b30df9bcc073122aa4064ce6ee0ca48224134fa61aea0 + +# Celo Mainnet Configuration +CELO_MAINNET_RPC_URL=https://forno.celo.org + +# Contract Addresses (Celo Mainnet) +ASSET_ADDRESS=0x765DE816845861e75A25fCA122bb6898B8B1282a +ATOKEN_ADDRESS=0xBba98352628B0B0c4b40583F593fFCb630935a45 +AAVE_PROVIDER_ADDRESS=0x9F7Cf9417D5251C59fE94fB9147feEe1aAd9Cea5 + +# Deployment Configuration +MAX_USER_DEPOSIT=1000 +MAX_TOTAL_DEPOSIT=10000 +ASSET_DECIMALS=18 + +# Optional: Identity verification (set to zero address to skip) +# VERIFIER_ADDRESS=0x0000000000000000000000000000000000000000 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 0b1a1bc..acf1b4a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,10 +3,12 @@ #dotenv .env +.env.local # Compilation output /dist + # pnpm deploy output /bundle @@ -21,3 +23,6 @@ # Hardhat coverage reports /coverage + +# Deployment output (addresses) +/deployment-addresses.json diff --git a/DEPLOYMENT.MD b/DEPLOYMENT.MD deleted file mode 100644 index ee36eeb..0000000 --- a/DEPLOYMENT.MD +++ /dev/null @@ -1,4 +0,0 @@ - VERIFIER_ADDRESS=0x5165370c71aacd3276cb18178812a4cc6541840c - STRATEGY_ADDRESS=0x5a8433c77871530840d769c2d3aee39196c1214f - VAULT_IMPL_ADDRESS=0xbf277f1e43d825a481fe807ab145f812a34233e6 - VAULT_PROXY_ADDRESS=0x00255f3452266d79d829662ff81d9f55f7a2eab9 \ No newline at end of file diff --git a/backend/BACKEND_TESTING_QUICK_REFERENCE.md b/backend/BACKEND_TESTING_QUICK_REFERENCE.md deleted file mode 100644 index 9bdae5c..0000000 --- a/backend/BACKEND_TESTING_QUICK_REFERENCE.md +++ /dev/null @@ -1,160 +0,0 @@ -# Backend Testing - Quick Reference - -Your backend is **production-ready** to test! Here's how to validate it works **without frontend**: - ---- - -## šŸš€ Fastest Way: cURL (2 minutes) - -```bash -# Terminal 1: Start your backend -npm run dev - -# Terminal 2: Test verification endpoint -curl -X POST http://localhost:3000/api/verify \ - -H "Content-Type: application/json" \ - -d '{ - "attestationId": 1, - "proof": {"pi_a":[],"pi_b":[],"pi_c":[]}, - "publicSignals": ["hash1","hash2"], - "userContextData": "0x1234567890123456789012345678901234567890" - }' - -# Terminal 2: Test check endpoint -curl -X POST http://localhost:3000/api/check-verification \ - -H "Content-Type: application/json" \ - -d '{"userId":"0x1234567890123456789012345678901234567890"}' -``` - -**You should see:** -- `POST /api/verify` → `{"status":"success","result":true}` or error message -- `POST /api/check-verification` → `{"verified":true,"userId":"0x..."}` - ---- - -## šŸ“¦ Three Testing Tools Provided - -| Tool | Best For | Command | -|------|----------|---------| -| **cURL** | Quick manual testing | `curl -X POST ...` | -| **Bash Script** | Automated testing | `./backend/test-backend.sh` | -| **Node Script** | Detailed testing | `node --loader ts-node/esm backend/test-backend.ts` | -| **Postman** | Visual testing | Import JSON collection | - ---- - -## šŸ“ Files Created - -1. **[TESTING.md](./TESTING.md)** - Complete testing guide with all details -2. **[test-backend.sh](./test-backend.sh)** - Automated bash testing script -3. **[test-backend.ts](./test-backend.ts)** - Node.js testing utility -4. **[Self-Protocol-Backend-Tests.postman_collection.json](./Self-Protocol-Backend-Tests.postman_collection.json)** - Postman collection -5. **[BACKEND_TESTING_QUICK_REFERENCE.md](./BACKEND_TESTING_QUICK_REFERENCE.md)** - This file - ---- - -## āœ… Validation Checklist - -Run these commands and verify responses: - -### āœ“ Can API be reached? -```bash -curl http://localhost:3000/api/verify -X POST -``` -Should NOT say "Connection refused" - -### āœ“ Does /api/verify accept proofs? -```bash -curl -X POST http://localhost:3000/api/verify \ - -H "Content-Type: application/json" \ - -d '{"attestationId":1,"proof":{},"publicSignals":[],"userContextData":"0xabc"}' -``` -Should return `{"status":"...","result":...}` - -### āœ“ Does /api/check-verification check users? -```bash -curl -X POST http://localhost:3000/api/check-verification \ - -H "Content-Type: application/json" \ - -d '{"userId":"0xabc"}' -``` -Should return `{"verified":true|false,"userId":"0xabc"}` - ---- - -## šŸŽÆ What's Tested - -| Component | Status | Note | -|-----------|--------|------| -| Backend endpoints exist | āœ… | `/api/verify` and `/api/check-verification` | -| Accept POST requests | āœ… | Correct HTTP method and headers | -| Process proof data | āœ… | Stores by userIdentifier | -| Return verification status | āœ… | Returns verified true/false | -| Nullifier included | āœ… | For sybil resistance | -| Multiple users supported | āœ… | Each user stored independently | - ---- - -## šŸ“‹ What Happens During Tests - -1. **Setup**: Start your backend server -2. **Verify Test**: Simulates Self relayers sending proof → Backend stores it -3. **Check Test**: Simulates miniapp checking user → Backend returns status -4. **Multi-user Test**: Tests that multiple users can be verified independently - ---- - -## šŸ”— Flow Reference - -``` -User Flow: - Frontend calls SelfAppBuilder deeplink - ↓ - Opens Self app → User scans passport - ↓ - Self relayers POST /api/verify with proof - ↓ - Backend stores verification ← [TEST THIS] - ↓ - Self app redirects to deeplinkCallback - ↓ - Frontend calls POST /api/check-verification ← [TEST THIS] - ↓ - Backend returns verified=true + nullifier - ↓ - Frontend stores on-chain (optional) -``` - ---- - -## 🚨 Common Issues & Fixes - -| Issue | Cause | Fix | -|-------|-------|-----| -| "Connection refused" | Backend not running | `npm run dev` | -| "404 Not Found" | Wrong endpoint path | Check route definitions in pages/api/ | -| "Proof validation failed" | Using dummy data (expected!) | Will work with real proofs from Self app | -| Empty `userId` in response | Endpoint not called | Ensure correct JSON body format | - ---- - -## šŸ“ž Ready for Frontend? - -Once you confirm all tests pass, tell your frontend team: - -**They need to implement:** -1. `SelfAppBuilder` with deeplink (no QR code) -2. `window.open(getUniversalLink(selfApp))` to open Self app -3. After user returns, call `POST /api/check-verification` -4. If `verified=true`, optionally store on-chain - -**Your backend endpoints are ready:** -- āœ… `POST /api/verify` - accepts proofs from Self Protocol -- āœ… `POST /api/check-verification` - returns verification status - ---- - -## šŸ“š See Also - -- [SELF_INTEGRATION.md](./SELF_INTEGRATION.md) - Backend setup & flow details -- [TESTING.md](./TESTING.md) - Comprehensive testing guide -- [../contracts/SelfProtocolVerifier.sol](../contracts/SelfProtocolVerifier.sol) - On-chain verification contract diff --git a/backend/check-verification.ts b/backend/check-verification.ts deleted file mode 100644 index 5f62f25..0000000 --- a/backend/check-verification.ts +++ /dev/null @@ -1,36 +0,0 @@ -// pages/api/check-verification.ts (Next.js API route) -// Called by miniapp when user returns from Self app (deeplinkCallback redirect). -// Checks if the user was verified by Self relayers via /api/verify. - -type ApiRequest = { method?: string; body?: Record }; -type ApiResponse = { status: (code: number) => ApiResponse; json: (body: unknown) => unknown }; -import { getVerification } from './lib/verification-store.js'; - -export default async function handler(req: ApiRequest, res: ApiResponse) { - if (req.method !== 'POST') { - return res.status(405).json({ error: 'Method not allowed' }); - } - - const { userId } = req.body ?? {}; - - if (!userId || typeof userId !== 'string') { - return res.status(400).json({ error: 'userId is required' }); - } - - const record = getVerification(userId); - - if (!record) { - return res.status(200).json({ - verified: false, - userId, - }); - } - - return res.status(200).json({ - verified: true, - userId, - verifiedAt: record.verifiedAt, - nullifier: record.nullifier, - sessionId: req.body?.sessionId, // Echo back if frontend passed it - }); -} diff --git a/backend/lib/verification-store.ts b/backend/lib/verification-store.ts deleted file mode 100644 index cd1e884..0000000 --- a/backend/lib/verification-store.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Verification storage for Self Protocol deeplink flow. - * Replace with your database (Postgres, Redis, etc.) in production. - * - * Flow: Self relayers call /api/verify → we store by userIdentifier. - * Miniapp calls /api/check-verification after user returns from Self app. - */ -export interface VerificationRecord { - userIdentifier: string; - nullifier: string; - verifiedAt: number; - attestationId: number; - nationality?: string; -} - -const verifiedUsers = new Map(); - -export function storeVerification(record: VerificationRecord): void { - verifiedUsers.set(record.userIdentifier.toLowerCase(), record); -} - -export function getVerification(userIdentifier: string): VerificationRecord | undefined { - return verifiedUsers.get(userIdentifier.toLowerCase()); -} - -export function isVerified(userIdentifier: string): boolean { - return verifiedUsers.has(userIdentifier.toLowerCase()); -} diff --git a/backend/test-backend.ts b/backend/test-backend.ts deleted file mode 100644 index 6678f87..0000000 --- a/backend/test-backend.ts +++ /dev/null @@ -1,225 +0,0 @@ -/** - * Backend Testing Utility for Self Protocol Integration - * - * This script tests the backend without needing the frontend. - * It simulates what the Self relayers would send and what the miniapp would call. - * - * Prerequisites: - * 1. Backend API running (Next.js dev server on http://localhost:3000) - * 2. Environment variables set in .env (.env.local for Next.js) - */ - -import fetch from 'node-fetch'; - -const API_BASE_URL = process.env.API_URL || 'http://localhost:3000'; - -// Mock data similar to what Self relayers would send -const MOCK_PROOF_DATA = { - attestationId: 1, // Passport = 1, EU ID = 2, Aadhaar = 3 - proof: { - pi_a: [ - '1234567890123456789012345678901234567890123456789012345678901234', - '1234567890123456789012345678901234567890123456789012345678901234', - ], - pi_b: [ - [ - '1234567890123456789012345678901234567890123456789012345678901234', - '1234567890123456789012345678901234567890123456789012345678901234', - ], - [ - '1234567890123456789012345678901234567890123456789012345678901234', - '1234567890123456789012345678901234567890123456789012345678901234', - ], - ], - pi_c: [ - '1234567890123456789012345678901234567890123456789012345678901234', - '1234567890123456789012345678901234567890123456789012345678901234', - ], - }, - publicSignals: [ - '12345678901234567890123456789012', // nullifier - '98765432109876543210987654321098', // userIdentifier - ], - userContextData: '0x1234567890123456789012345678901234567890', // wallet address -}; - -const TEST_USER_ADDRESS = '0x1234567890123456789012345678901234567890'; - -/** - * Step 1: Simulate Self relayers calling POST /api/verify - */ -async function testVerifyEndpoint(): Promise { - console.log('\nšŸ“ Step 1: Testing POST /api/verify'); - console.log(' Simulating Self relayers sending proof data...\n'); - - try { - const response = await fetch(`${API_BASE_URL}/api/verify`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(MOCK_PROOF_DATA), - }); - - const data = await response.json() as { status: string; result: boolean; reason?: string }; - - console.log(` Status: ${response.status}`); - console.log(` Response:`, JSON.stringify(data, null, 2)); - - if (data.status === 'success' && data.result === true) { - console.log(' āœ… Verification stored successfully!'); - return true; - } else { - console.log(` āš ļø Verification failed: ${data.reason}`); - return false; - } - } catch (error) { - console.error(` āŒ Error calling /api/verify:`, error); - return false; - } -} - -/** - * Step 2: Simulate miniapp calling POST /api/check-verification after user returns - */ -async function testCheckVerificationEndpoint(userId: string): Promise { - console.log('\nšŸ” Step 2: Testing POST /api/check-verification'); - console.log(` Checking if user ${userId} is verified...\n`); - - try { - const response = await fetch(`${API_BASE_URL}/api/check-verification`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ userId }), - }); - - const data = await response.json() as { - verified: boolean; - userId: string; - verifiedAt?: number; - nullifier?: string; - }; - - console.log(` Status: ${response.status}`); - console.log(` Response:`, JSON.stringify(data, null, 2)); - - if (data.verified) { - console.log(` āœ… User is verified!`); - console.log(` Verified at: ${new Date(data.verifiedAt!).toISOString()}`); - console.log(` Nullifier: ${data.nullifier}`); - return true; - } else { - console.log(` āš ļø User is not verified yet`); - return false; - } - } catch (error) { - console.error(` āŒ Error calling /api/check-verification:`, error); - return false; - } -} - -/** - * Step 3: Test with different user addresses - */ -async function testMultipleUsers(): Promise { - console.log('\nšŸ‘„ Step 3: Testing with multiple users\n'); - - const users = [ - { address: '0xaabbccddaabbccddaabbccddaabbccddaabbccdd', name: 'Alice' }, - { address: '0x1122334411223344112233441122334411223344', name: 'Bob' }, - ]; - - for (const user of users) { - console.log(`\n Testing ${user.name} (${user.address})...`); - - // Create new proof data with this user - const proofData = { - ...MOCK_PROOF_DATA, - userContextData: user.address, - publicSignals: [ - '99999999999999999999999999999999', // different nullifier - user.address.substring(2).padEnd(32, '0'), // user identifier - ], - }; - - // Call verify - const response = await fetch(`${API_BASE_URL}/api/verify`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(proofData), - }); - - const result = await response.json() as { status: string; result: boolean }; - - if (result.status === 'success') { - console.log(` āœ“ ${user.name} verification stored`); - - // Check verification - const checkResponse = await fetch(`${API_BASE_URL}/api/check-verification`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ userId: user.address }), - }); - - const checkResult = await checkResponse.json() as { verified: boolean }; - console.log(` āœ“ ${user.name} check: verified=${checkResult.verified}`); - } - } -} - -/** - * Main test runner - */ -async function runTests(): Promise { - console.log('šŸš€ Self Protocol Backend Integration Tests\n'); - console.log(`API URL: ${API_BASE_URL}`); - console.log('=' .repeat(60)); - - try { - // Test 1: Verify endpoint - const verifySuccess = await testVerifyEndpoint(); - - if (!verifySuccess) { - console.log('\nāŒ Verification failed. Check your backend is running and /api/verify is accessible.'); - console.log('\nTroubleshooting:'); - console.log(' 1. Is your Next.js dev server running? (npm run dev)'); - console.log(' 2. Are your environment variables set in .env.local?'); - console.log(' 3. Check the backend API logs for detailed errors'); - process.exit(1); - } - - // Give it a moment to store - await new Promise(resolve => setTimeout(resolve, 500)); - - // Test 2: Check verification endpoint - const checkSuccess = await testCheckVerificationEndpoint(TEST_USER_ADDRESS); - - if (!checkSuccess) { - console.log('\nāŒ Check verification failed.'); - process.exit(1); - } - - // Test 3: Multiple users - await testMultipleUsers(); - - console.log('\n' + '='.repeat(60)); - console.log('āœ… All tests passed!\n'); - console.log('šŸ“‹ Summary:'); - console.log(' āœ“ POST /api/verify - Accepts and stores proofs from Self relayers'); - console.log(' āœ“ POST /api/check-verification - Returns verification status to miniapp'); - console.log(' āœ“ Multiple users can be verified independently'); - console.log('\nšŸŽÆ Next Steps:'); - console.log(' 1. Frontend team implements SelfAppBuilder with deeplink'); - console.log(' 2. Frontend opens Self app for user verification'); - console.log(' 3. After user returns, frontend calls /api/check-verification'); - console.log(' 4. If verified, store on-chain via SelfProtocolVerifier contract\n'); - } catch (error) { - console.error('āŒ Test suite failed:', error); - process.exit(1); - } -} - -// Run if executed directly -if (import.meta.url === `file://${process.argv[1]}`) { - runTests().catch(console.error); -} - -export { testVerifyEndpoint, testCheckVerificationEndpoint, testMultipleUsers }; diff --git a/backend/verify.ts b/backend/verify.ts deleted file mode 100644 index 2414d26..0000000 --- a/backend/verify.ts +++ /dev/null @@ -1,105 +0,0 @@ -// pages/api/verify.ts (Next.js API route) -// Called by Self Protocol relayers when user completes verification in Self app. -// For deeplink flow: User opens Self app → verifies → relayers POST here → Self app redirects user back to miniapp. - -// Use Next.js types if available; otherwise define minimal compatible types -type ApiRequest = { method?: string; body?: Record }; -type ApiResponse = { status: (code: number) => ApiResponse; json: (body: unknown) => unknown }; -import { - SelfBackendVerifier, - DefaultConfigStore, - type AttestationId, -} from '@selfxyz/core'; - -// Allow passport (1), EU ID (2), Aadhaar (3) -const allowedIds = new Map([ - [1, true], - [2, true], - [3, true], -]); -import { storeVerification } from './lib/verification-store.js'; - -const SELF_SCOPE = process.env.SELF_SCOPE || 'liquifi-miniapp-v1'; -const SELF_ENDPOINT = process.env.SELF_ENDPOINT || 'https://your-domain.com/api/verify'; -const MOCK_PASSPORT = process.env.SELF_MOCK_PASSPORT === 'true'; // true = Celo Sepolia testnet -const USER_ID_TYPE = (process.env.SELF_USER_ID_TYPE || 'hex') as 'hex' | 'uuid'; - -// Verification config - MUST match frontend SelfAppBuilder disclosures -const excludedList = process.env.SELF_EXCLUDED_COUNTRIES - ? process.env.SELF_EXCLUDED_COUNTRIES.split(',').map((c) => c.trim()) - : ['IRN', 'PRK', 'RUS', 'SYR']; - -const configStore = new DefaultConfigStore({ - minimumAge: Number(process.env.SELF_MIN_AGE || 18), - // @ts-expect-error - Country3LetterCode[] expects literal types; runtime accepts valid ISO codes - excludedCountries: excludedList, - ofac: process.env.SELF_OFAC !== 'false', -}); - -const verifier = new SelfBackendVerifier( - SELF_SCOPE, - SELF_ENDPOINT, - MOCK_PASSPORT, - allowedIds, - configStore, - USER_ID_TYPE -); - -export default async function handler(req: ApiRequest, res: ApiResponse) { - if (req.method !== 'POST') { - return res.status(405).json({ status: 'error', result: false, reason: 'Method not allowed' }); - } - - try { - const body = req.body ?? {}; - const { attestationId, proof, publicSignals, userContextData } = body as { - attestationId?: number; - proof?: unknown; - publicSignals?: unknown; - userContextData?: string; - }; - - if (!proof || !publicSignals || !attestationId || !userContextData) { - return res.status(200).json({ - status: 'error', - result: false, - reason: 'Proof, publicSignals, attestationId and userContextData are required', - }); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const result = await verifier.verify(attestationId as AttestationId, proof as any, publicSignals as any, userContextData); - - const { isValid, isMinimumAgeValid, isOfacValid } = result.isValidDetails; - - if (!isValid || !isMinimumAgeValid || isOfacValid) { - let reason = 'Verification failed'; - if (!isMinimumAgeValid) reason = 'Minimum age verification failed'; - if (isOfacValid) reason = 'OFAC verification failed'; - return res.status(200).json({ status: 'error', result: false, reason }); - } - - // Store verification for check-verification endpoint - // userIdentifier is wallet address (hex) or uuid depending on frontend config - storeVerification({ - userIdentifier: result.userData.userIdentifier, - nullifier: result.discloseOutput.nullifier, - verifiedAt: Date.now(), - attestationId: result.attestationId, - nationality: result.discloseOutput.nationality || undefined, - }); - - return res.status(200).json({ - status: 'success', - result: true, - }); - } catch (error: unknown) { - console.error('Verification error:', error); - const reason = error instanceof Error ? error.message : 'Unknown error'; - return res.status(200).json({ - status: 'error', - result: false, - reason, - }); - } -} diff --git a/contracts/AaveV3Strategy.sol b/contracts/AaveV3Strategy.sol index fb65f71..ce6ccce 100644 --- a/contracts/AaveV3Strategy.sol +++ b/contracts/AaveV3Strategy.sol @@ -267,4 +267,4 @@ contract AaveV3Strategy is Ownable { asset.safeTransfer(owner(), balance); } } -} +} \ No newline at end of file diff --git a/hardhat.config.ts b/hardhat.config.ts index 46322de..92cad92 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -76,7 +76,9 @@ export default defineConfig({ }, ], }, - sourcify: { - enabled: true, + verify: { + sourcify: { + enabled: true, + }, }, }); diff --git a/package.json b/package.json index 2840632..9f7f18d 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "test": "hardhat test", - "deploy": "hardhat run scripts/deploy-vault.ts --network celoMainnet", + "deploy": "hardhat compile --build-profile production && hardhat run scripts/deploy-vault.ts --network celoMainnet", "deploy:verifier": "hardhat run scripts/deploy-verifier.ts --network celoMainnet", "verify": "hardhat run scripts/verify-contracts.ts --network celoMainnet", "query-aave": "hardhat run scripts/query-aave-addresses.ts" diff --git a/scripts/deploy-vault.ts b/scripts/deploy-vault.ts index 052184d..908fa79 100644 --- a/scripts/deploy-vault.ts +++ b/scripts/deploy-vault.ts @@ -1,5 +1,7 @@ import "dotenv/config"; import process from "node:process"; +import { writeFileSync } from "node:fs"; +import { join } from "node:path"; import { network } from "hardhat"; import { encodeFunctionData, parseUnits, createWalletClient, http } from "viem"; @@ -53,15 +55,15 @@ function getAmountEnv(name: string, decimals: number, fallback: string): bigint async function loadConfig(chainId: bigint): Promise { const assetDecimals = Number(process.env.ASSET_DECIMALS ?? "18"); - + // Get defaults based on chain // Convert to number for comparison to handle both bigint and number const chainIdNum = Number(chainId); const defaults = chainIdNum === 42220 - ? CELO_MAINNET_DEFAULTS + ? CELO_MAINNET_DEFAULTS : chainIdNum === 44787 - ? CELO_ALFAJORES_DEFAULTS - : null; + ? CELO_ALFAJORES_DEFAULTS + : null; if (!defaults) { console.warn(`āš ļø Unknown chain (chainId: ${chainIdNum}), using env vars only (no defaults)`); @@ -80,9 +82,9 @@ async function loadConfig(chainId: bigint): Promise { // Determine chainId based on network name (before connecting) // This avoids RPC calls that might timeout -const networkName = process.argv.find(arg => arg.includes("--network"))?.split("=")[1] || - process.argv[process.argv.indexOf("--network") + 1] || - "celoMainnet"; +const networkName = process.argv.find(arg => arg.includes("--network"))?.split("=")[1] || + process.argv[process.argv.indexOf("--network") + 1] || + "celoMainnet"; let chainId: bigint; if (networkName === "celoMainnet" || networkName.includes("mainnet")) { @@ -129,31 +131,39 @@ console.log(""); // Get contract artifacts from Hardhat const hre = await import("hardhat"); + const strategyArtifact = await hre.artifacts.readArtifact("AaveV3Strategy"); const vaultArtifact = await hre.artifacts.readArtifact("AttestifyVault"); -const proxyArtifact = await hre.artifacts.readArtifact("TestProxy"); + + +console.log("Deploying AttestifyVault..."); +const vaultHash = await deployer.deployContract({ + abi: vaultArtifact.abi, + bytecode: vaultArtifact.bytecode as `0x${string}`, + // No constructor args for upgradeable contract + gas: 8000000n, +}); +const vaultReceipt = await publicClient.waitForTransactionReceipt({ hash: vaultHash }); +const vaultAddress = vaultReceipt.contractAddress!; +console.log("Vault deployed at:", vaultAddress); + +// Deploy AaveV3Strategy first, since initialize needs its address console.log("Deploying AaveV3Strategy..."); const strategyHash = await deployer.deployContract({ abi: strategyArtifact.abi, bytecode: strategyArtifact.bytecode as `0x${string}`, - args: [params.asset, params.aToken, params.addressesProvider], + args: [params.asset, params.aToken, params.addressesProvider, vaultAddress], + gas: 8000000n, }); const strategyReceipt = await publicClient.waitForTransactionReceipt({ hash: strategyHash }); const strategyAddress = strategyReceipt.contractAddress!; console.log("Strategy deployed at:", strategyAddress); -console.log("Deploying AttestifyVault implementation..."); -const vaultHash = await deployer.deployContract({ - abi: vaultArtifact.abi, - bytecode: vaultArtifact.bytecode as `0x${string}`, -}); -const vaultReceipt = await publicClient.waitForTransactionReceipt({ hash: vaultHash }); -const vaultImplementationAddress = vaultReceipt.contractAddress!; -console.log("Vault implementation deployed at:", vaultImplementationAddress); - -// Encode init data using artifact ABI -const initData = encodeFunctionData({ +// Call initialize on the vault +console.log("Initializing AttestifyVault..."); +await deployer.writeContract({ + address: vaultAddress, abi: vaultArtifact.abi, functionName: "initialize", args: [ @@ -162,29 +172,10 @@ const initData = encodeFunctionData({ params.maxUserDeposit, params.maxTotalDeposit, ], + gas: 2000000n, }); +console.log("Vault initialized."); -console.log("Deploying ERC1967 proxy..."); -const proxyHash = await deployer.deployContract({ - abi: proxyArtifact.abi, - bytecode: proxyArtifact.bytecode as `0x${string}`, - args: [vaultImplementationAddress, initData], -}); -const proxyReceipt = await publicClient.waitForTransactionReceipt({ hash: proxyHash }); -const vaultAddress = proxyReceipt.contractAddress!; - -console.log("Vault proxy deployed at:", vaultAddress); - -// Wait for proxy deployment to be confirmed before next transaction -await publicClient.waitForTransactionReceipt({ hash: proxyHash }); - -console.log("Linking strategy to vault..."); -await deployer.writeContract({ - address: strategyAddress, - abi: strategyArtifact.abi, - functionName: "setVault", - args: [vaultAddress], -}); if (params.rebalancer && params.rebalancer !== account.address) { console.log("Setting custom rebalancer:", params.rebalancer); @@ -193,16 +184,32 @@ if (params.rebalancer && params.rebalancer !== account.address) { abi: vaultArtifact.abi, functionName: "setRebalancer", args: [params.rebalancer], + gas: 500000n, }); } +// Save deployment addresses for verification +const deploymentPath = join(process.cwd(), "deployment-addresses.json"); +const deployment = { + network: networkName, + chainId: chainId.toString(), + vault: vaultAddress, + strategy: strategyAddress, + strategyConstructorArgs: [ + params.asset, + params.aToken, + params.addressesProvider, + vaultAddress, + ], +}; +writeFileSync(deploymentPath, JSON.stringify(deployment, null, 2)); +console.log("\nDeployment saved to:", deploymentPath); + console.log("\nDeployment complete:"); +console.log("- Vault:", vaultAddress); console.log("- Strategy:", strategyAddress); -console.log("- Vault Implementation:", vaultImplementationAddress); -console.log("- Vault Proxy:", vaultAddress); console.log("\nšŸ“ Next steps:"); -console.log("1. Verify contracts: npx hardhat run scripts/verify-contracts.ts --network celoMainnet"); +console.log("1. Verify on Sourcify: npx hardhat run scripts/verify-contracts.ts --network celoMainnet"); console.log("2. Fund the vault with reserves if needed."); -console.log("3. Configure rebalancer/treasury roles and deposit limits as required."); - +console.log("3. Configure rebalancer/treasury roles and deposit limits as required."); \ No newline at end of file diff --git a/scripts/deploy-verifier.ts b/scripts/deploy-verifier.ts index 85f5b76..0d5390c 100644 --- a/scripts/deploy-verifier.ts +++ b/scripts/deploy-verifier.ts @@ -7,129 +7,4 @@ import { encodeAbiParameters, encodeFunctionData } from "viem"; import { network } from "hardhat"; import type { Address } from "viem"; -// Celo Mainnet addresses (from query) -const CELO_MAINNET_ADDRESSES = { - selfHubV2: "0xe57F4773bd9c9d8b6Cd70431117d353298B9f5BF" as Address, - cUSD: "0x765DE816845861e75A25fCA122bb6898B8B1282a" as Address, -} as const; - -// Celo Alfajores Testnet addresses -const CELO_ALFAJORES_ADDRESSES = { - selfHubV2: "0x18E05eAC6F31d03fb188FDc8e72FF354aB24EaB6" as Address, - cUSD: "0x874069Fa1Eb16D44d622F2e0Ca25eeA172369bC1" as Address, -} as const; - -function getAddresses(chainId: bigint | number) { - const id = typeof chainId === "bigint" ? chainId : BigInt(chainId); - if (id === 42220n) { - return CELO_MAINNET_ADDRESSES; - } else if (id === 44787n) { - return CELO_ALFAJORES_ADDRESSES; - } - throw new Error(`Unsupported chain ID: ${chainId}`); -} - -async function deployVerifier() { - const { viem } = await network.connect(); - const publicClient = await viem.getPublicClient(); - const [deployer] = await viem.getWalletClients(); - const chainId = await publicClient.getChainId(); - - console.log("Deploying SelfProtocolVerifier..."); - console.log("Deployer:", deployer.account.address); - console.log("Chain ID:", chainId.toString()); - - const addresses = getAddresses(chainId); - const hubV2 = process.env.SELF_HUB_V2 as Address | undefined || addresses.selfHubV2; - const scopeSeed = process.env.SELF_SCOPE_SEED || "attestify-v1"; - - // Verification config from env or use defaults - const minimumAge = Number(process.env.SELF_MIN_AGE || "18"); - const ofacEnabled = process.env.SELF_OFAC_ENABLED === "true"; - - // Parse forbidden countries from env (comma-separated) or use empty array - const forbiddenCountriesStr = process.env.SELF_FORBIDDEN_COUNTRIES || ""; - const forbiddenCountries = forbiddenCountriesStr - ? forbiddenCountriesStr.split(",").map((c) => c.trim()).filter(Boolean) - : []; - - console.log("\nConfiguration:"); - console.log("- Self Hub V2:", hubV2); - console.log("- Scope Seed:", scopeSeed); - console.log("- Minimum Age:", minimumAge); - console.log("- OFAC Enabled:", ofacEnabled); - console.log("- Forbidden Countries:", forbiddenCountries.length > 0 ? forbiddenCountries.join(", ") : "None"); - - // Build the verification config struct - // Note: SelfUtils.UnformattedVerificationConfigV2 expects: - // - olderThan: uint256 - // - forbiddenCountries: string[] - // - ofacEnabled: bool - const config = { - olderThan: BigInt(minimumAge), - forbiddenCountries: forbiddenCountries, - ofacEnabled: ofacEnabled, - }; - - console.log("\nDeploying SelfProtocolVerifier contract..."); - console.log("Config:", JSON.stringify(config, (_, v) => typeof v === 'bigint' ? v.toString() : v)); - - // Format config as explicit tuple for ABI encoding - const configTuple: [bigint, string[], boolean] = [ - config.olderThan, - config.forbiddenCountries, - config.ofacEnabled, - ]; - - // Read artifact directly - const artifactPath = join(process.cwd(), "artifacts", "contracts", "SelfProtocolVerifier.sol", "SelfProtocolVerifier.json"); - const artifact = JSON.parse(readFileSync(artifactPath, "utf-8")); - - // Encode constructor parameters - const constructorAbi = artifact.abi.find((item: any) => item.type === "constructor"); - if (!constructorAbi) { - throw new Error("Constructor not found in ABI"); - } - - const encodedArgs = encodeAbiParameters( - constructorAbi.inputs, - [hubV2, scopeSeed, configTuple] - ); - - // Deploy contract - const hash = await deployer.sendTransaction({ - data: (artifact.bytecode as string) + encodedArgs.slice(2), // Remove 0x prefix from encoded args - }); - - console.log("Transaction hash:", hash); - console.log("Waiting for deployment confirmation..."); - - // Wait for deployment - const receipt = await publicClient.waitForTransactionReceipt({ hash }); - - // Get deployed address from receipt - const verifierAddress = receipt.contractAddress; - - if (!verifierAddress) { - throw new Error("Contract deployment failed - no contract address in receipt"); - } - - console.log("Contract deployed at:", verifierAddress); - - const verifier = await viem.getContractAt("SelfProtocolVerifier", verifierAddress); - - console.log("\nāœ… SelfProtocolVerifier deployed!"); - console.log("Address:", verifier.address); - - console.log("\n=== For Vault Deployment ==="); - console.log("Set in your .env file:"); - console.log(`VERIFIER_ADDRESS=${verifier.address}`); - - return verifier.address; -} - -deployVerifier().catch((error) => { - console.error("Error deploying verifier:", error); - process.exit(1); -}); - +// Self protocol integration removed. Add your new verifier deployment logic here if needed. \ No newline at end of file diff --git a/scripts/test-deposit.js b/scripts/test-deposit.js index 676f59d..4a98e28 100644 --- a/scripts/test-deposit.js +++ b/scripts/test-deposit.js @@ -1,56 +1,50 @@ const { ethers } = require("hardhat"); +/** + * Check vault state before depositing. + * Current AttestifyVault has no on-chain verifier — anyone can deposit (no human verification gate). + */ async function main() { - const [signer] = await ethers.getSigners(); - - const vaultAddress = "0xbf277f1e43d825a481fe807ab145f812a34233e6"; - const cusdAddress = "0x765DE816845861e75A25fCA122bb6898B8B1282a"; - - const vault = await ethers.getContractAt("AttestifyVault", vaultAddress); - const cusd = await ethers.getContractAt("IERC20", cusdAddress); - - console.log("Checking vault state..."); - - // Check if initialized - const owner = await vault.owner(); - console.log("Owner:", owner); - console.log("Initialized:", owner !== ethers.constants.AddressZero); - - // Check paused - const paused = await vault.paused(); - console.log("Paused:", paused); - - // Check balance - const balance = await cusd.balanceOf(signer.address); - console.log("Your cUSD balance:", ethers.utils.formatEther(balance)); - - // Check allowance - const allowance = await cusd.allowance(signer.address, vaultAddress); - console.log("Vault allowance:", ethers.utils.formatEther(allowance)); - - // Check limits - const maxUser = await vault.maxUserDeposit(); - const maxTotal = await vault.maxTotalDeposit(); - const totalDeposits = await vault.totalDeposits(); - const userDeposit = await vault.getUserDeposit(signer.address); - - console.log("Max per user:", ethers.utils.formatEther(maxUser)); - console.log("Max total:", ethers.utils.formatEther(maxTotal)); - console.log("Current total:", ethers.utils.formatEther(totalDeposits)); - console.log("Your deposits:", ethers.utils.formatEther(userDeposit)); - - // Check verification - const verifierAddress = await vault.verifier(); - const verifier = await ethers.getContractAt("SelfProtocolVerifier", verifierAddress); - const isVerified = await verifier.isVerified(signer.address); - console.log("Self Protocol verified:", isVerified); - - console.log("\n=== Ready to deposit? ==="); - console.log("āœ… Initialized:", owner !== ethers.constants.AddressZero); - console.log("āœ… Not paused:", !paused); - console.log("āœ… Has cUSD:", balance.gt(0)); - console.log("āœ… Approved:", allowance.gt(0)); - console.log("āœ… Verified:", isVerified); + const [signer] = await ethers.getSigners(); + + // Update to your vault address (or use deployment-addresses.json) + const vaultAddress = process.env.VAULT_ADDRESS || "0x154e0a62d5d25bb405a6395ef8da0fdf33c6284a"; + const cusdAddress = "0x765DE816845861e75A25fCA122bb6898B8B1282a"; + + const vault = await ethers.getContractAt("AttestifyVault", vaultAddress); + const cusd = await ethers.getContractAt("IERC20", cusdAddress); + + console.log("Checking vault state..."); + + const owner = await vault.owner(); + console.log("Owner:", owner); + console.log("Initialized:", owner !== ethers.constants.AddressZero); + + const paused = await vault.paused(); + console.log("Paused:", paused); + + const balance = await cusd.balanceOf(signer.address); + console.log("Your cUSD balance:", ethers.utils.formatEther(balance)); + + const allowance = await cusd.allowance(signer.address, vaultAddress); + console.log("Vault allowance:", ethers.utils.formatEther(allowance)); + + const maxUser = await vault.maxUserDeposit(); + const maxTotal = await vault.maxTotalDeposit(); + const totalAssets = await vault.totalAssets(); + const userBalance = await vault.balanceOf(signer.address); + + console.log("Max per user:", ethers.utils.formatEther(maxUser)); + console.log("Max total:", ethers.utils.formatEther(maxTotal)); + console.log("Total assets (TVL):", ethers.utils.formatEther(totalAssets)); + console.log("Your vault balance:", ethers.utils.formatEther(userBalance)); + + console.log("\n=== Ready to deposit? ==="); + console.log("āœ… Initialized:", owner !== ethers.constants.AddressZero); + console.log("āœ… Not paused:", !paused); + console.log("āœ… Has cUSD:", balance.gt(0)); + console.log("āœ… Approved:", allowance.gt(0)); + console.log("(No on-chain human verification — vault does not gate deposits by verifier)"); } -main().catch(console.error); \ No newline at end of file +main().catch(console.error); diff --git a/scripts/verify-contracts.ts b/scripts/verify-contracts.ts index 4049c4e..e02c3ef 100644 --- a/scripts/verify-contracts.ts +++ b/scripts/verify-contracts.ts @@ -1,75 +1,111 @@ import "dotenv/config"; -import { network } from "hardhat"; +import process from "node:process"; +import { readFileSync, existsSync } from "node:fs"; +import { join } from "node:path"; -// Contract addresses from deployment -const CONTRACTS = { - strategy: "0x1ed36feb312b9d464d95fc1bab4b286ddc793341", - vaultImplementation: "0xbe70318eb8772d265642a2ab6fee32cd250ec844", - vaultProxy: "0x16a0ff8d36d9d660de8fd5257cff78adf11b8306", -}; - -// Constructor arguments for Strategy -const STRATEGY_ARGS = [ - "0x765DE816845861e75A25fCA122bb6898B8B1282a", // asset (cUSD) - "0xBba98352628B0B0c4b40583F593fFCb630935a45", // aToken (acUSD) - "0x9F7Cf9417D5251C59fE94fB9147feEe1aAd9Cea5", // addressesProvider -]; +import { verifyContract } from "@nomicfoundation/hardhat-verify/verify"; +/** + * Verify deployed contracts on Sourcify (Celo Mainnet). + * + * Addresses are read from: + * 1. deployment-addresses.json (created by deploy-vault.ts) + * 2. Or env vars: VAULT_ADDRESS, STRATEGY_ADDRESS, STRATEGY_CONSTRUCTOR_ARGS (JSON array) + * 3. Or CLI args: --vault 0x... --strategy 0x... + */ async function main() { - console.log("šŸ” Starting contract verification on Sourcify...\n"); - console.log("Network: Celo Mainnet (42220)\n"); + const chainId = 42220; + + // Resolve addresses + let vaultAddress: string; + let strategyAddress: string; + let strategyConstructorArgs: string[]; + + const deploymentPath = join(process.cwd(), "deployment-addresses.json"); + if (existsSync(deploymentPath)) { + const deployment = JSON.parse(readFileSync(deploymentPath, "utf-8")); + vaultAddress = deployment.vault; + strategyAddress = deployment.strategy; + strategyConstructorArgs = deployment.strategyConstructorArgs ?? []; + console.log("šŸ“‚ Using addresses from deployment-addresses.json\n"); + } else { + const vaultArg = process.argv.find((a) => a.startsWith("--vault="))?.split("=")[1]; + const strategyArg = process.argv.find((a) => a.startsWith("--strategy="))?.split("=")[1]; + vaultAddress = process.env.VAULT_ADDRESS ?? vaultArg ?? ""; + strategyAddress = process.env.STRATEGY_ADDRESS ?? strategyArg ?? ""; + + if (process.env.STRATEGY_CONSTRUCTOR_ARGS) { + strategyConstructorArgs = JSON.parse(process.env.STRATEGY_CONSTRUCTOR_ARGS); + } else if (!vaultAddress || !strategyAddress) { + throw new Error( + "No deployment-addresses.json found. Provide addresses via:\n" + + " - Run deploy-vault.ts first (creates deployment-addresses.json)\n" + + " - Env: VAULT_ADDRESS, STRATEGY_ADDRESS, STRATEGY_CONSTRUCTOR_ARGS\n" + + " - CLI: --vault=0x... --strategy=0x..." + ); + } else { + // Celo mainnet defaults for strategy constructor + strategyConstructorArgs = [ + "0x765DE816845861e75A25fCA122bb6898B8B1282a", // asset (cUSD) + "0xBba98352628B0B0c4b40583F593fFCb630935a45", // aToken (acUSD) + "0x9F7Cf9417D5251C59fE94fB9147feEe1aAd9Cea5", // addressesProvider + vaultAddress, // vault + ]; + } + } + + console.log("šŸ” Verifying contracts on Sourcify (Celo Mainnet - 42220)\n"); - // Import hardhat to get the run function const hre = await import("hardhat"); - // Verify Strategy + // Verify AaveV3Strategy console.log("1ļøāƒ£ Verifying AaveV3Strategy..."); try { - await hre.default.run("verify:verify", { - address: CONTRACTS.strategy, - constructorArguments: STRATEGY_ARGS, - contract: "contracts/AaveV3Strategy.sol:AaveV3Strategy", - }); - console.log("āœ… AaveV3Strategy verified successfully!\n"); - } catch (error: any) { - const errorMsg = error.message || String(error); - if (errorMsg.includes("Already Verified") || errorMsg.includes("already verified")) { + await verifyContract( + { + address: strategyAddress, + constructorArgs: strategyConstructorArgs, + contract: "contracts/AaveV3Strategy.sol:AaveV3Strategy", + provider: "sourcify", + }, + hre.default + ); + console.log("āœ… AaveV3Strategy verified!\n"); + } catch (error: unknown) { + const msg = error instanceof Error ? error.message : String(error); + if (msg.includes("Already Verified") || msg.includes("already verified") || msg.includes("already verified")) { console.log("āœ… AaveV3Strategy already verified!\n"); } else { - console.error("āŒ Error verifying AaveV3Strategy:"); - console.error(errorMsg); - console.log(""); + console.error("āŒ AaveV3Strategy verification failed:", msg, "\n"); } } - // Verify Vault Implementation - console.log("2ļøāƒ£ Verifying AttestifyVault implementation..."); + // Verify AttestifyVault (implementation, no constructor args) + console.log("2ļøāƒ£ Verifying AttestifyVault..."); try { - await hre.default.run("verify:verify", { - address: CONTRACTS.vaultImplementation, - constructorArguments: [], // Implementation has no constructor args (upgradeable) - contract: "contracts/AttestifyVault.sol:AttestifyVault", - }); - console.log("āœ… AttestifyVault implementation verified successfully!\n"); - } catch (error: any) { - const errorMsg = error.message || String(error); - if (errorMsg.includes("Already Verified") || errorMsg.includes("already verified")) { - console.log("āœ… AttestifyVault implementation already verified!\n"); + await verifyContract( + { + address: vaultAddress, + constructorArgs: [], + contract: "contracts/AttestifyVault.sol:AttestifyVault", + provider: "sourcify", + }, + hre.default + ); + console.log("āœ… AttestifyVault verified!\n"); + } catch (error: unknown) { + const msg = error instanceof Error ? error.message : String(error); + if (msg.includes("Already Verified") || msg.includes("already verified")) { + console.log("āœ… AttestifyVault already verified!\n"); } else { - console.error("āŒ Error verifying AttestifyVault:"); - console.error(errorMsg); - console.log(""); + console.error("āŒ AttestifyVault verification failed:", msg, "\n"); } } - // Note: Proxy contracts typically don't need verification as they're standard implementations - console.log("šŸ“ Note: Proxy contract verification skipped (standard ERC1967 implementation)"); - - console.log("\nšŸŽ‰ Verification process complete!"); - console.log("\nšŸ“‹ View verified contracts at:"); - console.log(` Strategy: https://sourcify.dev/#/contracts/full_match/42220/${CONTRACTS.strategy}`); - console.log(` Vault: https://sourcify.dev/#/contracts/full_match/42220/${CONTRACTS.vaultImplementation}`); - console.log(`\n Or check: https://repo.sourcify.dev/contracts/full_match/42220/`); + console.log("šŸŽ‰ Verification complete!"); + console.log("\nšŸ“‹ View verified contracts:"); + console.log(` Strategy: https://sourcify.dev/#/contracts/full_match/${chainId}/${strategyAddress}`); + console.log(` Vault: https://sourcify.dev/#/contracts/full_match/${chainId}/${vaultAddress}`); } main().catch((error) => { diff --git a/scripts/verify-sourcify.ts b/scripts/verify-sourcify.ts deleted file mode 100644 index 60ff7fb..0000000 --- a/scripts/verify-sourcify.ts +++ /dev/null @@ -1,176 +0,0 @@ -import "dotenv/config"; -import { readFileSync } from "fs"; -import { join, dirname } from "path"; -import { fileURLToPath } from "url"; -import process from "node:process"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); - -// Contract addresses from deployment -const CONTRACTS = { - strategy: "0x1ed36feb312b9d464d95fc1bab4b286ddc793341", - vaultImplementation: "0xbe70318eb8772d265642a2ab6fee32cd250ec844", - vaultProxy: "0x16a0ff8d36d9d660de8fd5257cff78adf11b8306", -}; - -const CHAIN_ID = 42220; // Celo Mainnet -const SOURCIFY_API = "https://sourcify.dev/server"; - -interface ContractFiles { - [key: string]: { - content: string; - }; -} - -async function verifyContract( - address: string, - contractName: string, - files: ContractFiles -) { - console.log(`\nšŸ” Verifying ${contractName} at ${address}...`); - - // Sourcify expects files in a specific format - const requestBody = { - address, - chain: CHAIN_ID.toString(), - files: files, - }; - - try { - const response = await fetch(`${SOURCIFY_API}/verify`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(requestBody), - }); - - if (!response.ok) { - const errorText = await response.text(); - console.log(`āŒ HTTP Error: ${response.status} - ${errorText}`); - return false; - } - - const result = await response.json(); - - if (result.status === "perfect" || result.status === "partial") { - console.log(`āœ… ${contractName} verified successfully!`); - console.log(` Status: ${result.status}`); - console.log(` View at: https://sourcify.dev/#/contracts/${result.status}/${CHAIN_ID}/${address}`); - return true; - } else if (result.error) { - console.log(`āŒ ${contractName} verification failed`); - console.log(` Error: ${result.error}`); - if (result.message) { - console.log(` Message: ${result.message}`); - } - return false; - } else { - console.log(`āŒ ${contractName} verification failed`); - console.log(` Response: ${JSON.stringify(result, null, 2)}`); - return false; - } - } catch (error: any) { - console.error(`āŒ Error verifying ${contractName}:`, error.message || error); - return false; - } -} - -function getContractFiles(contractName: string): { files: ContractFiles; metadata?: any } { - const files: ContractFiles = {}; - - // Read main contract - const contractPath = join(__dirname, "../contracts", `${contractName}.sol`); - try { - files[`contracts/${contractName}.sol`] = { - content: readFileSync(contractPath, "utf-8"), - }; - } catch (error) { - console.error(`Error reading ${contractName}.sol:`, error); - } - - // Read dependencies - const dependencies: string[] = []; - - if (contractName === "AaveV3Strategy") { - // AaveV3Strategy doesn't directly import IAave, but let's include it if needed - } else if (contractName === "AttestifyVault") { - dependencies.push("IAave"); - } - - // Read dependency files - for (const dep of dependencies) { - const depPath = join(__dirname, "../contracts", `${dep}.sol`); - try { - files[`contracts/${dep}.sol`] = { - content: readFileSync(depPath, "utf-8"), - }; - } catch (error) { - console.warn(`Warning: Could not read ${dep}.sol`); - } - } - - // Try to read metadata.json from artifacts - let metadata; - try { - const metadataPath = join(__dirname, "../artifacts/contracts", `${contractName}.sol`, `${contractName}.json`); - const artifact = JSON.parse(readFileSync(metadataPath, "utf-8")); - if (artifact.metadata) { - metadata = JSON.parse(artifact.metadata); - files["metadata.json"] = { - content: artifact.metadata, - }; - } - } catch (error) { - console.warn(`Warning: Could not read metadata for ${contractName}`); - } - - return { files, metadata }; -} - -async function main() { - console.log("šŸš€ Starting Sourcify verification for Celo Mainnet contracts...\n"); - - const results = { - strategy: false, - vaultImplementation: false, - vaultProxy: false, - }; - - // Verify Strategy - const strategyData = getContractFiles("AaveV3Strategy"); - results.strategy = await verifyContract( - CONTRACTS.strategy, - "AaveV3Strategy", - strategyData.files - ); - - // Verify Vault Implementation - const vaultData = getContractFiles("AttestifyVault"); - results.vaultImplementation = await verifyContract( - CONTRACTS.vaultImplementation, - "AttestifyVault", - vaultData.files - ); - - // Note: Proxy contracts (TestProxy) are typically not verified through Sourcify - // as they're standard proxy implementations - console.log("\nšŸ“ Note: Proxy contracts are typically not verified separately."); - console.log(" The proxy uses a standard ERC1967 implementation."); - - console.log("\nšŸ“Š Verification Summary:"); - console.log(` Strategy: ${results.strategy ? "āœ… Verified" : "āŒ Failed"}`); - console.log(` Vault Implementation: ${results.vaultImplementation ? "āœ… Verified" : "āŒ Failed"}`); - - if (results.strategy && results.vaultImplementation) { - console.log("\nšŸŽ‰ All contracts verified successfully!"); - } else { - console.log("\nāš ļø Some contracts failed verification. Check the errors above."); - } -} - -main().catch((error) => { - console.error("Error:", error); - process.exit(1); -});