The Spending Limit Policy enables Vincent App Users to set daily USD spending limits that restrict how much value Vincent Apps can spend on their behalf. This policy provides financial controls and risk management for DeFi operations by tracking and enforcing spending limits across all supported Vincent Abilities.
The Spending Limit Policy is built using the Vincent Policy SDK and operates through a three-phase validation and tracking system:
Precheck Phase: Validates proposed spending against current limits
Evaluate Phase: Re-validates spending during ability execution
precheck
Commit Phase: Records the actual spend to the blockchain
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:
Your Vincent App can only enable this Policy for Abilities that have been specifically configured to support it. Each Ability must be individually configured—having one compatible Ability doesn't automatically enable this Policy for all Abilities in your App.
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 several important considerations for executing Vincent Abilities on behalf of your users.
Vincent App Users set the daily spending limit for each Vincent App that has this Policy enabled for a Vincent Ability. If multiple Vincent Abilities that support this are enabled for a Vincent App, the spending limit is shared across all of them.
Additionally, the App User can update the spending limit at any time, so you cannot rely on what the spending limit is when you execute an Ability on behalf of your users, and you should call the Vincent Ability's precheck
function to check the spending limit before executing any Ability.
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 convert the token buy amount to ETH, then use Chainlink to convert the ETH amount to USD, and then check the calculated USD spend amount against the Vincent App User's daily spending limit for the Vincent App you're a Delegatee of.
If the proposed token buy amount is within the Vincent App User's daily spending limit, the precheck
function will return an Allow Response with the structure:
{
/**
* The user's maximum daily spending limit in USD
*/
maxSpendingLimitInUsd: number;
/**
* The calculated USD value of the proposed token buy amount
*/
buyAmountInUsd: number;
}
If the proposed token buy amount exceeds the Vincent App User's daily spending limit for the Vincent App you're a Delegatee of, the precheck
function will return a Deny Response with the structure:
{
/**
* The string: "Attempted buy amount exceeds daily limit"
*/
reason: string;
/**
* The user's maximum daily spending limit in USD
*/
maxSpendingLimitInUsd: number;
/**
* The calculated USD value of the proposed token buy amount
*/
buyAmountInUsd: number;
}
evaluate
FunctionWhen you execute an Ability's execute
function, and the Vincent User has enabled this Policy for the Ability, the evaluate
function of this Policy will also execute. This Policy's evaluate
function will perform the same validation as precheck
function, returning the same Allow and Deny responses.
If a Deny response is returned, the Ability's execute
function will cease execution and return a Failure response.
If you'd like to provide the users of your Vincent Ability with spending limit controls, you can start by installing the @lit-protocol/vincent-policy-spending-limit
package:
npm install --save @lit-protocol/vincent-policy-spending-limit
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-spending-limit';
const SpendingLimitPolicy = createVincentAbilityPolicy({
abilityParamsSchema: z.object({
/* your Ability's params schema */
}),
bundledVincentPolicy, // This is imported from the Spending Limit Policy package
abilityParameterMappings: {
ethRpcUrl: 'ethRpcUrl',
rpcUrlForUniswap: 'rpcUrlForUniswap',
chainIdForUniswap: 'chainIdForUniswap',
tokenInAddress: 'tokenAddress',
tokenInDecimals: 'tokenDecimals',
tokenInAmount: 'buyAmount',
},
});
abilityParameterMappings
PropertyThe Spending Limit Policy expects the following input parameters from your Vincent Ability:
{
/**
* An Ethereum Mainnet RPC Endpoint. This is used to check USD <> ETH prices via Chainlink.
*/
ethRpcUrl: string;
/**
* An RPC endpoint for any chain that is supported by the Uniswap. Must work for the chain specified in chainIdForUniswap.
*/
rpcUrlForUniswap: string;
/**
* The chain ID to execute the transaction on. For example: 8453 for Base.
*/
chainIdForUniswap: number;
/**
* The decimals of the token being spent. For example: 18 for WETH on Base.
*/
tokenDecimals: number;
/**
* The amount of tokens being spent. For example: 0.00001 for 0.00001 WETH.
*/
buyAmount: number;
}
Because the Policy is executed within the context of your Ability's execution, you need to provide the Policy with it's expected input parameters. To do this, you specify the abilityParameterMappings
property (as shown above) which maps the input parameter names your Ability receives when the precheck
or execute
function is called, to the parameter names the Policy expects.
In the above example, the object keys of abilityParameterMappings
are the parameter names your Ability expects, and the object values are the parameter names the Policy expects e.g. tokenInAddress
is an Ability parameter that's being mapped to the Policy's required tokenAddress
parameter.
The last step to have your Vincent Ability support the Spending Limit 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([SpendingLimitPolicy]),
});
At this point your Vincent Ability is configured to support the Spending Limit Policy, and Vincent Apps which enable your Ability will now be able to enable their users to set daily spending limits for operations performed by your Ability.
Deployed to the Lit Chronicle Yellowstone blockchain blockchain at the address: 0x756fa449de893446b26e10c6c66e62ccabee908c, the Spending Limit contract tracks spending for each Vincent App User using a sliding window mechanism.
The contract provides the following functions and events:
function checkLimit(address user, uint256 appId, uint256 amountToSpend, uint256 userMaxSpendLimit, uint256 duration) returns (bool)
true
if the spend is allowed, false
otherwisefunction getAppSpendHistory(address user, uint256 appId, uint256 duration) returns (Spend[] memory history)
Spend
structs with timestamp
and runningSpend
fieldsfunction getAppsSpentInDuration(address user, uint256[] appIds, uint256 duration) returns (uint256)
function getTotalSpent(address user, uint256 duration) returns (uint256)
function spend(uint256 appId, uint256 amount, uint256 userMaxSpendLimit, uint256 duration) returns (bool)
SpendLimitExceeded
if the limit would be exceededSpent
event upon successful recordingevent Spent(address indexed spender, uint256 indexed appId, uint256 amount, uint256 timestamp)
error SpendLimitExceeded(address user, uint256 appId, uint256 amount, uint256 limit)
error EmptyAppIdsArray(address user)
error ZeroAppIdNotAllowed(address user)
error ZeroDurationQuery(address user)
Spend
struct:
struct Spend {
uint256 timestamp; // When the spend occurred
uint256 runningSpend; // Cumulative spending up to this point (USD with 8 decimals)
}
All USD amounts use 8-decimal precision (e.g., $1.55 = 155000000) for consistency with Chainlink price feeds.
The Policy supports the networks supported by the @uniswap/sdk-core package where Uniswap V3 is deployed. Ensure the chainIdForUniswap
corresponds to one of the supported networks
Spending limits are enforced over a continuous 24-hour lookback window from the current time. As time moves forward, older transactions automatically fall outside the window and no longer count against the spending limit.
The Policy commit phase requires a transaction on the Lit Chronicle Yellowstone blockchain to record the spent amount of USD in the Spending Limit contract. The Vincent App User's Vincent Wallet must have sufficient Lit test tokens to pay for the gas fee of the spending update transaction.
Lit test tokens can be obtained from the Lit Testnet Faucet.
Common scenarios where spending limits may be exceeded or validation may fail:
tokenInAddress
/ ETH pair