Skip to content

Merge develop into main #47

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Jul 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
0e355aa
chore(development): release 1.0.0
github-actions[bot] Jun 11, 2024
359d37c
Merge pull request #36 from ubiquibot/release-please--branches--devel…
gentlementlegen Jun 11, 2024
ca6e472
fix: updated test suite to match the new schema, fixed the async test…
gentlementlegen Jun 11, 2024
ba853c5
Merge pull request #38 from gentlementlegen/fix/test-run
gentlementlegen Jun 11, 2024
f523f78
chore: gpt-4o usage
Keyrxng Jun 13, 2024
e72afd5
chore: gpt-4o only
Keyrxng Jun 14, 2024
f2f7db4
chore: remove js-tiktoken
Keyrxng Jun 14, 2024
2b53e68
feat: add erc20RewardToken config param
rndquu Jun 17, 2024
6fd15dd
feat: pass token address on permit generation
rndquu Jun 19, 2024
cb6f718
ci: run knip-reporter on failure
rndquu Jun 19, 2024
e064951
Merge pull request #42 from rndquu/ci/run-knip-on-fail
gitcoindev Jun 20, 2024
fdd46d7
chore: added Jest reporter
gentlementlegen Jun 22, 2024
67d2c13
chore: added Jest reporter
gentlementlegen Jun 22, 2024
6798ea5
Merge pull request #44 from gentlementlegen/development
0x4007 Jun 24, 2024
7e11f5d
Merge pull request #39 from ubq-testing/development
0x4007 Jun 24, 2024
f8159e1
fix: resolve conflicts
rndquu Jul 2, 2024
f2f86cc
docs: enable permit module
rndquu Jul 3, 2024
9ce0843
test: increase timeout to 10s
rndquu Jul 3, 2024
10c0752
style: apply prettier formating
rndquu Jul 3, 2024
f7ad975
feat: set default erc20 reward param to WXDAI
rndquu Jul 4, 2024
48eeb02
Merge pull request #40 from rndquu/feat/custom-erc20-reward
rndquu Jul 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 7 additions & 12 deletions .github/workflows/jest-testing.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
name: Run Jest Tests

name: Run Jest testing suite
on:
workflow_dispatch:
workflow_run:
workflows: ["Knip"]
types:
- completed
pull_request:

env:
NODE_ENV: "test"
Expand Down Expand Up @@ -33,10 +29,9 @@ jobs:
with:
fetch-depth: 0

- name: Jest With Coverage Comment
# Ensures this step is run even on previous step failure (e.g. test failed)
- name: Jest With Coverage
run: yarn install --immutable --immutable-cache --check-cache && yarn test

- name: Add Jest Report to Summary
if: always()
uses: ArtiomTr/jest-coverage-report-action@v2
with:
package-manager: yarn
prnumber: ${{ github.event.pull_request.number || github.event.workflow_run.pull_requests[0].number }}
run: echo "$(cat test-dashboard.md)" >> $GITHUB_STEP_SUMMARY
2 changes: 1 addition & 1 deletion .github/workflows/knip-reporter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:
jobs:
knip-reporter:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion != 'success' }}
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -35,7 +36,6 @@ jobs:
trim: true

- name: Report knip results to pull request
if: ${{ github.event.workflow_run.conclusion != 'success' }}
uses: gitcoindev/knip-reporter@main
with:
verbose: true
Expand Down
47 changes: 47 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Changelog

## 1.0.0 (2024-06-11)


### Features

