UNPKG

@allo-team/allo-v2-sdk

Version:
700 lines (554 loc) 16.7 kB
import { Chain, PublicClient, Transport, encodeAbiParameters, encodeFunctionData, extractChain, getContract, parseAbiParameters, } from "viem"; import { Allo } from "../../Allo/Allo"; import { abi as alloAbi } from "../../Allo/allo.config"; import { create } from "../../Client/Client"; import { abi as microGrantsAbi, bytecode as microGrantsBytecode, } from "./microGrants.config"; import { abi as microGrantsGovAbi, bytecode as microGrantsGovBytecode, } from "./microGrantsGov.config"; import { abi as microGrantsHatsAbi, bytecode as microGrantsHatsBytecode, } from "./microGrantsHats.config"; import { ConstructorArgs, DeployParams, TransactionData, ZERO_ADDRESS, } from "../../Common/types"; import { PayoutSummary, Status } from "../types"; import { supportedChains } from "../../chains.config"; import { Allocation, InitializeParams, InitializeParamsGov, InitializeParamsHats, Recipient, RegisterData, SetAllocatorData, StrategyType, } from "./types"; export class MicroGrantsStrategy { private client: PublicClient<Transport, Chain>; private contract: any; private strategy: `0x${string}` | undefined; private poolId: bigint; private allo: Allo; constructor({ chain, rpc, address, poolId }: ConstructorArgs) { const usedChain = extractChain({ chains: supportedChains, id: chain as any, }); this.client = create(usedChain, rpc); this.allo = new Allo({ chain, rpc }); // to call allocate if (address) { this.contract = getContract({ address: address, abi: microGrantsAbi, client: { public: this.client, } }); this.strategy = address; } this.poolId = poolId || BigInt(-1); } public async setPoolId(poolId: bigint): Promise<void> { this.poolId = poolId; const strategyAddress = await this.allo.getStrategy(poolId); this.setContract(strategyAddress as `0x${string}`); } public setContract(address: `0x${string}`): void { this.contract = getContract({ address: address, abi: microGrantsAbi, client: { public: this.client, } }); this.strategy = address; } private checkPoolId(): void { if (this.poolId === BigInt(-1)) throw new Error( "MicroGrantsStrategy: No poolId provided. Please call `setPoolId` first.", ); } private checkStrategy(): void { if (!this.strategy) throw new Error( "MicroGrantsStrategy: No strategy address provided. Please call `setContract` first.", ); } public async getNative(): Promise<string> { this.checkStrategy(); const native = await this.contract.read.NATIVE(); return native; } public async allocator(allocatorAddress: string): Promise<boolean> { this.checkStrategy(); const allocator = await this.contract.read.allocators([allocatorAddress]); return allocator; } public async allocated( allocatorAddress: string, recipientAddress: string, ): Promise<boolean> { this.checkStrategy(); const allocated = await this.contract.read.allocated([ allocatorAddress, recipientAddress, ]); return allocated; } public async allocationEndTime(): Promise<bigint> { this.checkStrategy(); const endTime = await this.contract.read.allocationEndTime(); return endTime; } public async allocationStartTime(): Promise<bigint> { this.checkStrategy(); const startTime = await this.contract.read.allocationStartTime(); return startTime; } public async approvalThreshold(): Promise<string> { this.checkStrategy(); const threshold = await this.contract.read.approvalThreshold(); return threshold; } public async getAllo(): Promise<Allo> { return this.allo; } public async getPayouts(recipientIds: string[]): Promise<PayoutSummary[]> { this.checkStrategy(); const emptyData = Array(recipientIds.length).fill("0x"); const payouts = await this.contract.read.getPayouts([ recipientIds, emptyData, ]); const payoutSummary: PayoutSummary[] = payouts.map((payout: any) => { this.checkStrategy(); return { address: payout.recipientAddress, amount: payout.amount, }; }); return payoutSummary; } public async getPoolAmount(): Promise<bigint> { this.checkStrategy(); const amount = await this.contract.read.getPoolAmount(); return amount; } public async getPoolId(): Promise<bigint> { this.checkStrategy(); const poolId = await this.contract.read.getPoolId(); return poolId; } public async getRecipient(recipientId: string): Promise<Recipient> { this.checkStrategy(); const recipient = await this.contract.read.getRecipient([recipientId]); return recipient; } public async getRecipientStatus(recipientId: string): Promise<Status> { this.checkStrategy(); const status = await this.contract.read.getRecipientStatus([recipientId]); return status; } public async getStrategyId(): Promise<string> { this.checkStrategy(); const id = await this.contract.read.getStrategyId(); return id; } public async isPoolActive(): Promise<boolean> { this.checkStrategy(); const active = await this.contract.read.isPoolActive(); return active; } public async isValidAllocator(allocatorAddress: string): Promise<boolean> { this.checkStrategy(); const valid = await this.contract.read.isValidAllocator([allocatorAddress]); return valid; } public async recipientAllocations( recipientId: string, status: Status, ): Promise<string> { this.checkStrategy(); const allocations = await this.contract.read.recipientAllocations([ recipientId, status, ]); return allocations; } public async maxRequestedAmount(): Promise<bigint> { this.checkStrategy(); const maxRequestedAmount = await this.contract.read.maxRequestedAmount(); return maxRequestedAmount; } public async useRegistryAnchor(): Promise<boolean> { this.checkStrategy(); const useRegistryAnchor = await this.contract.read.useRegistryAnchor(); return useRegistryAnchor; } public async getHatsAddress(): Promise<`0x${string}`> { this.checkStrategy(); const contractReader = getContract({ address: this.strategy!, abi: microGrantsHatsAbi, client: { public: this.client, } }); const hatsAddress: `0x${string}` = (await contractReader.read.hats()) as `0x${string}`; return hatsAddress; } public async getHatId(): Promise<bigint> { this.checkStrategy(); const contractReader = getContract({ address: this.strategy!, abi: microGrantsHatsAbi, client: { public: this.client, } }); const hatId: bigint = (await contractReader.read.hatId()) as bigint; return hatId; } public async getGovAddress(): Promise<`0x${string}`> { this.checkStrategy(); const contractReader = getContract({ address: this.strategy!, abi: microGrantsGovAbi, client: { public: this.client, } }); const govAddress: `0x${string}` = (await contractReader.read.gov()) as `0x${string}`; return govAddress; } public async getSnapshotReference(): Promise<bigint> { this.checkStrategy(); const contractReader = getContract({ address: this.strategy!, abi: microGrantsGovAbi, client: { public: this.client, } }); const reference: bigint = (await contractReader.read.snapshotReference()) as bigint; return reference; } public async getMinimumVotePower(): Promise<bigint> { this.checkStrategy(); const contractReader = getContract({ address: this.strategy!, abi: microGrantsGovAbi, client: { public: this.client, } }); const votePower: bigint = (await contractReader.read.minVotePower()) as bigint; return votePower; } public async getStrategyContractId( strategyContract: string, ): Promise<{ strategyId: `0x${string}` }> { const contractReader = getContract({ address: strategyContract as `0x${string}`, abi: microGrantsGovAbi, client: { public: this.client, } }); const strategyId = await contractReader.read.getStrategyId(); switch (strategyId) { case "0x697f0592ebd05466d2d24454477e11d69c475d7a7c4134f15ddc1ea9811bb16f": return { strategyId: strategyId, }; case "0x741ac1e2f387d83f219f6b5349d35ec34902cf94019d117335e0045d2e0ed912": return { strategyId: strategyId, }; case "0x5aa24dcfcd55a1e059a172e987b3456736b4856c71e57aaf52e9a965897318dd": return { strategyId: strategyId, }; case "0xb87f34c0968bd74d43a6a5b72831a5ea733a4783a026b9fc9b1d17adf51214d2": return { strategyId: strategyId, }; case "0x414f2ea9b91b8ee2e35a380fa0af0e14079832cc93530a61a4893b3dbf0a9aba": return { strategyId: strategyId, }; case "0xed28ce0387d1786c1a38404047e9eecc4d1dcaeff695b867e912483e36c3d770": return { strategyId: strategyId, }; case "0xc5263e972c91d7ff40708bc71239a2b6cbc8768704e210ca3069e2e11fc195df": return { strategyId: strategyId, }; case "0xecc48557f4826bd1181a4495232d6d07f248ef9cc0a650e64520f6c9f7458a8c": return { strategyId: strategyId, }; default: return { strategyId: "0x", }; } } public async getInitializeData( params: InitializeParams, ): Promise<`0x${string}`> { const encoded: `0x${string}` = encodeAbiParameters( parseAbiParameters("bool, uint64, uint64, uint256, uint256"), [ params.useRegistryAnchor, params.allocationStartTime, params.allocationEndTime, params.approvalThreshold, params.maxRequestedAmount, ], ); return encoded; } public async getInitializeDataHats( params: InitializeParamsHats, ): Promise<`0x${string}`> { const encoded: `0x${string}` = encodeAbiParameters( parseAbiParameters( "(bool, uint64, uint64, uint256, uint256), address, uint256", ), [ [ params.useRegistryAnchor, params.allocationStartTime, params.allocationEndTime, params.approvalThreshold, params.maxRequestedAmount, ], params.hats, params.hatId, ], ); return encoded; } public async getInitializeDataGov( params: InitializeParamsGov, ): Promise<`0x${string}`> { const encoded: `0x${string}` = encodeAbiParameters( parseAbiParameters( "bool, uint64, uint64, uint256, uint256, address, uint256, uint256", ), [ params.useRegistryAnchor, params.allocationStartTime, params.allocationEndTime, params.approvalThreshold, params.maxRequestedAmount, params.gov, params.snapshotReference, params.minVotePower, ], ); console.log(params); return encoded; } public getDeployParams(strategyType: string): DeployParams { const constructorArgs: `0x${string}` = encodeAbiParameters( parseAbiParameters("address, string"), [this.allo.address(), strategyType], ); const constructorArgsNo0x = constructorArgs.slice(2); // create the proper bytecode const bytecode = strategyType == StrategyType.Gov ? microGrantsGovBytecode : strategyType == StrategyType.Hats ? microGrantsHatsBytecode : microGrantsBytecode; const abi = strategyType == StrategyType.Gov ? microGrantsGovAbi : strategyType == StrategyType.Hats ? microGrantsHatsAbi : microGrantsAbi; return { abi: abi, bytecode: (bytecode + constructorArgsNo0x) as unknown as `0x${string}`, }; } public getBatchAllocationData(allocations: Allocation[]): TransactionData { this.checkPoolId(); const encodedParams: `0x${string}`[] = []; allocations.forEach((allocation) => { const encoded: `0x${string}` = encodeAbiParameters( parseAbiParameters("address, uint8"), [allocation.recipientId, allocation.status], ); encodedParams.push(encoded); }); const poolIds: bigint[] = Array(encodedParams.length).fill(this.poolId); const encodedData = encodeFunctionData({ abi: alloAbi, functionName: "batchAllocate", args: [poolIds, encodedParams], }); return { to: this.allo.address(), data: encodedData, value: "0", }; } public getAllocationData( recipientId: `0x${string}`, status: Status, ): TransactionData { this.checkPoolId(); const encoded: `0x${string}` = encodeAbiParameters( parseAbiParameters("address, uint8"), [recipientId, status], ); const encodedData = encodeFunctionData({ abi: alloAbi, functionName: "allocate", args: [this.poolId, encoded], }); return { to: this.allo.address(), data: encodedData, value: "0", }; } public getRegisterRecipientData(data: RegisterData): TransactionData { this.checkPoolId(); const encoded: `0x${string}` = encodeAbiParameters( parseAbiParameters("address, address, uint256, (uint256, string)"), [ data.registryAnchor || ZERO_ADDRESS, data.recipientAddress, data.requestedAmount, [data.metadata.protocol, data.metadata.pointer], ], ); const encodedData = encodeFunctionData({ abi: alloAbi, functionName: "registerRecipient", args: [this.poolId, encoded], }); return { to: this.allo.address(), data: encodedData, value: "0", }; } public getBatchRegisterRecipientData(data: RegisterData[]): TransactionData { this.checkPoolId(); const encodedParams: `0x${string}`[] = []; data.forEach((registerData) => { const encoded: `0x${string}` = encodeAbiParameters( parseAbiParameters("address, address, uint256, (uint256, string)"), [ registerData.registryAnchor || ZERO_ADDRESS, registerData.recipientAddress, registerData.requestedAmount, [registerData.metadata.protocol, registerData.metadata.pointer], ], ); encodedParams.push(encoded); }); const poolIds: bigint[] = Array(encodedParams.length).fill(this.poolId); const encodedData = encodeFunctionData({ abi: alloAbi, functionName: "batchRegisterRecipient", args: [poolIds, encodedParams], }); return { to: this.allo.address(), data: encodedData, value: "0", }; } public getIncreasemaxRequestedAmountData(amount: bigint): TransactionData { this.checkStrategy(); const encodedData = encodeFunctionData({ abi: microGrantsAbi, functionName: "increasemaxRequestedAmountAllowed", args: [amount], }); return { to: this.strategy!, data: encodedData, value: "0", }; } public getSetAllocatorData(data: SetAllocatorData): TransactionData { this.checkStrategy(); const encodedData = encodeFunctionData({ abi: microGrantsAbi, functionName: "setAllocator", args: [data.allocatorAddress, data.flag], }); return { to: this.strategy!, data: encodedData, value: "0", }; } public getBatchSetAllocatorData(data: SetAllocatorData[]): TransactionData { this.checkStrategy(); const allocatorArray: `0x${string}`[] = []; const flagArray: boolean[] = []; data.map((allocator) => { allocatorArray.push(allocator.allocatorAddress); flagArray.push(allocator.flag); }); const encodedData = encodeFunctionData({ abi: microGrantsAbi, functionName: "batchSetAllocator", args: [allocatorArray, flagArray], }); return { to: this.strategy!, data: encodedData, value: "0", }; } public getUpdatePoolTimestampsData( allocationStartTime: bigint, allocationEndTime: bigint, ): TransactionData { this.checkStrategy(); const encodedData = encodeFunctionData({ abi: microGrantsAbi, functionName: "updatePoolTimestamps", args: [allocationStartTime, allocationEndTime], }); return { to: this.strategy!, data: encodedData, value: "0", }; } }