From b757f452537d2162b03aace78a045a6b424334c5 Mon Sep 17 00:00:00 2001 From: hh Date: Tue, 7 Jan 2025 18:01:44 +0330 Subject: [PATCH 1/4] feat: add auto transfer configs --- src/helpers/web3.ts | 35 ++++++++++++++++++++++++++ src/parser/permit-generation-module.ts | 29 +++++++++++++++++++++ src/types/plugin-input.ts | 18 ++++++++++++- 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/helpers/web3.ts b/src/helpers/web3.ts index e7f8febc..87b2884e 100644 --- a/src/helpers/web3.ts +++ b/src/helpers/web3.ts @@ -34,3 +34,38 @@ export async function getErc20TokenSymbol(networkId: number, tokenAddress: strin const contract = new ethers.Contract(tokenAddress, abi, provider); return await contract.symbol(); } + +/** + * Returns ERC20 token balance of the funding wallet + * @param networkId Network id + * @param tokenAddress ERC20 token address + * @param fundingWalledAddress funding wallet address + * @returns ERC20 token balance of the funding wallet + */ +export async function getFundingWalletBalance(networkId: number, tokenAddress: string, fundingWalledAddress: string) { + const abi = ["function balanceOf(address) view returns (uint256)"]; + + // get fastest RPC + const config: HandlerConstructorConfig = { + networkName: null, + networkRpcs: null, + proxySettings: { + retryCount: 5, + retryDelay: 500, + logTier: null, + logger: null, + strictLogs: false, + }, + runtimeRpcs: null, + networkId: String(networkId) as NetworkId, + rpcTimeout: 1500, + autoStorage: false, + cacheRefreshCycles: 10, + }; + const handler = new RPCHandler(config); + const provider = await handler.getFastestRpcProvider(); + + // fetch token symbol + const contract = new ethers.Contract(tokenAddress, abi, provider); + return await contract.balanceOf(fundingWalledAddress); +} diff --git a/src/parser/permit-generation-module.ts b/src/parser/permit-generation-module.ts index 1e213344..c537fce3 100644 --- a/src/parser/permit-generation-module.ts +++ b/src/parser/permit-generation-module.ts @@ -25,6 +25,7 @@ import { EnvConfig } from "../types/env-type"; import { BaseModule } from "../types/module"; import { Result } from "../types/results"; import { isAdmin, isCollaborative } from "../helpers/checkers"; +import { getFundingWalletBalance } from "../helpers/web3"; interface Payload { evmNetworkId: number; @@ -36,6 +37,10 @@ interface Payload { export class PermitGenerationModule extends BaseModule { readonly _configuration: PermitGenerationConfiguration | null = this.context.config.incentives.permitGeneration; + readonly _autoTransferMode: boolean = this.context.config.automaticTransferMode; + readonly _fundingWalletAddress: string = this.context.config.fundingWalletAddress; + readonly _evmNetworkId: number = this.context.config.evmNetworkId; + readonly _erc20RewardToken: string = this.context.config.erc20RewardToken; readonly _supabase = createClient(this.context.env.SUPABASE_URL, this.context.env.SUPABASE_KEY); async transform(data: Readonly, result: Result): Promise { @@ -45,6 +50,22 @@ export class PermitGenerationModule extends BaseModule { this.context.logger.error("[PermitGenerationModule] Non collaborative issue detected, skipping."); return Promise.resolve(result); } + + const sumPayouts = await this._sumPayouts(result); + const fundingWalletBalance = await getFundingWalletBalance( + this._evmNetworkId, + this._erc20RewardToken, + this._fundingWalletAddress + ); + + if (this._autoTransferMode && sumPayouts < fundingWalletBalance) { + this.context.logger.debug( + "[PermitGenerationModule] AutoTransformMode is enabled, " + + "and sufficient funds are available in the funding wallet, skipping." + ); + return Promise.resolve(result); + } + const payload: Context["payload"] & Payload = { ...context.payload.inputs, issueUrl: this.context.payload.issue.html_url, @@ -207,6 +228,14 @@ export class PermitGenerationModule extends BaseModule { return isCollaborative(data); } + async _sumPayouts(result: Result) { + let sumPayouts = 0; + for (const value of Object.values(result)) { + sumPayouts += value.total; + } + return sumPayouts; + } + _deductFeeFromReward( result: Result, treasuryGithubData: RestEndpointMethodTypes["users"]["getByUsername"]["response"]["data"] diff --git a/src/types/plugin-input.ts b/src/types/plugin-input.ts index 1ac7d5ee..4344e6da 100644 --- a/src/types/plugin-input.ts +++ b/src/types/plugin-input.ts @@ -19,13 +19,29 @@ export const pluginSettingsSchema = T.Object( * The encrypted key to use for permit generation */ evmPrivateEncrypted: T.String({ - description: "The encrypted key to use for permit generation", + description: "The encrypted key to use for permit generation and auto transfers", + examples: ["0x000..."], + }), + /** + * Funding wallet address (corresponding to evmPrivateEncrypted) + */ + fundingWalletAddress: T.String({ + description: "The funding wallet address", examples: ["0x000..."], }), /** * Reward token for ERC20 permits, default WXDAI for gnosis chain */ erc20RewardToken: T.String({ default: "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d" }), + /** + * If set to false or if there are insufficient funds to settle the payment, + * permits will be generated instead of processing direct payouts. + */ + automaticTransferMode: T.Boolean({ + default: true, + description: + "If set to false or if there are insufficient funds to settle the payment, permits will be generated instead of processing direct payouts.", + }), incentives: T.Object( { /** From c7d396ef1e0950a1d74403ef4751390997edcb98 Mon Sep 17 00:00:00 2001 From: hh Date: Tue, 7 Jan 2025 19:58:22 +0330 Subject: [PATCH 2/4] feat: add the payment module --- src/helpers/web3.ts | 40 +++++- ...generation-module.ts => payment-module.ts} | 118 +++++++++++------- src/parser/processor.ts | 4 +- src/types/results.ts | 1 + 4 files changed, 115 insertions(+), 48 deletions(-) rename src/parser/{permit-generation-module.ts => payment-module.ts} (86%) diff --git a/src/helpers/web3.ts b/src/helpers/web3.ts index 87b2884e..aab0c02b 100644 --- a/src/helpers/web3.ts +++ b/src/helpers/web3.ts @@ -65,7 +65,45 @@ export async function getFundingWalletBalance(networkId: number, tokenAddress: s const handler = new RPCHandler(config); const provider = await handler.getFastestRpcProvider(); - // fetch token symbol + // fetch token balance const contract = new ethers.Contract(tokenAddress, abi, provider); return await contract.balanceOf(fundingWalledAddress); } + +/** + * Returns Transaction for the ERC20 token transfer + * @param networkId Network id + * @param tokenAddress ERC20 token address + * @param _evmPrivateEncrypted encrypted private key of the funding wallet address + * @param to reciever address + * @param amount Amount of ERC20 token to be transfered + * @returns Transaction for the ERC20 token transfer + */ +export async function transferTo(networkId: number, tokenAddress: string, _evmPrivateEncrypted: string, to: string, amount: string) { + const abi = ["function transfer(address,uint256) public returns (bool)"]; + + // get fastest RPC + const config: HandlerConstructorConfig = { + networkName: null, + networkRpcs: null, + proxySettings: { + retryCount: 5, + retryDelay: 500, + logTier: null, + logger: null, + strictLogs: false, + }, + runtimeRpcs: null, + networkId: String(networkId) as NetworkId, + rpcTimeout: 1500, + autoStorage: false, + cacheRefreshCycles: 10, + }; + const handler = new RPCHandler(config); + const provider = await handler.getFastestRpcProvider(); + + // send the transaction + // TODO: sign the transaction + const contract = new ethers.Contract(tokenAddress, abi, provider); + return await contract.transfer(to, amount); +} diff --git a/src/parser/permit-generation-module.ts b/src/parser/payment-module.ts similarity index 86% rename from src/parser/permit-generation-module.ts rename to src/parser/payment-module.ts index c537fce3..026ff0e7 100644 --- a/src/parser/permit-generation-module.ts +++ b/src/parser/payment-module.ts @@ -35,7 +35,7 @@ interface Payload { issue: { node_id: string }; } -export class PermitGenerationModule extends BaseModule { +export class PaymentModule extends BaseModule { readonly _configuration: PermitGenerationConfiguration | null = this.context.config.incentives.permitGeneration; readonly _autoTransferMode: boolean = this.context.config.automaticTransferMode; readonly _fundingWalletAddress: string = this.context.config.fundingWalletAddress; @@ -44,10 +44,10 @@ export class PermitGenerationModule extends BaseModule { readonly _supabase = createClient(this.context.env.SUPABASE_URL, this.context.env.SUPABASE_KEY); async transform(data: Readonly, result: Result): Promise { - const canGeneratePermits = await this._canGeneratePermit(data); + const canMakePayment = await this._canMakePayment(data); - if (!canGeneratePermits) { - this.context.logger.error("[PermitGenerationModule] Non collaborative issue detected, skipping."); + if (!canMakePayment) { + this.context.logger.error("[PaymentModule] Non collaborative issue detected, skipping."); return Promise.resolve(result); } @@ -58,12 +58,13 @@ export class PermitGenerationModule extends BaseModule { this._fundingWalletAddress ); + let shouldTransferDirectly = false; if (this._autoTransferMode && sumPayouts < fundingWalletBalance) { this.context.logger.debug( - "[PermitGenerationModule] AutoTransformMode is enabled, " + - "and sufficient funds are available in the funding wallet, skipping." + "[PaymentModule] AutoTransformMode is enabled, " + + "and sufficient funds are available in the funding wallet, skipping." ); - return Promise.resolve(result); + shouldTransferDirectly = true; } const payload: Context["payload"] & Payload = { @@ -86,7 +87,7 @@ export class PermitGenerationModule extends BaseModule { ); if (!isPrivateKeyAllowed) { this.context.logger.error( - "[PermitGenerationModule] Private key is not allowed to be used in this organization/repository." + "[PaymentModule] Private key is not allowed to be used in this organization/repository." ); return Promise.resolve(result); } @@ -117,21 +118,23 @@ export class PermitGenerationModule extends BaseModule { for (const [key, value] of Object.entries(result)) { this.context.logger.debug(`Updating result for user ${key}`); - try { - const config: Context["config"] = { - evmNetworkId: payload.evmNetworkId, - evmPrivateEncrypted: payload.evmPrivateEncrypted, - permitRequests: [ - { - amount: value.total, - username: key, - contributionType: "", - type: TokenType.ERC20, - tokenAddress: payload.erc20RewardToken, - }, - ], - }; - const permits = await generatePayoutPermit( + const config: Context["config"] = { + evmNetworkId: payload.evmNetworkId, + evmPrivateEncrypted: payload.evmPrivateEncrypted, + permitRequests: [ + { + amount: value.total, + username: key, + contributionType: "", + type: TokenType.ERC20, + tokenAddress: payload.erc20RewardToken, + }, + ], + }; + + if (shouldTransferDirectly) { + + const txid = await transferErc20( { env, eventName, @@ -151,17 +154,56 @@ export class PermitGenerationModule extends BaseModule { }, config.permitRequests ); - result[key].permitUrl = `https://pay.ubq.fi?claim=${encodePermits(permits)}`; - await this._savePermitsToDatabase(result[key].userId, { issueUrl: payload.issueUrl, issueId }, permits); - } catch (e) { - this.context.logger.error(`[PermitGenerationModule] Failed to generate permits for user ${key}`, { e }); + result[key].permitUrl = `https://gnosisscan.io/tx/${txid}`; + //TODO: We need to save this record in the database + } else { + try { + const permits = await generatePayoutPermit( + { + env, + eventName, + logger: permitLogger, + payload, + adapters: createAdapters(this._supabase, { + env, + eventName, + octokit, + config, + logger: permitLogger, + payload, + adapters, + }), + octokit, + config, + }, + config.permitRequests + ); + result[key].permitUrl = `https://pay.ubq.fi?claim=${encodePermits(permits)}`; + await this._savePermitsToDatabase(result[key].userId, { issueUrl: payload.issueUrl, issueId }, permits); + // remove treasury item from final result in order not to display permit fee in GitHub comments + if (env.PERMIT_TREASURY_GITHUB_USERNAME) delete result[env.PERMIT_TREASURY_GITHUB_USERNAME]; + } catch (e) { + this.context.logger.error(`[PaymentModule] Failed to generate permits for user ${key}`, { e }); + } } } + return result; + } - // remove treasury item from final result in order not to display permit fee in GitHub comments - if (env.PERMIT_TREASURY_GITHUB_USERNAME) delete result[env.PERMIT_TREASURY_GITHUB_USERNAME]; + async _sumPayouts(result: Result) { + let sumPayouts = 0; + for (const value of Object.values(result)) { + sumPayouts += value.total; + } + return sumPayouts; + } - return result; + async _canMakePayment(data: Readonly) { + if (!data.self?.closed_by || !data.self.user) return false; + + if (await isAdmin(data.self.user.login, this.context)) return true; + + return isCollaborative(data); } /** @@ -220,21 +262,7 @@ export class PermitGenerationModule extends BaseModule { return this._deductFeeFromReward(result, treasuryGithubData); } - async _canGeneratePermit(data: Readonly) { - if (!data.self?.closed_by || !data.self.user) return false; - if (await isAdmin(data.self.user.login, this.context)) return true; - - return isCollaborative(data); - } - - async _sumPayouts(result: Result) { - let sumPayouts = 0; - for (const value of Object.values(result)) { - sumPayouts += value.total; - } - return sumPayouts; - } _deductFeeFromReward( result: Result, @@ -417,7 +445,7 @@ export class PermitGenerationModule extends BaseModule { get enabled(): boolean { if (!Value.Check(permitGenerationConfigurationType, this._configuration)) { - this.context.logger.error("Invalid / missing configuration detected for PermitGenerationModule, disabling."); + this.context.logger.error("Invalid / missing configuration detected for PaymentModule, disabling."); return false; } return true; diff --git a/src/parser/processor.ts b/src/parser/processor.ts index b87e738c..9f100bbb 100644 --- a/src/parser/processor.ts +++ b/src/parser/processor.ts @@ -9,7 +9,7 @@ import { ContentEvaluatorModule } from "./content-evaluator-module"; import { DataPurgeModule } from "./data-purge-module"; import { FormattingEvaluatorModule } from "./formatting-evaluator-module"; import { GithubCommentModule } from "./github-comment-module"; -import { PermitGenerationModule } from "./permit-generation-module"; +import { PaymentModule } from "./payment-module"; import { UserExtractorModule } from "./user-extractor-module"; import { getTaskReward } from "../helpers/label-price-extractor"; import { GitHubIssue } from "../github-types"; @@ -25,7 +25,7 @@ export class Processor { .add(new DataPurgeModule(context)) .add(new FormattingEvaluatorModule(context)) .add(new ContentEvaluatorModule(context)) - .add(new PermitGenerationModule(context)) + .add(new PaymentModule(context)) .add(new GithubCommentModule(context)); this._context = context; this._configuration = this._context.config.incentives; diff --git a/src/types/results.ts b/src/types/results.ts index 8f405152..f0c746c5 100644 --- a/src/types/results.ts +++ b/src/types/results.ts @@ -10,6 +10,7 @@ export interface Result { }; feeRate?: number; permitUrl?: string; + explorerUrl?: string; userId: number; evaluationCommentHtml?: string; }; From 0a9fc5893789a107b4a9d9d84998e8d47c013d90 Mon Sep 17 00:00:00 2001 From: hh Date: Wed, 8 Jan 2025 08:37:04 +0330 Subject: [PATCH 3/4] feat: add direct transfer --- src/helpers/web3.ts | 138 ++++++++++++++++++++--------------- src/parser/payment-module.ts | 43 +++++++---- 2 files changed, 105 insertions(+), 76 deletions(-) diff --git a/src/helpers/web3.ts b/src/helpers/web3.ts index aab0c02b..e448b501 100644 --- a/src/helpers/web3.ts +++ b/src/helpers/web3.ts @@ -1,14 +1,36 @@ import { RPCHandler, HandlerConstructorConfig, NetworkId } from "@ubiquity-dao/rpc-handler"; -import { ethers } from "ethers"; +import { Context } from "@ubiquity-os/permit-generation"; +import { ethers, utils } from "ethers"; /** - * Returns ERC20 token symbol + * Returns the funding wallet + * @param privateKey of the funding wallet + * @param provider ethers.Provider + * @returns the funding wallet + */ +async function getFundingWallet(privateKey: string, provider: ethers.providers.Provider) { + try { + return new ethers.Wallet(privateKey, provider); + } catch (error) { + const errorMessage = `Failed to instantiate wallet: ${error}`; + throw new Error(errorMessage); + } +} + +/** + * Returns ERC20 token contract * @param networkId Network id * @param tokenAddress ERC20 token address - * @returns ERC20 token symbol + * @returns ERC20 token contract */ -export async function getErc20TokenSymbol(networkId: number, tokenAddress: string) { - const abi = ["function symbol() view returns (string)"]; + +async function getErc20TokenContract(networkId: number, tokenAddress: string) { + const abi = [ + "function symbol() view returns (string)", + "function decimals() public view returns (uint8)", + "function balanceOf(address) view returns (uint256)", + "function transfer(address,uint256) public returns (bool)", + ]; // get fastest RPC const config: HandlerConstructorConfig = { @@ -30,9 +52,26 @@ export async function getErc20TokenSymbol(networkId: number, tokenAddress: strin const handler = new RPCHandler(config); const provider = await handler.getFastestRpcProvider(); - // fetch token symbol - const contract = new ethers.Contract(tokenAddress, abi, provider); - return await contract.symbol(); + return new ethers.Contract(tokenAddress, abi, provider); +} +/** + * Returns ERC20 token symbol + * @param networkId Network id + * @param tokenAddress ERC20 token address + * @returns ERC20 token symbol + */ +export async function getErc20TokenSymbol(networkId: number, tokenAddress: string) { + return await (await getErc20TokenContract(networkId, tokenAddress)).symbol(); +} + +/** + * Returns ERC20 token decimals + * @param networkId Network id + * @param tokenAddress ERC20 token address + * @returns ERC20 token decimals + */ +async function getErc20TokenDecimals(networkId: number, tokenAddress: string) { + return await (await getErc20TokenContract(networkId, tokenAddress)).decimals(); } /** @@ -42,32 +81,10 @@ export async function getErc20TokenSymbol(networkId: number, tokenAddress: strin * @param fundingWalledAddress funding wallet address * @returns ERC20 token balance of the funding wallet */ -export async function getFundingWalletBalance(networkId: number, tokenAddress: string, fundingWalledAddress: string) { - const abi = ["function balanceOf(address) view returns (uint256)"]; - - // get fastest RPC - const config: HandlerConstructorConfig = { - networkName: null, - networkRpcs: null, - proxySettings: { - retryCount: 5, - retryDelay: 500, - logTier: null, - logger: null, - strictLogs: false, - }, - runtimeRpcs: null, - networkId: String(networkId) as NetworkId, - rpcTimeout: 1500, - autoStorage: false, - cacheRefreshCycles: 10, - }; - const handler = new RPCHandler(config); - const provider = await handler.getFastestRpcProvider(); - - // fetch token balance - const contract = new ethers.Contract(tokenAddress, abi, provider); - return await contract.balanceOf(fundingWalledAddress); +export async function getFundingWalletBalance(networkId: number, tokenAddress: string, privateKey: string) { + const contract = await getErc20TokenContract(networkId, tokenAddress); + const fundingWallet = await getFundingWallet(privateKey, contract.provider); + return await contract.balanceOf(await fundingWallet.getAddress()); } /** @@ -75,35 +92,36 @@ export async function getFundingWalletBalance(networkId: number, tokenAddress: s * @param networkId Network id * @param tokenAddress ERC20 token address * @param _evmPrivateEncrypted encrypted private key of the funding wallet address - * @param to reciever address - * @param amount Amount of ERC20 token to be transfered + * @param username github user name of the beneficiary + * @param amount Amount of ERC20 token to be transferred * @returns Transaction for the ERC20 token transfer */ -export async function transferTo(networkId: number, tokenAddress: string, _evmPrivateEncrypted: string, to: string, amount: string) { - const abi = ["function transfer(address,uint256) public returns (bool)"]; +export async function transferFromFundingWallet( + context: Context, + networkId: number, + tokenAddress: string, + privateKey: string, + username: string, + amount: string +) { + // Obtain the beneficiary wallet address from the github user name + const { data: userData } = await context.octokit.rest.users.getByUsername({ username }); + if (!userData) { + throw new Error(`GitHub user was not found for id ${username}`); + } + const userId = userData.id; + const { wallet } = context.adapters.supabase; + const beneficiaryWalletAddress = await wallet.getWalletByUserId(userId); + if (!beneficiaryWalletAddress) { + throw new Error("Beneficiary wallet not found"); + } - // get fastest RPC - const config: HandlerConstructorConfig = { - networkName: null, - networkRpcs: null, - proxySettings: { - retryCount: 5, - retryDelay: 500, - logTier: null, - logger: null, - strictLogs: false, - }, - runtimeRpcs: null, - networkId: String(networkId) as NetworkId, - rpcTimeout: 1500, - autoStorage: false, - cacheRefreshCycles: 10, - }; - const handler = new RPCHandler(config); - const provider = await handler.getFastestRpcProvider(); + const tokenDecimals = await getErc20TokenDecimals(networkId, tokenAddress); + const _contract = await getErc20TokenContract(networkId, tokenAddress); + // Construct the funding wallet from the privateKey + const fundingWallet = await getFundingWallet(privateKey, _contract.provider); // send the transaction - // TODO: sign the transaction - const contract = new ethers.Contract(tokenAddress, abi, provider); - return await contract.transfer(to, amount); + const contract = new ethers.Contract(tokenAddress, _contract.abi, fundingWallet); + return await contract.transfer(beneficiaryWalletAddress, utils.parseUnits(amount, tokenDecimals)); } diff --git a/src/parser/payment-module.ts b/src/parser/payment-module.ts index 026ff0e7..1b33576d 100644 --- a/src/parser/payment-module.ts +++ b/src/parser/payment-module.ts @@ -25,7 +25,7 @@ import { EnvConfig } from "../types/env-type"; import { BaseModule } from "../types/module"; import { Result } from "../types/results"; import { isAdmin, isCollaborative } from "../helpers/checkers"; -import { getFundingWalletBalance } from "../helpers/web3"; +import { getFundingWalletBalance, transferFromFundingWallet } from "../helpers/web3"; interface Payload { evmNetworkId: number; @@ -38,31 +38,27 @@ interface Payload { export class PaymentModule extends BaseModule { readonly _configuration: PermitGenerationConfiguration | null = this.context.config.incentives.permitGeneration; readonly _autoTransferMode: boolean = this.context.config.automaticTransferMode; - readonly _fundingWalletAddress: string = this.context.config.fundingWalletAddress; + readonly _evmPrivateEncrypted: string = this.context.config.evmPrivateEncrypted; readonly _evmNetworkId: number = this.context.config.evmNetworkId; readonly _erc20RewardToken: string = this.context.config.erc20RewardToken; readonly _supabase = createClient(this.context.env.SUPABASE_URL, this.context.env.SUPABASE_KEY); async transform(data: Readonly, result: Result): Promise { const canMakePayment = await this._canMakePayment(data); - + const privateKey = await this._getPrivateKey(this._evmPrivateEncrypted); if (!canMakePayment) { this.context.logger.error("[PaymentModule] Non collaborative issue detected, skipping."); return Promise.resolve(result); } const sumPayouts = await this._sumPayouts(result); - const fundingWalletBalance = await getFundingWalletBalance( - this._evmNetworkId, - this._erc20RewardToken, - this._fundingWalletAddress - ); + const fundingWalletBalance = await getFundingWalletBalance(this._evmNetworkId, this._erc20RewardToken, privateKey); let shouldTransferDirectly = false; if (this._autoTransferMode && sumPayouts < fundingWalletBalance) { this.context.logger.debug( "[PaymentModule] AutoTransformMode is enabled, " + - "and sufficient funds are available in the funding wallet, skipping." + "and sufficient funds are available in the funding wallet, skipping." ); shouldTransferDirectly = true; } @@ -133,8 +129,7 @@ export class PaymentModule extends BaseModule { }; if (shouldTransferDirectly) { - - const txid = await transferErc20( + const tx = await transferFromFundingWallet( { env, eventName, @@ -152,10 +147,14 @@ export class PaymentModule extends BaseModule { octokit, config, }, - config.permitRequests + + this._evmNetworkId, + this._erc20RewardToken, + privateKey, + key, + value.total.toString() ); - result[key].permitUrl = `https://gnosisscan.io/tx/${txid}`; - //TODO: We need to save this record in the database + result[key].explorerUrl = `https://gnosisscan.io/tx/${tx.hash}`; } else { try { const permits = await generatePayoutPermit( @@ -206,6 +205,20 @@ export class PaymentModule extends BaseModule { return isCollaborative(data); } + async _getPrivateKey(evmPrivateEncrypted: string) { + try { + const privateKeyDecrypted = await decrypt(evmPrivateEncrypted, String(process.env.X25519_PRIVATE_KEY)); + const privateKeyParsed = parseDecryptedPrivateKey(privateKeyDecrypted); + const privateKey = privateKeyParsed.privateKey; + if (!privateKey) throw new Error("Private key is not defined"); + return privateKey; + } catch (error) { + const errorMessage = `Failed to decrypt a private key: ${error}`; + this.context.logger.error(errorMessage); + throw new Error(errorMessage); + } + } + /** * Applies fees to the final result. * How it works: @@ -262,8 +275,6 @@ export class PaymentModule extends BaseModule { return this._deductFeeFromReward(result, treasuryGithubData); } - - _deductFeeFromReward( result: Result, treasuryGithubData: RestEndpointMethodTypes["users"]["getByUsername"]["response"]["data"] From 3142bf1d321f8aa7937a38d1cab73980cb06d311 Mon Sep 17 00:00:00 2001 From: hh Date: Wed, 8 Jan 2025 08:41:01 +0330 Subject: [PATCH 4/4] chore: remove unused plugin input --- src/types/plugin-input.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/types/plugin-input.ts b/src/types/plugin-input.ts index 4344e6da..635538f6 100644 --- a/src/types/plugin-input.ts +++ b/src/types/plugin-input.ts @@ -22,13 +22,6 @@ export const pluginSettingsSchema = T.Object( description: "The encrypted key to use for permit generation and auto transfers", examples: ["0x000..."], }), - /** - * Funding wallet address (corresponding to evmPrivateEncrypted) - */ - fundingWalletAddress: T.String({ - description: "The funding wallet address", - examples: ["0x000..."], - }), /** * Reward token for ERC20 permits, default WXDAI for gnosis chain */