diff --git a/src/bindings/config.ts b/src/bindings/config.ts index 43b5718fa..4599436ef 100644 --- a/src/bindings/config.ts +++ b/src/bindings/config.ts @@ -10,7 +10,7 @@ export const loadConfig = async (context: Context): Promise => { const { baseMultiplier, timeLabels, - privateKey, + privateKeyEncrypted, priorityLabels, incentives, paymentPermitMaxPrice, @@ -60,7 +60,7 @@ export const loadConfig = async (context: Context): Promise => { payout: { networkId: networkId, rpc: rpc, - privateKey: privateKey, + privateKeyEncrypted: privateKeyEncrypted || null, paymentToken: paymentToken, permitBaseUrl: process.env.PERMIT_BASE_URL || permitBaseUrl, }, @@ -113,7 +113,7 @@ export const loadConfig = async (context: Context): Promise => { newContributorGreeting: newContributorGreeting, }; - if (botConfig.payout.privateKey == "") { + if (!botConfig.payout.privateKeyEncrypted) { botConfig.mode.paymentPermitMaxPrice = 0; } diff --git a/src/handlers/payout/action.ts b/src/handlers/payout/action.ts index 25bf01562..9f996de40 100644 --- a/src/handlers/payout/action.ts +++ b/src/handlers/payout/action.ts @@ -27,7 +27,7 @@ export interface IncentivesCalculationResult { paymentToken: string; rpc: string; networkId: number; - privateKey: string; + privateKeyEncrypted: string | null; paymentPermitMaxPrice: number; baseMultiplier: number; incentives: Incentives; @@ -66,7 +66,7 @@ export interface RewardByUser { export const incentivesCalculation = async (): Promise => { const context = getBotContext(); const { - payout: { paymentToken, rpc, permitBaseUrl, networkId, privateKey }, + payout: { paymentToken, rpc, permitBaseUrl, networkId, privateKeyEncrypted }, mode: { incentiveMode, paymentPermitMaxPrice }, price: { incentives, issueCreatorMultiplier, baseMultiplier }, accessControl, @@ -147,7 +147,7 @@ export const incentivesCalculation = async (): Promise }, }; -type PayoutConfigPartial = Omit, "networkId" | "privateKey" | "permitBaseUrl">; +type PayoutConfigPartial = Omit, "networkId" | "privateKeyEncrypted" | "permitBaseUrl">; /** * Returns payout config for a particular network diff --git a/src/helpers/permit.ts b/src/helpers/permit.ts index deddcffe0..a0849529e 100644 --- a/src/helpers/permit.ts +++ b/src/helpers/permit.ts @@ -5,6 +5,7 @@ import { keccak256, toUtf8Bytes } from "ethers/lib/utils"; import Decimal from "decimal.js"; import { Payload } from "../types"; import { savePermit } from "../adapters/supabase"; +import { getPrivateKey } from "../utils/private"; const PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3"; // same on all networks @@ -59,11 +60,13 @@ export const generatePermit2Signature = async ( userId = "" ): Promise<{ txData: TxData; payoutUrl: string }> => { const { - payout: { networkId, privateKey, permitBaseUrl, rpc, paymentToken }, + payout: { networkId, privateKeyEncrypted, permitBaseUrl, rpc, paymentToken }, } = getBotConfig(); const logger = getLogger(); const provider = new ethers.providers.JsonRpcProvider(rpc); - const adminWallet = new ethers.Wallet(privateKey, provider); + + const privateKeyDecrypted = await getPrivateKey(privateKeyEncrypted); + const adminWallet = new ethers.Wallet(privateKeyDecrypted, provider); const permitTransferFromData: PermitTransferFrom = { permitted: { diff --git a/src/types/config.ts b/src/types/config.ts index a22683a28..4a807b74f 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -76,7 +76,7 @@ export type LogNotification = Static; export const PayoutConfigSchema = Type.Object({ networkId: Type.Number(), rpc: Type.String(), - privateKey: Type.String(), + privateKeyEncrypted: Type.Union([Type.Null(), Type.String()]), paymentToken: Type.String(), permitBaseUrl: Type.String(), }); diff --git a/src/utils/private.ts b/src/utils/private.ts index 44ba7fb15..57db827db 100644 --- a/src/utils/private.ts +++ b/src/utils/private.ts @@ -8,10 +8,10 @@ import { DefaultConfig } from "../configs"; import { validate } from "./ajv"; import { WideConfig, WideRepoConfig, WideConfigSchema } from "../types"; import { upsertLastCommentToIssue } from "../helpers"; +import { getLogger } from "../bindings"; const CONFIG_REPO = "ubiquibot-config"; const CONFIG_PATH = ".github/ubiquibot-config.yml"; -const KEY_NAME = "privateKeyEncrypted"; const KEY_PREFIX = "HSK_"; export const getConfigSuperset = async (context: Context, type: "org" | "repo", filePath: string): Promise => { @@ -64,17 +64,18 @@ export const getOrgAndRepoFromPath = (path: string) => { return { org, repo }; }; -export const getPrivateKey = async (cipherText: string): Promise => { +export const getPrivateKey = async (cipherText: string | null): Promise => { try { + if (!cipherText) throw new Error("Cipher text is empty"); + await _sodium.ready; const sodium = _sodium; const privateKey = process.env.X25519_PRIVATE_KEY; const publicKey = await getScalarKey(privateKey); - if (!publicKey || !privateKey) { - return undefined; - } + if (!privateKey) throw new Error("X25519_PRIVATE_KEY env variable is missing"); + if (!publicKey) throw new Error("Failed getting public key from X25519_PRIVATE_KEY env variable"); const binPub = sodium.from_base64(publicKey, sodium.base64_variants.URLSAFE_NO_PADDING); const binPriv = sodium.from_base64(privateKey, sodium.base64_variants.URLSAFE_NO_PADDING); @@ -84,7 +85,9 @@ export const getPrivateKey = async (cipherText: string): Promise { } const parsedDefault: MergedConfig = DefaultConfig; - let privateKeyDecrypted; - if (parsedRepo && parsedRepo[KEY_NAME]) { - privateKeyDecrypted = await getPrivateKey(parsedRepo[KEY_NAME]); - } else if (parsedOrg && parsedOrg[KEY_NAME]) { - privateKeyDecrypted = await getPrivateKey(parsedOrg[KEY_NAME]); - } else { - privateKeyDecrypted = undefined; - } - const configs: MergedConfigs = { parsedDefault, parsedOrg, parsedRepo }; const mergedConfigData: MergedConfig = mergeConfigs(configs); const configData = { networkId: mergedConfigData.evmNetworkId, - privateKey: privateKeyDecrypted ?? "", + privateKeyEncrypted: mergedConfigData.privateKeyEncrypted, assistivePricing: mergedConfigData.assistivePricing, commandSettings: mergedConfigData.commandSettings, baseMultiplier: mergedConfigData.priceMultiplier,