Skip to content

Latest commit

 

History

History
618 lines (513 loc) · 16.3 KB

README.md

File metadata and controls

618 lines (513 loc) · 16.3 KB

Bandada credentials

Bandada library to validate users' credentials.

Github license NPM version Downloads Linter eslint Code style prettier

This package provides a function to validate users' credentials by using a set of extendable validators.

🛠 Install

npm or yarn

Install the @bandada/credentials package with npm:

npm i @bandada/credentials

or yarn:

yarn add @bandada/credentials

📜 Usage

Validate credentials

Validate blockchain balance

# validateCredentials(credentials: Credentials, context: Context): Promise<boolean>

Validates the blockchain balance of a user.

  • credentials (Credentials):
    • id: The id for the blockchain balance validation.
    • criteria:
      • minBalance: The minimum number of balance required.
      • network: The blockchain network to validate against.
      • blockNumber (optional): The block number at which to check the balance.
  • context (Context):
    • address: The blockchain address to validate.
    • jsonRpcProvider: The JSON-RPC provider to use for blockchain interactions.
import {
    validateCredentials,
    blockchainBalance,
    getProvider,
    BlockchainProvider
} from "@bandada/credentials"

const provider = getProvider("blockchain")

const jsonRpcProvider = await (
    provider as BlockchainProvider
).getJsonRpcProvider("https://rpc-url.com")

validateCredentials(
    {
        id: blockchainBalance.id,
        criteria: {
            minBalance: "10",
            network: "sepolia",
            blockNumber: 4749638
        }
    },
    {
        address: "0x",
        jsonRpcProvider
    }
)

Validate blockchain transactions

# validateCredentials(credentials: Credentials, context: Context): Promise<boolean>

Validates the blockchain transactions of a user.

  • credentials (Credentials):
    • id: The id for the blockchain transactions validation.
    • criteria:
      • minTransactions: The minimum number of transactions required.
      • network: The blockchain network to validate against.
      • blockNumber (optional): The block number at which to check the transactions.
  • context (Context):
    • address: The blockchain address to validate.
    • jsonRpcProvider: The JSON-RPC provider to use for blockchain interactions.
import {
    validateCredentials,
    blockchainTransactions,
    getProvider,
    BlockchainProvider
} from "@bandada/credentials"

const provider = getProvider("blockchain")

const jsonRpcProvider = await (
    provider as BlockchainProvider
).getJsonRpcProvider("https://rpc-url.com")

validateCredentials(
    {
        id: blockchainTransactions.id,
        criteria: {
            minTransactions: 10,
            network: "sepolia",
            blockNumber: 4749638
        }
    },
    {
        address: "0x",
        jsonRpcProvider
    }
)

Validate EAS (Ethereum Attestation Service) attestations

# validateCredentials(credentials: Credentials, context: Context): Promise<boolean>

Validates the EAS attestations of a user.

  • credentials (Credentials):
    • id: The id for the EAS attestations validation.
    • criteria:
      • minAttestations: The minimum number of attestations required.
      • network: The id of the supported attestation network.
      • attester (optional): The attester of the attestation.
      • schemaId (optional): The schema id of the attestation.
      • revocable (optional): The revocable option of the attestation.
      • revoked (optional): The revocation status of the attestation.
      • isOffchain (optional): The type of chain of the attestation.
  • context (Context):
    • network: The EAS network chain.
    • address: The user address to validate.
import { easCredentialSupportedNetworks } from "@bandada/utils"
import {
    validateCredentials,
    easAttestations,
    EASNetworks
} from "@bandada/credentials"

const network = easCredentialSupportedNetworks.find("sepolia")

validateCredentials(
    {
        id: easAttestations.id,
        criteria: {
            minAttestations: 1,
            network: network.id,
            schemaId: "0x",
            attester: "0x1",
            revocable: false,
            revoked: false,
            isOffchain: false
        }
    },
    {
        address: "0x2"
    }
)

Validate GitHub followers

# validateCredentials(credentials: Credentials, context: Context): Promise<boolean>

Validates the number of followers of a GitHub user.

  • credentials (Credentials):
    • id: The id for the GitHub followers validation.
    • criteria:
      • minFollowers: The minimum number of GitHub followers required.
  • context (Context):
    • profile: The user's GitHub profile.
    • accessTokens:
      • github: The user's GitHub login access token.
