Contract Whitelist

The Contract Whitelist Policy enforces strict access control for blockchain transactions by ensuring that Vincent Apps can only interact with pre-approved smart contracts and execute specific whitelisted functions on those contracts.

What contract functions are whitelisted is specified per contract, per chain ID, enabling fine grained control over which contracts are accessible on each blockchain network and precisely which functions can be called on those contracts.

  • Multi-chain Support: Configure whitelists for multiple blockchain networks
  • Granular Function Control: Specify which functions are whitelisted using the Solidity function signature
  • Wildcard Support: Allow all functions for trusted contracts using the * wildcard

The Policy is built using the Vincent Policy SDK and validates transactions against a hierarchical whitelist. Here's how it operates:

  1. Transaction Parsing: Receives a serialized EVM transaction and parses it using ethers.js
  2. Data Extraction: Extracts the chain ID (the chainId field in the transaction), target contract address (the to field in the transaction), and function selector (first 4 bytes of the transaction data field)
  3. Whitelist Validation: Checks the transaction against the configured on-chain whitelist:
    • Is the chain ID whitelisted?
    • Is the contract address whitelisted for that chain?
    • Is the function selector allowed (explicitly or via wildcard)?
  4. Result: Returns an allow or deny response with additional details

Depending on your role in the Vincent Ecosystem, you'll be interacting with this Policy in different ways. Click on the link below that matches your role to see how to get started with this Policy:

  • Vincent App Managers: If you've created or are creating a Vincent App and you want to enable this Policy for your users to govern the execution of Vincent Abilities, go here.
  • Vincent App Delegatees: If you are a delegatee of a Vincent App that has a Vincent Ability enabled that supports this Policy, go here.
  • Vincent Ability Developers: If you've create or are creating a Vincent Ability and you want to support this Policy, go here.

Vincent Abilities determine which Vincent Policies they support. Your Vincent App can only enabled this Policy for your users if a Vincent Ability your App uses has been configured to work with that Policy - Policies are per Ability, so one Ability supporting this Policy doesn't mean your App can enable this Policy for every Ability it uses.

If the Abilities your App uses have not been configured to support this Policy, you can contact the developers of those Abilities to request that they do so, or you can fork their code and enable the Policy yourself (also see this guide to learn more about how to create your own Vincent Ability).

If you are a Delegatee to a Vincent App that has a Vincent Ability enabled that supports this Policy, there are a couple of things to be aware of as you execute Vincent Abilities on behalf of your users.

Vincent App Users set what contracts and functions are whitelisted per chain using the Policy parameters that are stored in the Vincent Registry contract. The Vincent App Users are able to update the whitelist at will, so you cannot rely on what contracts and functions are whitelisted for each chain when you execute an Ability on behalf of your users.

When you execute an Ability's precheck function, and the Vincent User has enabled this Policy for the Ability, the precheck function of this Policy will also execute. This Policy's precheck function will perform the same validation as the actual execution of the Policy, which will parse the transaction and check the chainId, to address, and function selector against the whitelist.

If the contract and function you're trying to interact with on the Vincent User's behalf is whitelisted, the precheck function will return Allow Response with the structure:

{
chainId: number; // The validated chain ID
contractAddress: string; // The validated contract address
functionSelector: string; // The validated function selector
wildcardUsed: boolean; // Whether wildcard was used for approval
}

The wildcardUsed field indicates whether the function was allowed via wildcard:

  • true: Function was allowed via wildcard
  • false: Function was explicitly whitelisted

If the contract and function you're trying to interact with on the Vincent User's behalf is not whitelisted, the precheck function will return Deny Response with the structure:

{
reason: string; // Why the transaction was denied
chainId?: number; // The chain ID (if available)
contractAddress?: string; // The contract address (if available)
functionSelector?: string; // The function selector (if available)
}

If you'd like to provide the users of your Vincent Ability with the ability to restrict what contracts and functions Vincent Apps can interact with on their behalf, you can start by installing the @lit-protocol/vincent-policy-contract-whitelist package:

npm install --save @lit-protocol/vincent-policy-contract-whitelist

After installing the Policy, the next step is to create an instance of VincentAbilityPolicy that configures the Policy specifically for your Ability:

import { createVincentAbilityPolicy } from '@lit-protocol/vincent-ability-sdk';
import { bundledVincentPolicy } from '@lit-protocol/vincent-policy-contract-whitelist';

const ContractWhitelistPolicy = createVincentAbilityPolicy({
abilityParamsSchema: z.object({
/* your Ability's params schema */
}),
bundledVincentPolicy, // This is imported from the Contract Whitelist Policy package
abilityParameterMappings: {
serializedTransaction: 'serializedTransaction',
},
});

The Contract Whitelist Policy expects a single parameter called serializedTransaction that contains the unsigned serialized EVM transaction to be evaluated by the Whitelist.

Whether your Vincent Ability accepts an unsigned serialized EVM transaction as a parameter, or it crafts one on behalf of the Vincent User, you'll need to map the name of the variable the unsigned serialized EVM transaction is defined as in your Vincent Ability, to the serializedTransaction parameter expected by the Contract Whitelist Policy.

In the above example, the Vincent Ability requires the serialized transaction as input using the same name: serializedTransaction, so we simply map that serializedTransaction parameter defined in the Ability to the serializedTransaction parameter expected by the Contract Whitelist Policy.

The last step to have your Vincent Ability support the Contract Whitelist Policy is to add the VincentAbilityPolicy instance to your Vincent Ability's supportedPolicies array:

const vincentAbility = createVincentAbility({
packageName: '@your-org/vincent-ability-your-ability-name' as const,
abilityDescription: 'Your ability description.' as const,
abilityParamsSchema: z.object({
/* your Ability's params schema */
}),
supportedPolicies: supportedPoliciesForAbility([ContractWhitelistPolicy]),
});

At this point your Vincent Ability is configured to support the Contract Whitelist Policy, and Vincent Apps which enable your Ability will now be able to enable their users to restrict what contract and functions your Ability can interact with on their behalf.