* cli argument to pass the issue URL to the program ([d4e9116](https://github.com/ubiquibot/conversation-rewards/commit/d4e91169ffd22b0f3bd0c26adc5829391c37437f))
* collect all user events ([147ba83](https://github.com/ubiquibot/conversation-rewards/commit/147ba83525c8626ebfccae97c30f368e087f4029))
* command line parsing arguments ([af93229](https://github.com/ubiquibot/conversation-rewards/commit/af932291d1b17f535b2cc5e5c02ce2ad4cfe7028))
* configuration parser ([0e6f3d1](https://github.com/ubiquibot/conversation-rewards/commit/0e6f3d192713bf5803b82aa5c80f73d8fab0989a))
* formatting is evaluated and influences the final score ([45d2831](https://github.com/ubiquibot/conversation-rewards/commit/45d2831ffb0337a68d4d4280f6a550c12c712d68))
* **get-activity:** properly fetches everything according to test ([6e067f7](https://github.com/ubiquibot/conversation-rewards/commit/6e067f71b69f58f1f1391ccce522c67fafd8fb94))
* github app login ([f4f4896](https://github.com/ubiquibot/conversation-rewards/commit/f4f4896b8611acd53f61685a6774665b5dfb8928))
* github app login ([b2efc68](https://github.com/ubiquibot/conversation-rewards/commit/b2efc68d996d9202ff4bd6a3385e9922e8eda846))
* github app login ([df34aa7](https://github.com/ubiquibot/conversation-rewards/commit/df34aa71a1c36563f34a14ea1fb4220642332012))
* github app login ([8add964](https://github.com/ubiquibot/conversation-rewards/commit/8add9648f2717d71b6fb32b806fb97fd7cad800c))
* github app login ([ad16266](https://github.com/ubiquibot/conversation-rewards/commit/ad1626672a42d5e2ba3f6404cb51db6d233e0c9c))
* github app login ([013519d](https://github.com/ubiquibot/conversation-rewards/commit/013519d80fad987f7ca7bfb2774f7d5ed00d9468))
* github app login ([39fa39d](https://github.com/ubiquibot/conversation-rewards/commit/39fa39d58f38e984e3b3120d09338becef753e36))
* link pull request from issue (not other way around) ([e6aa979](https://github.com/ubiquibot/conversation-rewards/commit/e6aa97973e7b8bb64551bd060ab6e2e005b6d4d3))
* moved tsx to production dependencies ([423f49e](https://github.com/ubiquibot/conversation-rewards/commit/423f49e2dfaff1b8ca4603100cd89aa41b0b6e52))
* pass in token from kernel to authenticate octokit client ([1f4ba00](https://github.com/ubiquibot/conversation-rewards/commit/1f4ba009bd81b3cbea79e8cde1735407d0504037))
* permit generation module ([925243f](https://github.com/ubiquibot/conversation-rewards/commit/925243f8ac5cc847b4b63ac76195d0d3de3c9fed))
* permit generation module ([50b396b](https://github.com/ubiquibot/conversation-rewards/commit/50b396b26e1bec433f193481004a7db6505f5ba5))
* read inputs from GitHub inputs instead of CLI ([30ac759](https://github.com/ubiquibot/conversation-rewards/commit/30ac759a2e81633304f91ff127a7d6848af420d2))
* saving permit to database ([aecd4e1](https://github.com/ubiquibot/conversation-rewards/commit/aecd4e127e9341ae18c18b14bf7c1c5dc8f98a6b))
* untested class to get all information ([f5104e1](https://github.com/ubiquibot/conversation-rewards/commit/f5104e14034cf2b6174bff1c6d3669aa177e438c))
* untested class to get all information ([a86c62f](https://github.com/ubiquibot/conversation-rewards/commit/a86c62f67c48a129dcb904d6fd69663c9e847f0d))
* updated jest test workflow ([a69f8d9](https://github.com/ubiquibot/conversation-rewards/commit/a69f8d9c82a8316b90f4c9f14b177185ebefcb25))
* updated jest test workflow ([834f821](https://github.com/ubiquibot/conversation-rewards/commit/834f821b42079c30d8e194749e6538e2d5a17ceb))


### Bug Fixes

* all tests pass ([db1868e](https://github.com/ubiquibot/conversation-rewards/commit/db1868e60fe96ea9f8a30a347d40e1cac7c9e067))
* **ci:** auth ([e897fdb](https://github.com/ubiquibot/conversation-rewards/commit/e897fdb4c0bcaeecbd6b6445a85a58d26b613338))
* cspell ([890a4a4](https://github.com/ubiquibot/conversation-rewards/commit/890a4a4c250d40d99fb6e127664c02544eef0826))
* cspell ignore words ([1160614](https://github.com/ubiquibot/conversation-rewards/commit/11606142d26cbd57c7c33f9e08d0e0a6bab689d2))
* fixed path for evm values ([2f3c2ee](https://github.com/ubiquibot/conversation-rewards/commit/2f3c2ee229400031e1fd95324d91677eda84925e))
* more characters are escaped (backtick, ampersand) to avoid display issues ([550869c](https://github.com/ubiquibot/conversation-rewards/commit/550869c13e48e4bb2865acb629bed66b6a3ab1e6))
* permit generation is skipped if price label is missing (configurable) ([d59cb0a](https://github.com/ubiquibot/conversation-rewards/commit/d59cb0a93c50770ec946514627ca34406e3da2e0))
* remove build action and changed trigger for Jest testing ([146580e](https://github.com/ubiquibot/conversation-rewards/commit/146580efc68b6d8ccaf56ba3873bc2dead03bd68))
* skip on issue close not completed status ([2c15e7c](https://github.com/ubiquibot/conversation-rewards/commit/2c15e7c44ea878221cce0afba4b93ffa3f4da067))
* **test:** resolve promises ([9d57104](https://github.com/ubiquibot/conversation-rewards/commit/9d571040cc8219c23a506ff8809273b991058f49))
* **test:** resolve promises ([1d62274](https://github.com/ubiquibot/conversation-rewards/commit/1d62274efb1cafea37356cf7d59069a4413bc436))
* types ([c4ad907](https://github.com/ubiquibot/conversation-rewards/commit/c4ad90732a3ba25098866ecb09103d8b780f05c8))
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ plugin: ubiquibot/conversation-rewards
with:
evmNetworkId: 100
evmPrivateEncrypted: "encrypted-key"
erc20RewardToken: "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"
incentives:
enabled: true
requirePriceLabel: true
Expand Down Expand Up @@ -115,7 +116,7 @@ with:
formattingMultiplier: 0.25
wordValue: 0.1
permitGeneration:
enabled: false
enabled: true
githubComment:
enabled: true
post: true
Expand Down
3 changes: 2 additions & 1 deletion jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ const cfg: Config = {
coveragePathIgnorePatterns: ["node_modules", "mocks"],
collectCoverage: true,
coverageReporters: ["json", "lcov", "text", "clover", "json-summary"],
reporters: ["default", "jest-junit"],
reporters: ["default", "jest-junit", "jest-md-dashboard"],
coverageDirectory: "coverage",
testTimeout: 10000,
};

export default cfg;
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@
"@octokit/webhooks": "13.2.7",
"@sinclair/typebox": "0.32.23",
"@supabase/supabase-js": "2.42.0",
"@ubiquibot/permit-generation": "1.2.2",
"@ubiquibot/permit-generation": "1.3.1",
"@ubiquity-dao/rpc-handler": "^1.1.0",
"decimal.js": "10.4.3",
"dotenv": "16.4.5",
"js-tiktoken": "1.0.10",
"ethers": "^6.13.0",
"jsdom": "24.0.0",
"lodash": "4.17.21",
"markdown-it": "14.1.0",
Expand Down Expand Up @@ -66,6 +67,7 @@
"husky": "8.0.3",
"jest": "29.7.0",
"jest-junit": "16.0.0",
"jest-md-dashboard": "0.8.0",
"knip": "5.7.0",
"lint-staged": "15.2.2",
"msw": "2.2.14",
Expand Down
4 changes: 4 additions & 0 deletions src/configuration/incentives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ export const incentivesConfigurationSchema = T.Object({
* The encrypted key to use for permit generation
*/
evmPrivateEncrypted: T.String(),
/**
* Reward token for ERC20 permits, default WXDAI for gnosis chain
*/
erc20RewardToken: T.String({ default: "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d" }),
incentives: T.Object({
/**
* Enables or disables the incentive plugin
Expand Down
26 changes: 26 additions & 0 deletions src/helpers/web3.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { RPCHandler, HandlerConstructorConfig } from "@ubiquity-dao/rpc-handler/";
import { ethers } from "ethers";

/**
* 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) {
const abi = ["function symbol() view returns (string)"];

// get fastest RPC
const config: HandlerConstructorConfig = {
networkId: 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.symbol();
}
4 changes: 3 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import * as core from "@actions/core";
import { run } from "./run";

run()
export default run()
.then((result) => {
core?.setOutput("result", result);
return result;
})
.catch((e) => {
console.error("Failed to run comment evaluation:", e);
core?.setFailed(e.toString());
return e;
});
50 changes: 5 additions & 45 deletions src/parser/content-evaluator-module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Decimal from "decimal.js";
import { encodingForModel } from "js-tiktoken";
import OpenAI from "openai";
import configuration from "../configuration/config-reader";
import { OPENAI_API_KEY } from "../configuration/constants";
Expand Down Expand Up @@ -50,7 +49,7 @@ export class ContentEvaluatorModule implements Module {
async _processComment(comments: Readonly<GithubCommentScore>[], specificationBody: string) {
const commentsWithScore: GithubCommentScore[] = [...comments];
const commentsBody = commentsWithScore.map((comment) => comment.content);
const relevance = await this._sampleRelevanceScoreResults(specificationBody, commentsBody);
const relevance = await this._evaluateComments(specificationBody, commentsBody);

if (relevance.length !== commentsWithScore.length) {
console.error("Relevance / Comment length mismatch! Skipping.");
Expand All @@ -71,12 +70,12 @@ export class ContentEvaluatorModule implements Module {
return commentsWithScore;
}

async _evaluateComments(specification: string, comments: string[]) {
async _evaluateComments(specification: string, comments: string[]): Promise<Decimal[]> {
const prompt = this._generatePrompt(specification, comments);

try {
const response: OpenAI.Chat.ChatCompletion = await this._openAi.chat.completions.create({
model: this._getOptimalModel(prompt),
model: "gpt-4o",
messages: [
{
role: "system",
Expand All @@ -99,44 +98,6 @@ export class ContentEvaluatorModule implements Module {
}
}

_getOptimalModel(prompt: string) {
const encoder = encodingForModel("gpt-3.5-turbo");
const totalSumOfTokens = encoder.encode(prompt).length;

if (totalSumOfTokens <= 4097) {
return "gpt-3.5-turbo";
} else if (totalSumOfTokens <= 16385) {
return "gpt-3.5-turbo-16k";
} else {
console.warn("Backup plan for development purposes only, but using gpt-4 due to huge context size");
return "gpt-4-turbo-preview";
}
}

async _sampleRelevanceScoreResults(specification: string, comments: string[]) {
const BATCH_SIZE = 10;
const evaluationPromises: ReturnType<typeof this._evaluateComments>[] = [];

for (let i = 0; i < BATCH_SIZE; ++i) {
evaluationPromises.push(this._evaluateComments(specification, comments));
}

const results = await Promise.all(evaluationPromises);

// Calculate the sum of each column
const columnSums: Decimal[] = [];
for (let j = 0; j < results[0].length; j++) {
let sum = new Decimal(0);
for (let i = 0; i < results.length; i++) {
sum = sum.plus(results[i][j] || 0);
}
columnSums.push(sum);
}

// Return the average of each column
return columnSums.map((sum) => sum.dividedBy(results.length));
}

_generatePrompt(issue: string, comments: string[]) {
if (!issue?.length) {
throw new Error("Issue specification comment is missing or empty");
Expand All @@ -145,8 +106,7 @@ export class ContentEvaluatorModule implements Module {
.map((comment) => comment)
.join(
"\n"
)}\n\`\`\`\n\n\nTo what degree are each of the comments in the conversation relevant and valuable to further defining the issue specification? Please reply with ONLY an array of float numbers between 0 and 1, corresponding to each comment in the order they appear. Each float should represent the degree of relevance and added value of the comment to the issue. The total length of the array in your response should equal exactly ${
comments.length
} elements.`;
)}\n\`\`\`\n\n\nTo what degree are each of the comments in the conversation relevant and valuable to further defining the issue specification? Please reply with ONLY an array of float numbers between 0 and 1, corresponding to each comment in the order they appear. Each float should represent the degree of relevance and added value of the comment to the issue. The total length of the array in your response should equal exactly ${comments.length
} elements.`;
}
}
10 changes: 6 additions & 4 deletions src/parser/github-comment-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import { GithubCommentConfiguration, githubCommentConfigurationType } from "../c
import { getOctokitInstance } from "../get-authentication-token";
import { IssueActivity } from "../issue-activity";
import { parseGitHubUrl } from "../start";
import { getPayoutConfigByNetworkId } from "../types/payout";
import program from "./command-line";
import { GithubCommentScore, Module, Result } from "./processor";
import { getERC20TokenSymbol } from "../helpers/web3";

interface SortedTasks {
issues: { specification: GithubCommentScore | null; comments: GithubCommentScore[] };
Expand All @@ -28,7 +28,7 @@ export class GithubCommentModule implements Module {
const bodyArray: (string | undefined)[] = [];

for (const [key, value] of Object.entries(result)) {
result[key].evaluationCommentHtml = this._generateHtml(key, value);
result[key].evaluationCommentHtml = await this._generateHtml(key, value);
bodyArray.push(result[key].evaluationCommentHtml);
}
const body = bodyArray.join("");
Expand Down Expand Up @@ -167,7 +167,7 @@ export class GithubCommentModule implements Module {
return content.join("");
}

_generateHtml(username: string, result: Result[0]) {
async _generateHtml(username: string, result: Result[0]) {
const sortedTasks = result.comments?.reduce<SortedTasks>(
(acc, curr) => {
if (curr.type & CommentType.ISSUE) {
Expand All @@ -184,13 +184,15 @@ export class GithubCommentModule implements Module {
{ issues: { specification: null, comments: [] }, reviews: [] }
);

const tokenSymbol = await getERC20TokenSymbol(configuration.evmNetworkId, configuration.erc20RewardToken);

return `
<details>
<summary>
<b>
<h3>
<a href="${result.permitUrl}" target="_blank" rel="noopener">
[ ${result.total} ${getPayoutConfigByNetworkId(configuration.evmNetworkId).symbol} ]
[ ${result.total} ${tokenSymbol} ]
</a>
</h3>
<h6>
Expand Down
11 changes: 7 additions & 4 deletions src/parser/permit-generation-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
Database,
encodePermits,
generatePayoutPermit,
Permit,
PermitReward,
SupportedEvents,
TokenType,
} from "@ubiquibot/permit-generation/core";
Expand All @@ -27,6 +27,7 @@ interface Payload {
evmNetworkId: number;
issueUrl: string;
evmPrivateEncrypted: string;
erc20RewardToken: string;
issue: { id: number };
}

Expand All @@ -40,6 +41,7 @@ export class PermitGenerationModule implements Module {
issueUrl: program.eventPayload.issue.html_url,
evmPrivateEncrypted: configuration.evmPrivateEncrypted,
evmNetworkId: configuration.evmNetworkId,
erc20RewardToken: configuration.erc20RewardToken,
};
const issueId = Number(payload.issueUrl.match(/[0-9]+$/)?.[0]);
payload.issue = {
Expand Down Expand Up @@ -78,6 +80,7 @@ export class PermitGenerationModule implements Module {
username: key,
contributionType: "",
type: TokenType.ERC20,
tokenAddress: payload.erc20RewardToken,
},
],
};
Expand Down Expand Up @@ -146,7 +149,7 @@ export class PermitGenerationModule implements Module {
return locationId;
}

async _savePermitsToDatabase(userId: number, issue: { issueId: number; issueUrl: string }, permits: Permit[]) {
async _savePermitsToDatabase(userId: number, issue: { issueId: number; issueUrl: string }, permits: PermitReward[]) {
for (const permit of permits) {
try {
const { data: userData } = await this._supabase.from("users").select("id").eq("id", userId).single();
Expand All @@ -155,8 +158,8 @@ export class PermitGenerationModule implements Module {
if (userData) {
const { error } = await this._supabase.from("permits").insert({
amount: permit.amount.toString(),
nonce: permit.nonce,
deadline: permit.deadline,
nonce: permit.nonce.toString(),
deadline: permit.deadline.toString(),
signature: permit.signature,
beneficiary_id: userData.id,
location_id: locationId,
Expand Down
Loading
Loading