diff --git a/libs/credentials/src/index.test.ts b/libs/credentials/src/index.test.ts index 2676fff3..5362bd7d 100644 --- a/libs/credentials/src/index.test.ts +++ b/libs/credentials/src/index.test.ts @@ -28,7 +28,7 @@ describe("Credentials library", () => { it("Should add a validator to the list of supported validators", () => { addValidator({} as any) - expect(validators).toHaveLength(7) + expect(validators).toHaveLength(8) }) }) @@ -36,7 +36,7 @@ describe("Credentials library", () => { it("Should add 2 validators to the list of supported validators", () => { addValidators([{} as any, {} as any]) - expect(validators).toHaveLength(9) + expect(validators).toHaveLength(10) }) }) diff --git a/libs/credentials/src/validators.ts b/libs/credentials/src/validators.ts index 00ecf8e9..c0b45280 100644 --- a/libs/credentials/src/validators.ts +++ b/libs/credentials/src/validators.ts @@ -5,7 +5,8 @@ import { githubRepositoryCommits, twitterFollowers, twitterFollowingUser, - blockchainTransactions + blockchainTransactions, + blockchainBalance } from "./validators/index" const validators: Validator[] = [ @@ -14,7 +15,8 @@ const validators: Validator[] = [ githubRepositoryCommits, twitterFollowers, twitterFollowingUser, - blockchainTransactions + blockchainTransactions, + blockchainBalance ] export default validators diff --git a/libs/credentials/src/validators/blockchainBalance/index.test.ts b/libs/credentials/src/validators/blockchainBalance/index.test.ts new file mode 100644 index 00000000..a1c31d96 --- /dev/null +++ b/libs/credentials/src/validators/blockchainBalance/index.test.ts @@ -0,0 +1,107 @@ +import { BigNumber } from "ethers" +import { validateCredentials } from "../.." +import blockchainBalance from "./index" + +describe("BlockchainBalance", () => { + const jsonRpcProviderMocked = { + getBalance: jest.fn() + } + + it("Should return true if an account has a balance greater than or equal to 10", async () => { + jsonRpcProviderMocked.getBalance.mockReturnValue(BigNumber.from(12)) + + const result = await validateCredentials( + { + id: blockchainBalance.id, + criteria: { + minBalance: "10" + } + }, + { + address: "0x", + jsonRpcProvider: jsonRpcProviderMocked + } + ) + + expect(result).toBeTruthy() + }) + + it("Should return true if an account has a balance greater than or equal to 10 using the block number", async () => { + jsonRpcProviderMocked.getBalance.mockReturnValue(BigNumber.from(12)) + + const result = await validateCredentials( + { + id: blockchainBalance.id, + criteria: { + minBalance: "10" + } + }, + { + address: "0x", + jsonRpcProvider: jsonRpcProviderMocked, + blockNumber: 4749638 + } + ) + + expect(result).toBeTruthy() + }) + + it("Should throw an error if a criteria parameter is missing", async () => { + const fun = () => + validateCredentials( + { + id: blockchainBalance.id, + criteria: {} + }, + { + address: "0x", + jsonRpcProvider: undefined + } + ) + + await expect(fun).rejects.toThrow( + "Parameter 'minBalance' has not been defined" + ) + }) + + it("Should throw an error if a criteria parameter should not exist", async () => { + const fun = () => + validateCredentials( + { + id: blockchainBalance.id, + criteria: { + minBalance: "100", + minStars: 200 + } + }, + { + address: "0x", + jsonRpcProvider: undefined + } + ) + + await expect(fun).rejects.toThrow( + "Parameter 'minStars' should not be part of the criteria" + ) + }) + + it("Should throw a type error if a criteria parameter has the wrong type", async () => { + const fun = () => + validateCredentials( + { + id: blockchainBalance.id, + criteria: { + minBalance: 100 + } + }, + { + address: "0x", + jsonRpcProvider: undefined + } + ) + + await expect(fun).rejects.toThrow( + "Parameter 'minBalance' is not a string" + ) + }) +}) diff --git a/libs/credentials/src/validators/blockchainBalance/index.ts b/libs/credentials/src/validators/blockchainBalance/index.ts new file mode 100644 index 00000000..dae998d3 --- /dev/null +++ b/libs/credentials/src/validators/blockchainBalance/index.ts @@ -0,0 +1,35 @@ +import { BigNumber } from "ethers" +import { BlockchainContext, Validator } from "../.." + +export type Criteria = { + minBalance: string +} + +const validator: Validator = { + id: "BLOCKCHAIN_BALANCE", + + criteriaABI: { + minBalance: "string" + }, + + /** + * It checks if a user has a balance greater than or equal to 'minBalance'. + * @param criteria The criteria used to check user's credentials. + * @param context Context variables. + * @returns True if the user meets the criteria. + */ + async validate(criteria: Criteria, context) { + if ("address" in context) { + const balance = await ( + context as BlockchainContext + ).jsonRpcProvider.getBalance( + (context as BlockchainContext).address, + (context as BlockchainContext).blockNumber + ) + return balance >= BigNumber.from(criteria.minBalance) + } + throw new Error("No address value found") + } +} + +export default validator diff --git a/libs/credentials/src/validators/index.ts b/libs/credentials/src/validators/index.ts index f8d60a08..3d12a6de 100644 --- a/libs/credentials/src/validators/index.ts +++ b/libs/credentials/src/validators/index.ts @@ -4,6 +4,7 @@ import githubRepositoryCommits from "./githubRepositoryCommits" import twitterFollowers from "./twitterFollowers" import twitterFollowingUser from "./twitterFollowingUser" import blockchainTransactions from "./blockchainTransactions" +import blockchainBalance from "./blockchainBalance" export { githubFollowers, @@ -11,5 +12,6 @@ export { twitterFollowers, twitterFollowingUser, githubPersonalStars, - blockchainTransactions + blockchainTransactions, + blockchainBalance }