Skip to content

Commit

Permalink
feat(qf-funding-score): to calculate score for each project from past…
Browse files Browse the repository at this point in the history
… donations

for thematters/developer-resource#350 & #103

1. add trust points details for each sender, in tsv format good for export/import spreadsheet for human review;
2. saved to s3 bucket `s3://matters-billboard/pre-rounds/` for automation later;
  • Loading branch information
49659410+tx0c committed Feb 3, 2024
1 parent e9c911f commit 511386a
Show file tree
Hide file tree
Showing 9 changed files with 13,196 additions and 10,361 deletions.
20 changes: 20 additions & 0 deletions bin/qf-calculate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env -S node --trace-warnings --loader ts-node/esm

import { calculateQFScore } from "../lib/qf-calculate.js";

async function main() {
const args = process.argv.slice(2);
const amount = BigInt(+(args?.[0] || 500) * 1e6);
const fromTime = args?.[1] || "2023-12-31";
const toTime = args?.[2] || "2024-12-31T23:59:59.999Z";

const res = await calculateQFScore({
fromTime, // : "2023-12-31",
toTime, // : "2024-12-31T23:59:59.999Z",
amount,
write_gist: true,
});
console.log(new Date(), "res:", res);
}

main().catch((err) => console.error(new Date(), "ERROR:", err));
79 changes: 79 additions & 0 deletions handlers/qf-calculate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { Context, APIGatewayProxyResult, APIGatewayEvent } from "aws-lambda";
import { calculateQFScore } from "../lib/qf-calculate.js";
import { s3GetFile } from "../lib/utils/aws.js";

export const handler = async (
event: APIGatewayEvent & {
fromTime?: string;
toTime?: string;
fromBlock?: string;
toBlock?: string;
amount?: string;
appendToRounds?: boolean;
forceRun?: boolean;
},
context: Context
): Promise<APIGatewayProxyResult> => {
console.log(`Event: ${JSON.stringify(event, null, 2)}`);
console.log(`Context: ${JSON.stringify(context, null, 2)}`);

const { method, path } = ((event?.requestContext as any)?.http as any) || {};
// const forceRun = !!(event?.queryStringParameters as any).forceRun;
const queryStringParameters = (event?.queryStringParameters as any) || {};
const forceRun = !!("forceRun" in queryStringParameters);
const { accept, origin }: { accept?: string; origin?: string } =
event?.headers || {};
if (
!(
event?.forceRun ||
(path === "/qf-calculator" && accept?.startsWith("application/json")) ||
(path === "/get-rounds" && accept)
)
) {
return {
statusCode: 400,
body: JSON.stringify({
error:
"input error, call with POST /qf-calculator with accept: application/json",
}),
};
}

if (path === "/get-rounds") {
const { key } = queryStringParameters;
const res = await s3GetFile({
bucket: "matters-billboard",
key: key?.endsWith(".json") ? key : `pre-rounds/rounds.json`,
}); // .then((res) => console.log(new Date(), `s3 get pre-rounds:`, res));
console.log(new Date(), `s3 get pre-rounds:`, res.ContentLength, res);
if (!res.Body) {
return { statusCode: 404, body: "file not found" };
}
const body = await res.Body.transformToString();
return {
statusCode: 200,
body: body,
};
}

const { fromTime, toTime, fromBlock, toBlock, amount, appendToRounds } =
event?.forceRun ? event : queryStringParameters;

const { root, gist_url } = await calculateQFScore({
fromTime,
toTime,
fromBlock: fromBlock ? BigInt(fromBlock) : undefined,
toBlock: toBlock ? BigInt(toBlock) : undefined,
amount: BigInt(+(amount || 500) * 1e6),
appendToRounds: !!appendToRounds,
});

return {
statusCode: 200,
body: JSON.stringify({
message: "done.",
root, // tree
gist_url,
}),
};
};
77 changes: 77 additions & 0 deletions lib/bigint-math.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// https://golb.hplar.ch/2018/09/javascript-bigint.html
export class BigIntMath {
static max(...values: Array<bigint | number>) {
if (values.length === 0) {
return null;
}

if (values.length === 1) {
return values[0];
}

let max = values[0];
for (let i = 1; i < values.length; i++) {
if (values[i] > max) {
max = values[i];
}
}
return max;
}

static min(...values: Array<bigint | number>) {
if (values.length === 0) {
return null;
}

if (values.length === 1) {
return values[0];
}

let min = values[0];
for (let i = 1; i < values.length; i++) {
if (values[i] < min) {
min = values[i];
}
}
return min;
}

static sign(value: bigint | number) {
if (value > 0n) {
return 1n;
}
if (value < 0n) {
return -1n;
}
return 0n;
}

static abs(value: bigint | number) {
if (this.sign(value) === -1n) {
return -value;
}
return value;
}

// https://stackoverflow.com/questions/53683995/javascript-big-integer-square-root/58863398#58863398
static rootNth(value: bigint, k: bigint = 2n) {
if (value < 0n) {
throw "negative number is not supported";
}

let o = 0n;
let x = value;
let limit = 100;

while (x ** k !== k && x !== o && --limit) {
o = x;
x = ((k - 1n) * x + value / x ** (k - 1n)) / k;
}

return x;
}

static sqrt(value: bigint) {
return BigIntMath.rootNth(value);
}
}
30 changes: 30 additions & 0 deletions lib/polygonscan.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const PolygonScanAPIKEY = process.env.MATTERS_POLYGONSCANAPIKEY || "";
// https://api.polygonscan.com/api?module=block&action=getblocknobytime&timestamp=1704184772&closest=before&apikey={key}

export class PolygonScanAPI {
static async getBlockFromTimestamp({
timestamp,
closest,
}: {
timestamp: number; // Date | string | number;
closest: "before" | "after";
}) {
const nowTs = Math.floor(+Date.now() / 1e3);
const params = new URLSearchParams({
module: "block",
action: "getblocknobytime",
timestamp: Math.min(nowTs, timestamp).toString(),
closest: timestamp >= nowTs ? "before" : closest, // override to before if pass now or future timestamp
apikey: PolygonScanAPIKEY,
});
const u = new URL(`https://api.polygonscan.com/api?${params}`);
console.log(new Date(), `get with:`, { params, u });
const res = await fetch(u).then((res) => res.json());

// {"status":"1","message":"OK","result":"51846093"}
if (!(res?.status === "1" && res?.message === "OK"))
console.error(new Date(), `non-ok result:`, res);

return BigInt(res?.result);
}
}
Loading

0 comments on commit 511386a

Please sign in to comment.