Skip to content
This repository has been archived by the owner on Sep 19, 2024. It is now read-only.

Commit

Permalink
Merge branch 'development' into default-labels
Browse files Browse the repository at this point in the history
  • Loading branch information
whilefoo authored Jul 17, 2023
2 parents 7b51b34 + e196a5b commit 9e4ae94
Show file tree
Hide file tree
Showing 15 changed files with 96 additions and 40 deletions.
3 changes: 2 additions & 1 deletion .github/ubiquibot-config.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
chain-id: 100
evm-network-id: 100
base-multiplier: 1500
time-labels:
- name: "Time: <1 Hour"
Expand Down Expand Up @@ -35,3 +35,4 @@ default-labels:
auto-pay-mode: true
analytics-mode: true
max-concurrent-bounties: 2
promotion-comment: `\n<h6>If you enjoy the DevPool experience, please follow <a href="https://github.com/ubiquity">Ubiquity on GitHub</a> and star <a href="https://github.com/ubiquity/devpool-directory">this repo</a> to show your support. It helps a lot!</h6>`
23 changes: 23 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,26 @@ jobs:

- name: Lint
run: yarn lint

run-migration:
runs-on: ubuntu-latest
needs: build
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/development')
env:
SUPABASE_ACCESS_TOKEN: ${{ github.ref == 'refs/heads/main' && secrets.PRODUCTION_SUPABASE_ACCESS_TOKEN || secrets.STAGING_SUPABASE_ACCESS_TOKEN }}
SUPABASE_DB_PASSWORD: ${{ github.ref == 'refs/heads/main' && secrets.PRODUCTION_SUPABASE_DB_PASSWORD || secrets.STAGING_SUPABASE_DB_PASSWORD }}
PROJECT_ID: ${{ github.ref == 'refs/heads/main' && secrets.PRODUCTION_SUPABASE_PROJECT_ID || secrets.STAGING_SUPABASE_PROJECT_ID }}

steps:
- name: Checkout repository
uses: actions/checkout@v3

- uses: supabase/setup-cli@v1
with:
version: latest

- name: Link Supabase project
run: supabase link --project-ref $PROJECT_ID

- name: Run migrations
run: supabase db push
12 changes: 8 additions & 4 deletions src/bindings/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import ms from "ms";

import { BotConfig, BotConfigSchema } from "../types";
import { DEFAULT_BOT_DELAY, DEFAULT_DISQUALIFY_TIME, DEFAULT_FOLLOWUP_TIME, DEFAULT_PERMIT_BASE_URL } from "../configs";
import { getPayoutConfigByChainId } from "../helpers";
import { getPayoutConfigByNetworkId } from "../helpers";
import { ajv } from "../utils";
import { Context } from "probot";
import { getScalarKey, getWideConfig } from "../utils/private";
Expand All @@ -18,13 +18,14 @@ export const loadConfig = async (context: Context): Promise<BotConfig> => {
analyticsMode,
bountyHunterMax,
incentiveMode,
chainId,
networkId,
issueCreatorMultiplier,
defaultLabels,
promotionComment,
} = await getWideConfig(context);

const publicKey = await getScalarKey(process.env.X25519_PRIVATE_KEY);
const { rpc, paymentToken } = getPayoutConfigByChainId(chainId);
const { rpc, paymentToken } = getPayoutConfigByNetworkId(networkId);

