From 3945b03db9aab234b6af67dc2f86176da1c5bd21 Mon Sep 17 00:00:00 2001 From: 0xKurt Date: Wed, 8 Jan 2025 14:04:38 +0100 Subject: [PATCH] Add Easy Retro Funding Strategy --- .../allo-v2/v1/EasyRetroFundingStrategy.ts | 711 ++++++++++++++++++ src/indexer/abis/index.ts | 3 +- src/indexer/allo/v2/handleEvent.ts | 67 ++ src/indexer/allo/v2/strategy.ts | 8 + src/indexer/types.ts | 7 + 5 files changed, 795 insertions(+), 1 deletion(-) create mode 100644 src/indexer/abis/allo-v2/v1/EasyRetroFundingStrategy.ts diff --git a/src/indexer/abis/allo-v2/v1/EasyRetroFundingStrategy.ts b/src/indexer/abis/allo-v2/v1/EasyRetroFundingStrategy.ts new file mode 100644 index 00000000..89aadf0b --- /dev/null +++ b/src/indexer/abis/allo-v2/v1/EasyRetroFundingStrategy.ts @@ -0,0 +1,711 @@ +export default [ + { + "type": "constructor", + "inputs": [ + { "name": "_allo", "type": "address", "internalType": "address" }, + { "name": "_name", "type": "string", "internalType": "string" } + ], + "stateMutability": "nonpayable" + }, + { "type": "receive", "stateMutability": "payable" }, + { + "type": "function", + "name": "NATIVE", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "allocate", + "inputs": [ + { "name": "_data", "type": "bytes", "internalType": "bytes" }, + { "name": "_sender", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "distribute", + "inputs": [ + { + "name": "_recipientIds", + "type": "address[]", + "internalType": "address[]" + }, + { "name": "_data", "type": "bytes", "internalType": "bytes" }, + { "name": "_sender", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "distributionMetadata", + "inputs": [], + "outputs": [ + { "name": "protocol", "type": "uint256", "internalType": "uint256" }, + { "name": "pointer", "type": "string", "internalType": "string" } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "distributionStarted", + "inputs": [], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getAllo", + "inputs": [], + "outputs": [ + { "name": "", "type": "address", "internalType": "contract IAllo" } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPayouts", + "inputs": [ + { + "name": "_recipientIds", + "type": "address[]", + "internalType": "address[]" + }, + { "name": "_data", "type": "bytes[]", "internalType": "bytes[]" } + ], + "outputs": [ + { + "name": "", + "type": "tuple[]", + "internalType": "struct IStrategy.PayoutSummary[]", + "components": [ + { + "name": "recipientAddress", + "type": "address", + "internalType": "address" + }, + { "name": "amount", "type": "uint256", "internalType": "uint256" } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPoolAmount", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPoolId", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRecipient", + "inputs": [ + { "name": "_recipientId", "type": "address", "internalType": "address" } + ], + "outputs": [ + { + "name": "recipient", + "type": "tuple", + "internalType": "struct EasyRetroFundingStrategy.Recipient", + "components": [ + { + "name": "useRegistryAnchor", + "type": "bool", + "internalType": "bool" + }, + { + "name": "recipientAddress", + "type": "address", + "internalType": "address" + }, + { + "name": "metadata", + "type": "tuple", + "internalType": "struct Metadata", + "components": [ + { + "name": "protocol", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "pointer", + "type": "string", + "internalType": "string" + } + ] + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRecipientStatus", + "inputs": [ + { "name": "_recipientId", "type": "address", "internalType": "address" } + ], + "outputs": [ + { "name": "", "type": "uint8", "internalType": "enum IStrategy.Status" } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getStrategyId", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "hasBeenDistributed", + "inputs": [ + { "name": "_index", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "increasePoolAmount", + "inputs": [ + { "name": "_amount", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { "name": "_poolId", "type": "uint256", "internalType": "uint256" }, + { "name": "_data", "type": "bytes", "internalType": "bytes" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isDistributionSet", + "inputs": [], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isPoolActive", + "inputs": [], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isValidAllocator", + "inputs": [ + { "name": "_allocator", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "metadataRequired", + "inputs": [], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "multicall", + "inputs": [ + { "name": "data", "type": "bytes[]", "internalType": "bytes[]" } + ], + "outputs": [ + { "name": "results", "type": "bytes[]", "internalType": "bytes[]" } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "poolEndTime", + "inputs": [], + "outputs": [{ "name": "", "type": "uint64", "internalType": "uint64" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "poolStartTime", + "inputs": [], + "outputs": [{ "name": "", "type": "uint64", "internalType": "uint64" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "recipientToStatusIndexes", + "inputs": [{ "name": "", "type": "address", "internalType": "address" }], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "recipientsCounter", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "registerRecipient", + "inputs": [ + { "name": "_data", "type": "bytes", "internalType": "bytes" }, + { "name": "_sender", "type": "address", "internalType": "address" } + ], + "outputs": [ + { "name": "recipientId", "type": "address", "internalType": "address" } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "registrationEndTime", + "inputs": [], + "outputs": [{ "name": "", "type": "uint64", "internalType": "uint64" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "registrationStartTime", + "inputs": [], + "outputs": [{ "name": "", "type": "uint64", "internalType": "uint64" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "reviewRecipients", + "inputs": [ + { + "name": "statuses", + "type": "tuple[]", + "internalType": "struct EasyRetroFundingStrategy.ApplicationStatus[]", + "components": [ + { "name": "index", "type": "uint256", "internalType": "uint256" }, + { + "name": "statusRow", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "refRecipientsCounter", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "statusesBitMap", + "inputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "totalPayoutAmount", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "updateDistribution", + "inputs": [ + { + "name": "_distributionMetadata", + "type": "tuple", + "internalType": "struct Metadata", + "components": [ + { + "name": "protocol", + "type": "uint256", + "internalType": "uint256" + }, + { "name": "pointer", "type": "string", "internalType": "string" } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updatePoolTimestamps", + "inputs": [ + { + "name": "_registrationStartTime", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "_registrationEndTime", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "_poolStartTime", + "type": "uint64", + "internalType": "uint64" + }, + { "name": "_poolEndTime", "type": "uint64", "internalType": "uint64" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "useRegistryAnchor", + "inputs": [], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "withdraw", + "inputs": [ + { "name": "_token", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "Allocated", + "inputs": [ + { + "name": "recipientId", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "BatchPayoutSuccessful", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Distributed", + "inputs": [ + { + "name": "recipientId", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "recipientAddress", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "sender", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "DistributionUpdated", + "inputs": [ + { + "name": "metadata", + "type": "tuple", + "indexed": false, + "internalType": "struct Metadata", + "components": [ + { + "name": "protocol", + "type": "uint256", + "internalType": "uint256" + }, + { "name": "pointer", "type": "string", "internalType": "string" } + ] + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "FundsDistributed", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "grantee", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "recipientId", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "poolId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "data", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PoolActive", + "inputs": [ + { + "name": "active", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RecipientStatusUpdated", + "inputs": [ + { + "name": "rowIndex", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "fullRow", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "sender", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Registered", + "inputs": [ + { + "name": "recipientId", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + }, + { + "name": "sender", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TimestampsUpdated", + "inputs": [ + { + "name": "registrationStartTime", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + }, + { + "name": "registrationEndTime", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + }, + { + "name": "poolStartTime", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + }, + { + "name": "poolEndTime", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + }, + { + "name": "sender", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "UpdatedRegistration", + "inputs": [ + { + "name": "recipientId", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + }, + { + "name": "sender", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "status", + "type": "uint8", + "indexed": false, + "internalType": "uint8" + } + ], + "anonymous": false + }, + { "type": "error", "name": "ALLOCATION_ACTIVE", "inputs": [] }, + { "type": "error", "name": "ALLOCATION_NOT_ACTIVE", "inputs": [] }, + { "type": "error", "name": "ALLOCATION_NOT_ENDED", "inputs": [] }, + { "type": "error", "name": "ALREADY_INITIALIZED", "inputs": [] }, + { "type": "error", "name": "AMOUNT_MISMATCH", "inputs": [] }, + { "type": "error", "name": "ANCHOR_ERROR", "inputs": [] }, + { "type": "error", "name": "ARRAY_MISMATCH", "inputs": [] }, + { "type": "error", "name": "INVALID", "inputs": [] }, + { "type": "error", "name": "INVALID_ADDRESS", "inputs": [] }, + { "type": "error", "name": "INVALID_FEE", "inputs": [] }, + { "type": "error", "name": "INVALID_METADATA", "inputs": [] }, + { "type": "error", "name": "INVALID_REGISTRATION", "inputs": [] }, + { "type": "error", "name": "IS_APPROVED_STRATEGY", "inputs": [] }, + { "type": "error", "name": "MISMATCH", "inputs": [] }, + { "type": "error", "name": "NONCE_NOT_AVAILABLE", "inputs": [] }, + { "type": "error", "name": "NON_ZERO_VALUE", "inputs": [] }, + { "type": "error", "name": "NOT_APPROVED_STRATEGY", "inputs": [] }, + { "type": "error", "name": "NOT_ENOUGH_FUNDS", "inputs": [] }, + { "type": "error", "name": "NOT_IMPLEMENTED", "inputs": [] }, + { "type": "error", "name": "NOT_INITIALIZED", "inputs": [] }, + { "type": "error", "name": "NOT_PENDING_OWNER", "inputs": [] }, + { "type": "error", "name": "POOL_ACTIVE", "inputs": [] }, + { "type": "error", "name": "POOL_INACTIVE", "inputs": [] }, + { "type": "error", "name": "POOL_NOT_ENDED", "inputs": [] }, + { "type": "error", "name": "RECIPIENT_ALREADY_ACCEPTED", "inputs": [] }, + { + "type": "error", + "name": "RECIPIENT_ERROR", + "inputs": [ + { "name": "recipientId", "type": "address", "internalType": "address" } + ] + }, + { "type": "error", "name": "RECIPIENT_NOT_ACCEPTED", "inputs": [] }, + { "type": "error", "name": "REGISTRATION_ACTIVE", "inputs": [] }, + { "type": "error", "name": "REGISTRATION_NOT_ACTIVE", "inputs": [] }, + { "type": "error", "name": "UNAUTHORIZED", "inputs": [] }, + { "type": "error", "name": "ZERO_ADDRESS", "inputs": [] } + ] as const; \ No newline at end of file diff --git a/src/indexer/abis/index.ts b/src/indexer/abis/index.ts index 730840d8..f39b04b1 100644 --- a/src/indexer/abis/index.ts +++ b/src/indexer/abis/index.ts @@ -28,6 +28,7 @@ import AlloV1ToV2ProfileMigration from "./allo-v2/AlloV1ToV2ProfileMigration.js" import AlloV2DirectGrantsLiteStrategy from "./allo-v2/v1/DirectGrantsLiteStrategy.js"; import AlloV2EasyRPGFStrategy from "./allo-v2/v1/EasyRPGFStrategy.js"; import AlloV2DirectAllocationStrategy from "./allo-v2/v1/DirectAllocationStrategy.js"; +import AlloV2EasyRetroFundingStrategy from "./allo-v2/v1/EasyRetroFundingStrategy.js"; // Gitcoin Attestation Network import GitcoinAttestationNetwork from "./gitcoin-attestation-network/GitcoinGrantsResolver.js"; @@ -72,7 +73,7 @@ const abis = { "AlloV2/DirectGrantsLiteStrategy/V1": AlloV2DirectGrantsLiteStrategy, "AlloV2/EasyRPGFStrategy/V1": AlloV2EasyRPGFStrategy, "AlloV2/DirectAllocationStrategy/V1": AlloV2DirectAllocationStrategy, - + "AlloV2/EasyRetroFundingStrategy/V1": AlloV2EasyRetroFundingStrategy, // Gitcoin Attestation Network "GitcoinAttestationNetwork/GitcoinGrantsResolver": GitcoinAttestationNetwork, } as const; diff --git a/src/indexer/allo/v2/handleEvent.ts b/src/indexer/allo/v2/handleEvent.ts index 7db6631f..d66433ae 100644 --- a/src/indexer/allo/v2/handleEvent.ts +++ b/src/indexer/allo/v2/handleEvent.ts @@ -26,6 +26,7 @@ import { DVMDApplicationData, DVMDExtendedApplicationData, DVMDTimeStampUpdatedData, + EasyRetroFundingTimeStampUpdatedData, } from "../../types.js"; import { fetchPoolMetadata } from "./poolMetadata.js"; import roleGranted from "./roleGranted.js"; @@ -332,6 +333,12 @@ export async function handleEvent( address: strategyAddress, }); break; + case "allov2.EasyRetroFundingStrategy": + subscribeToContract({ + contract: "AlloV2/EasyRetroFundingStrategy/V1", + address: strategyAddress, + }); + break; } let applicationsStartTime: Date | null = null; @@ -422,6 +429,55 @@ export async function handleEvent( registrationStartTimeResolved ); applicationsEndTime = getDateFromTimestamp(registrationEndTimeResolved); + } else if ( + strategy !== null && + strategy.name === "allov2.EasyRetroFundingStrategy" + ) { + const contract = "AlloV2/EasyRetroFundingStrategy/V1"; + const [registrationStartTimeResolved, registrationEndTimeResolved, poolStartTimeResolved, poolEndTimeResolved] = + await Promise.all([ + await readContract({ + contract, + address: strategyAddress, + functionName: "registrationStartTime", + }), + await readContract({ + contract, + address: strategyAddress, + functionName: "registrationEndTime", + }), + await readContract({ + contract, + address: strategyAddress, + functionName: "poolStartTime", + }), + await readContract({ + contract, + address: strategyAddress, + functionName: "poolEndTime", + }), + ]); + + applicationsStartTime = getDateFromTimestamp(registrationStartTimeResolved); + applicationsEndTime = getDateFromTimestamp(registrationEndTimeResolved); + donationsStartTime = getDateFromTimestamp(poolStartTimeResolved); + donationsEndTime = getDateFromTimestamp(poolEndTimeResolved); + + if (parsedMetadata.success && token !== null) { + matchAmount = parseUnits( + parsedMetadata.data.quadraticFundingConfig.matchingFundsAvailable.toString(), + token.decimals + ); + matchAmountInUsd = ( + await convertToUSD( + priceProvider, + chainId, + matchTokenAddress, + matchAmount, + event.blockNumber + ) + ).amount; + } } const fundedAmount = event.params.amount; @@ -808,6 +864,7 @@ export async function handleEvent( case "allov2.DonationVotingMerkleDistributionDirectTransferStrategy": case "allov2.DirectGrantsLiteStrategy": + case "allov2.EasyRetroFundingStrategy": values = decodeDVMDExtendedApplicationData(encodedData); id = (Number(values.recipientsCounter) - 1).toString(); break; @@ -882,6 +939,7 @@ export async function handleEvent( case "allov2.DirectGrantsLiteStrategy": case "allov2.DonationVotingMerkleDistributionDirectTransferStrategy": + case "allov2.EasyRetroFundingStrategy": values = decodeDVMDApplicationData(encodedData); break; @@ -973,6 +1031,15 @@ export async function handleEvent( break; + case "allov2.EasyRetroFundingStrategy": + params = event.params as EasyRetroFundingTimeStampUpdatedData; + + applicationsStartTime = getDateFromTimestamp(params.registrationStartTime); + applicationsEndTime = getDateFromTimestamp(params.registrationEndTime); + donationsStartTime = getDateFromTimestamp(params.poolStartTime); + donationsEndTime = getDateFromTimestamp(params.poolEndTime); + break; + default: throw new Error("Invalid strategy name"); } diff --git a/src/indexer/allo/v2/strategy.ts b/src/indexer/allo/v2/strategy.ts index 23f0b961..34d20ee9 100644 --- a/src/indexer/allo/v2/strategy.ts +++ b/src/indexer/allo/v2/strategy.ts @@ -123,6 +123,14 @@ export function extractStrategyFromId(_id: string): Strategy | null { name: "allov2.DirectAllocationStrategy", groups: ["allov2.DirectAllocationStrategy"], }; + + // EasyRetroFundingStrategyv1.0 + case "0x060ffd6c79f918819a622248c6823443412aedea610cc19c89d28dadcdef7fba": + return { + id: id, + name: "allov2.EasyRetroFundingStrategy", + groups: ["allov2.EasyRetroFundingStrategy"], + }; } return null; diff --git a/src/indexer/types.ts b/src/indexer/types.ts index f3b9b7cb..e3541cfd 100644 --- a/src/indexer/types.ts +++ b/src/indexer/types.ts @@ -28,6 +28,13 @@ export type DVMDTimeStampUpdatedData = { allocationEndTime: bigint; }; +export type EasyRetroFundingTimeStampUpdatedData = { + registrationStartTime: bigint; + registrationEndTime: bigint; + poolStartTime: bigint; + poolEndTime: bigint; +}; + export type DGTimeStampUpdatedData = { registrationStartTime: bigint; registrationEndTime: bigint;