-
Notifications
You must be signed in to change notification settings - Fork 205
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
Add GitPoap & Degenscore Data Provider #1555
Changes from 22 commits
8edd121
6386cc5
1177a98
2914970
98d590d
f4f757b
6881252
18fe54a
f22e7d3
68572d9
e7a33e9
87e8c6b
bfbeb2c
48ff526
39b7462
d46e8e7
dcf874c
fb3d2f5
0599a75
c358427
4056e32
8b21fef
61f7d4c
b3ba22f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<GroupWithData[]> => { | ||
const degenscoreProvider = new dataProviders.DegenScoreProvider(); | ||
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; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
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 { FetchedData } from "topics/group"; | ||
|
||
export class DegenScoreProvider { | ||
url: string; | ||
headers: { | ||
authorization: string; | ||
accept: string; | ||
}; | ||
|
||
provider: ethers.providers.JsonRpcProvider; | ||
|
||
constructor() { | ||
this.provider = new ethers.providers.JsonRpcProvider( | ||
"https://eth.llamarpc.com" | ||
); | ||
} | ||
|
||
public async getBeaconOwnersWithScore(args: { _score: number }) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @markuschick here you can only pass this: And create a score type like this: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed with fixed with 61f7d4c |
||
// fetch Beacons from API | ||
const data: BeaconResponse = await this.getBeacons(); | ||
|
||
const enrichedData: any = {}; | ||
|
||
// Add holder of each beacon | ||
data["beacons"].map(async (elem: any) => { | ||
const holder = await this.getTokenHolder(elem["address"]); | ||
enrichedData[holder] = elem["primaryTraits"]["degen_score"]; | ||
}); | ||
|
||
// filter for score over preset | ||
const returnData: FetchedData = {}; | ||
Object.keys(enrichedData).forEach((holder: string) => { | ||
if (enrichedData[holder] >= args._score) { | ||
returnData[holder] = 1; | ||
} | ||
}); | ||
return returnData; | ||
} | ||
|
||
public async getBeaconOwnersWithScoreCount(args: { _score: number }) { | ||
const data = await this.getBeaconOwnersWithScore({ _score: args._score }); | ||
return Object.keys(data).length; | ||
} | ||
|
||
private async getBeacons() { | ||
const { data: res } = await axios({ | ||
url: "https://beacon.degenscore.com/v1/beacons/", | ||
method: "get", | ||
}); | ||
return res; | ||
} | ||
|
||
private async getTokenHolder(beaconId: number): Promise<string> { | ||
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; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"name": "DegenScore", | ||
"iconUrl": "", | ||
"providerClassName": "DegenScoreProvider", | ||
"functions": [ | ||
{ | ||
"name": "Get holders of beacon", | ||
"functionName": "getBeaconOwnersWithScore", | ||
"countFunctionName": "getBeaconOwnersWithScoreCount", | ||
"description": "Returns all holders of a beacon above a min score and with a specific trait", | ||
"args": [ | ||
{ | ||
"name": "Score", | ||
"argName": "_score", | ||
"type": "string", | ||
"example": "730", | ||
"description": "A minimum beacon score" | ||
} | ||
] | ||
} | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
export type TokenHolder = { | ||
TokenHolderAddress: string; | ||
TokenHolderQuantity: string; | ||
}; | ||
|
||
export type EtherscanResponse = { | ||
status: string; | ||
message: string; | ||
result: TokenHolder[]; | ||
}; | ||
|
||
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 BeaconResponse = { | ||
beacons: [ | ||
{ | ||
address: string; | ||
primaryTraits: { | ||
degenScore: string; | ||
}; | ||
updatedAt: string; | ||
} | ||
]; | ||
}; | ||
|
||
export type UserBeaconData = { | ||
owner_address: string; | ||
balance: string; | ||
beaconData: BeaconInfoResponse; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import axios from "axios"; | ||
import { GitPoapAddresses } from "./types"; | ||
import { FetchedData } from "topics/group"; | ||
|
||
export class GitPoapProvider { | ||
url: string; | ||
|
||
|
||
public constructor() { | ||
this.url = "https://public-api.gitpoap.io/"; | ||
} | ||
|
||
private async getGitPoap(endpoint: string): Promise<any> { | ||
const { data: res } = await axios({ | ||
url: this.url + endpoint, | ||
method: "get", | ||
}); | ||
return res; | ||
} | ||
|
||
|
||
public async getGitPoapHoldersByEventId(getGitPoapHoldersArg: {gitPoapEventId: string} ): Promise<FetchedData> { | ||
const dataProfiles: FetchedData = {}; | ||
let holdersAddress: string[]; | ||
try { | ||
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); | ||
} | ||
|
||
await Promise.all(holdersAddress) | ||
.then((addresses) => { | ||
addresses.forEach((address) => { | ||
if (address != "") { | ||
dataProfiles[address] = 1; | ||
} | ||
}); | ||
}); | ||
|
||
return dataProfiles; | ||
} | ||
|
||
public async getGitPoapHoldersByEventIdCount(getGitPoapHoldersArg: {gitPoapEventId: string} ): Promise<number> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed with 61f7d4c |
||
const holders = this.getGitPoapHoldersByEventId(getGitPoapHoldersArg); | ||
return Object(holders).keys().length; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"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" | ||
} | ||
] | ||
} | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export type GitPoapAddresses = { | ||
addresses: string[], | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to change this part of your group,
getBeaconOwnersWithScore
require a typeScore
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed with b3ba22f