Module vincent-ability-sdk - v1.0.2

ability-sdk

This library was generated with Nx.

Run nx build ability-sdk to build the library.

Vincent Policy & Ability SDK

This library provides a type-safe lifecycle system for defining and composing policies and abilities, with strong TypeScript inference support throughout.

  • Policies encapsulate decision logic (precheck, evaluate, commit) and define their input/output schemas.
  • Abilities orchestrate multiple policies and expose precheck and execute lifecycle methods.
  • Context injection provides allow() / deny() and succeed() / fail() methods, with schema-safe return typing.
  • All inference is preserved automatically using createVincentPolicy, createVincentAbilityPolicy, and createVincentAbility.

Policies can define a commit() lifecycle method to finalize changes once an ability executes successfully. These commit() functions are injected automatically into the allowedPolicies object of the AbilityContext.

import { z } from 'zod';
import { createVincentPolicy } from '@lit-protocol/vincent-ability-sdk';

import { getAmountSpentToday, adjustDailySpendAmount } from '@my-org/spending-limit-client';

export const dailySpendPolicy = createVincentPolicy({
ipfsCid: 'policy-committable',
packageName: '@lit-protocol/max-spend-policy',

abilityParamsSchema: z.object({
buySomething: z.boolean(),
buyAmount: z.number(),
}),
userParamsSchema: z.object({
perBuyLimit: z.number(),
maxAmountPerDay: z.number(),
}),

evalAllowResultSchema: z.object({
ok: z.boolean(),
amountRemaining: z.number(),
amountToSpend: z.number(),
}),
evalDenyResultSchema: z.union([
z.object({
reason: z.literal('Buy amount request exceeds per-buy limit'),
buyAmount: z.number(),
}),
z.object({
reason: z.enum(['Buy amount request exceeds max amount per day']),
buyAmount: z.number(),
amountSpentToday: z.number(),
amountRemaining: z.number(),
}),
]),

commitParamsSchema: z.object({ amountSpent: z.number() }),
commitAllowResultSchema: z.object({
transactionId: z.string(),
timestamp: z.number(),
}),
commitDenyResultSchema: z.object({
errorCode: z.number().optional(),
message: z.string(),
}),

evaluate: async ({ abilityParams, userParams }, context) => {
const { maxAmountPerDay, perBuyLimit } = userParams;
const { buyAmount } = abilityParams;

if (buyAmount > perBuyLimit) {
return context.deny({
reason: 'Buy amount request exceeds per-buy limit',
buyAmount,
});
}

const amountSpentToday = await getAmountSpentToday(context.delegation.delegator);
const amountRemaining = maxAmountPerDay - amountSpentToday;

if (buyAmount > amountRemaining) {
return context.deny({
reason: 'Buy amount request exceeds max amount per day',
amountSpentToday,
buyAmount,
amountRemaining,
});
}

return context.allow({
ok: true,
amountRemaining,
amountToSpend: buyAmount,
});
},

commit: async ({ amountSpent }, context) => {
try {
const spendCommitResult: { transactionId: string; timestamp: number } =
await adjustDailySpendAmount(context.delegation.delegator, amountSpent);

return context.allow(spendCommitResult);
} catch (e: unknown) {
if (e instanceof Error) {
if ('errorCode' in e) {
return context.deny({
errorCode: e.errorCode as number,
message: e.message,
});
} else {
return context.deny({ message: e.message });
}
}

return context.deny({ message: String(e) });
}
},
});

import { z } from 'zod';

import {
createVincentAbilityPolicy,
createVincentAbility,
} from '@lit-protocol/vincent-ability-sdk';

import { dailySpendPolicy } from '@lit-protocol/max-spend-policy';

import uniswapV3Client from '@uniswap/v3-sdk';

const abilityParamsSchema = z.object({
buy: z.boolean(),
buyAmount: z.number(),
});

export const myTokenSwapAbility = createVincentAbility({
packageName: 'tokenswapability',
abilityDescription: 'Token Swap Ability',

abilityParamsSchema,

supportedPolicies: [
createVincentAbilityPolicy({
abilityParamsSchema,
PolicyConfig: dailySpendPolicy,
abilityParameterMappings: { buy: 'buyAmount' },
}),
],
executeSuccessSchema: z.object({
message: z.string(),
amountSpent: z.number().optional(),
spendCommitResult: z
.object({
transactionId: z.string(),
timestamp: z.number(),
})
.optional(),
}),

executeFailSchema: z.object({ error: z.string(), message: z.string() }),

async execute(abilityParams, { succeed, fail, policiesContext }) {
const spendPolicyContext = policiesContext.allowedPolicies['@lit-protocol/max-spend-policy'];

const amountSpent: number = await uniswapV3Client.performSwap({});

if (spendPolicyContext) {
const spendCommitResult = await spendPolicyContext.commit({
amountSpent,
});

if (!spendCommitResult.allow) {
return fail({
error: `Policy commit denied with code ${spendCommitResult.result.errorCode}`,
message: 'Ability executed but policy commit denied',
});
}

if (spendCommitResult.allow) {
return succeed({
amountSpent,
spendCommitResult: spendCommitResult.result,
message: 'Ability executed and spending limit policy commit completed',
});
}
}

return succeed({
message: 'Ability executed for user without enabled spending limit',
});
},
});

Ability and policy authors should export the result of createVincentPolicy() / createVincentAbility()

API Methods

supportedPoliciesForAbility
createVincentAbility
createVincentPolicy
createVincentAbilityPolicy

Interfaces

BaseAbilityContext
BundledVincentAbility
BundledVincentPolicy
PolicyContext
PolicyConfigLifecycleFunction
PolicyConfigCommitFunction
VincentAbility

Other

VINCENT_TOOL_API_VERSION
SchemaValidationError