Skip to content
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

BEPRO 2.28 #224

Merged
merged 7 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
65 changes: 54 additions & 11 deletions src/actions/get-bounty-closed-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,64 @@ import {Push} from "../services/analytics/push";
import {AnalyticEventName} from "../services/analytics/types/events";
import updateSeoCardBounty from "src/modules/handle-seo-card";
import { savePointEvent } from "../modules/points-system/save-point-event";
import calculateDistributedAmounts from "src/modules/calculate-distributed-amounts";
import { Proposal } from "@taikai/dappkit";
import { networksAttributes } from "src/db/models/networks";

export const name = "getBountyClosedEvents";
export const schedule = "*/12 * * * *";
export const description = "Move to 'Closed' status the bounty";
export const author = "clarkjoao";

async function updateUserPayments(proposal, transactionHash, issueId, tokenAmount) {
return Promise.all(
proposal.details.map(async (detail) => {
async function updateUserPayments(proposal: Proposal,
transactionHash: string,
issueId: number,
tokenAmount: string | number,
chainId: number,
network: networksAttributes,
merger: string) {
const chain = await db.chains.findOne({
where: {
chainId: chainId,
}
});

if (!chain?.closeFeePercentage || !network.mergeCreatorFeeShare || !network.proposerFeeShare) {
logger.warn(`Not possible to save payments for ${issueId} on ${chainId} as it's missing closeFeePercentage, mergeCreatorFeeShare or proposerFeeShare`);
return;
}

const distributedAmounts = calculateDistributedAmounts( chain.closeFeePercentage,
network.mergeCreatorFeeShare,
network.proposerFeeShare,
tokenAmount,
proposal.details);
return Promise.all([
db.users_payments.create({
address: merger,
ammount: +distributedAmounts.mergerAmount.value || 0,
issueId,
transactionHash,
}),
db.users_payments.create({
address: proposal.creator,
ammount: +distributedAmounts.proposerAmount.value || 0,
issueId,
transactionHash,
}),
...distributedAmounts.proposals.map(async (distributed) => {
const payment = {
address: detail?.["recipient"],
ammount:
Number((detail?.["percentage"] / 100) * +tokenAmount) || 0,
address: distributed.recipient,
ammount: +distributed.value || 0,
issueId,
transactionHash,
}
return db.users_payments.findOrCreate({
where: payment,
defaults: payment
})
}))
})
]);
}

async function updateCuratorProposal(address: string, networkId: number) {
Expand All @@ -53,7 +90,7 @@ export async function action(block: DecodedLog, query?: EventsQuery): Promise<Ev

const network = await getNetwork(chainId, address);
if (!network) {
logger.warn(NETWORK_NOT_FOUND(name, address))
logger.warn(NETWORK_NOT_FOUND(name, address));
return eventsProcessed;
}

Expand All @@ -66,12 +103,12 @@ export async function action(block: DecodedLog, query?: EventsQuery): Promise<Ev
});

if (!dbBounty) {
logger.warn(DB_BOUNTY_NOT_FOUND(name, bounty.cid, network.id))
logger.warn(DB_BOUNTY_NOT_FOUND(name, bounty.cid, network.id));
return eventsProcessed;
}

if (dbBounty.state === "closed") {
logger.warn(DB_BOUNTY_ALREADY_CLOSED(name, bounty.cid, network.id))
logger.warn(DB_BOUNTY_ALREADY_CLOSED(name, bounty.cid, network.id));
return eventsProcessed;
}

Expand Down Expand Up @@ -108,7 +145,13 @@ export async function action(block: DecodedLog, query?: EventsQuery): Promise<Ev

sendMessageToTelegramChannels(BOUNTY_CLOSED(dbBounty, dbProposal, proposalId));

await updateUserPayments(bounty.proposals[+proposalId], block.transactionHash, dbBounty.id, bounty.tokenAmount);
await updateUserPayments( bounty.proposals[+proposalId],
block.transactionHash,
dbBounty.id,
bounty.tokenAmount,
chainId,
network,
transaction.from);
await updateCuratorProposal(bounty.proposals[+proposalId].creator, network?.id)
updateLeaderboardNfts()
updateLeaderboardBounties("closed");
Expand Down
10 changes: 10 additions & 0 deletions src/actions/get-bounty-funded-updated-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {BOUNTY_FUNDED} from "../integrations/telegram/messages";
import {Push} from "../services/analytics/push";
import {AnalyticEventName} from "../services/analytics/types/events";
import updateSeoCardBounty from "src/modules/handle-seo-card";
import { handleFundedFundingPoints } from "src/modules/points-system/handle-funded-funding-points";
import { Network_v2 } from "@taikai/dappkit";

