Skip to content
44 changes: 5 additions & 39 deletions packages/delegation-toolkit/src/caveatBuilder/caveatBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,12 @@
import type { Caveat, DeleGatorEnvironment } from '../types';

export type Caveats = CaveatBuilder | Caveat[];

type CaveatWithOptionalArgs = Omit<Caveat, 'args'> & {
args?: Caveat['args'];
};

const INSECURE_UNRESTRICTED_DELEGATION_ERROR_MESSAGE =
'No caveats found. If you definitely want to create an empty caveat collection, set `allowInsecureUnrestrictedDelegation` to `true`.';

/**
* Resolves the array of Caveat from a Caveats argument.
* @param options - The caveats to be resolved, which can be either a CaveatBuilder or an array of Caveat.
* @param options.caveats - The caveats to be resolved, which can be either a CaveatBuilder or an array of Caveat.
* @param options.allowInsecureUnrestrictedDelegation - Whether to allow insecure unrestricted delegation.
* @returns The resolved array of caveats.
*/
export const resolveCaveats = ({
caveats,
allowInsecureUnrestrictedDelegation = false,
}: {
caveats: Caveats;
allowInsecureUnrestrictedDelegation?: boolean;
}) => {
if (Array.isArray(caveats)) {
if (caveats.length === 0 && !allowInsecureUnrestrictedDelegation) {
throw new Error(INSECURE_UNRESTRICTED_DELEGATION_ERROR_MESSAGE);
}
return caveats;
}
return caveats.build();
};

type RemoveFirst<TypeArray extends any[]> = TypeArray extends [
any,
...infer Rest,
]
? Rest
: never;