import {
    validateCredentials,
    githubFollowers,
    getProvider,
    Web2Provider
} from "@bandada/credentials"

const provider = getProvider("github")

const accessToken = await (provider as Web2Provider).getAccessToken(
    "clientId",
    "clientSecret",
    "oAuthCode",
    "oAuthState",
    "redirectUri"
)

const profile = await (provider as Web2Provider).getProfile(accessToken)

validateCredentials(
    {
        id: githubFollowers.id,
        criteria: {
            minFollowers: 100
        }
    },
    {
        profile,
        accessTokens: {
            github: accessToken
        }
    }
)

Validate GitHub personal stars

# validateCredentials(credentials: Credentials, context: Context): Promise<boolean>

Validates the number of stars in a GitHub user's personal repositories.

  • credentials (Credentials):
    • id: The id for the GitHub personal stars validation.
    • criteria:
      • minStars: The minimum number of GitHub personal stars required.
  • context (Context):
    • profile: The user's GitHub profile.
    • accessTokens:
      • github: The user's GitHub login access token.
import {
    validateCredentials,
    githubPersonalStars,
    getProvider,
    Web2Provider
} from "@bandada/credentials"

const provider = getProvider("github")

const accessToken = await (provider as Web2Provider).getAccessToken(
    "clientId",
    "clientSecret",
    "oAuthCode",
    "oAuthState",
    "redirectUri"
)

const profile = await (provider as Web2Provider).getProfile(accessToken)

validateCredentials(
    {
        id: githubPersonalStars.id,
        criteria: {
            minStars: 100
        }
    },
    {
        profile,
        accessTokens: {
            github: accessToken
        }
    }
)

Validate GitHub repository commits

# validateCredentials(credentials: Credentials, context: Context): Promise<boolean>

Validates the number of commits by a GitHub user in a specific repository.

  • credentials (Credentials):
    • id: The id for the GitHub repository commit validation.
    • criteria:
      • minCommits: The minimum number of GitHub commits required.
      • repository: The name of the target GitHub repository.
  • context (Context):
    • profile: The user's GitHub profile.
    • accessTokens:
      • github: The user's GitHub login access token.
import {
    validateCredentials,
    githubRepositoryCommits,
    getProvider,
    Web2Provider
} from "@bandada/credentials"

const provider = getProvider("github")

const accessToken = await (provider as Web2Provider).getAccessToken(
    "clientId",
    "clientSecret",
    "oAuthCode",
    "oAuthState",
    "redirectUri"
)

const profile = await (provider as Web2Provider).getProfile(accessToken)

validateCredentials(
    {
        id: githubRepositoryCommits.id,
        criteria: {
            repository: "hello-world",
            minCommits: 100
        }
    },
    {
        profile,
        accessTokens: {
            github: accessToken
        }
    }
)

Validate Twitter(X) followers

# validateCredentials(credentials: Credentials, context: Context): Promise<boolean>

Validates the number of followers of a Twitter(X) user.

  • credentials (Credentials):
    • id: The id for the Twitter(X) followers validation.
    • criteria:
      • minFollowers: The minimum number of followers required.
  • context (Context):
    • profile: The user's Twitter(X) profile.
    • accessTokens:
      • github: The user's Twitter(X) login access token.
import {
    validateCredentials,
    twitterFollowers,
    getProvider,
    Web2Provider
} from "@bandada/credentials"

const provider = getProvider("twitter")

const accessToken = await (provider as Web2Provider).getAccessToken(
    "clientId",
    "clientSecret",
    "oAuthCode",
    "oAuthState",
    "redirectUri"
)

const profile = await (provider as Web2Provider).getProfile(accessToken)

validateCredentials(
    {
        id: twitterFollowers.id,
        criteria: {
            minFollowers: 100
        }
    },
    {
        profile,
        accessTokens: {
            twitter: accessToken
        }
    }
)

Validate Twitter(X) following user

# validateCredentials(credentials: Credentials, context: Context): Promise<boolean>