export const name = "getBountyFundedEvents";
export const schedule = "*/14 * * * *";
Expand Down Expand Up @@ -56,6 +58,14 @@ export async function action(block: DecodedLog<BountyFunded['returnValues']>, qu

updateSeoCardBounty(dbBounty.id, name);

const _network = new Network_v2(connection, address);
await _network.start();

await handleFundedFundingPoints({
bounty: await _network.getBounty(dbBounty.contractId!),
issue: dbBounty
});

eventsProcessed[network.name!] = {
[dbBounty.id!.toString()]: {bounty: dbBounty, eventBlock: parseLogWithContext(block)}
};
Expand Down
26 changes: 21 additions & 5 deletions src/actions/get-bounty-moved-to-open.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import updateSeoCardBounty from "src/modules/handle-seo-card";
import { getCoinPrice } from "../services/coingecko";
import { savePointEvent } from "../modules/points-system/save-point-event";
import { getOrUpdateLastTokenPrice } from "../modules/tokens";
import { handleFundedFundingPoints } from "src/modules/points-system/handle-funded-funding-points";

export const name = "get-bounty-moved-to-open";
export const schedule = "*/1 * * * *";
Expand Down Expand Up @@ -84,13 +85,28 @@ export async function action(query?: EventsQuery): Promise<EventsProcessed> {
sendMessageToTelegramChannels(BOUNTY_STATE_CHANGED(dbBounty.state!, dbBounty));

updateSeoCardBounty(dbBounty.id, name);

const tokenPrice = await getOrUpdateLastTokenPrice(dbBounty.transactionalTokenId!, currency);

await savePointEvent( "created_task",
dbBounty.user.address!,
{ taskId: dbBounty.id, taskAmount: dbBounty.amount, tokenPrice, currency },
(pointsPerAction, scalingFactor) => pointsPerAction * scalingFactor * +dbBounty.amount! * tokenPrice);
if (!dbBounty.fundingAmount) {

await savePointEvent( "created_task",
dbBounty.user.address!,
{ taskId: dbBounty.id, taskAmount: dbBounty.amount, tokenPrice, currency },
(pointsPerAction, scalingFactor) => pointsPerAction * scalingFactor * +dbBounty.amount! * tokenPrice);
} else {
if (!!dbBounty.rewardAmount && +dbBounty.rewardAmount > 0) {
await savePointEvent( "give_funding_reward",
dbBounty.user.address!,
{ taskId: dbBounty.id, rewardAmount: dbBounty.rewardAmount, tokenPrice, currency },
(pointsPerAction, scalingFactor) => pointsPerAction * scalingFactor * +dbBounty.rewardAmount! * tokenPrice);
}

await handleFundedFundingPoints({
bounty: await _network.getBounty(dbBounty.contractId!),
issue: dbBounty
});
}

eventsProcessed[networkName!] = {
...eventsProcessed[networkName!],
Expand Down
1 change: 1 addition & 0 deletions src/assets/templates/user-profile.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
border: 3px solid #4250e4;
border-radius: 50%;
height: 250px;
width: 250px;
}
header h1, h3 {
Expand Down
10 changes: 5 additions & 5 deletions src/db/models/users_payments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { issues, issuesId } from './issues';
export interface users_paymentsAttributes {
id: number;
address: string;
ammount: number;
ammount?: number;
issueId: number;
transactionHash?: string;
createdAt: Date;
Expand All @@ -14,13 +14,13 @@ export interface users_paymentsAttributes {

export type users_paymentsPk = "id";
export type users_paymentsId = users_payments[users_paymentsPk];
export type users_paymentsOptionalAttributes = "id" | "transactionHash" | "createdAt" | "updatedAt";
export type users_paymentsOptionalAttributes = "id" | "ammount" | "transactionHash" | "createdAt" | "updatedAt";
export type users_paymentsCreationAttributes = Optional<users_paymentsAttributes, users_paymentsOptionalAttributes>;

export class users_payments extends Model<users_paymentsAttributes, users_paymentsCreationAttributes> implements users_paymentsAttributes {
id!: number;
address!: string;
ammount!: number;
ammount?: number;
issueId!: number;
transactionHash?: string;
createdAt!: Date;
Expand All @@ -45,8 +45,8 @@ export class users_payments extends Model<users_paymentsAttributes, users_paymen
allowNull: false
},
ammount: {
type: DataTypes.INTEGER,
allowNull: false
type: DataTypes.DOUBLE,
allowNull: true
},
issueId: {
type: DataTypes.INTEGER,
Expand Down
99 changes: 99 additions & 0 deletions src/modules/points-system/handle-funded-funding-points.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { Bounty } from "@taikai/dappkit";
import { Op, Sequelize } from "sequelize";

import models from "src/db";
import { issuesAttributes } from "src/db/models/issues";
import { usersAttributes } from "src/db/models/users";

import { savePointEvent } from "src/modules/points-system/save-point-event";
import { removePointEntry } from "src/modules/points-system/remove-point-event";
import { getOrUpdateLastTokenPrice } from "src/modules/tokens";

import logger from "src/utils/logger-handler";

interface HandleFundedFundingPointsProps {
bounty: Bounty;
issue: issuesAttributes;
}

type FundingEventInfo = {
taskId: number,
benefactorId: number,
amount: string;
tokenPrice: number;
}

const {
NEXT_PUBLIC_CURRENCY_MAIN: currency = "eur",
} = process.env;

export async function handleFundedFundingPoints({
bounty,
issue,
}: HandleFundedFundingPointsProps) {
try {
const pointsEventsOfIssue = await models.points_events.findAll({
where: {
actionName: "funded_funding_request",
info: {
taskId: {
[Op.eq]: issue.id
}
}
}
});

const users: usersAttributes[] = [];
const findUser = (address: string) => users.find(user => user?.address?.toLowerCase() === address.toLowerCase());

const benefactors = bounty.funding.map((funding, id) => ({ id, ...funding }));
for (const benefactor of benefactors) {
let user = findUser(benefactor.benefactor);

if (!user) {
const found = await models.users.findOne({
where: Sequelize.where( Sequelize.fn("LOWER", Sequelize.col("address")),
"=",
benefactor.benefactor.toLowerCase())
});

if (!found)
continue;

user = found;
users.push(found);
}

const hasPointEvent = pointsEventsOfIssue
.find(({ userId, info }) => (info as FundingEventInfo)?.benefactorId === benefactor.id && userId === user?.id);

if (!hasPointEvent && +benefactor.amount > 0) {
const tokenPrice = await getOrUpdateLastTokenPrice(issue.transactionalTokenId!, currency);
await savePointEvent("funded_funding_request", user.address!, {
taskId: issue.id,
benefactorId: benefactor.id,
amount: benefactor.amount,
tokenPrice,
currency
}, (pointsPerAction, scalingFactor) => pointsPerAction * scalingFactor * +benefactor.amount * tokenPrice);

logger.info(`handleFundedFundingPoints: point saved`, {
taskId: issue.id,
benefactorId: benefactor.id,
amount: benefactor.amount,
tokenPrice,
currency
});
} else if (hasPointEvent && +benefactor.amount === 0)
await removePointEntry(hasPointEvent.id);
logger.info(`handleFundedFundingPoints: point removed because fund was retracted`, {
taskId: issue.id,
benefactorId: benefactor.id,
amount: benefactor.amount,
currency,
});
}
} catch(error) {
logger.error(`handleFundedFundingPoints: failed to handle funded funding points`, { error, bounty, issue });
}
}
36 changes: 36 additions & 0 deletions src/modules/points-system/remove-point-event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import models from "src/db";
import logger from "src/utils/logger-handler";

export async function removePointEntry(pointEntryId: number) {
const pointEntry = await models.points_events.findOne({
where: {
id: pointEntryId
}
});

if (!pointEntry) {
logger.warn(`removePointEntry: Entry with id ${pointEntryId} not found on points_events`);
return;
}

if (pointEntry.pointsCounted) {
const user = await models.users.findOne({
where: {
id: pointEntry.userId
}
});

if (!user) {
logger.warn(`removePointEntry: User with id ${pointEntry.userId} not found`);
return;
}

user.totalPoints = user.totalPoints! - pointEntry.pointsWon;

await user.save();
}

await pointEntry.destroy();

logger.info(`PointsEvents ${pointEntryId} removed ${pointEntry.pointsCounted ? "and user totalPoints updated" : ""}`);
}
2 changes: 1 addition & 1 deletion src/modules/points-system/save-point-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import db from "src/db";
import logger from "src/utils/logger-handler";

type PointsEvents = "locked" | "delegated" | "created_marketplace" | "created_task" | "created_deliverable" |
"created_proposal" | "accepted_proposal";
"created_proposal" | "accepted_proposal" | "funded_funding_request" | "give_funding_reward";

export async function savePointEvent( event: PointsEvents,
participantAddress: string,
Expand Down
Loading