Skip to content

Commit 4dddd4e

Browse files
authored
Merge pull request #224 from layerx-labs/dev
BEPRO 2.28
2 parents edefede + 5cb8bce commit 4dddd4e

File tree

8 files changed

+227
-22
lines changed

8 files changed

+227
-22
lines changed

src/actions/get-bounty-closed-event.ts

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,64 @@ import {Push} from "../services/analytics/push";
1313
import {AnalyticEventName} from "../services/analytics/types/events";
1414
import updateSeoCardBounty from "src/modules/handle-seo-card";
1515
import { savePointEvent } from "../modules/points-system/save-point-event";
16+
import calculateDistributedAmounts from "src/modules/calculate-distributed-amounts";
17+
import { Proposal } from "@taikai/dappkit";
18+
import { networksAttributes } from "src/db/models/networks";
1619

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

22-
async function updateUserPayments(proposal, transactionHash, issueId, tokenAmount) {
23-
return Promise.all(
24-
proposal.details.map(async (detail) => {
25+
async function updateUserPayments(proposal: Proposal,
26+
transactionHash: string,
27+
issueId: number,
28+
tokenAmount: string | number,
29+
chainId: number,
30+
network: networksAttributes,
31+
merger: string) {
32+
const chain = await db.chains.findOne({
33+
where: {
34+
chainId: chainId,
35+
}
36+
});
37+
38+
if (!chain?.closeFeePercentage || !network.mergeCreatorFeeShare || !network.proposerFeeShare) {
39+
logger.warn(`Not possible to save payments for ${issueId} on ${chainId} as it's missing closeFeePercentage, mergeCreatorFeeShare or proposerFeeShare`);
40+
return;
41+
}
42+
43+
const distributedAmounts = calculateDistributedAmounts( chain.closeFeePercentage,
44+
network.mergeCreatorFeeShare,
45+
network.proposerFeeShare,
46+
tokenAmount,
47+
proposal.details);
48+
return Promise.all([
49+
db.users_payments.create({
50+
address: merger,
51+
ammount: +distributedAmounts.mergerAmount.value || 0,
52+
issueId,
53+
transactionHash,
54+
}),
55+
db.users_payments.create({
56+
address: proposal.creator,
57+
ammount: +distributedAmounts.proposerAmount.value || 0,
58+
issueId,
59+
transactionHash,
60+
}),
61+
...distributedAmounts.proposals.map(async (distributed) => {
2562
const payment = {
26-
address: detail?.["recipient"],
27-
ammount:
28-
Number((detail?.["percentage"] / 100) * +tokenAmount) || 0,
63+
address: distributed.recipient,
64+
ammount: +distributed.value || 0,
2965
issueId,
3066
transactionHash,
3167
}
3268
return db.users_payments.findOrCreate({
3369
where: payment,
3470
defaults: payment
3571
})
36-
}))
72+
})
73+
]);
3774
}
3875

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

5491
const network = await getNetwork(chainId, address);
5592
if (!network) {
56-
logger.warn(NETWORK_NOT_FOUND(name, address))
93+
logger.warn(NETWORK_NOT_FOUND(name, address));
5794
return eventsProcessed;
5895
}
5996

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

68105
if (!dbBounty) {
69-
logger.warn(DB_BOUNTY_NOT_FOUND(name, bounty.cid, network.id))
106+
logger.warn(DB_BOUNTY_NOT_FOUND(name, bounty.cid, network.id));
70107
return eventsProcessed;
71108
}
72109

73110
if (dbBounty.state === "closed") {
74-
logger.warn(DB_BOUNTY_ALREADY_CLOSED(name, bounty.cid, network.id))
111+
logger.warn(DB_BOUNTY_ALREADY_CLOSED(name, bounty.cid, network.id));
75112
return eventsProcessed;
76113
}
77114

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

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

111-
await updateUserPayments(bounty.proposals[+proposalId], block.transactionHash, dbBounty.id, bounty.tokenAmount);
148+
await updateUserPayments( bounty.proposals[+proposalId],
149+
block.transactionHash,
150+
dbBounty.id,
151+
bounty.tokenAmount,
152+
chainId,
153+
network,
154+
transaction.from);
112155
await updateCuratorProposal(bounty.proposals[+proposalId].creator, network?.id)
113156
updateLeaderboardNfts()
114157
updateLeaderboardBounties("closed");

src/actions/get-bounty-funded-updated-event.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {BOUNTY_FUNDED} from "../integrations/telegram/messages";
1212
import {Push} from "../services/analytics/push";
1313
import {AnalyticEventName} from "../services/analytics/types/events";
1414
import updateSeoCardBounty from "src/modules/handle-seo-card";
15+
import { handleFundedFundingPoints } from "src/modules/points-system/handle-funded-funding-points";
16+
import { Network_v2 } from "@taikai/dappkit";
1517

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

5759
updateSeoCardBounty(dbBounty.id, name);
5860

61+
const _network = new Network_v2(connection, address);
62+
await _network.start();
63+
64+
await handleFundedFundingPoints({
65+
bounty: await _network.getBounty(dbBounty.contractId!),
66+
issue: dbBounty
67+
});
68+
5969
eventsProcessed[network.name!] = {
6070
[dbBounty.id!.toString()]: {bounty: dbBounty, eventBlock: parseLogWithContext(block)}
6171
};

src/actions/get-bounty-moved-to-open.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import updateSeoCardBounty from "src/modules/handle-seo-card";
1313
import { getCoinPrice } from "../services/coingecko";
1414
import { savePointEvent } from "../modules/points-system/save-point-event";
1515
import { getOrUpdateLastTokenPrice } from "../modules/tokens";
16+
import { handleFundedFundingPoints } from "src/modules/points-system/handle-funded-funding-points";
1617

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

8687
updateSeoCardBounty(dbBounty.id, name);
87-
88+
8889
const tokenPrice = await getOrUpdateLastTokenPrice(dbBounty.transactionalTokenId!, currency);
8990

90-
await savePointEvent( "created_task",
91-
dbBounty.user.address!,
92-
{ taskId: dbBounty.id, taskAmount: dbBounty.amount, tokenPrice, currency },
93-
(pointsPerAction, scalingFactor) => pointsPerAction * scalingFactor * +dbBounty.amount! * tokenPrice);
91+
if (!dbBounty.fundingAmount) {
92+
93+
await savePointEvent( "created_task",
94+
dbBounty.user.address!,
95+
{ taskId: dbBounty.id, taskAmount: dbBounty.amount, tokenPrice, currency },
96+
(pointsPerAction, scalingFactor) => pointsPerAction * scalingFactor * +dbBounty.amount! * tokenPrice);
97+
} else {
98+
if (!!dbBounty.rewardAmount && +dbBounty.rewardAmount > 0) {
99+
await savePointEvent( "give_funding_reward",
100+
dbBounty.user.address!,
101+
{ taskId: dbBounty.id, rewardAmount: dbBounty.rewardAmount, tokenPrice, currency },
102+
(pointsPerAction, scalingFactor) => pointsPerAction * scalingFactor * +dbBounty.rewardAmount! * tokenPrice);
103+
}
104+
105+
await handleFundedFundingPoints({
106+
bounty: await _network.getBounty(dbBounty.contractId!),
107+
issue: dbBounty
108+
});
109+
}
94110

95111
eventsProcessed[networkName!] = {
96112
...eventsProcessed[networkName!],

src/assets/templates/user-profile.hbs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
border: 3px solid #4250e4;
5252
border-radius: 50%;
5353
height: 250px;
54+
width: 250px;
5455
}
5556
5657
header h1, h3 {

src/db/models/users_payments.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type { issues, issuesId } from './issues';
55
export interface users_paymentsAttributes {
66
id: number;
77
address: string;
8-
ammount: number;
8+
ammount?: number;
99
issueId: number;
1010
transactionHash?: string;
1111
createdAt: Date;
@@ -14,13 +14,13 @@ export interface users_paymentsAttributes {
1414

1515
export type users_paymentsPk = "id";
1616
export type users_paymentsId = users_payments[users_paymentsPk];
17-
export type users_paymentsOptionalAttributes = "id" | "transactionHash" | "createdAt" | "updatedAt";
17+
export type users_paymentsOptionalAttributes = "id" | "ammount" | "transactionHash" | "createdAt" | "updatedAt";
1818
export type users_paymentsCreationAttributes = Optional<users_paymentsAttributes, users_paymentsOptionalAttributes>;
1919

2020
export class users_payments extends Model<users_paymentsAttributes, users_paymentsCreationAttributes> implements users_paymentsAttributes {
2121
id!: number;
2222
address!: string;
23-
ammount!: number;
23+
ammount?: number;
2424
issueId!: number;
2525
transactionHash?: string;
2626
createdAt!: Date;
@@ -45,8 +45,8 @@ export class users_payments extends Model<users_paymentsAttributes, users_paymen
4545
allowNull: false
4646
},
4747
ammount: {
48-
type: DataTypes.INTEGER,
49-
allowNull: false
48+
type: DataTypes.DOUBLE,
49+
allowNull: true
5050
},
5151
issueId: {
5252
type: DataTypes.INTEGER,
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { Bounty } from "@taikai/dappkit";
2+
import { Op, Sequelize } from "sequelize";
3+
4+
import models from "src/db";
5+
import { issuesAttributes } from "src/db/models/issues";
6+
import { usersAttributes } from "src/db/models/users";
7+
8+
import { savePointEvent } from "src/modules/points-system/save-point-event";
9+
import { removePointEntry } from "src/modules/points-system/remove-point-event";
10+
import { getOrUpdateLastTokenPrice } from "src/modules/tokens";
11+
12+
import logger from "src/utils/logger-handler";
13+
14+
interface HandleFundedFundingPointsProps {
15+
bounty: Bounty;
16+
issue: issuesAttributes;
17+
}
18+
19+
type FundingEventInfo = {
20+
taskId: number,
21+
benefactorId: number,
22+
amount: string;
23+
tokenPrice: number;
24+
}
25+
26+
const {
27+
NEXT_PUBLIC_CURRENCY_MAIN: currency = "eur",
28+
} = process.env;
29+
30+
export async function handleFundedFundingPoints({
31+
bounty,
32+
issue,
33+
}: HandleFundedFundingPointsProps) {
34+
try {
35+
const pointsEventsOfIssue = await models.points_events.findAll({
36+
where: {
37+
actionName: "funded_funding_request",
38+
info: {
39+
taskId: {
40+
[Op.eq]: issue.id
41+
}
42+
}
43+
}
44+
});
45+
46+
const users: usersAttributes[] = [];
47+
const findUser = (address: string) => users.find(user => user?.address?.toLowerCase() === address.toLowerCase());
48+
49+
const benefactors = bounty.funding.map((funding, id) => ({ id, ...funding }));
50+
for (const benefactor of benefactors) {
51+
let user = findUser(benefactor.benefactor);
52+
53+
if (!user) {
54+
const found = await models.users.findOne({
55+
where: Sequelize.where( Sequelize.fn("LOWER", Sequelize.col("address")),
56+
"=",
57+
benefactor.benefactor.toLowerCase())
58+
});
59+
60+
if (!found)
61+
continue;
62+
63+
user = found;
64+
users.push(found);
65+
}
66+
67+
const hasPointEvent = pointsEventsOfIssue
68+
.find(({ userId, info }) => (info as FundingEventInfo)?.benefactorId === benefactor.id && userId === user?.id);
69+
70+
if (!hasPointEvent && +benefactor.amount > 0) {
71+
const tokenPrice = await getOrUpdateLastTokenPrice(issue.transactionalTokenId!, currency);
72+
await savePointEvent("funded_funding_request", user.address!, {
73+
taskId: issue.id,
74+
benefactorId: benefactor.id,
75+
amount: benefactor.amount,
76+
tokenPrice,
77+
currency
78+
}, (pointsPerAction, scalingFactor) => pointsPerAction * scalingFactor * +benefactor.amount * tokenPrice);
79+
80+
logger.info(`handleFundedFundingPoints: point saved`, {
81+
taskId: issue.id,
82+
benefactorId: benefactor.id,
83+
amount: benefactor.amount,
84+
tokenPrice,
85+
currency
86+
});
87+
} else if (hasPointEvent && +benefactor.amount === 0)
88+
await removePointEntry(hasPointEvent.id);
89+
logger.info(`handleFundedFundingPoints: point removed because fund was retracted`, {
90+
taskId: issue.id,
91+
benefactorId: benefactor.id,
92+
amount: benefactor.amount,
93+
currency,
94+
});
95+
}
96+
} catch(error) {
97+
logger.error(`handleFundedFundingPoints: failed to handle funded funding points`, { error, bounty, issue });
98+
}
99+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import models from "src/db";
2+
import logger from "src/utils/logger-handler";
3+
4+
export async function removePointEntry(pointEntryId: number) {
5+
const pointEntry = await models.points_events.findOne({
6+
where: {
7+
id: pointEntryId
8+
}
9+
});
10+
11+
if (!pointEntry) {
12+
logger.warn(`removePointEntry: Entry with id ${pointEntryId} not found on points_events`);
13+
return;
14+
}
15+
16+
if (pointEntry.pointsCounted) {
17+
const user = await models.users.findOne({
18+
where: {
19+
id: pointEntry.userId
20+
}
21+
});
22+
23+
if (!user) {
24+
logger.warn(`removePointEntry: User with id ${pointEntry.userId} not found`);
25+
return;
26+
}
27+
28+
user.totalPoints = user.totalPoints! - pointEntry.pointsWon;
29+
30+
await user.save();
31+
}
32+
33+
await pointEntry.destroy();
34+
35+
logger.info(`PointsEvents ${pointEntryId} removed ${pointEntry.pointsCounted ? "and user totalPoints updated" : ""}`);
36+
}

src/modules/points-system/save-point-event.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import db from "src/db";
44
import logger from "src/utils/logger-handler";
55

66
type PointsEvents = "locked" | "delegated" | "created_marketplace" | "created_task" | "created_deliverable" |
7-
"created_proposal" | "accepted_proposal";
7+
"created_proposal" | "accepted_proposal" | "funded_funding_request" | "give_funding_reward";
88

99
export async function savePointEvent( event: PointsEvents,
1010
participantAddress: string,

0 commit comments

Comments
 (0)