Validates whether a Twitter(X) user follows a specific user.

  • credentials (Credentials):
    • id: The id for the Twitter(X) following user validation.
    • criteria:
      • username: The username of the target Twitter(X) user.
  • context (Context):
    • profile: The user's Twitter(X) profile.
    • accessTokens:
      • github: The user's Twitter(X) login access token.
import {
    validateCredentials,
    twitterFollowingUser,
    getProvider,
    Web2Provider
} from "@bandada/credentials"

const provider = getProvider("twitter")

const accessToken = await (provider as Web2Provider).getAccessToken(
    "clientId",
    "clientSecret",
    "oAuthCode",
    "oAuthState",
    "redirectUri"
)

const profile = await (provider as Web2Provider).getProfile(accessToken)

validateCredentials(
    {
        id: twitterFollowingUser.id,
        criteria: {
            username: "hello"
        }
    },
    {
        profile,
        accessTokens: {
            twitter: accessToken
        }
    }
)

Validate many credentials

# validateManyCredentials(credentials: Credentials[], context: Context[], expression: string[]): Promise<boolean>

Validates many credentials with parentheses in the expression.

  • credentials (Credentials[]):
    • Refer to examples above for different criteria objects.
  • context (Context[]):
    • Refer to examples above for different context objects.
  • expressions (string[]):
    • Array of string for expressions.
import {
    validateManyCredentials,
    blockchainBalance,
    blockchainTransactions,
    githubPersonalStars
} from "@bandada/credentials"

const credentials = [
    {
        id: blockchainBalance.id,
        criteria: {
            minBalance: "10",
            network: "sepolia"
        }
    },
    {
        id: blockchainTransactions.id,
        criteria: {
            minTransactions: 10,
            network: "sepolia"
        }
    },
    {
        id: githubPersonalStars.id,
        criteria: {
            minStars: 100
        }
    }
]

const contexts = [
    {
        address: "0x",
        jsonRpcProvider
    },
    {
        address: "0x",
        jsonRpcProvider
    },
    {
        profile: {},
        accessTokens: { github: "token" }
    }
]

const expression = ["", "and", "(", "", "or", "", ")"]

validateManyCredentials(credentials, contexts, expression)

Custom validators

The library has been built to allow external devs to add their own validators. A validator is a simple file that exports 3 JavaScript values:

  1. id: The validator id. It must be unique and capitalized (snake case).
  2. criteriaABI: The criteria ABI. It contains the structure of your criteria with its types.
  3. validate: The validator handler. It usually consists of three steps: criteria types check, user data retrieval and credentials' validation.
import { Handler } from "@bandada/credentials"

// Typescript type for the handler criteria.
// This will be mainly used by this handler.
export type Criteria = {
    minFollowers: number
}

const validator: Validator = {
    id: "GITHUB_FOLLOWERS",

    // The criteria application binary interface. It contains
    // the structure of this validator credentials
    // with its parameter types.
    criteriaABI: {
        minFollowers: "number"
    },

    /**
     * It checks if a user has more than 'minFollowers' followers.
     * @param criteria The criteria used to check user's credentials.
     * @param context Utility functions and other context variables.
     * @returns True if the user meets the credentials.
     */
    async validate(criteria: Criteria, { utils }) {
        // Step 1: use the API to get the user's parameters.
        const { followers } = await utils.api("user")

        // Step 2: check if they meet the validator credentials.
        return followers >= criteria.minFollowers
    }
}

export default validator

Testing your validator is also important. If you use Jest you can use some test utilities to mock the API function easily.

import {
    addValidator,
    testUtils,
    validateCredentials
} from "@bandada/credentials"
import githubFollowers from "./index"

describe("GithubFollowers", () => {
    beforeAll(() => {
        addValidator(githubFollowers)
    })

    it("Should return true if a Github user has more than 100 followers", async () => {
        testUtils.mockAPIOnce({
            followers: 110
        })

        const result = await validateCredentials(
            {
                id: "GITHUB_FOLLOWERS",
                criteria: {
                    minFollowers: 100
                }
            },
            {
                accessTokens: {
                    github: "token"
                }
            }
        )

        expect(result).toBeTruthy()
    })
})

Once you create your own validator and publish your NPM package, you can open a PR to add your validator to the ones supported by Bandada (validators.ts file). You can also add a new provider to the providers.ts file.