Skip to main content
Vincent Abilities are modular, executable functions that define what operations your App can perform on behalf of users. This guide explains their structure, lifecycle, and implementation details.

Ability Lifecycle

Vincent Abilities execute in two phases to ensure reliability and security:
1

Precheck

Runs locally to validate that execution will likely succeed. This also runs precheck on the Vincent Policies to ensure they are valid as well
2

Execute

Runs in the Lit Action environment to perform the actual operation. Policies also run their evaluate function here
Only if all policies return allow results will your Ability’s function execute. After successful execution, the Ability can optionally call Policy commit functions to update state.

Defining Your Ability

packageName
string
required
The npm package name of your Ability (e.g., @your-org/ability-name)
abilityDescription
string
required
A clear description of what your Ability does
abilityParamsSchema
ZodSchema
required
Zod schema defining the input parameters your Ability requires
supportedPolicies
SupportedPolicies
required
Array of supported Vincent Policies, created with supportedPoliciesForAbility()
precheckSuccessSchema
ZodSchema
Zod schema for successful precheck return values
precheckFailSchema
ZodSchema
Zod schema for failed precheck return values
precheck
function
required
Async function that validates execution will likely succeed
executeSuccessSchema
ZodSchema
Zod schema for successful execution return values
executeFailSchema
ZodSchema
Zod schema for failed execution return values
execute
function
required
Async function that performs the actual Ability operation

Creating Vincent Abilities

Vincent Abilities are created using createVincentAbility from the Vincent Ability SDK:
import { createVincentAbility } from '@lit-protocol/vincent-ability-sdk';

export const vincentAbility = createVincentAbility({
  packageName: '@your-org/ability-name',
  abilityDescription: 'What this ability does',

  abilityParamsSchema,
  supportedPolicies: supportedPoliciesForAbility([]),

  precheckSuccessSchema,
  precheckFailSchema,
  precheck: async ({ abilityParams }, abilityContext) => {
    // Validation logic
  },

  executeSuccessSchema,
  executeFailSchema,
  execute: async ({ abilityParams }, abilityContext) => {
    // Main execution logic
  },
});

Example Implementation

import {
  createVincentAbility,
  createVincentAbilityPolicy,
  supportedPoliciesForAbility,
} from '@lit-protocol/vincent-ability-sdk';
import { bundledVincentPolicy } from '@lit-protocol/vincent-policy-spending-limit';
import { z } from 'zod';

const abilityParamsSchema = z.object({
  tokenAddress: z.string(),
  amountToSend: z.number(),
  recipientAddress: z.string(),
});

const SpendingLimitPolicy = createVincentAbilityPolicy({
  abilityParamsSchema,
  bundledVincentPolicy,
  abilityParameterMappings: {
    tokenAddress: 'tokenAddress',
    amountToSend: 'amount',
  },
});

export const vincentAbility = createVincentAbility({
  packageName: '@example/token-transfer-ability',
  abilityDescription: 'Transfer ERC20 tokens to a recipient address',

  abilityParamsSchema,
  supportedPolicies: supportedPoliciesForAbility([SpendingLimitPolicy]),

  precheckSuccessSchema: z.object({
    tokenBalance: z.number(),
    estimatedGas: z.number(),
  }),
  precheckFailSchema: z.object({
    reason: z.string(),
    currentBalance: z.number().optional(),
    requiredAmount: z.number().optional(),
  }),

  executeSuccessSchema: z.object({
    transferTransactionHash: z.string(),
    spendTransactionHash: z.string().optional(),
  }),
  executeFailSchema: z.object({
    error: z.string(),
    errorCode: z.string().optional(),
  }),

  precheck: async ({ abilityParams }, abilityContext) => {
    // Validation logic here
  },

  execute: async ({ abilityParams }, abilityContext) => {
    // Execution logic here
  },
});

Deep Dive Guides

I