type CaveatBuilderMap = {
[key: string]: (
environment: DeleGatorEnvironment,
Expand Down Expand Up @@ -91,7 +59,7 @@ export class CaveatBuilder<
TEnforcerName extends string,
TFunction extends (
environment: DeleGatorEnvironment,
...args: [...any]
config: any,
) => Caveat,
>(
name: TEnforcerName,
Expand All @@ -117,19 +85,17 @@ export class CaveatBuilder<
/**
* Adds a caveat using a named enforcer function.
* @param name - The name of the enforcer function to use.
* @param args - The arguments to pass to the enforcer function.
* @param config - The configuration to pass to the enforcer function.
* @returns The CaveatBuilder instance for chaining.
*/
addCaveat<TEnforcerName extends keyof TCaveatBuilderMap>(
name: TEnforcerName,
...args: RemoveFirst<Parameters<TCaveatBuilderMap[TEnforcerName]>>
config: Parameters<TCaveatBuilderMap[TEnforcerName]>[1],
): CaveatBuilder<TCaveatBuilderMap>;

addCaveat<TEnforcerName extends keyof TCaveatBuilderMap>(
nameOrCaveat: TEnforcerName | CaveatWithOptionalArgs,
...args: typeof nameOrCaveat extends CaveatWithOptionalArgs
? []
: RemoveFirst<Parameters<TCaveatBuilderMap[TEnforcerName]>>
config?: Parameters<TCaveatBuilderMap[TEnforcerName]>[1],
): CaveatBuilder<TCaveatBuilderMap> {
if (typeof nameOrCaveat === 'object') {
const caveat = {
Expand All @@ -145,7 +111,7 @@ export class CaveatBuilder<

const func = this.#enforcerBuilders[name];
if (typeof func === 'function') {
const result = func(this.#environment, ...args);
const result = func(this.#environment, config);

this.#results = [...this.#results, result];

Expand Down
204 changes: 204 additions & 0 deletions packages/delegation-toolkit/src/caveatBuilder/coreCaveatBuilder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
import type { DeleGatorEnvironment } from '../types';
import {
allowedCalldata,
allowedCalldataBuilder,
} from './allowedCalldataBuilder';
import { allowedMethods, allowedMethodsBuilder } from './allowedMethodsBuilder';
import { allowedTargets, allowedTargetsBuilder } from './allowedTargetsBuilder';
import {
argsEqualityCheck,
argsEqualityCheckBuilder,
} from './argsEqualityCheckBuilder';
import { blockNumber, blockNumberBuilder } from './blockNumberBuilder';
import type { CaveatBuilderConfig } from './caveatBuilder';
import { CaveatBuilder } from './caveatBuilder';
import { deployed, deployedBuilder } from './deployedBuilder';
import {
erc1155BalanceChange,
erc1155BalanceChangeBuilder,
} from './erc1155BalanceChangeBuilder';
import {
erc20BalanceChange,
erc20BalanceChangeBuilder,
} from './erc20BalanceChangeBuilder';
import {
erc20PeriodTransfer,
erc20PeriodTransferBuilder,
} from './erc20PeriodTransferBuilder';
import { erc20Streaming, erc20StreamingBuilder } from './erc20StreamingBuilder';
import {
erc20TransferAmount,
erc20TransferAmountBuilder,
} from './erc20TransferAmountBuilder';
import {
erc721BalanceChange,
erc721BalanceChangeBuilder,
} from './erc721BalanceChangeBuilder';
import { erc721Transfer, erc721TransferBuilder } from './erc721TransferBuilder';
import {
exactCalldataBatch,
exactCalldataBatchBuilder,
} from './exactCalldataBatchBuilder';
import { exactCalldata, exactCalldataBuilder } from './exactCalldataBuilder';
import {
exactExecutionBatch,
exactExecutionBatchBuilder,
} from './exactExecutionBatchBuilder';
import { exactExecution, exactExecutionBuilder } from './exactExecutionBuilder';
import { id, idBuilder } from './idBuilder';
import { limitedCalls, limitedCallsBuilder } from './limitedCallsBuilder';
import {
multiTokenPeriod,
multiTokenPeriodBuilder,
} from './multiTokenPeriodBuilder';
import {
nativeBalanceChange,
nativeBalanceChangeBuilder,
} from './nativeBalanceChangeBuilder';
import {
nativeTokenPayment,
nativeTokenPaymentBuilder,
} from './nativeTokenPaymentBuilder';
import {
nativeTokenPeriodTransfer,
nativeTokenPeriodTransferBuilder,
} from './nativeTokenPeriodTransferBuilder';
import {
nativeTokenStreaming,
nativeTokenStreamingBuilder,
} from './nativeTokenStreamingBuilder';
import {
nativeTokenTransferAmount,
nativeTokenTransferAmountBuilder,
} from './nativeTokenTransferAmountBuilder';
import { nonce, nonceBuilder } from './nonceBuilder';
import {
ownershipTransfer,
ownershipTransferBuilder,
} from './ownershipTransferBuilder';
import { redeemer, redeemerBuilder } from './redeemerBuilder';
import {
specificActionERC20TransferBatch,
specificActionERC20TransferBatchBuilder,
} from './specificActionERC20TransferBatchBuilder';
import { timestamp, timestampBuilder } from './timestampBuilder';
import { valueLte, valueLteBuilder } from './valueLteBuilder';

// While we could derive CoreCaveatMap from the createCaveatBuilder function,
// doing so would significantly complicate type resolution. By explicitly
// declaring the return type of createCaveatBuilder, we ensure the caveat
// map remains synchronized with the actual implementation.
type CoreCaveatMap = {
allowedMethods: typeof allowedMethodsBuilder;
allowedTargets: typeof allowedTargetsBuilder;
deployed: typeof deployedBuilder;
allowedCalldata: typeof allowedCalldataBuilder;
erc20BalanceChange: typeof erc20BalanceChangeBuilder;
erc721BalanceChange: typeof erc721BalanceChangeBuilder;
erc1155BalanceChange: typeof erc1155BalanceChangeBuilder;
valueLte: typeof valueLteBuilder;
limitedCalls: typeof limitedCallsBuilder;
id: typeof idBuilder;
nonce: typeof nonceBuilder;
timestamp: typeof timestampBuilder;
blockNumber: typeof blockNumberBuilder;
erc20TransferAmount: typeof erc20TransferAmountBuilder;
erc20Streaming: typeof erc20StreamingBuilder;
nativeTokenStreaming: typeof nativeTokenStreamingBuilder;
erc721Transfer: typeof erc721TransferBuilder;
nativeTokenTransferAmount: typeof nativeTokenTransferAmountBuilder;
nativeBalanceChange: typeof nativeBalanceChangeBuilder;
redeemer: typeof redeemerBuilder;
nativeTokenPayment: typeof nativeTokenPaymentBuilder;
argsEqualityCheck: typeof argsEqualityCheckBuilder;
specificActionERC20TransferBatch: typeof specificActionERC20TransferBatchBuilder;
erc20PeriodTransfer: typeof erc20PeriodTransferBuilder;
nativeTokenPeriodTransfer: typeof nativeTokenPeriodTransferBuilder;
exactCalldataBatch: typeof exactCalldataBatchBuilder;
exactCalldata: typeof exactCalldataBuilder;
exactExecution: typeof exactExecutionBuilder;
exactExecutionBatch: typeof exactExecutionBatchBuilder;
multiTokenPeriod: typeof multiTokenPeriodBuilder;
ownershipTransfer: typeof ownershipTransferBuilder;
};

/**
* A caveat builder type that includes all core caveat types pre-configured.
* This type represents a fully configured caveat builder with all the standard
* caveat builders available for use.
*/
export type CoreCaveatBuilder = CaveatBuilder<CoreCaveatMap>;

type ExtractCaveatMapType<TCaveatBuilder extends CaveatBuilder<any>> =
TCaveatBuilder extends CaveatBuilder<infer TCaveatMap> ? TCaveatMap : never;
type ExtractedCoreMap = ExtractCaveatMapType<CoreCaveatBuilder>;

export type CaveatConfigurations = {
[TType in keyof ExtractedCoreMap]: {
type: TType;
} & Parameters<ExtractedCoreMap[TType]>[1];
}[keyof ExtractedCoreMap];

export type CaveatConfiguration<
TCaveatBuilder extends CaveatBuilder<any>,
CaveatMap = ExtractCaveatMapType<TCaveatBuilder>,
> =
CaveatMap extends Record<string, (...args: any[]) => any>
? {
[TType in keyof CaveatMap]: {
type: TType;
} & Parameters<CaveatMap[TType]>[1];
}[keyof CaveatMap]
: never;

export type CoreCaveatConfiguration = CaveatConfiguration<CoreCaveatBuilder>;

/**
* Creates a caveat builder with all core caveat types pre-configured.
*
* @param environment - The DeleGator environment configuration.
* @param config - Optional configuration for the caveat builder.
* @returns A fully configured CoreCaveatBuilder instance with all core caveat types.
*/
export const createCaveatBuilder = (
environment: DeleGatorEnvironment,
config?: CaveatBuilderConfig,
): CoreCaveatBuilder => {
const caveatBuilder = new CaveatBuilder(environment, config)
.extend(allowedMethods, allowedMethodsBuilder)
.extend(allowedTargets, allowedTargetsBuilder)
.extend(deployed, deployedBuilder)
.extend(allowedCalldata, allowedCalldataBuilder)
.extend(erc20BalanceChange, erc20BalanceChangeBuilder)
.extend(erc721BalanceChange, erc721BalanceChangeBuilder)
.extend(erc1155BalanceChange, erc1155BalanceChangeBuilder)
.extend(valueLte, valueLteBuilder)
.extend(limitedCalls, limitedCallsBuilder)
.extend(id, idBuilder)
.extend(nonce, nonceBuilder)
.extend(timestamp, timestampBuilder)
.extend(blockNumber, blockNumberBuilder)
.extend(erc20TransferAmount, erc20TransferAmountBuilder)
.extend(erc20Streaming, erc20StreamingBuilder)
.extend(nativeTokenStreaming, nativeTokenStreamingBuilder)
.extend(erc721Transfer, erc721TransferBuilder)
.extend(nativeTokenTransferAmount, nativeTokenTransferAmountBuilder)
.extend(nativeBalanceChange, nativeBalanceChangeBuilder)
.extend(redeemer, redeemerBuilder)
.extend(nativeTokenPayment, nativeTokenPaymentBuilder)
.extend(argsEqualityCheck, argsEqualityCheckBuilder)
.extend(
specificActionERC20TransferBatch,
specificActionERC20TransferBatchBuilder,
)
.extend(erc20PeriodTransfer, erc20PeriodTransferBuilder)
.extend(nativeTokenPeriodTransfer, nativeTokenPeriodTransferBuilder)
.extend(exactCalldataBatch, exactCalldataBatchBuilder)
.extend(exactCalldata, exactCalldataBuilder)
.extend(exactExecution, exactExecutionBuilder)
.extend(exactExecutionBatch, exactExecutionBatchBuilder)
.extend(multiTokenPeriod, multiTokenPeriodBuilder)
.extend(ownershipTransfer, ownershipTransferBuilder);

return caveatBuilder;
};
Loading
Loading