const botConfig: BotConfig = {
log: {
Expand All @@ -39,8 +40,11 @@ export const loadConfig = async (context: Context): Promise<BotConfig> => {
commentElementPricing,
defaultLabels,
},
comments: {
promotionComment: promotionComment,
},
payout: {
chainId: chainId,
networkId: networkId,
rpc: rpc,
privateKey: privateKey,
paymentToken: paymentToken,
Expand Down
3 changes: 2 additions & 1 deletion src/configs/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const COLORS = {
export const DEFAULT_BOT_DELAY = 100; // 100ms
export const DEFAULT_TIME_RANGE_FOR_MAX_ISSUE = 24;
export const DEFAULT_TIME_RANGE_FOR_MAX_ISSUE_ENABLED = true;
export const ASSIGN_COMMAND_ENABLED = true;
/**
* ms('2 days') // 172800000
* ms('1d') // 86400000
Expand All @@ -24,7 +25,7 @@ export const DEFAULT_TIME_RANGE_FOR_MAX_ISSUE_ENABLED = true;
export const DEFAULT_FOLLOWUP_TIME = "4 days"; // 4 days
export const DEFAULT_DISQUALIFY_TIME = "7 days"; // 7 days

export const DEFAULT_CHAIN_ID = 1; // ethereum
export const DEFAULT_NETWORK_ID = 1; // ethereum
export const DEFAULT_RPC_ENDPOINT = "https://rpc-bot.ubq.fi/v1/mainnet";
export const DEFAULT_PERMIT_BASE_URL = "https://pay.ubq.fi";
export const COMMAND_INSTRUCTIONS = generateHelpMenu();
1 change: 1 addition & 0 deletions src/configs/strings.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const GLOBAL_STRINGS = {
unassignComment: "Releasing the bounty back to dev pool because the allocated duration already ended!",
askUpdate: "Do you have any updates",
assignCommandDisabledComment: "The `/assign` command is disabled for this repository.",
};
12 changes: 9 additions & 3 deletions src/handlers/comment/handlers/assign.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { addAssignees, getAssignedIssues, getCommentsOfIssue, getAvailableOpenedPullRequests } from "../../../helpers";
import { addAssignees, getAssignedIssues, getCommentsOfIssue, getAvailableOpenedPullRequests, addCommentToIssue } from "../../../helpers";
import { getBotConfig, getBotContext, getLogger } from "../../../bindings";
import { Payload, LabelItem, Comment, IssueType } from "../../../types";
import { deadLinePrefix } from "../../shared";
import { getWalletAddress, getWalletMultiplier, getMultiplierReason } from "../../../adapters/supabase";
import { tableComment } from "./table";
import { bountyInfo } from "../../wildcard";
import { ASSIGN_COMMAND_ENABLED, GLOBAL_STRINGS } from "../../../configs";

export const assign = async (body: string) => {
const { payload: _payload } = getBotContext();
Expand All @@ -19,8 +20,14 @@ export const assign = async (body: string) => {
return "Skipping '/assign' because of no issue instance";
}

if (!ASSIGN_COMMAND_ENABLED) {
logger.info(`Ignore '/assign' command from user: ASSIGN_COMMAND_ENABLED config is set false`);
await addCommentToIssue(GLOBAL_STRINGS.assignCommandDisabledComment, issue.number);
return;
}

const openedPullRequests = await getAvailableOpenedPullRequests(payload.sender.login);
logger.info(`Opened Pull Requests with no reviews but over 24 hours have passed: ${JSON.stringify(openedPullRequests)}`);
logger.info(`Opened Pull Requests with approved reviews or with no reviews but over 24 hours have passed: ${JSON.stringify(openedPullRequests)}`);

const assignedIssues = await getAssignedIssues(payload.sender.login);
logger.info(`Max issue allowed is ${config.assign.bountyHunterMax}`);
Expand Down Expand Up @@ -91,7 +98,6 @@ export const assign = async (body: string) => {
<ul>`,
};


if (!assignees.map((i) => i.login).includes(payload.sender.login)) {
logger.info(`Adding the assignee: ${payload.sender.login}`);
await addAssignees(issue.number, [payload.sender.login]);
Expand Down
4 changes: 3 additions & 1 deletion src/handlers/comment/handlers/help.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { userCommands } from ".";
import { getBotContext, getLogger } from "../../../bindings";
import { ASSIGN_COMMAND_ENABLED } from "../../../configs";
import { IssueType, Payload } from "../../../types";
import { IssueCommentCommands } from "../commands";

Expand Down Expand Up @@ -33,6 +34,7 @@ export const generateHelpMenu = () => {
// if first command, add a new line
if (command.id === userCommands[0].id) {
helpMenu += `\n`;
if (!ASSIGN_COMMAND_ENABLED) return;
}
helpMenu += `- ${command.id}: ${command.description}`;
// if not last command, add a new line (fixes too much space below)
Expand All @@ -41,6 +43,6 @@ export const generateHelpMenu = () => {
}
});

helpMenu += "```";
if (!ASSIGN_COMMAND_ENABLED) helpMenu += "```\n***_To assign yourself to an issue, please open a draft pull request that is linked to it._***";
return helpMenu;
};
9 changes: 3 additions & 6 deletions src/handlers/comment/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,12 @@ export const commentParser = (body: string): IssueCommentCommands[] => {

export const issueClosedCallback = async (): Promise<void> => {
const { payload: _payload } = getBotContext();
const { comments } = getBotConfig();
const issue = (_payload as Payload).issue;
if (!issue) return;
try {
const comment = await handleIssueClosed();
if (comment) await addCommentToIssue(comment, issue.number);
await addCommentToIssue(
`If you enjoy the DevPool experience, please follow <a href="https://github.com/ubiquity">Ubiquity on GitHub</a> and star <a href="https://github.com/ubiquity/devpool-directory">this repo</a> to show your support. It helps a lot!`,
issue.number
);
if (comment) await addCommentToIssue(comment + comments.promotionComment, issue.number);
} catch (err: unknown) {
return await addCommentToIssue(`Error: ${err}`, issue.number);
}
Expand Down Expand Up @@ -120,7 +117,7 @@ export const userCommands: UserCommands[] = [
},*/
{
id: IssueCommentCommands.MULTIPLIER,
description: `Set bounty multiplier (for treasury)`,
description: `Set the bounty payout multiplier for a specific contributor, and provide the reason for why. \n example usage: "/wallet @user 0.5 'Multiplier reason'"`,
handler: multiplier,
callback: commandCallback,
},
Expand Down
2 changes: 1 addition & 1 deletion src/handlers/payout/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const handleIssueClosed = async () => {
const multiplier = await getWalletMultiplier(assignee.login);

if (multiplier === 0) {
const errMsg = "Refusing to generate the payment permit because" + `@${assignee.login}` + "'s payment `multiplier` is `0`";
const errMsg = "Refusing to generate the payment permit because " + `@${assignee.login}` + "'s payment `multiplier` is `0`";
logger.info(errMsg);
return errMsg;
}
Expand Down
5 changes: 4 additions & 1 deletion src/helpers/issue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,10 @@ export const getAvailableOpenedPullRequests = async (username: string) => {
const pr = opened_prs[i];
const reviews = await getAllPullRequestReviews(context, pr.number);

if (reviews.length > 0) result.push(pr);
if (reviews.length > 0) {
const approvedReviews = reviews.find((review) => review.state === "APPROVED");
if (approvedReviews) result.push(pr);
}

if (reviews.length === 0 && (new Date().getTime() - new Date(pr.created_at).getTime()) / (1000 * 60 * 60) >= DEFAULT_TIME_RANGE_FOR_MAX_ISSUE) {
result.push(pr);
Expand Down
14 changes: 7 additions & 7 deletions src/helpers/payout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { DEFAULT_RPC_ENDPOINT } from "../configs";
import { PayoutConfigSchema } from "../types";

// available tokens for payouts
const PAYMENT_TOKEN_PER_CHAIN: Record<string, { rpc: string; token: string }> = {
const PAYMENT_TOKEN_PER_NETWORK: Record<string, { rpc: string; token: string }> = {
"1": {
rpc: DEFAULT_RPC_ENDPOINT,
token: "0x6B175474E89094C44Da98b954EedeAC495271d0F", // DAI
Expand All @@ -27,17 +27,17 @@ const PAYMENT_TOKEN_PER_CHAIN: Record<string, { rpc: string; token: string }> =
},
};

type PayoutConfigPartial = Omit<Static<typeof PayoutConfigSchema>, "chainId" | "privateKey" | "permitBaseUrl">;
type PayoutConfigPartial = Omit<Static<typeof PayoutConfigSchema>, "networkId" | "privateKey" | "permitBaseUrl">;

/**
* Returns payout config for a particular chain
* @param chainId chain id
* Returns payout config for a particular network
* @param networkId network id
* @returns RPC URL and payment token
*/
export const getPayoutConfigByChainId = (chainId: number): PayoutConfigPartial => {
const paymentToken = PAYMENT_TOKEN_PER_CHAIN[chainId.toString()];
export const getPayoutConfigByNetworkId = (networkId: number): PayoutConfigPartial => {
const paymentToken = PAYMENT_TOKEN_PER_NETWORK[networkId.toString()];
if (!paymentToken) {
throw new Error(`No config setup for chainId: ${chainId}`);
throw new Error(`No config setup for networkId: ${networkId}`);
}

return {
Expand Down
8 changes: 4 additions & 4 deletions src/helpers/permit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { BigNumber, ethers } from "ethers";
import { getBotConfig, getLogger } from "../bindings";
import { keccak256, toUtf8Bytes } from "ethers/lib/utils";

const PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3"; // same on all chains
const PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3"; // same on all networks

/**
* Generates permit2 signature data with `spender` and `amountInETH`
Expand All @@ -15,7 +15,7 @@ const PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3"; // same on
*/
export const generatePermit2Signature = async (spender: string, amountInEth: string, identifier: string): Promise<string> => {
const {
payout: { chainId, privateKey, permitBaseUrl, rpc, paymentToken },
payout: { networkId, privateKey, permitBaseUrl, rpc, paymentToken },
} = getBotConfig();
const logger = getLogger();
const provider = new ethers.providers.JsonRpcProvider(rpc);
Expand All @@ -35,7 +35,7 @@ export const generatePermit2Signature = async (spender: string, amountInEth: str
deadline: MaxUint256,
};

const { domain, types, values } = SignatureTransfer.getPermitData(permitTransferFromData, PERMIT2_ADDRESS, chainId);
const { domain, types, values } = SignatureTransfer.getPermitData(permitTransferFromData, PERMIT2_ADDRESS, networkId);

const signature = await adminWallet._signTypedData(domain, types, values);
const txData = {
Expand All @@ -57,7 +57,7 @@ export const generatePermit2Signature = async (spender: string, amountInEth: str

const base64encodedTxData = Buffer.from(JSON.stringify(txData)).toString("base64");

const result = `${permitBaseUrl}?claim=${base64encodedTxData}&network=${chainId}`;
const result = `${permitBaseUrl}?claim=${base64encodedTxData}&network=${networkId}`;
logger.info(`Generated permit2 url: ${result}`);
return result;
};
7 changes: 6 additions & 1 deletion src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const TelegramBotConfigSchema = Type.Object({
});

export const PayoutConfigSchema = Type.Object({
chainId: Type.Number(),
networkId: Type.Number(),
rpc: Type.String(),
privateKey: Type.String(),
paymentToken: Type.String(),
Expand Down Expand Up @@ -63,6 +63,10 @@ export const SodiumSchema = Type.Object({
privateKey: Type.String(),
});

export const CommentsSchema = Type.Object({
promotionComment: Type.String(),
});

export const BotConfigSchema = Type.Object({
log: LogConfigSchema,
price: PriceConfigSchema,
Expand All @@ -73,6 +77,7 @@ export const BotConfigSchema = Type.Object({
mode: ModeSchema,
assign: AssignSchema,
sodium: SodiumSchema,
comments: CommentsSchema,
});

export type BotConfig = Static<typeof BotConfigSchema>;
24 changes: 17 additions & 7 deletions src/utils/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { DEFAULT_CHAIN_ID, DefaultPriceConfig } from "../configs";
import { DEFAULT_NETWORK_ID, DefaultPriceConfig } from "../configs";
import { CommentElementPricing } from "../types";
import { WideLabel, WideOrgConfig, WideRepoConfig } from "./private";

export const getChainId = (parsedRepo: WideRepoConfig | undefined, parsedOrg: WideOrgConfig | undefined): number => {
if (parsedRepo && parsedRepo["chain-id"] && !Number.isNaN(Number(parsedRepo["chain-id"]))) {
return Number(parsedRepo["chain-id"]);
} else if (parsedOrg && parsedOrg["chain-id"] && !Number.isNaN(Number(parsedOrg["chain-id"]))) {
return Number(parsedOrg["chain-id"]);
export const getNetworkId = (parsedRepo: WideRepoConfig | undefined, parsedOrg: WideOrgConfig | undefined): number => {
if (parsedRepo && parsedRepo["evm-network-id"] && !Number.isNaN(Number(parsedRepo["evm-network-id"]))) {
return Number(parsedRepo["evm-network-id"]);
} else if (parsedOrg && parsedOrg["evm-network-id"] && !Number.isNaN(Number(parsedOrg["evm-network-id"]))) {
return Number(parsedOrg["evm-network-id"]);
} else {
return DEFAULT_CHAIN_ID;
return DEFAULT_NETWORK_ID;
}
};

Expand Down Expand Up @@ -82,6 +82,16 @@ export const getAnalyticsMode = (parsedRepo: WideRepoConfig | undefined, parsedO
}
};

export const getPromotionComment = (parsedRepo: WideRepoConfig | undefined, parsedOrg: WideOrgConfig | undefined): string => {
if (parsedRepo && parsedRepo["promotion-comment"] && typeof parsedRepo["promotion-comment"] === "string") {
return parsedRepo["promotion-comment"];
} else if (parsedOrg && parsedOrg["promotion-comment"] && typeof parsedOrg["promotion-comment"] === "string") {
return parsedOrg["promotion-comment"];
} else {
return "";
}
};

export const getIncentiveMode = (parsedRepo?: WideRepoConfig, parsedOrg?: WideOrgConfig): boolean => {
if (parsedRepo && parsedRepo["incentive-mode"] && typeof parsedRepo["incentive-mode"] === "boolean") {
return parsedRepo["incentive-mode"];
Expand Down
9 changes: 6 additions & 3 deletions src/utils/private.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import {
getCreatorMultiplier,
getBountyHunterMax,
getIncentiveMode,
getChainId,
getNetworkId,
getPriorityLabels,
getTimeLabels,
getCommentItemPrice,
getDefaultLabels,
getPromotionComment,
} from "./helpers";

const CONFIG_REPO = "ubiquibot-config";
Expand Down Expand Up @@ -48,12 +49,13 @@ export interface WideLabel {
}

export interface WideConfig {
"chain-id"?: number;
"evm-network-id"?: number;
"base-multiplier"?: number;
"issue-creator-multiplier": number;
"time-labels"?: WideLabel[];
"priority-labels"?: WideLabel[];
"auto-pay-mode"?: boolean;
"promotion-comment"?: string;
"analytics-mode"?: boolean;
"incentive-mode"?: boolean;
"max-concurrent-bounties"?: number;
Expand Down Expand Up @@ -128,7 +130,7 @@ export const getWideConfig = async (context: Context) => {
const privateKeyDecrypted = parsedOrg && parsedOrg[KEY_NAME] ? await getPrivateKey(parsedOrg[KEY_NAME]) : undefined;

const configData = {
chainId: getChainId(parsedRepo, parsedOrg),
networkId: getNetworkId(parsedRepo, parsedOrg),
privateKey: privateKeyDecrypted ?? "",
baseMultiplier: getBaseMultiplier(parsedRepo, parsedOrg),
issueCreatorMultiplier: getCreatorMultiplier(parsedRepo, parsedOrg),
Expand All @@ -140,6 +142,7 @@ export const getWideConfig = async (context: Context) => {
incentiveMode: getIncentiveMode(parsedRepo, parsedOrg),
commentElementPricing: getCommentItemPrice(parsedRepo, parsedOrg),
defaultLabels: getDefaultLabels(parsedRepo, parsedOrg),
promotionComment: getPromotionComment(parsedRepo, parsedOrg),
};

return configData;
Expand Down

0 comments on commit 9e4ae94

Please sign in to comment.