Skip to content

Commit

Permalink
refactor: bounty to task
Browse files Browse the repository at this point in the history
  • Loading branch information
0x4007 committed Sep 25, 2023
1 parent 7062a04 commit 5f6d28d
Show file tree
Hide file tree
Showing 21 changed files with 91 additions and 91 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/bot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ on:
- edited

jobs:
calculate_bounty_job:
calculate_task_job:
# ignore events invoked by bots
if: >-
github.event.pull_request.payload.sender.type != 'Bot' && github.repository != 'ubiquity/ubiquibot'
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ yarn start:watch
- `DISQUALIFY_TIME`: (optional) Set a custom disqualify time (default: 7 days).
- `OPENAI_API_HOST`: (optional) Set OpenAI host url (default: https://api.openai.com).
- `OPENAI_API_KEY`: Set OpenAI key.
- `CHATGPT_USER_PROMPT_FOR_IMPORTANT_WORDS`: (optional) Set a custom user prompt for finding important words
- `CHATGPT_USER_PROMPT_FOR_IMPORTANT_WORDS`: (optional) Set a custom user prompt for finding important words
(default: "I need your help to find important words (e.g. unique adjectives) from github issue below and I want to parse them easily so please separate them using #(No other contexts needed). Please separate the words by # so I can parse them easily. Please answer simply as I only need the important words. Here is the issue content.\n").
- `CHATGPT_USER_PROMPT_FOR_MEASURE_SIMILARITY`: (optional) Set a custom user prompt for measuring similarity
- `CHATGPT_USER_PROMPT_FOR_MEASURE_SIMILARITY`: (optional) Set a custom user prompt for measuring similarity
(default: 'I have two github issues and I need to measure the possibility of the 2 issues are the same content (No other contents needed and give me only the number in %).\n Give me in number format and add % after the number.\nDo not tell other things since I only need the number (e.g. 85%). Here are two issues:\n 1. "%first%"\n2. "%second%"').
- `SIMILARITY_THRESHOLD`: (optional) Set similarity threshold (default: 80).
- `MEASURE_SIMILARITY_AI_TEMPERATURE`: (optional) Set ChatGPT temperature for measuring similarity (default: 0).
Expand Down Expand Up @@ -63,12 +63,12 @@ To test the bot, you can:

`price-multiplier` is a base number that will be used to calculate bounty price based on the following formula: `price = price-multiplier * time-label-weight * priority-label-weight * 100`

`time-labels` are labels for marking the time limit of the bounty:
`time-labels` are labels for marking the time limit of the task:

- `name` is a human-readable name
- `value` is number of seconds that corresponds to the time limit of the bounty

`priority-labels` are labels for marking the priority of the bounty:
`priority-labels` are labels for marking the priority of the task:

- `name` is a human-readable name

Expand Down Expand Up @@ -139,7 +139,7 @@ DISQUALIFY_TIME="7 days" // 7 days
6. Open `localhost:3000` and follow instructions to add the bot to one of your repositories.

At this point the `.env` files auto-fill the empty fields (`PRIVATE_KEY` and `APP_ID`) if it is not previously filled.
Now you can make changes to the repository on GitHub (e.g. add a bounty) and the bot should react.
Now you can make changes to the repository on GitHub (e.g. add a task) and the bot should react.

You can, for example:

Expand Down
8 changes: 4 additions & 4 deletions src/adapters/supabase/helpers/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -473,10 +473,10 @@ const getDbDataFromPermit = (permit: InsertPermit): Record<string, unknown> => {
repository_id: permit.repositoryId,
issue_id: permit.issueId,
network_id: permit.evmNetworkId,
bounty_hunter_id: permit.bountyHunterId,
task_hunter_id: permit.taskHunterId,
token_address: permit.tokenAddress,
payout_amount: permit.payoutAmount,
bounty_hunter_address: permit.bountyHunterAddress,
task_hunter_address: permit.taskHunterAddress,
nonce: permit.nonce,
deadline: permit.deadline,
signature: permit.signature,
Expand All @@ -492,10 +492,10 @@ const getPermitFromDbData = (data: Record<string, unknown>): Permit => {
repositoryId: data.repository_i,
issueId: data.issue_id,
evmNetworkId: data.network_id,
bountyHunterId: data.bounty_hunter_id,
taskHunterId: data.task_hunter_id,
tokenAddress: data.token_address,
payoutAmount: data.payout_amount,
bountyHunterAddress: data.bounty_hunter_address,
taskHunterAddress: data.task_hunter_address,
nonce: data.nonce,
deadline: data.deadline,
signature: data.signature,
Expand Down
4 changes: 2 additions & 2 deletions src/bindings/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const loadConfig = async (context: Context): Promise<BotConfig> => {
commandSettings,
assistivePricing,
registerWalletWithVerification,
staleBountyTime,
staleTaskTime,
publicAccessControl,
openAIKey,
openAITokenLimit,
Expand Down Expand Up @@ -93,7 +93,7 @@ export const loadConfig = async (context: Context): Promise<BotConfig> => {
command: commandSettings,
assign: {
maxConcurrentTasks: maxConcurrentTasks,
staleBountyTime: ms(staleBountyTime),
staleTaskTime: ms(staleTaskTime),
},
sodium: {
privateKey: process.env.X25519_PRIVATE_KEY ?? "",
Expand Down
2 changes: 1 addition & 1 deletion src/configs/ubiquibot-config-default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export const DefaultConfig: MergedConfig = {
setLabel: true,
fundExternalClosedIssue: true,
},
staleBountyTime: "0d",
staleTaskTime: "0d",
newContributorGreeting: {
enabled: false,
header:
Expand Down
24 changes: 12 additions & 12 deletions src/handlers/comment/handlers/assign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Payload, LabelItem, Comment, IssueType, Issue } from "../../../types";
import { deadLinePrefix } from "../../shared";
import { getWalletAddress, getWalletMultiplier } from "../../../adapters/supabase";
import { tableComment } from "./table";
import { bountyInfo } from "../../wildcard";
import { taskInfo } from "../../wildcard";
import { ASSIGN_COMMAND_ENABLED, GLOBAL_STRINGS } from "../../../configs";
import { isParentIssue } from "../../pricing";

Expand All @@ -18,7 +18,7 @@ export const assign = async (body: string) => {

const id = organization?.id || repository?.id; // repository?.id as fallback

const staleBounty = config.assign.staleBountyTime;
const staleBounty = config.assign.staleTaskTime;

logger.info(`Received '/start' command from user: ${payload.sender.login}, body: ${body}`);
const issue = (_payload as Payload).issue;
Expand Down Expand Up @@ -103,7 +103,7 @@ export const assign = async (body: string) => {
<ul>
<li>Use <code>/wallet 0x0000...0000</code> if you want to update your registered payment wallet address @${payload.sender.login}.</li>
<li>Be sure to open a draft pull request as soon as possible to communicate updates on your progress.</li>
<li>Be sure to provide timely updates to us when requested, or you will be automatically unassigned from the bounty.</li>
<li>Be sure to provide timely updates to us when requested, or you will be automatically unassigned from the task.</li>
<ul>`,
};

Expand All @@ -114,12 +114,12 @@ export const assign = async (body: string) => {

let days: number | undefined;
let staleToDays: number | undefined;
let isBountyStale = false;
let isTaskStale = false;

if (staleBounty !== 0) {
days = Math.floor((new Date().getTime() - new Date(issue.created_at).getTime()) / (1000 * 60 * 60 * 24));
staleToDays = Math.floor(staleBounty / (1000 * 60 * 60 * 24));
isBountyStale = days >= staleToDays;
isTaskStale = days >= staleToDays;
}

// double check whether the assign message has been already posted or not
Expand All @@ -128,8 +128,8 @@ export const assign = async (body: string) => {
const comments = issueComments.sort((a: Comment, b: Comment) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
const latestComment = comments.length > 0 ? comments[0].body : undefined;
if (latestComment && comment.commit != latestComment) {
const { multiplier, reason, bounty } = await getMultiplierInfoToDisplay(payload.sender.login, id?.toString(), issue);
return tableComment({ ...comment, multiplier, reason, bounty, isBountyStale, days }) + comment.tips;
const { multiplier, reason, task } = await getMultiplierInfoToDisplay(payload.sender.login, id?.toString(), issue);
return tableComment({ ...comment, multiplier, reason, task, isTaskStale, days }) + comment.tips;
}
return;
};
Expand All @@ -139,7 +139,7 @@ const getMultiplierInfoToDisplay = async (senderLogin: string, org_id: string, i

const multiplier = value?.toFixed(2) || "1.00";

let _multiplierToDisplay, _reasonToDisplay, _bountyToDisplay;
let _multiplierToDisplay, _reasonToDisplay, _taskToDisplay;

if (value == 1) {
if (reason) {
Expand All @@ -152,11 +152,11 @@ const getMultiplierInfoToDisplay = async (senderLogin: string, org_id: string, i
} else {
_multiplierToDisplay = multiplier;
_reasonToDisplay = reason;
_bountyToDisplay = `Permit generation disabled because price label is not set.`;
const issueDetailed = bountyInfo(issue);
_taskToDisplay = `Permit generation disabled because price label is not set.`;
const issueDetailed = taskInfo(issue);
if (issueDetailed.priceLabel) {
_bountyToDisplay = (+issueDetailed.priceLabel.substring(7, issueDetailed.priceLabel.length - 4) * value).toString() + " USD";
_taskToDisplay = (+issueDetailed.priceLabel.substring(7, issueDetailed.priceLabel.length - 4) * value).toString() + " USD";
}
}
return { multiplier: _multiplierToDisplay, reason: _reasonToDisplay, bounty: _bountyToDisplay };
return { multiplier: _multiplierToDisplay, reason: _reasonToDisplay, task: _taskToDisplay };
};
2 changes: 1 addition & 1 deletion src/handlers/comment/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ export const issueReopenedCallback = async (): Promise<void> => {
}

await addCommentToIssue(
`@${assignee} please be sure to review this conversation and implement any necessary fixes. Unless this is closed as completed, its payment of **${formattedAmount} ${tokenSymbol}** will be deducted from your next bounty.`,
`@${assignee} please be sure to review this conversation and implement any necessary fixes. Unless this is closed as completed, its payment of **${formattedAmount} ${tokenSymbol}** will be deducted from your next task.`,
issue.number
);
} else {
Expand Down
16 changes: 8 additions & 8 deletions src/handlers/comment/handlers/multiplier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ export const multiplier = async (body: string) => {
matches?.shift();

if (matches) {
let bountyMultiplier = 1;
let taskMultiplier = 1;
let username = "";
let reason = "";

for (const part of matches) {
if (!isNaN(parseFloat(part))) {
bountyMultiplier = parseFloat(part);
taskMultiplier = parseFloat(part);
} else if (part.startsWith("@")) {
username = part.substring(1);
} else {
Expand All @@ -68,20 +68,20 @@ export const multiplier = async (body: string) => {
return "Insufficient permissions to update the payout multiplier. You are not an `admin` or `billing_manager`";
}
}
logger.info(`Upserting to the wallet table, username: ${username}, bountyMultiplier: ${bountyMultiplier}, reason: ${reason}}`);
logger.info(`Upserting to the wallet table, username: ${username}, taskMultiplier: ${taskMultiplier}, reason: ${reason}}`);

await upsertWalletMultiplier(username, bountyMultiplier?.toString(), reason, id?.toString());
if (bountyMultiplier > 1) {
return `Successfully changed the payout multiplier for @${username} to ${bountyMultiplier}. The reason ${
await upsertWalletMultiplier(username, taskMultiplier?.toString(), reason, id?.toString());
if (taskMultiplier > 1) {
return `Successfully changed the payout multiplier for @${username} to ${taskMultiplier}. The reason ${
reason ? `provided is "${reason}"` : "is not provided"
}. This feature is designed to limit the contributor's compensation for any bounty on the current repository due to other compensation structures (i.e. salary.) are you sure you want to use a bounty multiplier above 1?`;
} else {
return `Successfully changed the payout multiplier for @${username} to ${bountyMultiplier}. The reason ${
return `Successfully changed the payout multiplier for @${username} to ${taskMultiplier}. The reason ${
reason ? `provided is "${reason}"` : "is not provided"
}.`;
}
} else {
logger.error("Invalid body for bountyMultiplier command");
logger.error("Invalid body for taskMultiplier command");
return `Invalid syntax for wallet command \n example usage: "/multiplier @user 0.5 'Multiplier reason'"`;
}
};
12 changes: 6 additions & 6 deletions src/handlers/comment/handlers/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,23 @@ export const tableComment = ({
wallet,
multiplier,
reason,
bounty,
isBountyStale,
task,
isTaskStale,
days,
}: {
deadline: string;
wallet: string;
multiplier?: string;
reason?: string;
bounty?: string;
isBountyStale?: boolean;
task?: string;
isTaskStale?: boolean;
days?: number;
}) => {
return `
<code>
<table>
${
isBountyStale
isTaskStale
? `<tr><td>Warning!</td> <td>This task was created over ${days} days ago. Please confirm that this issue specification is accurate before starting.</td></tr>`
: ``
}
Expand All @@ -33,6 +33,6 @@ ${
</tr>
${multiplier ? `<tr><td>Payment Multiplier</td><td>${multiplier}</td></tr>` : ``}
${reason ? `<tr><td>Multiplier Reason</td><td>${reason}</td></tr>` : ``}
${bounty ? `<tr><td>Total Bounty</td><td>${bounty}</td></tr>` : ``}
${task ? `<tr><td>Total Task</td><td>${task}</td></tr>` : ``}
</table></code>`;
};
30 changes: 15 additions & 15 deletions src/handlers/payout/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
} from "../../helpers";
import { UserType, Payload, StateReason, Comment, User, Incentives, Issue } from "../../types";
import { shortenEthAddress } from "../../utils";
import { bountyInfo } from "../wildcard";
import { taskInfo } from "../wildcard";
import Decimal from "decimal.js";
import { GLOBAL_STRINGS } from "../../configs";
import { isParentIssue } from "../pricing";
Expand All @@ -38,7 +38,7 @@ export interface IncentivesCalculationResult {
payload: Payload;
comments: Comment[];
issueDetailed: {
isBounty: boolean;
isTask: boolean;
timelabel: string;
priorityLabel: string;
priceLabel: string;
Expand Down Expand Up @@ -183,15 +183,15 @@ export const incentivesCalculation = async (): Promise<IncentivesCalculationResu
throw new Error(`Permit generation disabled because permitMaxPrice is 0.`);
}

const issueDetailed = bountyInfo(issue);
if (!issueDetailed.isBounty) {
logger.info(`Skipping... its not a bounty`);
throw new Error(`Permit generation disabled because this issue didn't qualify as bounty.`);
const issueDetailed = taskInfo(issue);
if (!issueDetailed.isTask) {
logger.info(`Skipping... its not a task`);
throw new Error(`Permit generation disabled because this issue didn't qualify for funding.`);
}

if (!issueDetailed.priceLabel || !issueDetailed.priorityLabel || !issueDetailed.timelabel) {
logger.info(`Skipping... its not a bounty`);
throw new Error(`Permit generation disabled because this issue didn't qualify as bounty.`);
logger.info(`Skipping... its not a task`);
throw new Error(`Permit generation disabled because this issue didn't qualify for funding.`);
}

const assignees = issue?.assignees ?? [];
Expand Down Expand Up @@ -237,7 +237,7 @@ export const incentivesCalculation = async (): Promise<IncentivesCalculationResu
payload,
comments,
issueDetailed: {
isBounty: issueDetailed.isBounty,
isTask: issueDetailed.isTask,
timelabel: issueDetailed.timelabel,
priorityLabel: issueDetailed.priorityLabel,
priceLabel: issueDetailed.priceLabel,
Expand Down Expand Up @@ -272,22 +272,22 @@ export const calculateIssueAssigneeReward = async (incentivesCalculation: Incent
incentivesCalculation.evmNetworkId.toString()
);
if (penaltyAmount.gt(0)) {
logger.info(`Deducting penalty from bounty`);
const bountyAmount = ethers.utils.parseUnits(priceInEth.toString(), 18);
const bountyAmountAfterPenalty = bountyAmount.sub(penaltyAmount);
if (bountyAmountAfterPenalty.lte(0)) {
logger.info(`Deducting penalty from task`);
const taskAmount = ethers.utils.parseUnits(priceInEth.toString(), 18);
const taskAmountAfterPenalty = taskAmount.sub(penaltyAmount);
if (taskAmountAfterPenalty.lte(0)) {
await removePenalty(
assigneeLogin,
incentivesCalculation.payload.repository.full_name,
incentivesCalculation.paymentToken,
incentivesCalculation.evmNetworkId.toString(),
bountyAmount
taskAmount
);
const msg = `Permit generation disabled because bounty amount after penalty is 0.`;
logger.info(msg);
return { error: msg };
}
priceInEth = new Decimal(ethers.utils.formatUnits(bountyAmountAfterPenalty, 18));
priceInEth = new Decimal(ethers.utils.formatUnits(taskAmountAfterPenalty, 18));
}

const account = await getWalletAddress(assigneeLogin);
Expand Down
10 changes: 5 additions & 5 deletions src/handlers/payout/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { getLatestPullRequest, gitLinkedPrParser } from "../../helpers/parser";
import { Incentives, MarkdownItem, Payload, UserType } from "../../types";
import { RewardsResponse, commentParser } from "../comment";
import Decimal from "decimal.js";
import { bountyInfo } from "../wildcard";
import { taskInfo } from "../wildcard";
import { IncentivesCalculationResult } from "./action";
import { BigNumber } from "ethers";

Expand Down Expand Up @@ -106,10 +106,10 @@ export const calculateIssueCreatorReward = async (incentivesCalculation: Incenti
const title = `Task Creator`;
const logger = getLogger();

const issueDetailed = bountyInfo(incentivesCalculation.issue);
if (!issueDetailed.isBounty) {
logger.info(`incentivizeCreatorComment: its not a bounty`);
return { error: `incentivizeCreatorComment: its not a bounty` };
const issueDetailed = taskInfo(incentivesCalculation.issue);
if (!issueDetailed.isTask) {
logger.info(`incentivizeCreatorComment: its not a funded task`);
return { error: `incentivizeCreatorComment: its not a funded task` };
}

const comments = await getAllIssueComments(incentivesCalculation.issue.number);
Expand Down
4 changes: 2 additions & 2 deletions src/handlers/pricing/pre.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getBotConfig, getLogger } from "../../bindings";
import { calculateWeight, createLabel, listLabelsForRepo } from "../../helpers";
import { calculateBountyPrice } from "../shared";
import { calculateTaskPrice } from "../shared";

/**
* @dev This just checks all the labels in the config have been set in gh issue
Expand All @@ -22,7 +22,7 @@ export const validatePriceLabels = async (): Promise<void> => {
const aiLabels: string[] = [];
for (const timeLabel of config.price.timeLabels) {
for (const priorityLabel of config.price.priorityLabels) {
const targetPrice = calculateBountyPrice(calculateWeight(timeLabel), calculateWeight(priorityLabel), config.price.baseMultiplier);
const targetPrice = calculateTaskPrice(calculateWeight(timeLabel), calculateWeight(priorityLabel), config.price.baseMultiplier);
const targetPriceLabel = `Price: ${targetPrice} USD`;
aiLabels.push(targetPriceLabel);
}
Expand Down
Loading

0 comments on commit 5f6d28d

Please sign in to comment.