From a89704cdcd0dedc26981e3f52b05427f4f372493 Mon Sep 17 00:00:00 2001 From: nigiri <168690269+0xnigir1@users.noreply.github.com> Date: Tue, 15 Oct 2024 16:49:09 -0300 Subject: [PATCH] feat: implement PoolCreated event handling --- packages/processors/package.json | 3 +- .../allo-v2/v1/DirectGrantsLiteStrategy.ts | 857 ++++++++++++ .../allo-v2/v1/DirectGrantsSimpleStrategy.ts | 1167 ++++++++++++++++ ...erkleDistributionDirectTransferStrategy.ts | 1172 +++++++++++++++++ .../processors/src/allo/allo.processor.ts | 33 +- .../processors/src/allo/handlers/index.ts | 1 + .../src/allo/handlers/poolCreated.handler.ts | 272 ++++ packages/processors/src/helpers/schemas.ts | 11 + packages/processors/src/helpers/strategy.ts | 320 +++++ packages/processors/src/helpers/tokenMath.ts | 34 + packages/processors/src/helpers/utils.ts | 10 + .../src/interfaces/eventHandler.interface.ts | 24 + packages/processors/src/interfaces/index.ts | 1 + .../src/interfaces/processor.interface.ts | 2 +- .../src/strategy/strategy.processor.ts | 2 +- packages/shared/src/constants/address.ts | 6 + packages/shared/src/external.ts | 7 +- packages/shared/src/types/events/allo.ts | 9 + packages/shared/src/types/events/common.ts | 9 + pnpm-lock.yaml | 3 + 20 files changed, 3934 insertions(+), 9 deletions(-) create mode 100644 packages/processors/src/abis/allo-v2/v1/DirectGrantsLiteStrategy.ts create mode 100644 packages/processors/src/abis/allo-v2/v1/DirectGrantsSimpleStrategy.ts create mode 100644 packages/processors/src/abis/allo-v2/v1/DonationVotingMerkleDistributionDirectTransferStrategy.ts create mode 100644 packages/processors/src/allo/handlers/index.ts create mode 100644 packages/processors/src/allo/handlers/poolCreated.handler.ts create mode 100644 packages/processors/src/helpers/schemas.ts create mode 100644 packages/processors/src/helpers/strategy.ts create mode 100644 packages/processors/src/helpers/tokenMath.ts create mode 100644 packages/processors/src/helpers/utils.ts create mode 100644 packages/processors/src/interfaces/eventHandler.interface.ts diff --git a/packages/processors/package.json b/packages/processors/package.json index 5fec498..95643e1 100644 --- a/packages/processors/package.json +++ b/packages/processors/package.json @@ -32,6 +32,7 @@ "@grants-stack-indexer/pricing": "workspace:*", "@grants-stack-indexer/repository": "workspace:*", "@grants-stack-indexer/shared": "workspace:*", - "viem": "2.21.19" + "viem": "2.21.19", + "zod": "3.23.8" } } diff --git a/packages/processors/src/abis/allo-v2/v1/DirectGrantsLiteStrategy.ts b/packages/processors/src/abis/allo-v2/v1/DirectGrantsLiteStrategy.ts new file mode 100644 index 0000000..cacbf28 --- /dev/null +++ b/packages/processors/src/abis/allo-v2/v1/DirectGrantsLiteStrategy.ts @@ -0,0 +1,857 @@ +export default [ + { + inputs: [ + { + internalType: "address", + name: "_allo", + type: "address", + }, + { + internalType: "string", + name: "_name", + type: "string", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + inputs: [], + name: "ALLOCATION_ACTIVE", + type: "error", + }, + { + inputs: [], + name: "ALLOCATION_NOT_ACTIVE", + type: "error", + }, + { + inputs: [], + name: "ALLOCATION_NOT_ENDED", + type: "error", + }, + { + inputs: [], + name: "ALREADY_INITIALIZED", + type: "error", + }, + { + inputs: [], + name: "AMOUNT_MISMATCH", + type: "error", + }, + { + inputs: [], + name: "ANCHOR_ERROR", + type: "error", + }, + { + inputs: [], + name: "ARRAY_MISMATCH", + type: "error", + }, + { + inputs: [], + name: "INVALID", + type: "error", + }, + { + inputs: [], + name: "INVALID_ADDRESS", + type: "error", + }, + { + inputs: [], + name: "INVALID_FEE", + type: "error", + }, + { + inputs: [], + name: "INVALID_METADATA", + type: "error", + }, + { + inputs: [], + name: "INVALID_REGISTRATION", + type: "error", + }, + { + inputs: [], + name: "IS_APPROVED_STRATEGY", + type: "error", + }, + { + inputs: [], + name: "MISMATCH", + type: "error", + }, + { + inputs: [], + name: "NONCE_NOT_AVAILABLE", + type: "error", + }, + { + inputs: [], + name: "NON_ZERO_VALUE", + type: "error", + }, + { + inputs: [], + name: "NOT_APPROVED_STRATEGY", + type: "error", + }, + { + inputs: [], + name: "NOT_ENOUGH_FUNDS", + type: "error", + }, + { + inputs: [], + name: "NOT_IMPLEMENTED", + type: "error", + }, + { + inputs: [], + name: "NOT_INITIALIZED", + type: "error", + }, + { + inputs: [], + name: "NOT_PENDING_OWNER", + type: "error", + }, + { + inputs: [], + name: "POOL_ACTIVE", + type: "error", + }, + { + inputs: [], + name: "POOL_INACTIVE", + type: "error", + }, + { + inputs: [], + name: "RECIPIENT_ALREADY_ACCEPTED", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "recipientId", + type: "address", + }, + ], + name: "RECIPIENT_ERROR", + type: "error", + }, + { + inputs: [], + name: "RECIPIENT_NOT_ACCEPTED", + type: "error", + }, + { + inputs: [], + name: "REGISTRATION_ACTIVE", + type: "error", + }, + { + inputs: [], + name: "REGISTRATION_NOT_ACTIVE", + type: "error", + }, + { + inputs: [], + name: "UNAUTHORIZED", + type: "error", + }, + { + inputs: [], + name: "ZERO_ADDRESS", + type: "error", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "recipientId", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "token", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "Allocated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "recipientId", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "recipientAddress", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "Distributed", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "poolId", + type: "uint256", + }, + { + indexed: false, + internalType: "bytes", + name: "data", + type: "bytes", + }, + ], + name: "Initialized", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "bool", + name: "active", + type: "bool", + }, + ], + name: "PoolActive", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "rowIndex", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "fullRow", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "RecipientStatusUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "recipientId", + type: "address", + }, + { + indexed: false, + internalType: "bytes", + name: "data", + type: "bytes", + }, + { + indexed: false, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "Registered", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint64", + name: "registrationStartTime", + type: "uint64", + }, + { + indexed: false, + internalType: "uint64", + name: "registrationEndTime", + type: "uint64", + }, + { + indexed: false, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "TimestampsUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "recipientId", + type: "address", + }, + { + indexed: false, + internalType: "bytes", + name: "data", + type: "bytes", + }, + { + indexed: false, + internalType: "address", + name: "sender", + type: "address", + }, + { + indexed: false, + internalType: "uint8", + name: "status", + type: "uint8", + }, + ], + name: "UpdatedRegistration", + type: "event", + }, + { + inputs: [], + name: "NATIVE", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes", + name: "_data", + type: "bytes", + }, + { + internalType: "address", + name: "_sender", + type: "address", + }, + ], + name: "allocate", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + internalType: "address[]", + name: "_recipientIds", + type: "address[]", + }, + { + internalType: "bytes", + name: "_data", + type: "bytes", + }, + { + internalType: "address", + name: "_sender", + type: "address", + }, + ], + name: "distribute", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "getAllo", + outputs: [ + { + internalType: "contract IAllo", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address[]", + name: "_recipientIds", + type: "address[]", + }, + { + internalType: "bytes[]", + name: "_data", + type: "bytes[]", + }, + ], + name: "getPayouts", + outputs: [ + { + components: [ + { + internalType: "address", + name: "recipientAddress", + type: "address", + }, + { + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + internalType: "struct IStrategy.PayoutSummary[]", + name: "", + type: "tuple[]", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getPoolAmount", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getPoolId", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_recipientId", + type: "address", + }, + ], + name: "getRecipient", + outputs: [ + { + components: [ + { + internalType: "bool", + name: "useRegistryAnchor", + type: "bool", + }, + { + internalType: "address", + name: "recipientAddress", + type: "address", + }, + { + components: [ + { + internalType: "uint256", + name: "protocol", + type: "uint256", + }, + { + internalType: "string", + name: "pointer", + type: "string", + }, + ], + internalType: "struct Metadata", + name: "metadata", + type: "tuple", + }, + ], + internalType: "struct DirectGrantsLiteStrategy.Recipient", + name: "recipient", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_recipientId", + type: "address", + }, + ], + name: "getRecipientStatus", + outputs: [ + { + internalType: "enum IStrategy.Status", + name: "", + type: "uint8", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getStrategyId", + outputs: [ + { + internalType: "bytes32", + name: "", + type: "bytes32", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_amount", + type: "uint256", + }, + ], + name: "increasePoolAmount", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_poolId", + type: "uint256", + }, + { + internalType: "bytes", + name: "_data", + type: "bytes", + }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "isPoolActive", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_allocator", + type: "address", + }, + ], + name: "isValidAllocator", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "metadataRequired", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes[]", + name: "data", + type: "bytes[]", + }, + ], + name: "multicall", + outputs: [ + { + internalType: "bytes[]", + name: "results", + type: "bytes[]", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + name: "recipientToStatusIndexes", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "recipientsCounter", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes", + name: "_data", + type: "bytes", + }, + { + internalType: "address", + name: "_sender", + type: "address", + }, + ], + name: "registerRecipient", + outputs: [ + { + internalType: "address", + name: "recipientId", + type: "address", + }, + ], + stateMutability: "payable", + type: "function", + }, + { + inputs: [], + name: "registrationEndTime", + outputs: [ + { + internalType: "uint64", + name: "", + type: "uint64", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "registrationStartTime", + outputs: [ + { + internalType: "uint64", + name: "", + type: "uint64", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + components: [ + { + internalType: "uint256", + name: "index", + type: "uint256", + }, + { + internalType: "uint256", + name: "statusRow", + type: "uint256", + }, + ], + internalType: "struct DirectGrantsLiteStrategy.ApplicationStatus[]", + name: "statuses", + type: "tuple[]", + }, + { + internalType: "uint256", + name: "refRecipientsCounter", + type: "uint256", + }, + ], + name: "reviewRecipients", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + name: "statusesBitMap", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint64", + name: "_registrationStartTime", + type: "uint64", + }, + { + internalType: "uint64", + name: "_registrationEndTime", + type: "uint64", + }, + ], + name: "updatePoolTimestamps", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "useRegistryAnchor", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_token", + type: "address", + }, + ], + name: "withdraw", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + stateMutability: "payable", + type: "receive", + }, +] as const; diff --git a/packages/processors/src/abis/allo-v2/v1/DirectGrantsSimpleStrategy.ts b/packages/processors/src/abis/allo-v2/v1/DirectGrantsSimpleStrategy.ts new file mode 100644 index 0000000..c802b3e --- /dev/null +++ b/packages/processors/src/abis/allo-v2/v1/DirectGrantsSimpleStrategy.ts @@ -0,0 +1,1167 @@ +export default [ + { + inputs: [ + { + internalType: "address", + name: "_allo", + type: "address", + }, + { + internalType: "string", + name: "_name", + type: "string", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + inputs: [], + name: "ALLOCATION_ACTIVE", + type: "error", + }, + { + inputs: [], + name: "ALLOCATION_EXCEEDS_POOL_AMOUNT", + type: "error", + }, + { + inputs: [], + name: "ALLOCATION_NOT_ACTIVE", + type: "error", + }, + { + inputs: [], + name: "ALLOCATION_NOT_ENDED", + type: "error", + }, + { + inputs: [], + name: "ALREADY_INITIALIZED", + type: "error", + }, + { + inputs: [], + name: "AMOUNT_MISMATCH", + type: "error", + }, + { + inputs: [], + name: "ANCHOR_ERROR", + type: "error", + }, + { + inputs: [], + name: "ARRAY_MISMATCH", + type: "error", + }, + { + inputs: [], + name: "INVALID", + type: "error", + }, + { + inputs: [], + name: "INVALID_ADDRESS", + type: "error", + }, + { + inputs: [], + name: "INVALID_FEE", + type: "error", + }, + { + inputs: [], + name: "INVALID_METADATA", + type: "error", + }, + { + inputs: [], + name: "INVALID_MILESTONE", + type: "error", + }, + { + inputs: [], + name: "INVALID_REGISTRATION", + type: "error", + }, + { + inputs: [], + name: "IS_APPROVED_STRATEGY", + type: "error", + }, + { + inputs: [], + name: "MILESTONES_ALREADY_SET", + type: "error", + }, + { + inputs: [], + name: "MILESTONE_ALREADY_ACCEPTED", + type: "error", + }, + { + inputs: [], + name: "MISMATCH", + type: "error", + }, + { + inputs: [], + name: "NONCE_NOT_AVAILABLE", + type: "error", + }, + { + inputs: [], + name: "NON_ZERO_VALUE", + type: "error", + }, + { + inputs: [], + name: "NOT_APPROVED_STRATEGY", + type: "error", + }, + { + inputs: [], + name: "NOT_ENOUGH_FUNDS", + type: "error", + }, + { + inputs: [], + name: "NOT_IMPLEMENTED", + type: "error", + }, + { + inputs: [], + name: "NOT_INITIALIZED", + type: "error", + }, + { + inputs: [], + name: "NOT_PENDING_OWNER", + type: "error", + }, + { + inputs: [], + name: "POOL_ACTIVE", + type: "error", + }, + { + inputs: [], + name: "POOL_INACTIVE", + type: "error", + }, + { + inputs: [], + name: "RECIPIENT_ALREADY_ACCEPTED", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "recipientId", + type: "address", + }, + ], + name: "RECIPIENT_ERROR", + type: "error", + }, + { + inputs: [], + name: "RECIPIENT_NOT_ACCEPTED", + type: "error", + }, + { + inputs: [], + name: "REGISTRATION_ACTIVE", + type: "error", + }, + { + inputs: [], + name: "REGISTRATION_NOT_ACTIVE", + type: "error", + }, + { + inputs: [], + name: "UNAUTHORIZED", + type: "error", + }, + { + inputs: [], + name: "ZERO_ADDRESS", + type: "error", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "recipientId", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "token", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "Allocated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "recipientId", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "recipientAddress", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "Distributed", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "poolId", + type: "uint256", + }, + { + indexed: false, + internalType: "bytes", + name: "data", + type: "bytes", + }, + ], + name: "Initialized", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "recipientId", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "milestoneId", + type: "uint256", + }, + { + indexed: false, + internalType: "enum IStrategy.Status", + name: "status", + type: "uint8", + }, + ], + name: "MilestoneStatusChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "recipientId", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "milestoneId", + type: "uint256", + }, + { + components: [ + { + internalType: "uint256", + name: "protocol", + type: "uint256", + }, + { + internalType: "string", + name: "pointer", + type: "string", + }, + ], + indexed: false, + internalType: "struct Metadata", + name: "metadata", + type: "tuple", + }, + ], + name: "MilestoneSubmitted", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "recipientId", + type: "address", + }, + { + indexed: false, + internalType: "enum IStrategy.Status", + name: "status", + type: "uint8", + }, + ], + name: "MilestonesReviewed", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "recipientId", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "milestonesLength", + type: "uint256", + }, + ], + name: "MilestonesSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "bool", + name: "active", + type: "bool", + }, + ], + name: "PoolActive", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "recipientId", + type: "address", + }, + { + indexed: false, + internalType: "enum IStrategy.Status", + name: "status", + type: "uint8", + }, + ], + name: "RecipientStatusChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "recipientId", + type: "address", + }, + { + indexed: false, + internalType: "bytes", + name: "data", + type: "bytes", + }, + { + indexed: false, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "Registered", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint64", + name: "registrationStartTime", + type: "uint64", + }, + { + indexed: false, + internalType: "uint64", + name: "registrationEndTime", + type: "uint64", + }, + { + indexed: false, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "TimestampsUpdated", + type: "event", + }, + { + inputs: [], + name: "NATIVE", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes", + name: "_data", + type: "bytes", + }, + { + internalType: "address", + name: "_sender", + type: "address", + }, + ], + name: "allocate", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [], + name: "allocatedGrantAmount", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address[]", + name: "_recipientIds", + type: "address[]", + }, + { + internalType: "bytes", + name: "_data", + type: "bytes", + }, + { + internalType: "address", + name: "_sender", + type: "address", + }, + ], + name: "distribute", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "getAllo", + outputs: [ + { + internalType: "contract IAllo", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_recipientId", + type: "address", + }, + { + internalType: "uint256", + name: "_milestoneId", + type: "uint256", + }, + ], + name: "getMilestoneStatus", + outputs: [ + { + internalType: "enum IStrategy.Status", + name: "", + type: "uint8", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_recipientId", + type: "address", + }, + ], + name: "getMilestones", + outputs: [ + { + components: [ + { + internalType: "uint256", + name: "amountPercentage", + type: "uint256", + }, + { + components: [ + { + internalType: "uint256", + name: "protocol", + type: "uint256", + }, + { + internalType: "string", + name: "pointer", + type: "string", + }, + ], + internalType: "struct Metadata", + name: "metadata", + type: "tuple", + }, + { + internalType: "enum IStrategy.Status", + name: "milestoneStatus", + type: "uint8", + }, + ], + internalType: "struct DirectGrantsSimpleStrategy.Milestone[]", + name: "", + type: "tuple[]", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address[]", + name: "_recipientIds", + type: "address[]", + }, + { + internalType: "bytes[]", + name: "_data", + type: "bytes[]", + }, + ], + name: "getPayouts", + outputs: [ + { + components: [ + { + internalType: "address", + name: "recipientAddress", + type: "address", + }, + { + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + internalType: "struct IStrategy.PayoutSummary[]", + name: "", + type: "tuple[]", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getPoolAmount", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getPoolId", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_recipientId", + type: "address", + }, + ], + name: "getRecipient", + outputs: [ + { + components: [ + { + internalType: "bool", + name: "useRegistryAnchor", + type: "bool", + }, + { + internalType: "address", + name: "recipientAddress", + type: "address", + }, + { + internalType: "uint256", + name: "grantAmount", + type: "uint256", + }, + { + components: [ + { + internalType: "uint256", + name: "protocol", + type: "uint256", + }, + { + internalType: "string", + name: "pointer", + type: "string", + }, + ], + internalType: "struct Metadata", + name: "metadata", + type: "tuple", + }, + { + internalType: "enum IStrategy.Status", + name: "recipientStatus", + type: "uint8", + }, + { + internalType: "enum IStrategy.Status", + name: "milestonesReviewStatus", + type: "uint8", + }, + ], + internalType: "struct DirectGrantsSimpleStrategy.Recipient", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_recipientId", + type: "address", + }, + ], + name: "getRecipientStatus", + outputs: [ + { + internalType: "enum IStrategy.Status", + name: "", + type: "uint8", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getStrategyId", + outputs: [ + { + internalType: "bytes32", + name: "", + type: "bytes32", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "grantAmountRequired", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_amount", + type: "uint256", + }, + ], + name: "increasePoolAmount", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_poolId", + type: "uint256", + }, + { + internalType: "bytes", + name: "_data", + type: "bytes", + }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "isPoolActive", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_allocator", + type: "address", + }, + ], + name: "isValidAllocator", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "metadataRequired", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + name: "milestones", + outputs: [ + { + internalType: "uint256", + name: "amountPercentage", + type: "uint256", + }, + { + components: [ + { + internalType: "uint256", + name: "protocol", + type: "uint256", + }, + { + internalType: "string", + name: "pointer", + type: "string", + }, + ], + internalType: "struct Metadata", + name: "metadata", + type: "tuple", + }, + { + internalType: "enum IStrategy.Status", + name: "milestoneStatus", + type: "uint8", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes", + name: "_data", + type: "bytes", + }, + { + internalType: "address", + name: "_sender", + type: "address", + }, + ], + name: "registerRecipient", + outputs: [ + { + internalType: "address", + name: "recipientId", + type: "address", + }, + ], + stateMutability: "payable", + type: "function", + }, + { + inputs: [], + name: "registrationEndTime", + outputs: [ + { + internalType: "uint64", + name: "", + type: "uint64", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "registrationStartTime", + outputs: [ + { + internalType: "uint64", + name: "", + type: "uint64", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "registryGating", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_recipientId", + type: "address", + }, + { + internalType: "uint256", + name: "_milestoneId", + type: "uint256", + }, + ], + name: "rejectMilestone", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_recipientId", + type: "address", + }, + { + internalType: "enum IStrategy.Status", + name: "_status", + type: "uint8", + }, + { + internalType: "bytes32", + name: "milestonesHash", + type: "bytes32", + }, + ], + name: "reviewSetMilestones", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_recipientId", + type: "address", + }, + { + components: [ + { + internalType: "uint256", + name: "amountPercentage", + type: "uint256", + }, + { + components: [ + { + internalType: "uint256", + name: "protocol", + type: "uint256", + }, + { + internalType: "string", + name: "pointer", + type: "string", + }, + ], + internalType: "struct Metadata", + name: "metadata", + type: "tuple", + }, + { + internalType: "enum IStrategy.Status", + name: "milestoneStatus", + type: "uint8", + }, + ], + internalType: "struct DirectGrantsSimpleStrategy.Milestone[]", + name: "_milestones", + type: "tuple[]", + }, + ], + name: "setMilestones", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "bool", + name: "_flag", + type: "bool", + }, + ], + name: "setPoolActive", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address[]", + name: "_recipientIds", + type: "address[]", + }, + ], + name: "setRecipientStatusToInReview", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_recipientId", + type: "address", + }, + { + internalType: "uint256", + name: "_milestoneId", + type: "uint256", + }, + { + components: [ + { + internalType: "uint256", + name: "protocol", + type: "uint256", + }, + { + internalType: "string", + name: "pointer", + type: "string", + }, + ], + internalType: "struct Metadata", + name: "_metadata", + type: "tuple", + }, + ], + name: "submitMilestone", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + name: "upcomingMilestone", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint64", + name: "_registrationStartTime", + type: "uint64", + }, + { + internalType: "uint64", + name: "_registrationEndTime", + type: "uint64", + }, + ], + name: "updatePoolTimestamps", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_amount", + type: "uint256", + }, + ], + name: "withdraw", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + stateMutability: "payable", + type: "receive", + }, +] as const; diff --git a/packages/processors/src/abis/allo-v2/v1/DonationVotingMerkleDistributionDirectTransferStrategy.ts b/packages/processors/src/abis/allo-v2/v1/DonationVotingMerkleDistributionDirectTransferStrategy.ts new file mode 100644 index 0000000..8f5f0fe --- /dev/null +++ b/packages/processors/src/abis/allo-v2/v1/DonationVotingMerkleDistributionDirectTransferStrategy.ts @@ -0,0 +1,1172 @@ +export default [ + { + inputs: [ + { + internalType: "address", + name: "_allo", + type: "address", + }, + { + internalType: "string", + name: "_name", + type: "string", + }, + { + internalType: "contract ISignatureTransfer", + name: "_permit2", + type: "address", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + inputs: [], + name: "ALLOCATION_ACTIVE", + type: "error", + }, + { + inputs: [], + name: "ALLOCATION_NOT_ACTIVE", + type: "error", + }, + { + inputs: [], + name: "ALLOCATION_NOT_ENDED", + type: "error", + }, + { + inputs: [], + name: "ALREADY_INITIALIZED", + type: "error", + }, + { + inputs: [], + name: "AMOUNT_MISMATCH", + type: "error", + }, + { + inputs: [], + name: "ANCHOR_ERROR", + type: "error", + }, + { + inputs: [], + name: "ARRAY_MISMATCH", + type: "error", + }, + { + inputs: [], + name: "INVALID", + type: "error", + }, + { + inputs: [], + name: "INVALID_ADDRESS", + type: "error", + }, + { + inputs: [], + name: "INVALID_FEE", + type: "error", + }, + { + inputs: [], + name: "INVALID_METADATA", + type: "error", + }, + { + inputs: [], + name: "INVALID_REGISTRATION", + type: "error", + }, + { + inputs: [], + name: "IS_APPROVED_STRATEGY", + type: "error", + }, + { + inputs: [], + name: "MISMATCH", + type: "error", + }, + { + inputs: [], + name: "NONCE_NOT_AVAILABLE", + type: "error", + }, + { + inputs: [], + name: "NON_ZERO_VALUE", + type: "error", + }, + { + inputs: [], + name: "NOT_APPROVED_STRATEGY", + type: "error", + }, + { + inputs: [], + name: "NOT_ENOUGH_FUNDS", + type: "error", + }, + { + inputs: [], + name: "NOT_IMPLEMENTED", + type: "error", + }, + { + inputs: [], + name: "NOT_INITIALIZED", + type: "error", + }, + { + inputs: [], + name: "NOT_PENDING_OWNER", + type: "error", + }, + { + inputs: [], + name: "POOL_ACTIVE", + type: "error", + }, + { + inputs: [], + name: "POOL_INACTIVE", + type: "error", + }, + { + inputs: [], + name: "RECIPIENT_ALREADY_ACCEPTED", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "recipientId", + type: "address", + }, + ], + name: "RECIPIENT_ERROR", + type: "error", + }, + { + inputs: [], + name: "RECIPIENT_NOT_ACCEPTED", + type: "error", + }, + { + inputs: [], + name: "REGISTRATION_ACTIVE", + type: "error", + }, + { + inputs: [], + name: "REGISTRATION_NOT_ACTIVE", + type: "error", + }, + { + inputs: [], + name: "UNAUTHORIZED", + type: "error", + }, + { + inputs: [], + name: "ZERO_ADDRESS", + type: "error", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "recipientId", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "token", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "sender", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "origin", + type: "address", + }, + ], + name: "Allocated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "BatchPayoutSuccessful", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "recipientId", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "recipientAddress", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "Distributed", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "bytes32", + name: "merkleRoot", + type: "bytes32", + }, + { + components: [ + { + internalType: "uint256", + name: "protocol", + type: "uint256", + }, + { + internalType: "string", + name: "pointer", + type: "string", + }, + ], + indexed: false, + internalType: "struct Metadata", + name: "metadata", + type: "tuple", + }, + ], + name: "DistributionUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "grantee", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "token", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "recipientId", + type: "address", + }, + ], + name: "FundsDistributed", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "poolId", + type: "uint256", + }, + { + indexed: false, + internalType: "bytes", + name: "data", + type: "bytes", + }, + ], + name: "Initialized", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "bool", + name: "active", + type: "bool", + }, + ], + name: "PoolActive", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "rowIndex", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "fullRow", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "RecipientStatusUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "recipientId", + type: "address", + }, + { + indexed: false, + internalType: "bytes", + name: "data", + type: "bytes", + }, + { + indexed: false, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "Registered", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint64", + name: "registrationStartTime", + type: "uint64", + }, + { + indexed: false, + internalType: "uint64", + name: "registrationEndTime", + type: "uint64", + }, + { + indexed: false, + internalType: "uint64", + name: "allocationStartTime", + type: "uint64", + }, + { + indexed: false, + internalType: "uint64", + name: "allocationEndTime", + type: "uint64", + }, + { + indexed: false, + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "TimestampsUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "recipientId", + type: "address", + }, + { + indexed: false, + internalType: "bytes", + name: "data", + type: "bytes", + }, + { + indexed: false, + internalType: "address", + name: "sender", + type: "address", + }, + { + indexed: false, + internalType: "uint8", + name: "status", + type: "uint8", + }, + ], + name: "UpdatedRegistration", + type: "event", + }, + { + inputs: [], + name: "NATIVE", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "PERMIT2", + outputs: [ + { + internalType: "contract ISignatureTransfer", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes", + name: "_data", + type: "bytes", + }, + { + internalType: "address", + name: "_sender", + type: "address", + }, + ], + name: "allocate", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [], + name: "allocationEndTime", + outputs: [ + { + internalType: "uint64", + name: "", + type: "uint64", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "allocationStartTime", + outputs: [ + { + internalType: "uint64", + name: "", + type: "uint64", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + name: "allowedTokens", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address[]", + name: "_recipientIds", + type: "address[]", + }, + { + internalType: "bytes", + name: "_data", + type: "bytes", + }, + { + internalType: "address", + name: "_sender", + type: "address", + }, + ], + name: "distribute", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "distributionMetadata", + outputs: [ + { + internalType: "uint256", + name: "protocol", + type: "uint256", + }, + { + internalType: "string", + name: "pointer", + type: "string", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "distributionStarted", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getAllo", + outputs: [ + { + internalType: "contract IAllo", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address[]", + name: "_recipientIds", + type: "address[]", + }, + { + internalType: "bytes[]", + name: "_data", + type: "bytes[]", + }, + ], + name: "getPayouts", + outputs: [ + { + components: [ + { + internalType: "address", + name: "recipientAddress", + type: "address", + }, + { + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + internalType: "struct IStrategy.PayoutSummary[]", + name: "", + type: "tuple[]", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getPoolAmount", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getPoolId", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_recipientId", + type: "address", + }, + ], + name: "getRecipient", + outputs: [ + { + components: [ + { + internalType: "bool", + name: "useRegistryAnchor", + type: "bool", + }, + { + internalType: "address", + name: "recipientAddress", + type: "address", + }, + { + components: [ + { + internalType: "uint256", + name: "protocol", + type: "uint256", + }, + { + internalType: "string", + name: "pointer", + type: "string", + }, + ], + internalType: "struct Metadata", + name: "metadata", + type: "tuple", + }, + ], + internalType: "struct DonationVotingMerkleDistributionBaseStrategy.Recipient", + name: "recipient", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_recipientId", + type: "address", + }, + ], + name: "getRecipientStatus", + outputs: [ + { + internalType: "enum IStrategy.Status", + name: "", + type: "uint8", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getStrategyId", + outputs: [ + { + internalType: "bytes32", + name: "", + type: "bytes32", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_index", + type: "uint256", + }, + ], + name: "hasBeenDistributed", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_amount", + type: "uint256", + }, + ], + name: "increasePoolAmount", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_poolId", + type: "uint256", + }, + { + internalType: "bytes", + name: "_data", + type: "bytes", + }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "isDistributionSet", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "isPoolActive", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_allocator", + type: "address", + }, + ], + name: "isValidAllocator", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "merkleRoot", + outputs: [ + { + internalType: "bytes32", + name: "", + type: "bytes32", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "metadataRequired", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes[]", + name: "data", + type: "bytes[]", + }, + ], + name: "multicall", + outputs: [ + { + internalType: "bytes[]", + name: "results", + type: "bytes[]", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + name: "recipientToStatusIndexes", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "recipientsCounter", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes", + name: "_data", + type: "bytes", + }, + { + internalType: "address", + name: "_sender", + type: "address", + }, + ], + name: "registerRecipient", + outputs: [ + { + internalType: "address", + name: "recipientId", + type: "address", + }, + ], + stateMutability: "payable", + type: "function", + }, + { + inputs: [], + name: "registrationEndTime", + outputs: [ + { + internalType: "uint64", + name: "", + type: "uint64", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "registrationStartTime", + outputs: [ + { + internalType: "uint64", + name: "", + type: "uint64", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + components: [ + { + internalType: "uint256", + name: "index", + type: "uint256", + }, + { + internalType: "uint256", + name: "statusRow", + type: "uint256", + }, + ], + internalType: + "struct DonationVotingMerkleDistributionBaseStrategy.ApplicationStatus[]", + name: "statuses", + type: "tuple[]", + }, + { + internalType: "uint256", + name: "refRecipientsCounter", + type: "uint256", + }, + ], + name: "reviewRecipients", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes", + name: "sig", + type: "bytes", + }, + ], + name: "splitSignature", + outputs: [ + { + internalType: "bytes32", + name: "r", + type: "bytes32", + }, + { + internalType: "bytes32", + name: "s", + type: "bytes32", + }, + { + internalType: "uint8", + name: "v", + type: "uint8", + }, + ], + stateMutability: "pure", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + name: "statusesBitMap", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "totalPayoutAmount", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes32", + name: "_merkleRoot", + type: "bytes32", + }, + { + components: [ + { + internalType: "uint256", + name: "protocol", + type: "uint256", + }, + { + internalType: "string", + name: "pointer", + type: "string", + }, + ], + internalType: "struct Metadata", + name: "_distributionMetadata", + type: "tuple", + }, + ], + name: "updateDistribution", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint64", + name: "_registrationStartTime", + type: "uint64", + }, + { + internalType: "uint64", + name: "_registrationEndTime", + type: "uint64", + }, + { + internalType: "uint64", + name: "_allocationStartTime", + type: "uint64", + }, + { + internalType: "uint64", + name: "_allocationEndTime", + type: "uint64", + }, + ], + name: "updatePoolTimestamps", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "useRegistryAnchor", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_token", + type: "address", + }, + ], + name: "withdraw", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + stateMutability: "payable", + type: "receive", + }, +] as const; diff --git a/packages/processors/src/allo/allo.processor.ts b/packages/processors/src/allo/allo.processor.ts index b59e1ef..692e386 100644 --- a/packages/processors/src/allo/allo.processor.ts +++ b/packages/processors/src/allo/allo.processor.ts @@ -1,11 +1,34 @@ -import { Changeset } from "@grants-stack-indexer/repository"; -import { AlloEvent, ProtocolEvent } from "@grants-stack-indexer/shared"; +import { Chain, PublicClient, Transport } from "viem"; + +import type { IMetadataProvider } from "@grants-stack-indexer/metadata"; +import type { IPricingProvider } from "@grants-stack-indexer/pricing"; +import { Changeset, IRoundReadRepository } from "@grants-stack-indexer/repository"; +import { AlloEvent, ChainId, ProtocolEvent } from "@grants-stack-indexer/shared"; import type { IProcessor } from "../internal.js"; +import { PoolCreatedHandler } from "./handlers/index.js"; export class AlloProcessor implements IProcessor<"Allo", AlloEvent> { - //TODO: Implement - process(_event: ProtocolEvent<"Allo", AlloEvent>): Promise { - throw new Error("Method not implemented."); + constructor( + private readonly chainId: ChainId, + //TODO: replace with provider abstraction + private readonly viemClient: PublicClient, + private readonly pricingProvider: IPricingProvider, + private readonly metadataProvider: IMetadataProvider, + private readonly roundRepository: IRoundReadRepository, + ) {} + + process(event: ProtocolEvent<"Allo", AlloEvent>): Promise { + switch (event.eventName) { + case "PoolCreated": + return new PoolCreatedHandler(event, this.chainId, { + viemClient: this.viemClient, + pricingProvider: this.pricingProvider, + metadataProvider: this.metadataProvider, + roundRepository: this.roundRepository, + }).handle(); + default: + throw new Error("Unknown event name"); + } } } diff --git a/packages/processors/src/allo/handlers/index.ts b/packages/processors/src/allo/handlers/index.ts new file mode 100644 index 0000000..7f0b311 --- /dev/null +++ b/packages/processors/src/allo/handlers/index.ts @@ -0,0 +1 @@ +export * from "./poolCreated.handler.js"; diff --git a/packages/processors/src/allo/handlers/poolCreated.handler.ts b/packages/processors/src/allo/handlers/poolCreated.handler.ts new file mode 100644 index 0000000..a71834e --- /dev/null +++ b/packages/processors/src/allo/handlers/poolCreated.handler.ts @@ -0,0 +1,272 @@ +import { + Address, + encodePacked, + getAddress, + keccak256, + pad, + parseUnits, + PublicClient, + zeroAddress, +} from "viem"; + +import type { IMetadataProvider } from "@grants-stack-indexer/metadata"; +import type { IPricingProvider } from "@grants-stack-indexer/pricing"; +import type { Changeset, IRoundReadRepository, NewRound } from "@grants-stack-indexer/repository"; +import type { ChainId, ProtocolEvent } from "@grants-stack-indexer/shared"; +import { isAlloNativeToken } from "@grants-stack-indexer/shared/"; + +import type { IEventHandler } from "../../internal.js"; +import { RoundMetadataSchema } from "../../helpers/schemas.js"; +import { extractStrategyFromId, getStrategyTimings } from "../../helpers/strategy.js"; +import { calculateAmountInUsd } from "../../helpers/tokenMath.js"; + +/** + /** + * Handles the PoolCreated event for the Allo protocol. + * + * This handler performs the following core actions when a new pool is created: + * - Retrieves the metadata associated with the pool + * - Determines the correct token address, handling native tokens appropriately. + * - Extracts the correct strategy information from the provided strategy ID. + * - Calculates the funded amount in USD based on the token's pricing. + * - Creates a new round object + */ +export class PoolCreatedHandler implements IEventHandler<"Allo", "PoolCreated"> { + private readonly viemClient: PublicClient; + private readonly pricingProvider: IPricingProvider; + private readonly metadataProvider: IMetadataProvider; + private readonly roundRepository: IRoundReadRepository; + + constructor( + readonly event: ProtocolEvent<"Allo", "PoolCreated">, + private readonly chainId: ChainId, + dependencies: { + viemClient: PublicClient; + pricingProvider: IPricingProvider; + metadataProvider: IMetadataProvider; + roundRepository: IRoundReadRepository; + }, + ) { + this.viemClient = dependencies.viemClient; + this.pricingProvider = dependencies.pricingProvider; + this.metadataProvider = dependencies.metadataProvider; + this.roundRepository = dependencies.roundRepository; + } + + async handle(): Promise { + const { pointer: metadataPointer } = this.event.params.metadata; + const { + poolId, + strategyId, + token: tokenAddress, + contractAddress: strategyAddress, + amount: fundedAmount, + } = this.event.params; + const { hash: txHash, from: txFrom } = this.event.transactionFields; + + try { + const metadata = await this.metadataProvider.getMetadata<{ + round?: unknown; + application?: unknown; + }>(metadataPointer); + const parsedRoundMetadata = RoundMetadataSchema.safeParse(metadata?.round); + + const checksummedTokenAddress = getAddress(tokenAddress); + const matchTokenAddress = isAlloNativeToken(checksummedTokenAddress) + ? zeroAddress + : checksummedTokenAddress; + + const strategy = extractStrategyFromId(strategyId); + + // TODO: get token for the chain + const token = { + address: matchTokenAddress, + decimals: 18, //TODO: get decimals from token + symbol: "USDC", //TODO: get symbol from token + name: "USDC", //TODO: get name from token + }; + + let strategyTimings: { + applicationsStartTime: Date | null; + applicationsEndTime: Date | null; + donationsStartTime: Date | null; + donationsEndTime: Date | null; + } = { + applicationsStartTime: null, + applicationsEndTime: null, + donationsStartTime: null, + donationsEndTime: null, + }; + + let matchAmount = 0n; + let matchAmountInUsd = 0; + + if (strategy) { + strategyTimings = await getStrategyTimings( + this.viemClient, + strategy, + strategyAddress, + ); + + //when creating strategy handlers, should this be moved there? + if ( + strategy.name === + "allov2.DonationVotingMerkleDistributionDirectTransferStrategy" && + parsedRoundMetadata.success && + token !== null + ) { + matchAmount = parseUnits( + parsedRoundMetadata.data.quadraticFundingConfig.matchingFundsAvailable.toString(), + token.decimals, + ); + + matchAmountInUsd = await this.getTokenAmountInUsd( + token, + matchAmount, + this.event.blockTimestamp, + ); + } + } + + let fundedAmountInUsd = 0; + + if (token !== null && fundedAmount > 0n) { + fundedAmountInUsd = await this.getTokenAmountInUsd( + token, + fundedAmount, + this.event.blockTimestamp, + ); + } + + // transaction sender + const createdBy = + txFrom ?? (await this.viemClient.getTransaction({ hash: txHash })).from; + + const roundRoles = this.getRoundRoles(poolId); + + const newRound: NewRound = { + chainId: this.chainId, + id: poolId.toString(), + tags: ["allo-v2", ...(parsedRoundMetadata.success ? ["grants-stack"] : [])], + totalDonationsCount: 0, + totalAmountDonatedInUsd: 0, + uniqueDonorsCount: 0, + matchTokenAddress, + matchAmount, + matchAmountInUsd, + fundedAmount, + fundedAmountInUsd, + applicationMetadataCid: metadataPointer, + applicationMetadata: metadata?.application ?? {}, + roundMetadataCid: metadataPointer, + roundMetadata: metadata?.round ?? null, + ...strategyTimings, + ...roundRoles, + strategyAddress, + strategyId, + strategyName: strategy?.name ?? "", + createdByAddress: getAddress(createdBy), + createdAtBlock: BigInt(this.event.blockNumber), + updatedAtBlock: BigInt(this.event.blockNumber), + projectId: this.event.params.profileId, + totalDistributed: 0n, + readyForPayoutTransaction: null, + matchingDistribution: null, + }; + + const changes: Changeset[] = [ + { + type: "InsertRound", + args: { round: newRound }, + }, + ]; + + changes.push(...(await this.handlePendingRoles(this.chainId, poolId.toString()))); + + return changes; + } catch (error: unknown) { + console.error( + `An error occurred while processing the PoolCreated event. Event: ${this.event} - Error: ${error}`, + ); + return []; + } + } + + /** + * Get the manager and admin roles for the pool + * Note: POOL_MANAGER_ROLE = bytes32(poolId); + * Note: POOL_ADMIN_ROLE = keccak256(abi.encodePacked(poolId, "admin")); + * @param poolId - The ID of the pool. + * @returns The manager and admin roles. + */ + private getRoundRoles(poolId: bigint): { managerRole: string; adminRole: string } { + // POOL_MANAGER_ROLE = bytes32(poolId); + const managerRole = pad(`0x${poolId.toString(16)}`); + + // POOL_ADMIN_ROLE = keccak256(abi.encodePacked(poolId, "admin")); + const adminRawRole = encodePacked(["uint256", "string"], [poolId, "admin"]); + const adminRole = keccak256(adminRawRole); + return { managerRole, adminRole }; + } + + /** + * Creates the admin and manager roles for the pool and deletes the pending roles. + * @param chainId - The ID of the chain. + * @param roundId - The ID of the round. + * @returns The changesets. + * @Note + * Admin/Manager roles for the pool are emitted before the pool is created + * so a pending round role is inserted in the db. + * Now that the PoolCreated event is emitted, we can convert + * pending roles to actual round roles. + */ + private async handlePendingRoles(chainId: ChainId, roundId: string): Promise { + const changes: Changeset[] = []; + + for (const roleName of ["admin", "manager"] as const) { + const pendingRoles = await this.roundRepository.getPendingRoundRoles(chainId, roleName); + for (const pr of pendingRoles) { + changes.push({ + type: "InsertRoundRole", + args: { + roundRole: { + chainId, + roundId, + address: pr.address, + role: roleName, + createdAtBlock: pr.createdAtBlock, + }, + }, + }); + } + + if (pendingRoles.length > 0) { + changes.push({ + type: "DeletePendingRoundRoles", + args: { ids: pendingRoles.map((r) => r.id!) }, + }); + } + } + + return changes; + } + + private async getTokenAmountInUsd( + token: { address: Address; decimals: number }, + amount: bigint, + timestamp: number, + ): Promise { + const tokenPrice = await this.pricingProvider.getTokenPrice( + this.chainId, + token.address, + timestamp, + timestamp + 1200000, + ); + + if (!tokenPrice) { + throw new Error("Token price not found"); + } + + return calculateAmountInUsd(amount, tokenPrice, token.decimals); + } +} diff --git a/packages/processors/src/helpers/schemas.ts b/packages/processors/src/helpers/schemas.ts new file mode 100644 index 0000000..6b23423 --- /dev/null +++ b/packages/processors/src/helpers/schemas.ts @@ -0,0 +1,11 @@ +import { z } from "zod"; + +export const RoundMetadataSchema = z + .object({ + name: z.string(), + roundType: z.union([z.literal("private"), z.literal("public")]), + quadraticFundingConfig: z.object({ + matchingFundsAvailable: z.number(), + }), + }) + .passthrough(); diff --git a/packages/processors/src/helpers/strategy.ts b/packages/processors/src/helpers/strategy.ts new file mode 100644 index 0000000..bf0ef57 --- /dev/null +++ b/packages/processors/src/helpers/strategy.ts @@ -0,0 +1,320 @@ +import { Address, PublicClient } from "viem"; + +import { Branded } from "@grants-stack-indexer/shared"; + +import DirectGrantsLiteStrategy from "../abis/allo-v2/v1/DirectGrantsLiteStrategy.js"; +import DonationVotingMerkleDistributionDirectTransferStrategy from "../abis/allo-v2/v1/DonationVotingMerkleDistributionDirectTransferStrategy.js"; +import { getDateFromTimestamp } from "./utils.js"; + +type SanitizedStrategyId = Branded; +type Strategy = { + id: SanitizedStrategyId; + name: string | null; + // TODO: check if groups are required + groups: string[]; +}; + +/* + * Extracts the strategy from the ID. + * @param _id - The ID of the strategy. + * @returns The strategy. + */ +export function extractStrategyFromId(_id: Address): Strategy | undefined { + const id = _id.toLowerCase(); + /* eslint-disable no-fallthrough */ + switch (id) { + // SQFSuperfluidv1 + case "0xf8a14294e80ff012e54157ec9d1b2827421f1e7f6bde38c06730b1c031b3f935": + return { + id: id as SanitizedStrategyId, + name: "allov2.SQFSuperFluidStrategy", + groups: ["allov2.SQFSuperFluidStrategy"], + }; + + // MicroGrantsv1 + case "0x697f0592ebd05466d2d24454477e11d69c475d7a7c4134f15ddc1ea9811bb16f": + return { + id: id as SanitizedStrategyId, + name: "allov2.MicroGrantsStrategy", + groups: ["allov2.MicroGrantsStrategy", "allov2.MicroGrantsCommon"], + }; + + // MicroGrantsGovv1 + case "0x741ac1e2f387d83f219f6b5349d35ec34902cf94019d117335e0045d2e0ed912": + return { + id: id as SanitizedStrategyId, + name: "allov2.MicroGrantsGovStrategy", + groups: ["allov2.MicroGrantsGovStrategy", "allov2.MicroGrantsCommon"], + }; + + // MicroGrantsHatsv1 + case "0x5aa24dcfcd55a1e059a172e987b3456736b4856c71e57aaf52e9a965897318dd": + return { + id: id as SanitizedStrategyId, + name: "allov2.MicroGrantsHatsStrategy", + groups: ["allov2.MicroGrantsHatsStrategy", "allov2.MicroGrantsCommon"], + }; + + // RFPSimpleStrategyv1.0 + case "0x0d459e12d9e91d2b2a8fa12be8c7eb2b4f1c35e74573990c34b436613bc2350f": + return { + id: id as SanitizedStrategyId, + name: "allov2.RFPSimpleStrategy", + groups: ["allov2.RFPSimpleStrategy"], + }; + + // RFPCommitteeStrategyv1.0 + case "0x7d143166a83c6a8a303ae32a6ccd287e48d79818f5d15d89e185391199909803": + return { + id: id as SanitizedStrategyId, + name: "allov2.RFPCommitteeStrategy", + groups: ["allov2.RFPCommitteeStrategy"], + }; + + // QVSimpleStrategyv1.0 + case "0x22d006e191d6dc5ff1a25bb0733f47f64a9c34860b6703df88dea7cb3987b4c3": + return { + id: id as SanitizedStrategyId, + name: "allov2.QVSimpleStrategy", + groups: ["allov2.QVSimpleStrategy"], + }; + + // DonationVotingMerkleDistributionDirectTransferStrategyv1.0 + case "0x6f9291df02b2664139cec5703c124e4ebce32879c74b6297faa1468aa5ff9ebf": + // DonationVotingMerkleDistributionDirectTransferStrategyv1.1 + case "0x2f46bf157821dc41daa51479e94783bb0c8699eac63bf75ec450508ab03867ce": + // DonationVotingMerkleDistributionDirectTransferStrategyv2.0 + case "0x2f0250d534b2d59b8b5cfa5eb0d0848a59ccbf5de2eaf72d2ba4bfe73dce7c6b": + // DonationVotingMerkleDistributionDirectTransferStrategyv2.1 + case "0x9fa6890423649187b1f0e8bf4265f0305ce99523c3d11aa36b35a54617bb0ec0": + return { + id: id as SanitizedStrategyId, + name: "allov2.DonationVotingMerkleDistributionDirectTransferStrategy", + groups: ["allov2.DonationVotingMerkleDistributionDirectTransferStrategy"], + }; + + // DonationVotingMerkleDistributionVaultStrategyv1.0 + case "0x7e75375f0a7cd9f7ea159c8b065976e4f764f9dcef1edf692f31dd1842f70c87": + // DonationVotingMerkleDistributionVaultStrategyv1.1 + case "0x093072375737c0e8872fef36808849aeba7f865e182d495f2b98308115c9ef13": + return { + id: id as SanitizedStrategyId, + name: "allov2.DonationVotingMerkleDistributionVaultStrategy", + groups: ["allov2.DonationVotingMerkleDistributionVaultStrategy"], + }; + + // DirectGrantsSimpleStrategyv1.1 + case "0x263cb916541b6fc1fb5543a244829ccdba75264b097726e6ecc3c3cfce824bf5": + // DirectGrantsSimpleStrategyv2.1 + case "0x53fb9d3bce0956ca2db5bb1441f5ca23050cb1973b33789e04a5978acfd9ca93": + return { + id: id as SanitizedStrategyId, + name: "allov2.DirectGrantsSimpleStrategy", + groups: ["allov2.DirectGrantsSimpleStrategy"], + }; + + // DirectGrantsLiteStrategyv1.0 + case "0x103732a8e473467a510d4128ee11065262bdd978f0d9dad89ba68f2c56127e27": + return { + id: id as SanitizedStrategyId, + name: "allov2.DirectGrantsLiteStrategy", + groups: ["allov2.DirectGrantsLiteStrategy"], + }; + + // EasyRPGFStrategy1.0 + case "0x662f5a0d3ea7e9b6ed1b351a9d96ac636a3c3ed727390aeff4ec931ae760d5ae": + return { + id: id as SanitizedStrategyId, + name: "allov2.EasyRPGFStrategy", + groups: ["allov2.EasyRPGFStrategy"], + }; + + // DirectAllocationStrategyv1.1 + case "0x4cd0051913234cdd7d165b208851240d334786d6e5afbb4d0eec203515a9c6f3": + return { + id: id as SanitizedStrategyId, + name: "allov2.DirectAllocationStrategy", + groups: ["allov2.DirectAllocationStrategy"], + }; + } + + return undefined; +} + +//TODO: refactor this into the StrategyHandler when implemented +export const getStrategyTimings = async ( + viemClient: PublicClient, + strategy: Strategy, + strategyAddress: Address, +): Promise<{ + applicationsStartTime: Date | null; + applicationsEndTime: Date | null; + donationsStartTime: Date | null; + donationsEndTime: Date | null; +}> => { + switch (strategy.name) { + case "allov2.DonationVotingMerkleDistributionDirectTransferStrategy": + return getDonationVotingMerkleDistributionDirectTransferStrategyTimings( + viemClient, + strategyAddress, + ); + case "allov2.DirectGrantsSimpleStrategy": + case "allov2.DirectGrantsLiteStrategy": + return getDirectGrantsStrategyTimings(viemClient, strategyAddress); + default: + return { + applicationsStartTime: null, + applicationsEndTime: null, + donationsStartTime: null, + donationsEndTime: null, + }; + } +}; + +/** + * Gets the strategy data for the DonationVotingMerkleDistributionDirectTransferStrategy + * @param viemClient - The viem client + * @param strategyId - The address of the strategy + * @returns The strategy data + */ +export const getDonationVotingMerkleDistributionDirectTransferStrategyTimings = async ( + viemClient: PublicClient, + strategyId: Address, +): Promise<{ + applicationsStartTime: Date | null; + applicationsEndTime: Date | null; + donationsStartTime: Date | null; + donationsEndTime: Date | null; +}> => { + let registrationStartTimeResolved: bigint; + let registrationEndTimeResolved: bigint; + let allocationStartTimeResolved: bigint; + let allocationEndTimeResolved: bigint; + + if (viemClient.chain?.contracts?.multicall3) { + const results = await viemClient.multicall({ + contracts: [ + { + abi: DonationVotingMerkleDistributionDirectTransferStrategy, + functionName: "registrationStartTime", + address: strategyId, + }, + { + abi: DonationVotingMerkleDistributionDirectTransferStrategy, + functionName: "registrationEndTime", + address: strategyId, + }, + { + abi: DonationVotingMerkleDistributionDirectTransferStrategy, + functionName: "allocationStartTime", + address: strategyId, + }, + { + abi: DonationVotingMerkleDistributionDirectTransferStrategy, + functionName: "allocationEndTime", + address: strategyId, + }, + ], + allowFailure: false, + }); + registrationStartTimeResolved = results[0]; + registrationEndTimeResolved = results[1]; + allocationStartTimeResolved = results[2]; + allocationEndTimeResolved = results[3]; + } else { + const results = await Promise.all([ + viemClient.readContract({ + abi: DonationVotingMerkleDistributionDirectTransferStrategy, + functionName: "registrationStartTime", + address: strategyId, + }), + viemClient.readContract({ + abi: DonationVotingMerkleDistributionDirectTransferStrategy, + functionName: "registrationEndTime", + address: strategyId, + }), + viemClient.readContract({ + abi: DonationVotingMerkleDistributionDirectTransferStrategy, + functionName: "allocationStartTime", + address: strategyId, + }), + viemClient.readContract({ + abi: DonationVotingMerkleDistributionDirectTransferStrategy, + functionName: "allocationEndTime", + address: strategyId, + }), + ]); + registrationStartTimeResolved = results[0]; + registrationEndTimeResolved = results[1]; + allocationStartTimeResolved = results[2]; + allocationEndTimeResolved = results[3]; + } + + return { + applicationsStartTime: getDateFromTimestamp(registrationStartTimeResolved), + applicationsEndTime: getDateFromTimestamp(registrationEndTimeResolved), + donationsStartTime: getDateFromTimestamp(allocationStartTimeResolved), + donationsEndTime: getDateFromTimestamp(allocationEndTimeResolved), + }; +}; + +/** + * Gets the strategy data for the DirectGrantsStrategy + * @param viemClient - The viem client + * @param strategyAddress - The address of the strategy + * @returns The strategy data + */ +export const getDirectGrantsStrategyTimings = async ( + viemClient: PublicClient, + strategyAddress: Address, +): Promise<{ + applicationsStartTime: Date | null; + applicationsEndTime: Date | null; + donationsStartTime: Date | null; + donationsEndTime: Date | null; +}> => { + let registrationStartTimeResolved: bigint; + let registrationEndTimeResolved: bigint; + + if (viemClient.chain?.contracts?.multicall3) { + const results = await viemClient.multicall({ + contracts: [ + { + abi: DirectGrantsLiteStrategy, + functionName: "registrationStartTime", + address: strategyAddress, + }, + { + abi: DirectGrantsLiteStrategy, + functionName: "registrationEndTime", + address: strategyAddress, + }, + ], + allowFailure: false, + }); + registrationStartTimeResolved = results[0]; + registrationEndTimeResolved = results[1]; + } else { + const results = await Promise.all([ + viemClient.readContract({ + abi: DirectGrantsLiteStrategy, + functionName: "registrationStartTime", + address: strategyAddress, + }), + viemClient.readContract({ + abi: DirectGrantsLiteStrategy, + functionName: "registrationEndTime", + address: strategyAddress, + }), + ]); + registrationStartTimeResolved = results[0]; + registrationEndTimeResolved = results[1]; + } + + return { + applicationsStartTime: getDateFromTimestamp(registrationStartTimeResolved), + applicationsEndTime: getDateFromTimestamp(registrationEndTimeResolved), + donationsStartTime: null, + donationsEndTime: null, + }; +}; diff --git a/packages/processors/src/helpers/tokenMath.ts b/packages/processors/src/helpers/tokenMath.ts new file mode 100644 index 0000000..c0fed42 --- /dev/null +++ b/packages/processors/src/helpers/tokenMath.ts @@ -0,0 +1,34 @@ +import { formatUnits, parseUnits } from "viem"; + +import { TokenPrice } from "@grants-stack-indexer/pricing"; + +/** + * Calculates the amount in USD + * @param amount - The amount to convert to USD + * @param tokenPrice - The price of the token in USD + * @param tokenDecimals - The number of decimals the token has + * @param truncateDecimals (optional) - The number of decimals to truncate the final result to. Must be between 0 and 18. + * @returns The amount in USD + */ +export const calculateAmountInUsd = ( + amount: bigint, + tokenPrice: TokenPrice, + tokenDecimals: number, + truncateDecimals?: number, +): number => { + const amountInUsd = Number( + formatUnits( + amount * parseUnits(tokenPrice.priceUsd.toString(), tokenDecimals), + tokenDecimals * 2, + ), + ); + + if (truncateDecimals) { + if (truncateDecimals < 0 || truncateDecimals > 18) { + throw new Error("Truncate decimals must be between 0 and 18"); + } + return Number(amountInUsd.toFixed(truncateDecimals)); + } + + return amountInUsd; +}; diff --git a/packages/processors/src/helpers/utils.ts b/packages/processors/src/helpers/utils.ts new file mode 100644 index 0000000..cd1e01c --- /dev/null +++ b/packages/processors/src/helpers/utils.ts @@ -0,0 +1,10 @@ +const UINT64_MAX = 18446744073709551615n; + +/** + * Converts a timestamp to a date + * @param timestamp - The timestamp to convert to a date + * @returns The date or null if the timestamp is greater than 18446744073709551615 + */ +export const getDateFromTimestamp = (timestamp: bigint): Date | null => { + return timestamp >= 0n && timestamp < UINT64_MAX ? new Date(Number(timestamp) * 1000) : null; +}; diff --git a/packages/processors/src/interfaces/eventHandler.interface.ts b/packages/processors/src/interfaces/eventHandler.interface.ts new file mode 100644 index 0000000..03ee946 --- /dev/null +++ b/packages/processors/src/interfaces/eventHandler.interface.ts @@ -0,0 +1,24 @@ +import type { Changeset } from "@grants-stack-indexer/repository"; +import type { + ContractName, + ContractToEventName, + ProtocolEvent, +} from "@grants-stack-indexer/shared"; + +/** + * Interface for an event handler. + * @template C - The contract name. + * @template E - The event name. + */ +export interface IEventHandler> { + /** + * The event to handle. + */ + readonly event: ProtocolEvent; + + /** + * Handles the event. + * @returns A promise that resolves to an array of changesets. + */ + handle(): Promise; +} diff --git a/packages/processors/src/interfaces/index.ts b/packages/processors/src/interfaces/index.ts index d9d3380..057ac8d 100644 --- a/packages/processors/src/interfaces/index.ts +++ b/packages/processors/src/interfaces/index.ts @@ -1 +1,2 @@ export * from "./processor.interface.js"; +export * from "./eventHandler.interface.js"; diff --git a/packages/processors/src/interfaces/processor.interface.ts b/packages/processors/src/interfaces/processor.interface.ts index f8aeb02..4f8c943 100644 --- a/packages/processors/src/interfaces/processor.interface.ts +++ b/packages/processors/src/interfaces/processor.interface.ts @@ -7,5 +7,5 @@ export interface IProcessor): Promise; + process(event: ProtocolEvent): Promise; } diff --git a/packages/processors/src/strategy/strategy.processor.ts b/packages/processors/src/strategy/strategy.processor.ts index 6f4d499..9c2c4ae 100644 --- a/packages/processors/src/strategy/strategy.processor.ts +++ b/packages/processors/src/strategy/strategy.processor.ts @@ -4,7 +4,7 @@ import { ProtocolEvent, StrategyEvent } from "@grants-stack-indexer/shared"; import type { IProcessor } from "../internal.js"; export class StrategyProcessor implements IProcessor<"Strategy", StrategyEvent> { - process(_event: ProtocolEvent<"Strategy", StrategyEvent>): Promise { + process(_event: ProtocolEvent<"Strategy", StrategyEvent>): Promise { //TODO: Implement throw new Error("Method not implemented."); } diff --git a/packages/shared/src/constants/address.ts b/packages/shared/src/constants/address.ts index e1884d2..01a413e 100644 --- a/packages/shared/src/constants/address.ts +++ b/packages/shared/src/constants/address.ts @@ -2,6 +2,12 @@ import { Address } from "viem"; export const NATIVE_TOKEN_ADDRESS: Address = "0x0000000000000000000000000000000000000001"; +export const ALLO_NATIVE_TOKEN = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; + export const isNativeToken = (address: Address): boolean => { return address === NATIVE_TOKEN_ADDRESS; }; + +export const isAlloNativeToken = (address: Address): boolean => { + return address === ALLO_NATIVE_TOKEN; +}; diff --git a/packages/shared/src/external.ts b/packages/shared/src/external.ts index 6547286..80fefd6 100644 --- a/packages/shared/src/external.ts +++ b/packages/shared/src/external.ts @@ -1,3 +1,8 @@ export type * from "./types/index.js"; export type { Address } from "./internal.js"; -export { NATIVE_TOKEN_ADDRESS, isNativeToken } from "./constants/index.js"; +export { + NATIVE_TOKEN_ADDRESS, + isNativeToken, + ALLO_NATIVE_TOKEN, + isAlloNativeToken, +} from "./constants/index.js"; diff --git a/packages/shared/src/types/events/allo.ts b/packages/shared/src/types/events/allo.ts index 8e5a39d..353d39d 100644 --- a/packages/shared/src/types/events/allo.ts +++ b/packages/shared/src/types/events/allo.ts @@ -17,4 +17,13 @@ export type AlloEventParams = T extends "PoolCreated" // ============================================================================= export type PoolCreatedParams = { contractAddress: Address; + poolId: bigint; + profileId: Address; + strategyId: Address; + token: Address; + amount: bigint; + metadata: { + pointer: string; + protocol: bigint; + }; }; diff --git a/packages/shared/src/types/events/common.ts b/packages/shared/src/types/events/common.ts index 3b4921b..ad2a38d 100644 --- a/packages/shared/src/types/events/common.ts +++ b/packages/shared/src/types/events/common.ts @@ -1,9 +1,17 @@ +import { Hex } from "viem"; + import { Address } from "../../internal.js"; import { AlloEvent, AlloEventParams, StrategyEvent, StrategyEventParams } from "./index.js"; export type ContractName = "Strategy" | "Allo"; export type AnyEvent = StrategyEvent | AlloEvent; +type TransactionFields = { + hash: Hex; + transactionIndex: number; + from?: Address; +}; + /** * This type is used to map contract names to their respective event names. */ @@ -39,6 +47,7 @@ export type ProtocolEvent; srcAddress: Address; + transactionFields: TransactionFields; }; export type AnyProtocolEvent = ProtocolEvent>; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 442ab68..c5ec297 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -163,6 +163,9 @@ importers: viem: specifier: 2.21.19 version: 2.21.19(typescript@5.5.4)(zod@3.23.8) + zod: + specifier: 3.23.8 + version: 3.23.8 packages/repository: dependencies: