Skip to content

Commit

Permalink
feat(leaderboard): Subgraph (#58)
Browse files Browse the repository at this point in the history
* feat(leaderboard): Subgraph

* chore(leaderboard): Refactor global logic
  • Loading branch information
ChefKai authored May 27, 2021
1 parent 34fd8b6 commit 9913c46
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 53 deletions.
64 changes: 39 additions & 25 deletions api/leaderboard/global.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,51 @@
import { VercelRequest, VercelResponse } from "@vercel/node";
import { toChecksumAddress } from "ethereumjs-util";
import { getModel } from "../../utils/mongo";
import { User } from "../../utils/types";
import { gql, request } from "graphql-request";
import { TRADING_COMPETITION_V1_SUBGRAPH } from "../../utils";

interface User {
id: string;
volumeUSD: string;
team: {
id: string;
};
}

export default async (req: VercelRequest, res: VercelResponse): Promise<VercelResponse | void> => {
if (req.method?.toUpperCase() === "OPTIONS") {
return res.status(204).end();
}

const userModel = await getModel("User");

const volume = await userModel.aggregate([
{
$group: {
_id: null,
volume: { $sum: "$leaderboard.volume" },
},
},
]);

const users = await userModel
.find({ leaderboard: { $exists: true } })
.sort({ "leaderboard.global": "asc" })
.limit(20)
.exec();
const result = await request(
TRADING_COMPETITION_V1_SUBGRAPH,
gql`
{
competition(id: "1") {
id
userCount
volumeUSD
}
users(first: 500, orderBy: volumeUSD, orderDirection: desc, block: { number: 6553043 }) {
id
volumeUSD
team {
id
}
}
}
`
);

const data = users.map((user: User) => ({
rank: user.leaderboard?.global,
address: toChecksumAddress(user.address),
username: user.username,
volume: user.leaderboard?.volume,
teamId: parseInt(user?.team),
const data = result.users.map((user: User, index: number) => ({
rank: index + 1,
address: toChecksumAddress(user.id),
volume: parseFloat(user.volumeUSD),
teamId: parseInt(user.team.id),
}));

return res.status(200).json({ total: users.length, volume: volume[0].volume, data });
return res.status(200).json({
total: parseInt(result.competition.userCount),
volume: parseFloat(result.competition.volumeUSD),
data,
});
};
66 changes: 38 additions & 28 deletions api/leaderboard/team.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { VercelRequest, VercelResponse } from "@vercel/node";
import { toChecksumAddress } from "ethereumjs-util";
import { getModel } from "../../utils/mongo";
import { User } from "../../utils/types";
import { gql, request } from "graphql-request";
import { TRADING_COMPETITION_V1_SUBGRAPH } from "../../utils";

interface User {
id: string;
volumeUSD: string;
team: {
id: string;
};
}

export default async (req: VercelRequest, res: VercelResponse): Promise<VercelResponse | void> => {
if (req.method?.toUpperCase() === "OPTIONS") {
Expand All @@ -12,34 +20,36 @@ export default async (req: VercelRequest, res: VercelResponse): Promise<VercelRe
teamId = teamId as string;

if (teamId) {
const userModel = await getModel("User");

const volume = await userModel.aggregate([
{ $match: { team: teamId } },
{ $limit: 500 },
{
$group: {
_id: null,
volume: { $sum: "$leaderboard.volume" },
},
},
]);

const users = await userModel
.find({ team: teamId, leaderboard: { $exists: true } })
.sort({ "leaderboard.team": "asc" })
.limit(20)
.exec();

const data = users.map((user: User) => ({
rank: user.leaderboard?.team,
address: toChecksumAddress(user.address),
username: user.username,
volume: user.leaderboard?.volume,
teamId: parseInt(user?.team),
const result = await request(
TRADING_COMPETITION_V1_SUBGRAPH,
gql`
{
users (first: 500, where: { team: "${teamId}" }, orderBy: volumeUSD, orderDirection: desc, block: { number: 6553043 }) {
id
volumeUSD
team {
id
userCount
}
}
}
`
);

const volume = result.users.reduce((acc: number, user: User) => {
return acc + parseFloat(user.volumeUSD);
}, 0);

const data = result.users.map((user: User, index: number) => ({
rank: index + 1,
address: toChecksumAddress(user.id),
volume: parseFloat(user.volumeUSD),
teamId: parseInt(user.team.id),
}));

return res.status(200).json({ total: users.length, volume: volume[0].volume, data });
return res
.status(200)
.json({ total: parseInt(result.users[0].team.userCount), volume: volume, data });
}

return res.status(400).json({ error: { message: "Team unknown." } });
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
},
"dependencies": {
"ethereumjs-util": "^7.0.10",
"graphql": "^15.5.0",
"graphql-request": "^3.4.0",
"mongoose": "^5.12.11"
},
"devDependencies": {
Expand Down
3 changes: 3 additions & 0 deletions utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import {
import blacklist from "./blacklist.json";
import { getModel } from "./mongo";

export const TRADING_COMPETITION_V1_SUBGRAPH =
"https://api.thegraph.com/subgraphs/name/pancakeswap/trading-competition-v1";

/**
* Recover the msg.sender for a given signature based on a message.
*
Expand Down
31 changes: 31 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1522,6 +1522,13 @@ create-require@^1.1.0:
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==

cross-fetch@^3.0.6:
version "3.1.4"
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39"
integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==
dependencies:
node-fetch "2.6.1"

cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
Expand Down Expand Up @@ -1947,6 +1954,11 @@ expect@^27.0.1:
jest-message-util "^27.0.1"
jest-regex-util "^27.0.1"

extract-files@^9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-9.0.0.tgz#8a7744f2437f81f5ed3250ed9f1550de902fe54a"
integrity sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ==

fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
Expand Down Expand Up @@ -2170,6 +2182,20 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4:
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee"
integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==

graphql-request@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-3.4.0.tgz#3a400cd5511eb3c064b1873afb059196bbea9c2b"
integrity sha512-acrTzidSlwAj8wBNO7Q/UQHS8T+z5qRGquCQRv9J1InwR01BBWV9ObnoE+JS5nCCEj8wSGS0yrDXVDoRiKZuOg==
dependencies:
cross-fetch "^3.0.6"
extract-files "^9.0.0"
form-data "^3.0.0"

graphql@^15.5.0:
version "15.5.0"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.5.0.tgz#39d19494dbe69d1ea719915b578bf920344a69d5"
integrity sha512-OmaM7y0kaK31NKG31q4YbD2beNYa6jBBKtMFT6gLYJljHLJr42IqJ8KX08u3Li/0ifzTU5HjmoOOrwa5BRLeDA==

hard-rejection@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883"
Expand Down Expand Up @@ -3286,6 +3312,11 @@ node-addon-api@^2.0.0:
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32"
integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==

[email protected]:
version "2.6.1"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==

node-gyp-build@^4.2.0:
version "4.2.3"
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.2.3.tgz#ce6277f853835f718829efb47db20f3e4d9c4739"
Expand Down

0 comments on commit 9913c46

Please sign in to comment.