From 8edd1219105d0567e123eda4504c038f7ab30228 Mon Sep 17 00:00:00 2001 From: mme <9083787+mme022@users.noreply.github.com> Date: Fri, 17 Mar 2023 13:15:16 +0000 Subject: [PATCH 01/20] space for degenscore --- .../data-providers/degenscore/index.ts | 134 ++++++++++++++++++ .../degenscore/interface-schema.json | 37 +++++ .../data-providers/degenscore/types.ts | 111 +++++++++++++++ 3 files changed, 282 insertions(+) create mode 100644 group-generators/helpers/data-providers/degenscore/index.ts create mode 100644 group-generators/helpers/data-providers/degenscore/interface-schema.json create mode 100644 group-generators/helpers/data-providers/degenscore/types.ts diff --git a/group-generators/helpers/data-providers/degenscore/index.ts b/group-generators/helpers/data-providers/degenscore/index.ts new file mode 100644 index 000000000..0997ca1c3 --- /dev/null +++ b/group-generators/helpers/data-providers/degenscore/index.ts @@ -0,0 +1,134 @@ +import axios from "axios"; +import { + DiscourseUser, + DiscourseBadge, + DiscourseGroup, + DiscourseGroupMember, + UsersWithBadgesCountRequest, + UsersCountRequest, +} from "./types"; +import { FetchedData } from "topics/group"; + +export class DiscourseProvider { + url: string; + headers: { + authorization: string; + accept: string; + }; + + public async getDiscourse(endpoint: string): Promise { + const { data: res } = await axios({ + url: this.url + "/" + endpoint, + method: "get", + headers: this.headers, + }); + return res; + } + + public async getAllUsers(): Promise { + try { + const res = await this.getDiscourse("admin/users/list/active.json"); + const users: DiscourseUser[] = res.result.members; + return users; + } catch (error) { + throw new Error("Error fetching the users:" + error); + } + } + + public async getUsers(): Promise { + const res: FetchedData = {}; + try { + const users = await this.getAllUsers(); + + users.forEach((user) => { + res[user.id] = 1; + }); + + return res; + } catch (error) { + throw new Error("Error fetching the users: " + error); + } + } + + public async getUsersCount(requestData: UsersCountRequest): Promise { + this.url = requestData.discourseDomain; + this.headers = { + authorization: requestData.apiKey as string, + accept: "application/json", + }; + const users = await this.getUsers(); + return Object.keys(users).length; + } + + public async getAllBadges(): Promise { + try { + const res = await this.getDiscourse("admin/badges.json"); + const badges: DiscourseBadge[] = res.result.badges; + return badges; + } catch (error) { + throw new Error("Error fetching the badges: " + error); + } + } + + public async getGroups(): Promise { + try { + const res = await this.getDiscourse("admin/users/list/active.json"); + const groups: DiscourseGroup[] = res.result; + return groups; + } catch (error) { + throw new Error("Error fetching the groups: " + error); + } + } + + public async getMembersGroup(id: number): Promise { + try { + const res = await this.getDiscourse(`/groups/${id}/members.json`); + const members: DiscourseGroupMember[] = res.result; + return members; + } catch (error) { + throw new Error("Error fetching the groups: " + error); + } + } + + async getBadgesForUser(userName: string): Promise { + try { + const res = await this.getDiscourse(`user-badges/${userName}.json`); + const badges: DiscourseBadge[] = res.result.badges; + return badges; + } catch (error) { + throw new Error( + "Error fetching badges of users: " + userName + " with error " + error + ); + } + } + + public async getUsersWithBadges( + requestData: UsersWithBadgesCountRequest + ): Promise { + const users: FetchedData = {}; + + const listOfUsers = await this.getAllUsers(); + + for (const user of listOfUsers) { + const badgesForUser = await this.getBadgesForUser(user.username); + badgesForUser.forEach((badges) => { + if (badges.id == requestData.badgeId) { + users[user.id] = 1; + } + }); + } + return users; + } + + public async getUsersWithBadgesCount( + requestData: UsersWithBadgesCountRequest + ): Promise { + this.url = requestData.discourseDomain; + this.headers = { + authorization: requestData.apiKey as string, + accept: "application/json", + }; + const users = await this.getUsersWithBadges(requestData); + return Object.keys(users).length; + } +} diff --git a/group-generators/helpers/data-providers/degenscore/interface-schema.json b/group-generators/helpers/data-providers/degenscore/interface-schema.json new file mode 100644 index 000000000..b0bb6deab --- /dev/null +++ b/group-generators/helpers/data-providers/degenscore/interface-schema.json @@ -0,0 +1,37 @@ +{ + "name": "Discourse", + "iconUrl": "", + "providerClassName": "DiscourseProvider", + "functions": [ + { + "name": "Get Users with specific forum badge", + "functionName": "getUsersWithBadges", + "countFunctionName": "getUsersWithBadgesCount", + "description": "Returns all users for a specific badge", + "args": [ + { + "name": "Data to submit", + "argName": "requestData", + "type": "string", + "example": "{'discourseDomain': 'https://sismo-integration.discourse.group/', 'apiKey': '922829fcd93ca388de49ace49c4a5682eaad5c7a260f99299e2d88a388c08d7aw', 'badgeId': 42}", + "description": "The object containing the domain of the website using discourse, its apiKey and the identifier of the badge we want the users to be filtered for" + } + ] + }, + { + "name": "Get user registered in forum", + "functionName": "getAllUsers", + "countFunctionName": "getUsersCount", + "description": "Returns all users registered in your forum", + "args": [ + { + "name": "Data to submit", + "argName": "requestData", + "type": "string", + "example": "{'discourseDomain': 'https://sismo-integration.discourse.group/', 'apiKey': '922829fcd93ca388de49ace49c4a5682eaad5c7a260f99299e2d88a388c08d7aw'}", + "description": "The object containing the domain of the website using discourse, its apiKey and the identifier of the badge we want the users to be filtered for" + } + ] + } + ] +} diff --git a/group-generators/helpers/data-providers/degenscore/types.ts b/group-generators/helpers/data-providers/degenscore/types.ts new file mode 100644 index 000000000..2e76665ee --- /dev/null +++ b/group-generators/helpers/data-providers/degenscore/types.ts @@ -0,0 +1,111 @@ + +// discourse api + +export type DiscourseUser = { + id: number; + username: string; + name: string; + email: string; + secondary_emails: []; + active: boolean; + admin: boolean; + moderator: boolean; + last_seen_at: string; + last_emailed_at: string; + created_at: string; + last_seen_age: number; + last_emailed_age: number; + created_at_age: number; + trust_level: number; + manual_locked_trust_level: string; + flag_level: number; + title: string; + time_read: number; + staged: boolean; + days_visited: number; + posts_read_count: number; + topics_entered: number; + post_count: number; +}; + +export type DiscourseBadge = { + id: number; + name: string; + description: string; + grant_count: number; + allow_title: boolean; + multiple_grant: boolean; + icon: string; + image_url: string; + listable: boolean; + enabled: boolean; + badge_grouping_id: number; + system: boolean; + slug: string; + manually_grantable: boolean; + badge_type_id: number; +}; + +export type DiscourseGroup = { + id: number, + automatic: boolean, + name: string, + display_name: string, + user_count: number, + mentionable_level: number, + messageable_level: number, + visibility_level: number, + primary_group: boolean, + title: string | null, + grant_trust_level: string | null, + incoming_email: string | null, + has_messages: boolean, + flair_url: string | null, + flair_bg_color: string | null, + flair_color: string | null, + bio_raw: string | null, + bio_cooked: string | null, + bio_excerpt: string | null, + public_admission: boolean, + public_exit: boolean, + allow_membership_requests: boolean, + full_name: string | null, + default_notification_level: number, + membership_request_template: string | null, + is_group_user: boolean, + is_group_owner: boolean, + members_visibility_level: number, + can_see_members: boolean, + can_admin_group: boolean, + can_edit_group: boolean, + publish_read_state: boolean, +} + +// Discorse GroupMembers +export type DiscourseGroupMember = { + id: 0, + username: string, + name: string, + avatar_template: string, + title: string, + last_posted_at: string, + last_seen_at: string, + added_at: string, + timezone: string +} + +// user defined types + +export type Users = { + id: number, + name: string, +} + +export type UsersWithBadgesCountRequest = { + discourseDomain: string, apiKey: string, badgeId: number +} + +export type UsersCountRequest = { + discourseDomain: string, apiKey: string +} + From 6386cc5d516eebc0543d1c9ebbca50bc45d8fe70 Mon Sep 17 00:00:00 2001 From: mme <9083787+mme022@users.noreply.github.com> Date: Fri, 17 Mar 2023 13:37:06 +0000 Subject: [PATCH 02/20] added function to fetch tokenholders from etherscan --- .../data-providers/degenscore/index.ts | 41 +++--- .../degenscore/interface-schema.json | 42 +++---- .../data-providers/degenscore/types.ts | 118 +++--------------- 3 files changed, 54 insertions(+), 147 deletions(-) diff --git a/group-generators/helpers/data-providers/degenscore/index.ts b/group-generators/helpers/data-providers/degenscore/index.ts index 0997ca1c3..6f27fc512 100644 --- a/group-generators/helpers/data-providers/degenscore/index.ts +++ b/group-generators/helpers/data-providers/degenscore/index.ts @@ -1,21 +1,24 @@ import axios from "axios"; -import { - DiscourseUser, - DiscourseBadge, - DiscourseGroup, - DiscourseGroupMember, - UsersWithBadgesCountRequest, - UsersCountRequest, -} from "./types"; +// eslint-disable-next-line no-restricted-imports +import { TokenHolder } from "../transpose/types"; +import { UsersWithBadgesCountRequest, UsersCountRequest } from "./types"; import { FetchedData } from "topics/group"; -export class DiscourseProvider { +export class DegenScoreProvider { url: string; headers: { authorization: string; accept: string; }; + public async getTokenHolders(): Promise { + const { data: res } = await axios({ + url: "https://api.etherscan.io/api?module=token&action=tokenholderlist&contractaddress=0x0521FA0bf785AE9759C7cB3CBE7512EbF20Fbdaa&page=1&offset=10&apikey=process.env.ETHERSCAN_API_KEY", + method: "get", + }); + return res.result; + } + public async getDiscourse(endpoint: string): Promise { const { data: res } = await axios({ url: this.url + "/" + endpoint, @@ -25,10 +28,10 @@ export class DiscourseProvider { return res; } - public async getAllUsers(): Promise { + public async getAllUsers(): Promise { try { const res = await this.getDiscourse("admin/users/list/active.json"); - const users: DiscourseUser[] = res.result.members; + const users: any[] = res.result.members; return users; } catch (error) { throw new Error("Error fetching the users:" + error); @@ -60,40 +63,40 @@ export class DiscourseProvider { return Object.keys(users).length; } - public async getAllBadges(): Promise { + public async getAllBadges(): Promise { try { const res = await this.getDiscourse("admin/badges.json"); - const badges: DiscourseBadge[] = res.result.badges; + const badges: any[] = res.result.badges; return badges; } catch (error) { throw new Error("Error fetching the badges: " + error); } } - public async getGroups(): Promise { + public async getGroups(): Promise { try { const res = await this.getDiscourse("admin/users/list/active.json"); - const groups: DiscourseGroup[] = res.result; + const groups: any[] = res.result; return groups; } catch (error) { throw new Error("Error fetching the groups: " + error); } } - public async getMembersGroup(id: number): Promise { + public async getMembersGroup(id: number): Promise { try { const res = await this.getDiscourse(`/groups/${id}/members.json`); - const members: DiscourseGroupMember[] = res.result; + const members: any[] = res.result; return members; } catch (error) { throw new Error("Error fetching the groups: " + error); } } - async getBadgesForUser(userName: string): Promise { + async getBadgesForUser(userName: string): Promise { try { const res = await this.getDiscourse(`user-badges/${userName}.json`); - const badges: DiscourseBadge[] = res.result.badges; + const badges: any[] = res.result.badges; return badges; } catch (error) { throw new Error( diff --git a/group-generators/helpers/data-providers/degenscore/interface-schema.json b/group-generators/helpers/data-providers/degenscore/interface-schema.json index b0bb6deab..f67a40d4d 100644 --- a/group-generators/helpers/data-providers/degenscore/interface-schema.json +++ b/group-generators/helpers/data-providers/degenscore/interface-schema.json @@ -1,35 +1,27 @@ { - "name": "Discourse", + "name": "DegenScore", "iconUrl": "", - "providerClassName": "DiscourseProvider", + "providerClassName": "DegenScoreProvider", "functions": [ { - "name": "Get Users with specific forum badge", - "functionName": "getUsersWithBadges", - "countFunctionName": "getUsersWithBadgesCount", - "description": "Returns all users for a specific badge", + "name": "Get holders of beacon", + "functionName": "TODO", + "countFunctionName": "TODO", + "description": "Returns all holders of a beacon above a min score and with a specific trait", "args": [ { - "name": "Data to submit", - "argName": "requestData", - "type": "string", - "example": "{'discourseDomain': 'https://sismo-integration.discourse.group/', 'apiKey': '922829fcd93ca388de49ace49c4a5682eaad5c7a260f99299e2d88a388c08d7aw', 'badgeId': 42}", - "description": "The object containing the domain of the website using discourse, its apiKey and the identifier of the badge we want the users to be filtered for" - } - ] - }, - { - "name": "Get user registered in forum", - "functionName": "getAllUsers", - "countFunctionName": "getUsersCount", - "description": "Returns all users registered in your forum", - "args": [ + "name": "score", + "argName": "TODO", + "type": "TODO", + "example": "730", + "description": "A minimum beacon score" + }, { - "name": "Data to submit", - "argName": "requestData", - "type": "string", - "example": "{'discourseDomain': 'https://sismo-integration.discourse.group/', 'apiKey': '922829fcd93ca388de49ace49c4a5682eaad5c7a260f99299e2d88a388c08d7aw'}", - "description": "The object containing the domain of the website using discourse, its apiKey and the identifier of the badge we want the users to be filtered for" + "name": "trait", + "argName": "TODO", + "type": "TODO", + "example": "TODO", + "description": "A specific trait identifier" } ] } diff --git a/group-generators/helpers/data-providers/degenscore/types.ts b/group-generators/helpers/data-providers/degenscore/types.ts index 2e76665ee..1d1810d82 100644 --- a/group-generators/helpers/data-providers/degenscore/types.ts +++ b/group-generators/helpers/data-providers/degenscore/types.ts @@ -1,111 +1,23 @@ +// discourse api -// discourse api - -export type DiscourseUser = { - id: number; - username: string; - name: string; - email: string; - secondary_emails: []; - active: boolean; - admin: boolean; - moderator: boolean; - last_seen_at: string; - last_emailed_at: string; - created_at: string; - last_seen_age: number; - last_emailed_age: number; - created_at_age: number; - trust_level: number; - manual_locked_trust_level: string; - flag_level: number; - title: string; - time_read: number; - staged: boolean; - days_visited: number; - posts_read_count: number; - topics_entered: number; - post_count: number; +export type TokenHolder = { + TokenHolderAddress: string; + TokenHolderQuantity: string; }; -export type DiscourseBadge = { - id: number; - name: string; - description: string; - grant_count: number; - allow_title: boolean; - multiple_grant: boolean; - icon: string; - image_url: string; - listable: boolean; - enabled: boolean; - badge_grouping_id: number; - system: boolean; - slug: string; - manually_grantable: boolean; - badge_type_id: number; +export type EtherscanResponse = { + status: string; + message: string; + result: TokenHolder[]; }; -export type DiscourseGroup = { - id: number, - automatic: boolean, - name: string, - display_name: string, - user_count: number, - mentionable_level: number, - messageable_level: number, - visibility_level: number, - primary_group: boolean, - title: string | null, - grant_trust_level: string | null, - incoming_email: string | null, - has_messages: boolean, - flair_url: string | null, - flair_bg_color: string | null, - flair_color: string | null, - bio_raw: string | null, - bio_cooked: string | null, - bio_excerpt: string | null, - public_admission: boolean, - public_exit: boolean, - allow_membership_requests: boolean, - full_name: string | null, - default_notification_level: number, - membership_request_template: string | null, - is_group_user: boolean, - is_group_owner: boolean, - members_visibility_level: number, - can_see_members: boolean, - can_admin_group: boolean, - can_edit_group: boolean, - publish_read_state: boolean, -} - -// Discorse GroupMembers -export type DiscourseGroupMember = { - id: 0, - username: string, - name: string, - avatar_template: string, - title: string, - last_posted_at: string, - last_seen_at: string, - added_at: string, - timezone: string -} - -// user defined types - -export type Users = { - id: number, - name: string, -} - export type UsersWithBadgesCountRequest = { - discourseDomain: string, apiKey: string, badgeId: number -} + discourseDomain: string; + apiKey: string; + badgeId: number; +}; export type UsersCountRequest = { - discourseDomain: string, apiKey: string -} - + discourseDomain: string; + apiKey: string; +}; From 1177a98c51013f07189d91a17a5c5e512985cccb Mon Sep 17 00:00:00 2001 From: mme <9083787+mme022@users.noreply.github.com> Date: Fri, 17 Mar 2023 15:27:43 +0000 Subject: [PATCH 03/20] added the first draft of functions --- .../data-providers/degenscore/index.ts | 137 ++++-------------- .../data-providers/degenscore/types.ts | 44 ++++-- 2 files changed, 61 insertions(+), 120 deletions(-) diff --git a/group-generators/helpers/data-providers/degenscore/index.ts b/group-generators/helpers/data-providers/degenscore/index.ts index 6f27fc512..c80629994 100644 --- a/group-generators/helpers/data-providers/degenscore/index.ts +++ b/group-generators/helpers/data-providers/degenscore/index.ts @@ -1,8 +1,8 @@ import axios from "axios"; // eslint-disable-next-line no-restricted-imports import { TokenHolder } from "../transpose/types"; -import { UsersWithBadgesCountRequest, UsersCountRequest } from "./types"; -import { FetchedData } from "topics/group"; +//import { FetchedData } from "topics/group"; +import { UserBeaconData } from "./types"; export class DegenScoreProvider { url: string; @@ -13,125 +13,40 @@ export class DegenScoreProvider { public async getTokenHolders(): Promise { const { data: res } = await axios({ - url: "https://api.etherscan.io/api?module=token&action=tokenholderlist&contractaddress=0x0521FA0bf785AE9759C7cB3CBE7512EbF20Fbdaa&page=1&offset=10&apikey=process.env.ETHERSCAN_API_KEY", + url: + "https://api.etherscan.io/api?module=token&action=tokenholderlist&contractaddress=0x0521FA0bf785AE9759C7cB3CBE7512EbF20Fbdaa&page=1&offset=10&apikey=" + + process.env.ETHERSCAN_API_KEY, method: "get", }); return res.result; } - public async getDiscourse(endpoint: string): Promise { - const { data: res } = await axios({ - url: this.url + "/" + endpoint, - method: "get", - headers: this.headers, - }); - return res; - } - - public async getAllUsers(): Promise { - try { - const res = await this.getDiscourse("admin/users/list/active.json"); - const users: any[] = res.result.members; - return users; - } catch (error) { - throw new Error("Error fetching the users:" + error); - } - } + public async getBeaconDataForHolders(): Promise { + const tokenholders: TokenHolder[] = await this.getTokenHolders(); - public async getUsers(): Promise { - const res: FetchedData = {}; - try { - const users = await this.getAllUsers(); + const userBeaconData: any[] = []; - users.forEach((user) => { - res[user.id] = 1; + tokenholders.forEach(async (holder) => { + const { data: res } = await axios({ + url: "https://beacon.degenscore.com/v1/beacon/" + holder.owner_address, + method: "get", }); - - return res; - } catch (error) { - throw new Error("Error fetching the users: " + error); - } - } - - public async getUsersCount(requestData: UsersCountRequest): Promise { - this.url = requestData.discourseDomain; - this.headers = { - authorization: requestData.apiKey as string, - accept: "application/json", - }; - const users = await this.getUsers(); - return Object.keys(users).length; - } - - public async getAllBadges(): Promise { - try { - const res = await this.getDiscourse("admin/badges.json"); - const badges: any[] = res.result.badges; - return badges; - } catch (error) { - throw new Error("Error fetching the badges: " + error); - } - } - - public async getGroups(): Promise { - try { - const res = await this.getDiscourse("admin/users/list/active.json"); - const groups: any[] = res.result; - return groups; - } catch (error) { - throw new Error("Error fetching the groups: " + error); - } - } - - public async getMembersGroup(id: number): Promise { - try { - const res = await this.getDiscourse(`/groups/${id}/members.json`); - const members: any[] = res.result; - return members; - } catch (error) { - throw new Error("Error fetching the groups: " + error); - } - } - - async getBadgesForUser(userName: string): Promise { - try { - const res = await this.getDiscourse(`user-badges/${userName}.json`); - const badges: any[] = res.result.badges; - return badges; - } catch (error) { - throw new Error( - "Error fetching badges of users: " + userName + " with error " + error - ); - } - } - - public async getUsersWithBadges( - requestData: UsersWithBadgesCountRequest - ): Promise { - const users: FetchedData = {}; - - const listOfUsers = await this.getAllUsers(); - - for (const user of listOfUsers) { - const badgesForUser = await this.getBadgesForUser(user.username); - badgesForUser.forEach((badges) => { - if (badges.id == requestData.badgeId) { - users[user.id] = 1; - } + userBeaconData.push({ + owner_address: holder.owner_address, + quantity: holder.balance, + beaconData: res, }); - } - return users; + }); + return userBeaconData; } - public async getUsersWithBadgesCount( - requestData: UsersWithBadgesCountRequest - ): Promise { - this.url = requestData.discourseDomain; - this.headers = { - authorization: requestData.apiKey as string, - accept: "application/json", - }; - const users = await this.getUsersWithBadges(requestData); - return Object.keys(users).length; + public async getBeaconHolders(score: string /*, trait: string*/) { + const userBeaconData: UserBeaconData[] = + await this.getBeaconDataForHolders(); + + const filter = userBeaconData.filter((elem: any) => { + elem["quantity"] >= score; + }); + return filter; } } diff --git a/group-generators/helpers/data-providers/degenscore/types.ts b/group-generators/helpers/data-providers/degenscore/types.ts index 1d1810d82..3d38927c0 100644 --- a/group-generators/helpers/data-providers/degenscore/types.ts +++ b/group-generators/helpers/data-providers/degenscore/types.ts @@ -1,5 +1,3 @@ -// discourse api - export type TokenHolder = { TokenHolderAddress: string; TokenHolderQuantity: string; @@ -11,13 +9,41 @@ export type EtherscanResponse = { result: TokenHolder[]; }; -export type UsersWithBadgesCountRequest = { - discourseDomain: string; - apiKey: string; - badgeId: number; +export type DegenScoreTrait = { + name: string; + description: string; + image: string; + value: string | number; + valueType: string; + traitType: string; + rarity: string; + id: string; + tags: { id: string; value: string }[]; +}; + +export type TraitInfoResponse = { + name: string; + description: string; + image: string; + properties: { + valueType: string; + }; +}; + +export type BeaconInfoResponse = { + name: string; + description: string; + image: string; + properties: any; + updatedAt: string; + isConfirmed: boolean; + external_url: string; + animation_url: string; + traits: DegenScoreTrait; }; -export type UsersCountRequest = { - discourseDomain: string; - apiKey: string; +export type UserBeaconData = { + owner_address: string; + balance: string; + beaconData: BeaconInfoResponse; }; From 29149702df74866bcf0e66a26cc7f93834679175 Mon Sep 17 00:00:00 2001 From: mme <9083787+mme022@users.noreply.github.com> Date: Fri, 17 Mar 2023 16:29:19 +0000 Subject: [PATCH 04/20] added functionality to retrieve addresses matching criteria --- .../data-providers/degenscore/index.ts | 45 ++++++++++++------- .../degenscore/interface-schema.json | 12 ++--- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/group-generators/helpers/data-providers/degenscore/index.ts b/group-generators/helpers/data-providers/degenscore/index.ts index c80629994..e450b0f41 100644 --- a/group-generators/helpers/data-providers/degenscore/index.ts +++ b/group-generators/helpers/data-providers/degenscore/index.ts @@ -1,8 +1,8 @@ import axios from "axios"; // eslint-disable-next-line no-restricted-imports import { TokenHolder } from "../transpose/types"; -//import { FetchedData } from "topics/group"; import { UserBeaconData } from "./types"; +import { FetchedData } from "topics/group"; export class DegenScoreProvider { url: string; @@ -11,18 +11,29 @@ export class DegenScoreProvider { accept: string; }; - public async getTokenHolders(): Promise { - const { data: res } = await axios({ - url: - "https://api.etherscan.io/api?module=token&action=tokenholderlist&contractaddress=0x0521FA0bf785AE9759C7cB3CBE7512EbF20Fbdaa&page=1&offset=10&apikey=" + - process.env.ETHERSCAN_API_KEY, - method: "get", + public async getBeaconHolders(apiKey: string, score: string, trait: string) { + const userBeaconData: UserBeaconData[] = await this.getBeaconDataForHolders( + apiKey + ); + + const result: FetchedData = {}; + + userBeaconData.map((elem: any) => { + if (elem["quantity"] >= score) { + elem["beaconData"]["traits"].forEach((traitElem: any) => { + if (traitElem["traitType"] == trait) { + result[elem["owner_address"]] = 1; + } + }); + } }); - return res.result; + return result; } - public async getBeaconDataForHolders(): Promise { - const tokenholders: TokenHolder[] = await this.getTokenHolders(); + private async getBeaconDataForHolders( + apiKey: string + ): Promise { + const tokenholders: TokenHolder[] = await this.getTokenHolders(apiKey); const userBeaconData: any[] = []; @@ -40,13 +51,13 @@ export class DegenScoreProvider { return userBeaconData; } - public async getBeaconHolders(score: string /*, trait: string*/) { - const userBeaconData: UserBeaconData[] = - await this.getBeaconDataForHolders(); - - const filter = userBeaconData.filter((elem: any) => { - elem["quantity"] >= score; + private async getTokenHolders(apiKey: string): Promise { + const { data: res } = await axios({ + url: + "https://api.etherscan.io/api?module=token&action=tokenholderlist&contractaddress=0x0521FA0bf785AE9759C7cB3CBE7512EbF20Fbdaa&page=1&offset=10&apikey=" + + apiKey, + method: "get", }); - return filter; + return res.result; } } diff --git a/group-generators/helpers/data-providers/degenscore/interface-schema.json b/group-generators/helpers/data-providers/degenscore/interface-schema.json index f67a40d4d..4b18f7ff2 100644 --- a/group-generators/helpers/data-providers/degenscore/interface-schema.json +++ b/group-generators/helpers/data-providers/degenscore/interface-schema.json @@ -5,22 +5,22 @@ "functions": [ { "name": "Get holders of beacon", - "functionName": "TODO", + "functionName": "getBeaconHolders", "countFunctionName": "TODO", "description": "Returns all holders of a beacon above a min score and with a specific trait", "args": [ { "name": "score", - "argName": "TODO", - "type": "TODO", + "argName": "score", + "type": "string", "example": "730", "description": "A minimum beacon score" }, { "name": "trait", - "argName": "TODO", - "type": "TODO", - "example": "TODO", + "argName": "trait", + "type": "string", + "example": "TRAIT_TYPE_PRIMARY", "description": "A specific trait identifier" } ] From 98d590de6a5ccc8c2e802364f8663489cbad60f0 Mon Sep 17 00:00:00 2001 From: mme <9083787+mme022@users.noreply.github.com> Date: Fri, 17 Mar 2023 16:48:33 +0000 Subject: [PATCH 05/20] finished degenscore provider --- .../helpers/data-providers/degenscore/index.ts | 9 +++++++++ .../data-providers/degenscore/interface-schema.json | 9 ++++++++- group-generators/helpers/data-providers/index.ts | 13 +++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/group-generators/helpers/data-providers/degenscore/index.ts b/group-generators/helpers/data-providers/degenscore/index.ts index e450b0f41..c432dba7e 100644 --- a/group-generators/helpers/data-providers/degenscore/index.ts +++ b/group-generators/helpers/data-providers/degenscore/index.ts @@ -30,6 +30,15 @@ export class DegenScoreProvider { return result; } + public async getBeaconHoldersCount( + apiKey: string, + score: string, + trait: string + ) { + const result = await this.getBeaconHolders(apiKey, score, trait); + return Object.keys(result).length; + } + private async getBeaconDataForHolders( apiKey: string ): Promise { diff --git a/group-generators/helpers/data-providers/degenscore/interface-schema.json b/group-generators/helpers/data-providers/degenscore/interface-schema.json index 4b18f7ff2..f5b412f37 100644 --- a/group-generators/helpers/data-providers/degenscore/interface-schema.json +++ b/group-generators/helpers/data-providers/degenscore/interface-schema.json @@ -6,9 +6,16 @@ { "name": "Get holders of beacon", "functionName": "getBeaconHolders", - "countFunctionName": "TODO", + "countFunctionName": "getBeaconHoldersCount", "description": "Returns all holders of a beacon above a min score and with a specific trait", "args": [ + { + "name": "Etherscan API key", + "argName": "apiKey", + "type": "string", + "example": "asdfgnmjuytfg76trew34rtghi876tre4345tyhb", + "description": "API key for etherscan, used to fetch beacon holders" + }, { "name": "score", "argName": "score", diff --git a/group-generators/helpers/data-providers/index.ts b/group-generators/helpers/data-providers/index.ts index 4d2b9de71..fa03f4f9a 100644 --- a/group-generators/helpers/data-providers/index.ts +++ b/group-generators/helpers/data-providers/index.ts @@ -1,4 +1,5 @@ import { BigQueryProvider } from "./big-query/big-query"; +import { DegenScoreProvider } from "./degenscore"; import { EnsProvider } from "./ens"; import { EthLeaderboardProvider } from "./eth-leaderboard"; import { FarcasterProvider } from "./farcaster"; @@ -37,6 +38,7 @@ export const dataProviders = { EnsProvider, EthLeaderboardProvider, FarcasterProvider, + DegenScoreProvider, GithubProvider, GraphQLProvider, HiveProvider, @@ -67,6 +69,17 @@ export const dataProvidersInterfacesSchemas = [ ]; export const dataProvidersAPIEndpoints = { + DegenScoreProvider: { + getBeaconHoldersCount: async ({ + apiKey, + score, + trait, + }: { + apiKey: string; + score: string; + trait: string; + }) => new DegenScoreProvider().getBeaconHoldersCount(apiKey, score, trait), + }, GithubProvider: { getRepositoriesContributorsCount: async (_: any) => new GithubProvider().getRepositoriesContributorsCount(_), From f4f757bc23c23ef205002019bf9716cf5488b1cb Mon Sep 17 00:00:00 2001 From: MarkuSchick Date: Fri, 17 Mar 2023 20:21:09 +0000 Subject: [PATCH 06/20] feat: add gitpoap as data provider --- .../helpers/data-providers/gitpoap/index.ts | 84 +++++++++++++++++++ .../gitpoap/interface-schema.json | 37 ++++++++ .../helpers/data-providers/gitpoap/types.ts | 20 +++++ .../helpers/data-providers/index.ts | 10 +++ 4 files changed, 151 insertions(+) create mode 100644 group-generators/helpers/data-providers/gitpoap/index.ts create mode 100644 group-generators/helpers/data-providers/gitpoap/interface-schema.json create mode 100644 group-generators/helpers/data-providers/gitpoap/types.ts diff --git a/group-generators/helpers/data-providers/gitpoap/index.ts b/group-generators/helpers/data-providers/gitpoap/index.ts new file mode 100644 index 000000000..cc820cb76 --- /dev/null +++ b/group-generators/helpers/data-providers/gitpoap/index.ts @@ -0,0 +1,84 @@ +import axios from "axios"; +import { GitPoap, GitPoapAddresses } from "./types"; +import { FetchedData } from "topics/group"; + + +// fixes https://github.com/sismo-core/sismo-hub/issues/1454 +// api docs https://docs.gitpoap.io/api + +export class GitPoapProvider { + url: string; + + + public constructor() { + this.url = "https://public-api.gitpoap.io/"; + } + + public async getGitPoap(endpoint: string): Promise { + const { data: res } = await axios({ + url: this.url + endpoint, + method: "get", + }); + return res; + } + + + public async getGitPoapHoldersByEventId(gitPoapEventId: string ): Promise { + const dataProfiles: FetchedData = {}; + let holdersAddress: string[]; + try { + const req: GitPoapAddresses= await this.getGitPoap("/v1/gitpoaps/" + gitPoapEventId + "/addresses"); + holdersAddress = req.addresses; + } catch (error) { + throw new Error("Error fetching total number of users: " + error); + } + + await Promise.all(holdersAddress) + .then((addresses) => { + addresses.forEach((address) => { + if (address != "") { + dataProfiles[address] = 1; + } + }); + }); + + return dataProfiles; + } + + public async getGitPoapHoldersByEventIdCount(gitPoapEventId: string): Promise { + const holders = this.getGitPoapHoldersByEventId(gitPoapEventId); + return Object(holders).keys().length; + } + + public async getGitPoapEventsIDByAddress(address: string ): Promise { + const dataProfiles: FetchedData = {}; + const gitPoapEventsID: number[] = []; + try { + const req: GitPoap[]= await this.getGitPoap("/v1/address/" + address + "/gitpoaps"); + for (let index = 0; index < req.length; index++) { + gitPoapEventsID.push(req[index].gitPoapEventId); + } + + } catch (error) { + throw new Error("Error fetching total number of users: " + error); + } + + await Promise.all(gitPoapEventsID) + .then((events) => { + events.forEach((event) => { + if (event != 0) { + gitPoapEventsID[event] = 1; + } + }); + }); + + return dataProfiles; + } + + + public async getGitPoapEventsIDByAddressCount(address: string): Promise { + const gitPoaps = this.getGitPoapEventsIDByAddress(address); + return Object(gitPoaps).keys().length; + } + +} diff --git a/group-generators/helpers/data-providers/gitpoap/interface-schema.json b/group-generators/helpers/data-providers/gitpoap/interface-schema.json new file mode 100644 index 000000000..7fded27fd --- /dev/null +++ b/group-generators/helpers/data-providers/gitpoap/interface-schema.json @@ -0,0 +1,37 @@ +{ + "name": "GitPOAP", + "iconUrl": "", + "providerClassName": "GitPoapProvider", + "functions": [ + { + "name": "Get GitPOAP holders given an GitPOAPEventID", + "functionName": "getGitPoapHoldersByEventId", + "countFunctionName": "getGitPoapHoldersByEventIdCount", + "description": "Returns all Ethereum Addresses which have received a GitPoap with a given eventId", + "args": [ + { + "name": "gitPoapEventId", + "argName": "gitPoapEventId", + "type": "string", + "example": "37428", + "description": "Event id of the GitPOAP token" + } + ] + }, + { + "name": "Get GitPOAPEventIds given an Ethereum Address or ENS name", + "functionName": "getGitPoapEventsIDByAddress", + "countFunctionName": "getGitPoapEventsIDByAddressCount", + "description": "Returns all the Event Ids of all POAPs owned by an Ethereum Address or ENS name", + "args": [ + { + "name": "ethereum wallet address", + "argName": "address", + "type": "string", + "example": "0x02738d122e0970aAf8DEADf0c6A217a1923E1e99, gitpoap.eth", + "description": "Ethereum wallet address of the holders of the GitPOAP tokens" + } + ] + } + ] +} diff --git a/group-generators/helpers/data-providers/gitpoap/types.ts b/group-generators/helpers/data-providers/gitpoap/types.ts new file mode 100644 index 000000000..3b8c9c783 --- /dev/null +++ b/group-generators/helpers/data-providers/gitpoap/types.ts @@ -0,0 +1,20 @@ + +export type GitPoap = { + gitPoapId: number, + gitPoapEventId: number, + poapTokenId: number, + poapEventId: number, + poapEventFancyId: string, + name: string, + year: number, + description: string, + imageUrl: string, + repositories: string, + earnedAt: Date, + mintedAt: Date +}; + + +export type GitPoapAddresses = { + addresses: string[], +} \ No newline at end of file diff --git a/group-generators/helpers/data-providers/index.ts b/group-generators/helpers/data-providers/index.ts index 6191aa0ac..d4a32fbf4 100644 --- a/group-generators/helpers/data-providers/index.ts +++ b/group-generators/helpers/data-providers/index.ts @@ -4,6 +4,8 @@ import { EthLeaderboardProvider } from "./eth-leaderboard"; import { FarcasterProvider } from "./farcaster"; import { GithubProvider } from "./github"; import githubInterfaceSchema from "./github/interface-schema.json"; +import { GitPoapProvider } from "./gitpoap"; +import gitPoapInterfaceSchema from "./gitpoap/interface-schema.json"; import { GraphQLProvider } from "./graphql"; import { HiveProvider } from "./hive"; import HiveInterfaceSchema from "./hive/interface-schema.json"; @@ -39,6 +41,7 @@ export const dataProviders = { EthLeaderboardProvider, FarcasterProvider, GithubProvider, + GitPoapProvider, GraphQLProvider, HiveProvider, JsonRpcProvider, @@ -58,6 +61,7 @@ export const dataProviders = { export const dataProvidersInterfacesSchemas = [ githubInterfaceSchema, + gitPoapInterfaceSchema, HiveInterfaceSchema, lensInterfaceSchema, poapInterfaceSchema, @@ -75,6 +79,12 @@ export const dataProvidersAPIEndpoints = { getRepositoriesStargazersCount: async (_: any) => new GithubProvider().getRepositoriesStargazersCount(_), }, + GitPoapProvider: { + getGitPoapHoldersByEventIdCount: async (_: any) => + new GitPoapProvider().getGitPoapHoldersByEventIdCount(_), + getGitPoapEventsIDByAddressCount: async (_: any) => + new GitPoapProvider().getGitPoapEventsIDByAddressCount(_), + }, LensProvider: { getFollowersCount: async (_: any) => new LensProvider().getFollowersCount(_), From 68812529217fb76baed29ee0e74f6aa8fe29f849 Mon Sep 17 00:00:00 2001 From: MarkuSchick Date: Fri, 17 Mar 2023 20:42:42 +0000 Subject: [PATCH 07/20] chore: make unused function private --- group-generators/helpers/data-providers/gitpoap/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/group-generators/helpers/data-providers/gitpoap/index.ts b/group-generators/helpers/data-providers/gitpoap/index.ts index cc820cb76..a8a256f48 100644 --- a/group-generators/helpers/data-providers/gitpoap/index.ts +++ b/group-generators/helpers/data-providers/gitpoap/index.ts @@ -14,7 +14,7 @@ export class GitPoapProvider { this.url = "https://public-api.gitpoap.io/"; } - public async getGitPoap(endpoint: string): Promise { + async getGitPoap(endpoint: string): Promise { const { data: res } = await axios({ url: this.url + endpoint, method: "get", From f22e7d36e936355182c6dc92f975162bdb4c0f16 Mon Sep 17 00:00:00 2001 From: mme <9083787+mme022@users.noreply.github.com> Date: Fri, 17 Mar 2023 21:53:13 +0000 Subject: [PATCH 08/20] changed to retrieve beacons first, holders to itsecond --- .../data-providers/degenscore/index.ts | 107 +++++++++++------- .../degenscore/interface-schema.json | 6 +- .../data-providers/degenscore/types.ts | 12 ++ .../helpers/data-providers/index.ts | 11 +- 4 files changed, 80 insertions(+), 56 deletions(-) diff --git a/group-generators/helpers/data-providers/degenscore/index.ts b/group-generators/helpers/data-providers/degenscore/index.ts index c432dba7e..ae633c534 100644 --- a/group-generators/helpers/data-providers/degenscore/index.ts +++ b/group-generators/helpers/data-providers/degenscore/index.ts @@ -1,7 +1,8 @@ import axios from "axios"; // eslint-disable-next-line no-restricted-imports -import { TokenHolder } from "../transpose/types"; -import { UserBeaconData } from "./types"; +import { ethers } from "ethers"; +// eslint-disable-next-line import/no-unresolved, @typescript-eslint/no-unused-vars +import { BeaconResponse } from "./types"; import { FetchedData } from "topics/group"; export class DegenScoreProvider { @@ -11,62 +12,80 @@ export class DegenScoreProvider { accept: string; }; - public async getBeaconHolders(apiKey: string, score: string, trait: string) { - const userBeaconData: UserBeaconData[] = await this.getBeaconDataForHolders( - apiKey + provider: ethers.providers.JsonRpcProvider; + + constructor() { + this.provider = new ethers.providers.JsonRpcProvider( + process.env.JSON_RPC_URL ); + } + + public async getBeaconOwnersWithScore(_score: number) { + // fetch Beacons from API + const data: BeaconResponse = await this.getBeacons(); - const result: FetchedData = {}; + const enrichedData: any = {}; - userBeaconData.map((elem: any) => { - if (elem["quantity"] >= score) { - elem["beaconData"]["traits"].forEach((traitElem: any) => { - if (traitElem["traitType"] == trait) { - result[elem["owner_address"]] = 1; - } - }); - } + // Add holder of each beacon + data["beacons"].map(async (elem: any) => { + const holder = await this.getTokenHolder(elem["address"]); + enrichedData[holder] = elem["primaryTraits"]["degen_score"]; }); - return result; - } - public async getBeaconHoldersCount( - apiKey: string, - score: string, - trait: string - ) { - const result = await this.getBeaconHolders(apiKey, score, trait); - return Object.keys(result).length; + // filter for score over preset + const returnData: FetchedData = {}; + Object(enrichedData) + .keys() + .forEach((holder: string) => { + if (enrichedData[holder] >= _score) { + returnData[holder] = 1; + } + }); } - private async getBeaconDataForHolders( - apiKey: string - ): Promise { - const tokenholders: TokenHolder[] = await this.getTokenHolders(apiKey); + public async getBeaconOwnersWithScoreCount(_score: number) { + const data: BeaconResponse = await this.getBeacons(); - const userBeaconData: any[] = []; + const enrichedData: any = {}; - tokenholders.forEach(async (holder) => { - const { data: res } = await axios({ - url: "https://beacon.degenscore.com/v1/beacon/" + holder.owner_address, - method: "get", - }); - userBeaconData.push({ - owner_address: holder.owner_address, - quantity: holder.balance, - beaconData: res, - }); + data["beacons"].map(async (elem: any) => { + const holder = await this.getTokenHolder(elem["address"]); + enrichedData[holder] = elem["primaryTraits"]["degen_score"]; }); - return userBeaconData; + + const returnData: FetchedData = {}; + Object(enrichedData) + .keys() + .forEach((holder: string) => { + if (enrichedData[holder] >= _score) { + returnData[holder] = 1; + } + }); } - private async getTokenHolders(apiKey: string): Promise { + private async getBeacons() { const { data: res } = await axios({ - url: - "https://api.etherscan.io/api?module=token&action=tokenholderlist&contractaddress=0x0521FA0bf785AE9759C7cB3CBE7512EbF20Fbdaa&page=1&offset=10&apikey=" + - apiKey, + url: "https://beacon.degenscore.com/v1/beacons/", method: "get", }); - return res.result; + return res; + } + + private async getTokenHolder(beaconId: number): Promise { + const abi = [ + "function ownerOfBeacon(uint128) public view returns (string)", + ]; + const beaconInterface = new ethers.utils.Interface(abi); + const beaconRequestData = beaconInterface.encodeFunctionData( + "ownerOfBeacon", + [beaconId] + ); + const tokenHolder = await this.provider.send("eth_call", [ + { + to: "0x0521FA0bf785AE9759C7cB3CBE7512EbF20Fbdaa", + data: beaconRequestData, + }, + ]); + return tokenHolder; } } diff --git a/group-generators/helpers/data-providers/degenscore/interface-schema.json b/group-generators/helpers/data-providers/degenscore/interface-schema.json index f5b412f37..a70a3a87b 100644 --- a/group-generators/helpers/data-providers/degenscore/interface-schema.json +++ b/group-generators/helpers/data-providers/degenscore/interface-schema.json @@ -17,17 +17,17 @@ "description": "API key for etherscan, used to fetch beacon holders" }, { - "name": "score", + "name": "Score", "argName": "score", "type": "string", "example": "730", "description": "A minimum beacon score" }, { - "name": "trait", + "name": "Trait", "argName": "trait", "type": "string", - "example": "TRAIT_TYPE_PRIMARY", + "example": "active_user_compound_v2", "description": "A specific trait identifier" } ] diff --git a/group-generators/helpers/data-providers/degenscore/types.ts b/group-generators/helpers/data-providers/degenscore/types.ts index 3d38927c0..ca77ec8d8 100644 --- a/group-generators/helpers/data-providers/degenscore/types.ts +++ b/group-generators/helpers/data-providers/degenscore/types.ts @@ -42,6 +42,18 @@ export type BeaconInfoResponse = { traits: DegenScoreTrait; }; +export type BeaconResponse = { + beacons: [ + { + address: string; + primaryTraits: { + degenScore: string; + }; + updatedAt: string; + } + ]; +}; + export type UserBeaconData = { owner_address: string; balance: string; diff --git a/group-generators/helpers/data-providers/index.ts b/group-generators/helpers/data-providers/index.ts index fa03f4f9a..dbda3b1ab 100644 --- a/group-generators/helpers/data-providers/index.ts +++ b/group-generators/helpers/data-providers/index.ts @@ -70,15 +70,8 @@ export const dataProvidersInterfacesSchemas = [ export const dataProvidersAPIEndpoints = { DegenScoreProvider: { - getBeaconHoldersCount: async ({ - apiKey, - score, - trait, - }: { - apiKey: string; - score: string; - trait: string; - }) => new DegenScoreProvider().getBeaconHoldersCount(apiKey, score, trait), + getBeaconOwnersWithScoreCount: async ({ score }: { score: number }) => + new DegenScoreProvider().getBeaconOwnersWithScoreCount(score), }, GithubProvider: { getRepositoriesContributorsCount: async (_: any) => From e7a33e922476fc367fa27be77bf0fe53644bf215 Mon Sep 17 00:00:00 2001 From: mme <9083787+mme022@users.noreply.github.com> Date: Fri, 17 Mar 2023 22:03:51 +0000 Subject: [PATCH 09/20] added fixes to return users and count function --- .../data-providers/degenscore/index.ts | 32 +++++-------------- 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/group-generators/helpers/data-providers/degenscore/index.ts b/group-generators/helpers/data-providers/degenscore/index.ts index ae633c534..ac8f59cee 100644 --- a/group-generators/helpers/data-providers/degenscore/index.ts +++ b/group-generators/helpers/data-providers/degenscore/index.ts @@ -34,33 +34,17 @@ export class DegenScoreProvider { // filter for score over preset const returnData: FetchedData = {}; - Object(enrichedData) - .keys() - .forEach((holder: string) => { - if (enrichedData[holder] >= _score) { - returnData[holder] = 1; - } - }); + Object.keys(enrichedData).forEach((holder: string) => { + if (enrichedData[holder] >= _score) { + returnData[holder] = 1; + } + }); + return returnData; } public async getBeaconOwnersWithScoreCount(_score: number) { - const data: BeaconResponse = await this.getBeacons(); - - const enrichedData: any = {}; - - data["beacons"].map(async (elem: any) => { - const holder = await this.getTokenHolder(elem["address"]); - enrichedData[holder] = elem["primaryTraits"]["degen_score"]; - }); - - const returnData: FetchedData = {}; - Object(enrichedData) - .keys() - .forEach((holder: string) => { - if (enrichedData[holder] >= _score) { - returnData[holder] = 1; - } - }); + const data = await this.getBeaconOwnersWithScore(_score); + return Object.keys(data).length; } private async getBeacons() { From bfbeb2c993cf5f19324abed9ac1e47ea08584f95 Mon Sep 17 00:00:00 2001 From: 3Vis Date: Fri, 17 Mar 2023 22:14:08 +0000 Subject: [PATCH 10/20] fix schema --- .../degenscore/interface-schema.json | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/group-generators/helpers/data-providers/degenscore/interface-schema.json b/group-generators/helpers/data-providers/degenscore/interface-schema.json index a70a3a87b..22c0e0e66 100644 --- a/group-generators/helpers/data-providers/degenscore/interface-schema.json +++ b/group-generators/helpers/data-providers/degenscore/interface-schema.json @@ -9,26 +9,12 @@ "countFunctionName": "getBeaconHoldersCount", "description": "Returns all holders of a beacon above a min score and with a specific trait", "args": [ - { - "name": "Etherscan API key", - "argName": "apiKey", - "type": "string", - "example": "asdfgnmjuytfg76trew34rtghi876tre4345tyhb", - "description": "API key for etherscan, used to fetch beacon holders" - }, { "name": "Score", - "argName": "score", + "argName": "_score", "type": "string", "example": "730", "description": "A minimum beacon score" - }, - { - "name": "Trait", - "argName": "trait", - "type": "string", - "example": "active_user_compound_v2", - "description": "A specific trait identifier" } ] } From 39b74620ee76b81113e37b7f3426f728d3f9d406 Mon Sep 17 00:00:00 2001 From: MarkuSchick Date: Sat, 18 Mar 2023 01:16:34 +0000 Subject: [PATCH 11/20] chore: remove unnecessary function --- .../helpers/data-providers/gitpoap/index.ts | 35 ++----------------- .../gitpoap/interface-schema.json | 15 -------- .../helpers/data-providers/gitpoap/types.ts | 17 --------- .../helpers/data-providers/index.ts | 2 -- 4 files changed, 2 insertions(+), 67 deletions(-) diff --git a/group-generators/helpers/data-providers/gitpoap/index.ts b/group-generators/helpers/data-providers/gitpoap/index.ts index a8a256f48..448e30a90 100644 --- a/group-generators/helpers/data-providers/gitpoap/index.ts +++ b/group-generators/helpers/data-providers/gitpoap/index.ts @@ -1,5 +1,5 @@ import axios from "axios"; -import { GitPoap, GitPoapAddresses } from "./types"; +import { GitPoapAddresses } from "./types"; import { FetchedData } from "topics/group"; @@ -14,7 +14,7 @@ export class GitPoapProvider { this.url = "https://public-api.gitpoap.io/"; } - async getGitPoap(endpoint: string): Promise { + private async getGitPoap(endpoint: string): Promise { const { data: res } = await axios({ url: this.url + endpoint, method: "get", @@ -50,35 +50,4 @@ export class GitPoapProvider { return Object(holders).keys().length; } - public async getGitPoapEventsIDByAddress(address: string ): Promise { - const dataProfiles: FetchedData = {}; - const gitPoapEventsID: number[] = []; - try { - const req: GitPoap[]= await this.getGitPoap("/v1/address/" + address + "/gitpoaps"); - for (let index = 0; index < req.length; index++) { - gitPoapEventsID.push(req[index].gitPoapEventId); - } - - } catch (error) { - throw new Error("Error fetching total number of users: " + error); - } - - await Promise.all(gitPoapEventsID) - .then((events) => { - events.forEach((event) => { - if (event != 0) { - gitPoapEventsID[event] = 1; - } - }); - }); - - return dataProfiles; - } - - - public async getGitPoapEventsIDByAddressCount(address: string): Promise { - const gitPoaps = this.getGitPoapEventsIDByAddress(address); - return Object(gitPoaps).keys().length; - } - } diff --git a/group-generators/helpers/data-providers/gitpoap/interface-schema.json b/group-generators/helpers/data-providers/gitpoap/interface-schema.json index 7fded27fd..10a9a7d3b 100644 --- a/group-generators/helpers/data-providers/gitpoap/interface-schema.json +++ b/group-generators/helpers/data-providers/gitpoap/interface-schema.json @@ -17,21 +17,6 @@ "description": "Event id of the GitPOAP token" } ] - }, - { - "name": "Get GitPOAPEventIds given an Ethereum Address or ENS name", - "functionName": "getGitPoapEventsIDByAddress", - "countFunctionName": "getGitPoapEventsIDByAddressCount", - "description": "Returns all the Event Ids of all POAPs owned by an Ethereum Address or ENS name", - "args": [ - { - "name": "ethereum wallet address", - "argName": "address", - "type": "string", - "example": "0x02738d122e0970aAf8DEADf0c6A217a1923E1e99, gitpoap.eth", - "description": "Ethereum wallet address of the holders of the GitPOAP tokens" - } - ] } ] } diff --git a/group-generators/helpers/data-providers/gitpoap/types.ts b/group-generators/helpers/data-providers/gitpoap/types.ts index 3b8c9c783..1cfff923f 100644 --- a/group-generators/helpers/data-providers/gitpoap/types.ts +++ b/group-generators/helpers/data-providers/gitpoap/types.ts @@ -1,20 +1,3 @@ - -export type GitPoap = { - gitPoapId: number, - gitPoapEventId: number, - poapTokenId: number, - poapEventId: number, - poapEventFancyId: string, - name: string, - year: number, - description: string, - imageUrl: string, - repositories: string, - earnedAt: Date, - mintedAt: Date -}; - - export type GitPoapAddresses = { addresses: string[], } \ No newline at end of file diff --git a/group-generators/helpers/data-providers/index.ts b/group-generators/helpers/data-providers/index.ts index f0f5ae475..cffeb146f 100644 --- a/group-generators/helpers/data-providers/index.ts +++ b/group-generators/helpers/data-providers/index.ts @@ -88,8 +88,6 @@ export const dataProvidersAPIEndpoints = { GitPoapProvider: { getGitPoapHoldersByEventIdCount: async (_: any) => new GitPoapProvider().getGitPoapHoldersByEventIdCount(_), - getGitPoapEventsIDByAddressCount: async (_: any) => - new GitPoapProvider().getGitPoapEventsIDByAddressCount(_), }, LensProvider: { getFollowersCount: async (_: any) => From d46e8e77c4afd89fd95fd5ca06967db07fb48005 Mon Sep 17 00:00:00 2001 From: MarkuSchick Date: Sat, 18 Mar 2023 01:28:35 +0000 Subject: [PATCH 12/20] chore: remove comments --- group-generators/helpers/data-providers/gitpoap/index.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/group-generators/helpers/data-providers/gitpoap/index.ts b/group-generators/helpers/data-providers/gitpoap/index.ts index 448e30a90..8c205f228 100644 --- a/group-generators/helpers/data-providers/gitpoap/index.ts +++ b/group-generators/helpers/data-providers/gitpoap/index.ts @@ -2,10 +2,6 @@ import axios from "axios"; import { GitPoapAddresses } from "./types"; import { FetchedData } from "topics/group"; - -// fixes https://github.com/sismo-core/sismo-hub/issues/1454 -// api docs https://docs.gitpoap.io/api - export class GitPoapProvider { url: string; From dcf874c48612ea304a92429010f61fee745d8204 Mon Sep 17 00:00:00 2001 From: MarkuSchick Date: Sat, 18 Mar 2023 01:29:39 +0000 Subject: [PATCH 13/20] feat: add defillama json rpc --- group-generators/helpers/data-providers/degenscore/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/group-generators/helpers/data-providers/degenscore/index.ts b/group-generators/helpers/data-providers/degenscore/index.ts index ac8f59cee..5fb60c58c 100644 --- a/group-generators/helpers/data-providers/degenscore/index.ts +++ b/group-generators/helpers/data-providers/degenscore/index.ts @@ -16,7 +16,7 @@ export class DegenScoreProvider { constructor() { this.provider = new ethers.providers.JsonRpcProvider( - process.env.JSON_RPC_URL + "https://eth.llamarpc.com" ); } From fb3d2f54e266d3ea9c41235cb645d28785c34fa1 Mon Sep 17 00:00:00 2001 From: mme <9083787+mme022@users.noreply.github.com> Date: Sat, 18 Mar 2023 09:55:19 +0000 Subject: [PATCH 14/20] added group for degenscore --- .../generators/degenscore-over-900/index.ts | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 group-generators/generators/degenscore-over-900/index.ts diff --git a/group-generators/generators/degenscore-over-900/index.ts b/group-generators/generators/degenscore-over-900/index.ts new file mode 100644 index 000000000..bf089fb13 --- /dev/null +++ b/group-generators/generators/degenscore-over-900/index.ts @@ -0,0 +1,31 @@ +import { dataProviders } from "@group-generators/helpers/data-providers"; +import { GroupWithData, Tags, ValueType } from "topics/group"; +import { + GenerationContext, + GenerationFrequency, + GroupGenerator, +} from "topics/group-generator"; + +const generator: GroupGenerator = { + generationFrequency: GenerationFrequency.Weekly, + + generate: async (context: GenerationContext): Promise => { + // Instantiate your snapshot provider + const degenscoreProvider = new dataProviders.DegenScoreProvider(); + // Query all voters + const addresses = await degenscoreProvider.getBeaconOwnersWithScore(900); + return [ + { + name: "degens-score-over-900", + description: "Get all degens with a score of minimum 900", + specs: "", + timestamp: context.timestamp, + data: addresses, + valueType: ValueType.Info, + tags: [Tags.User], + }, + ]; + }, +}; + +export default generator; From 0599a75130abcac5e857d8403c6c18ed70b5ddf9 Mon Sep 17 00:00:00 2001 From: mme <9083787+mme022@users.noreply.github.com> Date: Sat, 18 Mar 2023 09:57:16 +0000 Subject: [PATCH 15/20] removed old comments --- group-generators/generators/degenscore-over-900/index.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/group-generators/generators/degenscore-over-900/index.ts b/group-generators/generators/degenscore-over-900/index.ts index bf089fb13..82fdf09d4 100644 --- a/group-generators/generators/degenscore-over-900/index.ts +++ b/group-generators/generators/degenscore-over-900/index.ts @@ -10,9 +10,7 @@ const generator: GroupGenerator = { generationFrequency: GenerationFrequency.Weekly, generate: async (context: GenerationContext): Promise => { - // Instantiate your snapshot provider const degenscoreProvider = new dataProviders.DegenScoreProvider(); - // Query all voters const addresses = await degenscoreProvider.getBeaconOwnersWithScore(900); return [ { From c35842744ef70f5113a31c2d34f02e237d51cb94 Mon Sep 17 00:00:00 2001 From: mme022 <9083787+mme022@users.noreply.github.com> Date: Sat, 18 Mar 2023 10:02:32 +0000 Subject: [PATCH 16/20] Update interface-schema.json --- .../helpers/data-providers/degenscore/interface-schema.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/group-generators/helpers/data-providers/degenscore/interface-schema.json b/group-generators/helpers/data-providers/degenscore/interface-schema.json index 22c0e0e66..5304a68b8 100644 --- a/group-generators/helpers/data-providers/degenscore/interface-schema.json +++ b/group-generators/helpers/data-providers/degenscore/interface-schema.json @@ -5,8 +5,8 @@ "functions": [ { "name": "Get holders of beacon", - "functionName": "getBeaconHolders", - "countFunctionName": "getBeaconHoldersCount", + "functionName": "getBeaconOwnersWithScore", + "countFunctionName": "getBeaconOwnersWithScoreCount", "description": "Returns all holders of a beacon above a min score and with a specific trait", "args": [ { From 4056e32418c72c28b3bd4c5f8bece53f8c5429e7 Mon Sep 17 00:00:00 2001 From: mme <9083787+mme022@users.noreply.github.com> Date: Sat, 18 Mar 2023 10:23:04 +0000 Subject: [PATCH 17/20] fixed the arguments to fit factory specs --- .../helpers/data-providers/degenscore/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/group-generators/helpers/data-providers/degenscore/index.ts b/group-generators/helpers/data-providers/degenscore/index.ts index 5fb60c58c..5db9696ae 100644 --- a/group-generators/helpers/data-providers/degenscore/index.ts +++ b/group-generators/helpers/data-providers/degenscore/index.ts @@ -20,7 +20,7 @@ export class DegenScoreProvider { ); } - public async getBeaconOwnersWithScore(_score: number) { + public async getBeaconOwnersWithScore(args: { _score: number }) { // fetch Beacons from API const data: BeaconResponse = await this.getBeacons(); @@ -35,15 +35,15 @@ export class DegenScoreProvider { // filter for score over preset const returnData: FetchedData = {}; Object.keys(enrichedData).forEach((holder: string) => { - if (enrichedData[holder] >= _score) { + if (enrichedData[holder] >= args._score) { returnData[holder] = 1; } }); return returnData; } - public async getBeaconOwnersWithScoreCount(_score: number) { - const data = await this.getBeaconOwnersWithScore(_score); + public async getBeaconOwnersWithScoreCount(args: { _score: number }) { + const data = await this.getBeaconOwnersWithScore({ _score: args._score }); return Object.keys(data).length; } From 8b21fef174ab9ed3a5b3b92a8535794cba850c46 Mon Sep 17 00:00:00 2001 From: MarkuSchick Date: Sat, 18 Mar 2023 10:27:45 +0000 Subject: [PATCH 18/20] fixed gitpoap arguments to fit factory specs --- group-generators/helpers/data-providers/gitpoap/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/group-generators/helpers/data-providers/gitpoap/index.ts b/group-generators/helpers/data-providers/gitpoap/index.ts index 8c205f228..83b992990 100644 --- a/group-generators/helpers/data-providers/gitpoap/index.ts +++ b/group-generators/helpers/data-providers/gitpoap/index.ts @@ -19,11 +19,11 @@ export class GitPoapProvider { } - public async getGitPoapHoldersByEventId(gitPoapEventId: string ): Promise { + public async getGitPoapHoldersByEventId(getGitPoapHoldersArg: {gitPoapEventId: string} ): Promise { const dataProfiles: FetchedData = {}; let holdersAddress: string[]; try { - const req: GitPoapAddresses= await this.getGitPoap("/v1/gitpoaps/" + gitPoapEventId + "/addresses"); + const req: GitPoapAddresses= await this.getGitPoap("/v1/gitpoaps/" + getGitPoapHoldersArg.gitPoapEventId + "/addresses"); holdersAddress = req.addresses; } catch (error) { throw new Error("Error fetching total number of users: " + error); @@ -41,8 +41,8 @@ export class GitPoapProvider { return dataProfiles; } - public async getGitPoapHoldersByEventIdCount(gitPoapEventId: string): Promise { - const holders = this.getGitPoapHoldersByEventId(gitPoapEventId); + public async getGitPoapHoldersByEventIdCount(getGitPoapHoldersArg: {gitPoapEventId: string} ): Promise { + const holders = this.getGitPoapHoldersByEventId(getGitPoapHoldersArg); return Object(holders).keys().length; } From 61f7d4ca117c2c18b17d5ea8a23e4a75f94314f3 Mon Sep 17 00:00:00 2001 From: MarkuSchick Date: Sat, 18 Mar 2023 11:35:07 +0000 Subject: [PATCH 19/20] refactor: create type for input args --- .../helpers/data-providers/degenscore/index.ts | 10 +++++----- .../helpers/data-providers/degenscore/types.ts | 2 ++ .../helpers/data-providers/gitpoap/index.ts | 10 +++++----- .../helpers/data-providers/gitpoap/types.ts | 2 ++ 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/group-generators/helpers/data-providers/degenscore/index.ts b/group-generators/helpers/data-providers/degenscore/index.ts index 5db9696ae..c33bf73af 100644 --- a/group-generators/helpers/data-providers/degenscore/index.ts +++ b/group-generators/helpers/data-providers/degenscore/index.ts @@ -2,7 +2,7 @@ import axios from "axios"; // eslint-disable-next-line no-restricted-imports import { ethers } from "ethers"; // eslint-disable-next-line import/no-unresolved, @typescript-eslint/no-unused-vars -import { BeaconResponse } from "./types"; +import { BeaconResponse, Score } from "./types"; import { FetchedData } from "topics/group"; export class DegenScoreProvider { @@ -20,7 +20,7 @@ export class DegenScoreProvider { ); } - public async getBeaconOwnersWithScore(args: { _score: number }) { + public async getBeaconOwnersWithScore({ _score }: Score) { // fetch Beacons from API const data: BeaconResponse = await this.getBeacons(); @@ -35,15 +35,15 @@ export class DegenScoreProvider { // filter for score over preset const returnData: FetchedData = {}; Object.keys(enrichedData).forEach((holder: string) => { - if (enrichedData[holder] >= args._score) { + if (enrichedData[holder] >= _score) { returnData[holder] = 1; } }); return returnData; } - public async getBeaconOwnersWithScoreCount(args: { _score: number }) { - const data = await this.getBeaconOwnersWithScore({ _score: args._score }); + public async getBeaconOwnersWithScoreCount({ _score }: Score) { + const data = await this.getBeaconOwnersWithScore({ _score: _score }); return Object.keys(data).length; } diff --git a/group-generators/helpers/data-providers/degenscore/types.ts b/group-generators/helpers/data-providers/degenscore/types.ts index ca77ec8d8..17f622863 100644 --- a/group-generators/helpers/data-providers/degenscore/types.ts +++ b/group-generators/helpers/data-providers/degenscore/types.ts @@ -1,3 +1,5 @@ +export type Score = { _score: number } + export type TokenHolder = { TokenHolderAddress: string; TokenHolderQuantity: string; diff --git a/group-generators/helpers/data-providers/gitpoap/index.ts b/group-generators/helpers/data-providers/gitpoap/index.ts index 83b992990..7d859a891 100644 --- a/group-generators/helpers/data-providers/gitpoap/index.ts +++ b/group-generators/helpers/data-providers/gitpoap/index.ts @@ -1,5 +1,5 @@ import axios from "axios"; -import { GitPoapAddresses } from "./types"; +import { GitPoapAddresses, GitPoapEventId } from "./types"; import { FetchedData } from "topics/group"; export class GitPoapProvider { @@ -19,11 +19,11 @@ export class GitPoapProvider { } - public async getGitPoapHoldersByEventId(getGitPoapHoldersArg: {gitPoapEventId: string} ): Promise { + public async getGitPoapHoldersByEventId({gitPoapEventId }: GitPoapEventId ): Promise { const dataProfiles: FetchedData = {}; let holdersAddress: string[]; try { - const req: GitPoapAddresses= await this.getGitPoap("/v1/gitpoaps/" + getGitPoapHoldersArg.gitPoapEventId + "/addresses"); + const req: GitPoapAddresses= await this.getGitPoap("/v1/gitpoaps/" + gitPoapEventId + "/addresses"); holdersAddress = req.addresses; } catch (error) { throw new Error("Error fetching total number of users: " + error); @@ -41,8 +41,8 @@ export class GitPoapProvider { return dataProfiles; } - public async getGitPoapHoldersByEventIdCount(getGitPoapHoldersArg: {gitPoapEventId: string} ): Promise { - const holders = this.getGitPoapHoldersByEventId(getGitPoapHoldersArg); + public async getGitPoapHoldersByEventIdCount({gitPoapEventId }: GitPoapEventId ): Promise { + const holders = this.getGitPoapHoldersByEventId({gitPoapEventId }); return Object(holders).keys().length; } diff --git a/group-generators/helpers/data-providers/gitpoap/types.ts b/group-generators/helpers/data-providers/gitpoap/types.ts index 1cfff923f..78358ec4d 100644 --- a/group-generators/helpers/data-providers/gitpoap/types.ts +++ b/group-generators/helpers/data-providers/gitpoap/types.ts @@ -1,3 +1,5 @@ +export type GitPoapEventId = { gitPoapEventId: string } + export type GitPoapAddresses = { addresses: string[], } \ No newline at end of file From b3ba22fdf668b90d64dd038267c881c1596e3869 Mon Sep 17 00:00:00 2001 From: MarkuSchick Date: Sat, 18 Mar 2023 12:27:08 +0000 Subject: [PATCH 20/20] fix some test --- .../generators/degenscore-over-900/index.ts | 2 +- group-generators/generators/gitpoap/index.ts | 29 +++++++++++++++++++ .../helpers/data-providers/index.ts | 4 +-- 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 group-generators/generators/gitpoap/index.ts diff --git a/group-generators/generators/degenscore-over-900/index.ts b/group-generators/generators/degenscore-over-900/index.ts index 82fdf09d4..2e06aa2b0 100644 --- a/group-generators/generators/degenscore-over-900/index.ts +++ b/group-generators/generators/degenscore-over-900/index.ts @@ -11,7 +11,7 @@ const generator: GroupGenerator = { generate: async (context: GenerationContext): Promise => { const degenscoreProvider = new dataProviders.DegenScoreProvider(); - const addresses = await degenscoreProvider.getBeaconOwnersWithScore(900); + const addresses = await degenscoreProvider.getBeaconOwnersWithScore({_score: 900}); return [ { name: "degens-score-over-900", diff --git a/group-generators/generators/gitpoap/index.ts b/group-generators/generators/gitpoap/index.ts new file mode 100644 index 000000000..1ad68b412 --- /dev/null +++ b/group-generators/generators/gitpoap/index.ts @@ -0,0 +1,29 @@ +import { dataProviders } from "@group-generators/helpers/data-providers"; +import { GroupWithData, Tags, ValueType } from "topics/group"; +import { + GenerationContext, + GenerationFrequency, + GroupGenerator, +} from "topics/group-generator"; + +const generator: GroupGenerator = { + generationFrequency: GenerationFrequency.Weekly, + + generate: async (context: GenerationContext): Promise => { + const degenscoreProvider = new dataProviders.GitPoapProvider(); + const addresses = await degenscoreProvider.getGitPoapHoldersByEventId({gitPoapEventId: "37428"}); + return [ + { + name: "poap-holder-of-37428", + description: "Get all POAP holder of the event id 37428", + specs: "", + timestamp: context.timestamp, + data: addresses, + valueType: ValueType.Info, + tags: [Tags.User], + }, + ]; + }, +}; + +export default generator; diff --git a/group-generators/helpers/data-providers/index.ts b/group-generators/helpers/data-providers/index.ts index cffeb146f..cc6b9782e 100644 --- a/group-generators/helpers/data-providers/index.ts +++ b/group-generators/helpers/data-providers/index.ts @@ -76,8 +76,8 @@ export const dataProvidersInterfacesSchemas = [ export const dataProvidersAPIEndpoints = { DegenScoreProvider: { - getBeaconOwnersWithScoreCount: async ({ score }: { score: number }) => - new DegenScoreProvider().getBeaconOwnersWithScoreCount(score), + getBeaconOwnersWithScoreCount: async (_: any) => + new DegenScoreProvider().getBeaconOwnersWithScoreCount(_), }, GithubProvider: { getRepositoriesContributorsCount: async (_: any) =>