-
Notifications
You must be signed in to change notification settings - Fork 461
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(app, platforms): base trusta labs stamp
- Loading branch information
Showing
14 changed files
with
257 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { AppContext, ProviderPayload } from "../types"; | ||
import { Platform } from "../utils/platform"; | ||
|
||
export class TrustaLabsPlatform extends Platform { | ||
platformId = "TrustaLabs"; | ||
path = "TrustaLabs"; | ||
isEVM = true; | ||
|
||
async getProviderPayload(_appContext: AppContext): Promise<ProviderPayload> { | ||
return await Promise.resolve({}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { PlatformSpec, PlatformGroupSpec, Provider } from "../types"; | ||
import { TrustaLabsProvider } from "./Providers/TrustaLabs"; | ||
|
||
export const PlatformDetails: PlatformSpec = { | ||
icon: "./assets/trustalabsStampIcon.svg", | ||
platform: "TrustaLabs", | ||
name: "Trusta Labs", | ||
description: "Connect your existing TrustaLabs Account to verify", | ||
connectMessage: "Connect Account", | ||
}; | ||
|
||
export const ProviderConfig: PlatformGroupSpec[] = [ | ||
{ platformGroup: "Trusta Labs", providers: [{ title: "Sybil Score", name: "TrustaLabs" }] }, | ||
]; | ||
|
||
export const providers: Provider[] = [new TrustaLabsProvider()]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
import type { Provider, ProviderOptions } from "../../types"; | ||
import { RequestPayload, VerifiedPayload } from "@gitcoin/passport-types"; | ||
|
||
// ----- Libs | ||
import axios from "axios"; | ||
|
||
// ----- Credential verification | ||
import { ProviderExternalVerificationError } from "../../types"; | ||
|
||
interface SubScore { | ||
bulkOperationRisk: number; | ||
starlikeAssetsNetworkRisk: number; | ||
chainlikeAssetsNetworkRisk: number; | ||
similarBehaviorSequenceRisk: number; | ||
blacklistRisk: number; | ||
} | ||
|
||
interface TrustaLabsData { | ||
address: string; | ||
sybilRiskScore: number; | ||
sybilRiskLevel: string; | ||
subScore: SubScore; | ||
} | ||
|
||
interface TrustaLabsResponse { | ||
data: TrustaLabsData; | ||
success?: boolean; | ||
code?: number; | ||
message?: string; | ||
} | ||
|
||
interface AxiosResponse { | ||
data: TrustaLabsResponse; | ||
} | ||
|
||
const TRUSTA_LABS_API_ENDPOINT = "https://www.trustalabs.ai/service/openapi/queryRiskSummaryScore"; | ||
|
||
// Based on https://axios-http.com/docs/handling_errors | ||
const handleAxiosError = (error: any, label: string, secretsToHide?: string[]) => { | ||
if (axios.isAxiosError(error)) { | ||
let message = `Error making ${label} request, `; | ||
if (error.response) { | ||
// Received a non 2xx response | ||
const { data, status, headers } = error.response; | ||
message += `received error response with code ${status}: ${JSON.stringify(data)}, headers: ${JSON.stringify( | ||
headers | ||
)}`; | ||
} else if (error.request) { | ||
// No response received | ||
message += "no response received"; | ||
} else { | ||
// Something happened in setting up the request that triggered an Error | ||
message += error.message; | ||
} | ||
secretsToHide?.forEach((secret) => { | ||
message = message.replace(secret, "[SECRET]"); | ||
}); | ||
throw new ProviderExternalVerificationError(message); | ||
} | ||
throw error; | ||
}; | ||
|
||
const createUpdateDBScore = async (address: string, score: number) => { | ||
const accessToken = process.env.CGRANTS_API_TOKEN; | ||
try { | ||
await axios.post( | ||
`${process.env.SCORER_ENDPOINT}/trusta_labs/trusta-labs-score`, | ||
{ address, score }, | ||
{ | ||
headers: { | ||
Authorization: accessToken, | ||
}, | ||
} | ||
); | ||
} catch (error) { | ||
handleAxiosError(error, "report score", [accessToken]); | ||
} | ||
}; | ||
|
||
const makeSybilScoreRequest = async (address: string) => { | ||
const accessToken = process.env.TRUSTA_LABS_ACCESS_TOKEN; | ||
try { | ||
const result: AxiosResponse = await axios.post( | ||
TRUSTA_LABS_API_ENDPOINT, | ||
{ | ||
address, | ||
chainId: "1", | ||
}, | ||
{ | ||
headers: { | ||
Authorization: `Bearer ${accessToken}`, | ||
}, | ||
} | ||
); | ||
return result.data.data.sybilRiskScore; | ||
} catch (error) { | ||
handleAxiosError(error, "sybil score", [accessToken]); | ||
} | ||
}; | ||
|
||
const verifyTrustaLabsRiskScore = async (address: string): Promise<{ valid: boolean; errors: string[] }> => { | ||
const sybilRiskScore = await makeSybilScoreRequest(address); | ||
await createUpdateDBScore(address, sybilRiskScore); | ||
|
||
const lowerBound = -1; | ||
const upperBound = 60; | ||
|
||
if (sybilRiskScore >= lowerBound && sybilRiskScore <= upperBound) { | ||
return { | ||
valid: true, | ||
errors: [], | ||
}; | ||
} else { | ||
return { | ||
valid: false, | ||
errors: [`Sybil score ${sybilRiskScore} is outside of the allowed range (${lowerBound} to ${upperBound})`], | ||
}; | ||
} | ||
}; | ||
|
||
export class TrustaLabsProvider implements Provider { | ||
type = "TrustaLabs"; | ||
|
||
// Options can be set here and/or via the constructor | ||
_options = {}; | ||
|
||
// construct the provider instance with supplied options | ||
constructor(options: ProviderOptions = {}) { | ||
this._options = { ...this._options, ...options }; | ||
} | ||
|
||
async verify(payload: RequestPayload): Promise<VerifiedPayload> { | ||
const { address } = payload; | ||
|
||
// if a signer is provider we will use that address to verify against | ||
const { valid, errors } = await verifyTrustaLabsRiskScore(address); | ||
|
||
return { | ||
valid, | ||
errors, | ||
record: { | ||
address, | ||
}, | ||
}; | ||
} | ||
} |
59 changes: 59 additions & 0 deletions
59
platforms/src/TrustaLabs/Providers/__tests__/TrustaLabs.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/* eslint-disable */ | ||
// ---- Test subject | ||
import { RequestPayload } from "@gitcoin/passport-types"; | ||
import { TrustaLabsProvider } from "../../Providers/TrustaLabs"; | ||
|
||
// ----- Libs | ||
import axios from "axios"; | ||
|
||
jest.mock("axios"); | ||
const mockedAxios = axios as jest.Mocked<typeof axios>; | ||
|
||
const MOCK_ADDRESS = "0xcF314CE817E25b4F784bC1f24c9A79A525fEC50f"; | ||
const MOCK_ADDRESS_LOWER = MOCK_ADDRESS.toLocaleLowerCase(); | ||
|
||
const makeResponse = (score: number) => ({ | ||
data: { | ||
data: { | ||
address: MOCK_ADDRESS_LOWER, | ||
sybilRiskScore: score, | ||
}, | ||
success: true, | ||
code: 0, | ||
message: "", | ||
}, | ||
}); | ||
|
||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
describe("TrustaLabs", () => { | ||
it.each([ | ||
[20, true], | ||
[30.000045668, true], | ||
[60, true], | ||
[80, false], | ||
[-1, true], | ||
[-2, false], | ||
])("should return %s for score %s", async (score: number, expected: boolean) => { | ||
mockedAxios.post.mockResolvedValue(makeResponse(score)); | ||
|
||
const trustaLabs = new TrustaLabsProvider(); | ||
const verifiedPayload = await trustaLabs.verify({ | ||
address: MOCK_ADDRESS, | ||
} as RequestPayload); | ||
|
||
expect(axios.post).toHaveBeenCalledTimes(2); | ||
|
||
const { valid, record, errors } = verifiedPayload; | ||
if (expected) { | ||
expect(valid).toBe(true); | ||
expect(record).toEqual({ address: MOCK_ADDRESS }); | ||
expect(errors).toEqual([]); | ||
} else { | ||
expect(valid).toBe(false); | ||
expect(errors).toEqual([`Sybil score ${score} is outside of the allowed range (-1 to 60)`]); | ||
} | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { TrustaLabsProvider } from "./TrustaLabs"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export { TrustaLabsPlatform } from "./App-Bindings"; | ||
export { ProviderConfig, PlatformDetails, providers } from "./Providers-config"; | ||
export { TrustaLabsProvider } from "./Providers/TrustaLabs"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters