-
Notifications
You must be signed in to change notification settings - Fork 468
/
Copy pathonChainStamps.ts
127 lines (114 loc) · 3.75 KB
/
onChainStamps.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import onchainInfo from "../../deployments/onchainInfo.json";
import PassportResolverAbi from "../../deployments/abi/GitcoinResolver.json";
import PassportDecoderAbi from "../../deployments/abi/GitcoinPassportDecoder.json";
import { datadogLogs } from "@datadog/browser-logs";
import { datadogRum } from "@datadog/browser-rum";
import { Abi, formatUnits, PublicClient } from "viem";
import { PROVIDER_ID } from "@gitcoin/passport-types";
import { cleanAndParseAbi } from "./helpers";
import { ZERO_BYTES32 } from "@ethereum-attestation-service/eas-sdk";
type CachedScore = {
score: number;
time: bigint;
expirationTime: bigint;
};
type CachedStamp = {
provider: string;
hash: string;
issuanceDate: bigint;
expirationDate: bigint;
};
export type AttestationData = {
providers: {
providerName: PROVIDER_ID;
credentialHash: string;
issuanceDate: Date;
expirationDate: Date;
}[];
score: {
value: number;
expirationDate: Date;
};
};
const SCORE_MAX_AGE_MILLISECONDS = 1000 * 60 * 60 * 24 * 90; // 90 days
const getPassport = async ({
publicClient,
address,
decoderAddress,
decoderAbi,
}: {
publicClient: PublicClient;
address: `0x${string}`;
decoderAddress: string;
decoderAbi: Abi;
}): Promise<CachedStamp[]> => {
try {
return (await publicClient.readContract({
abi: decoderAbi,
address: decoderAddress as `0x${string}`,
functionName: "getPassport",
args: [address],
})) as CachedStamp[];
} catch {
return [];
}
};
export async function getAttestationData({
publicClient,
address,
chainId,
customScorerId,
}: {
publicClient: PublicClient;
address: `0x${string}`;
chainId: keyof typeof onchainInfo;
customScorerId?: number;
}): Promise<AttestationData | undefined> {
try {
const resolverAddress = onchainInfo[chainId].GitcoinResolver.address;
const resolverAbi = cleanAndParseAbi(PassportResolverAbi[chainId]);
const decoderAddress = onchainInfo[chainId].GitcoinPassportDecoder.address;
const decoderAbi = cleanAndParseAbi(PassportDecoderAbi[chainId]);
const cachedScore = (await publicClient.readContract({
abi: resolverAbi,
address: resolverAddress as `0x${string}`,
functionName: "getCachedScore",
args: customScorerId ? [customScorerId, address] : [address],
})) as CachedScore;
const score = {
value: parseFloat(formatUnits(BigInt(cachedScore.score), 4)),
expirationDate: new Date(parseInt(cachedScore.time.toString()) * 1000 + SCORE_MAX_AGE_MILLISECONDS),
};
const passportSchema = onchainInfo[chainId].easSchemas.passport.uid;
// check if user has attestations
const passportUid = (await publicClient.readContract({
abi: resolverAbi,
address: resolverAddress as `0x${string}`,
functionName: "userAttestations", // Name of the function in your contract ABI
args: [address, passportSchema], // Arguments to the function
})) as `0x${string}`;
let providers: AttestationData["providers"] = [];
if (passportUid !== ZERO_BYTES32) {
const cachedPassport = await getPassport({
publicClient,
address,
decoderAddress,
decoderAbi,
});
providers = cachedPassport.map(({ provider, hash, issuanceDate, expirationDate }) => ({
providerName: provider as PROVIDER_ID,
credentialHash: `v0.0.0:${Buffer.from(hash.slice(2), "hex").toString("base64")}`,
issuanceDate: new Date(Number(issuanceDate) * 1000),
expirationDate: new Date(Number(expirationDate) * 1000),
}));
}
return {
providers,
score,
};
} catch (e: any) {
console.error("Failed to get attestation data for", chainId, address, e);
datadogLogs.logger.error("Failed to check onchain status", e);
datadogRum.addError(e);
}
}