diff --git a/packages/delegator-e2e/test/caveats/allowedCalldata.test.ts b/packages/delegator-e2e/test/caveats/allowedCalldata.test.ts index b7315bb..c49715f 100644 --- a/packages/delegator-e2e/test/caveats/allowedCalldata.test.ts +++ b/packages/delegator-e2e/test/caveats/allowedCalldata.test.ts @@ -10,6 +10,7 @@ import { } from '@metamask/smart-accounts-kit'; import { createCaveatBuilder, + CaveatType, encodeExecutionCalldatas, encodeDelegations, } from '@metamask/smart-accounts-kit/utils'; @@ -77,6 +78,13 @@ test('maincase: Bob redeems the delegation with the exact calldata', async () => await runTest_expectSuccess(newCount, [{ from: 4, calldata }]); }); +test('maincase (string literal): Bob redeems the delegation with the exact calldata', async () => { + const calldata = randomBytes(32); + const newCount = hexToBigInt(calldata); + + await runTest_expectSuccess(newCount, [{ from: 4, calldata }], 'allowedCalldata'); +}); + test('Bob redeems the delegation where the delegation requires a substring of the calldata', async () => { const calldata = randomBytes(32); const newCount = hexToBigInt(calldata); @@ -88,6 +96,19 @@ test('Bob redeems the delegation where the delegation requires a substring of th ]); }); +test('Bob redeems the delegation where the delegation requires a substring of the calldata (string literal)', async () => { + const calldata = randomBytes(32); + const newCount = hexToBigInt(calldata); + + const requiredCalldata = slice(calldata, 0, 34); + + await runTest_expectSuccess( + newCount, + [{ from: 4, calldata: requiredCalldata }], + 'allowedCalldata', + ); +}); + test('Bob redeems the delegation where the calldata matches multiple caveats', async () => { const calldata = randomBytes(32); const newCount = hexToBigInt(calldata); @@ -101,6 +122,23 @@ test('Bob redeems the delegation where the calldata matches multiple caveats', a ]); }); +test('Bob redeems the delegation where the calldata matches multiple caveats (string literal)', async () => { + const calldata = randomBytes(32); + const newCount = hexToBigInt(calldata); + + const firstSlice = slice(calldata, 0, 34); + const secondSlice = slice(calldata, 20); + + await runTest_expectSuccess( + newCount, + [ + { from: 4, calldata: firstSlice }, + { from: 24, calldata: secondSlice }, + ], + 'allowedCalldata', + ); +}); + test('Bob attempts to redeem the delegation with incorrect calldata', async () => { const newCount = 1n; @@ -117,6 +155,23 @@ test('Bob attempts to redeem the delegation with incorrect calldata', async () = ); }); +test('Bob attempts to redeem the delegation with incorrect calldata (string literal)', async () => { + const newCount = 1n; + + const executedCalldata = encodeFunctionData({ + abi: aliceCounter.abi, + functionName: 'setCount', + args: [newCount], + }); + + await runTest_expectFailure( + executedCalldata, + [{ from: 0, calldata: randomBytes(32) }], + 'AllowedCalldataEnforcer:invalid-calldata', + 'allowedCalldata', + ); +}); + test('Bob attempts to redeem the delegation with no calldata', async () => { const executedCalldata = '0x'; @@ -127,9 +182,21 @@ test('Bob attempts to redeem the delegation with no calldata', async () => { ); }); +test('Bob attempts to redeem the delegation with no calldata (string literal)', async () => { + const executedCalldata = '0x'; + + await runTest_expectFailure( + executedCalldata, + [{ from: 0, calldata: randomBytes(32) }], + 'AllowedCalldataEnforcer:invalid-calldata', + 'allowedCalldata', + ); +}); + const runTest_expectSuccess = async ( newCount: bigint, caveats: { from: number; calldata: Hex }[], + caveatForm: typeof CaveatType.AllowedCalldata | 'allowedCalldata' = CaveatType.AllowedCalldata, ) => { const { environment } = aliceSmartAccount; @@ -140,7 +207,7 @@ const runTest_expectSuccess = async ( salt: '0x0', caveats: caveats .reduce((builder, caveat) => { - builder.addCaveat('allowedCalldata', { + builder.addCaveat(caveatForm, { startIndex: caveat.from, value: caveat.calldata, }); @@ -208,6 +275,7 @@ const runTest_expectFailure = async ( executedCalldata: Hex, caveats: { from: number; calldata: Hex }[], expectedError: string, + caveatForm: typeof CaveatType.AllowedCalldata | 'allowedCalldata' = CaveatType.AllowedCalldata, ) => { const { environment } = aliceSmartAccount; @@ -218,7 +286,7 @@ const runTest_expectFailure = async ( salt: '0x0', caveats: caveats .reduce((builder, caveat) => { - builder.addCaveat('allowedCalldata', { + builder.addCaveat(caveatForm, { startIndex: caveat.from, value: caveat.calldata, }); diff --git a/packages/delegator-e2e/test/caveats/allowedMethods.test.ts b/packages/delegator-e2e/test/caveats/allowedMethods.test.ts index 42ea4cb..25b69db 100644 --- a/packages/delegator-e2e/test/caveats/allowedMethods.test.ts +++ b/packages/delegator-e2e/test/caveats/allowedMethods.test.ts @@ -15,7 +15,7 @@ import type { MetaMaskSmartAccount, Delegation, } from '@metamask/smart-accounts-kit'; -import { createCaveatBuilder } from '@metamask/smart-accounts-kit/utils'; +import { createCaveatBuilder, CaveatType } from '@metamask/smart-accounts-kit/utils'; import { gasPrice, sponsoredBundlerClient, @@ -146,7 +146,7 @@ const runTest_expectSuccess = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('allowedMethods', { selectors: allowedMethods }) + .addCaveat(CaveatType.AllowedMethods, { selectors: allowedMethods }) .build(), signature: '0x', }; @@ -216,7 +216,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('allowedMethods', { selectors: allowedMethods }) + .addCaveat(CaveatType.AllowedMethods, { selectors: allowedMethods }) .build(), signature: '0x', }; diff --git a/packages/delegator-e2e/test/caveats/allowedTargets.test.ts b/packages/delegator-e2e/test/caveats/allowedTargets.test.ts index fcff935..d91cacc 100644 --- a/packages/delegator-e2e/test/caveats/allowedTargets.test.ts +++ b/packages/delegator-e2e/test/caveats/allowedTargets.test.ts @@ -10,6 +10,7 @@ import { } from '@metamask/smart-accounts-kit'; import { createCaveatBuilder, + CaveatType, encodeExecutionCalldatas, encodeDelegations, } from '@metamask/smart-accounts-kit/utils'; @@ -114,7 +115,7 @@ const runTest_expectSuccess = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('allowedTargets', { targets: allowedTargets }) + .addCaveat(CaveatType.AllowedTargets, { targets: allowedTargets }) .build(), signature: '0x', }; @@ -184,7 +185,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('allowedTargets', { targets: allowedTargets }) + .addCaveat(CaveatType.AllowedTargets, { targets: allowedTargets }) .build(), signature: '0x', }; diff --git a/packages/delegator-e2e/test/caveats/argsEqualityCheck.test.ts b/packages/delegator-e2e/test/caveats/argsEqualityCheck.test.ts index 9a90e76..bb1153b 100644 --- a/packages/delegator-e2e/test/caveats/argsEqualityCheck.test.ts +++ b/packages/delegator-e2e/test/caveats/argsEqualityCheck.test.ts @@ -10,6 +10,7 @@ import { } from '@metamask/smart-accounts-kit'; import { createCaveatBuilder, + CaveatType, encodeExecutionCalldatas, encodeDelegations, } from '@metamask/smart-accounts-kit/utils'; @@ -138,7 +139,7 @@ const runTest_expectSuccess = async (args: Hex, actualArgs: Hex) => { authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('argsEqualityCheck', { args }) + .addCaveat(CaveatType.ArgsEqualityCheck, { args }) .build(), signature: '0x', }; @@ -210,7 +211,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('argsEqualityCheck', { args }) + .addCaveat(CaveatType.ArgsEqualityCheck, { args }) .build(), signature: '0x', }; diff --git a/packages/delegator-e2e/test/caveats/blockNumber.test.ts b/packages/delegator-e2e/test/caveats/blockNumber.test.ts index a1870ee..5a7c9dc 100644 --- a/packages/delegator-e2e/test/caveats/blockNumber.test.ts +++ b/packages/delegator-e2e/test/caveats/blockNumber.test.ts @@ -10,6 +10,7 @@ import { } from '@metamask/smart-accounts-kit'; import { createCaveatBuilder, + CaveatType, encodeExecutionCalldatas, encodeDelegations, } from '@metamask/smart-accounts-kit/utils'; @@ -181,7 +182,7 @@ const runTest_expectSuccess = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('blockNumber', { + .addCaveat(CaveatType.BlockNumber, { afterThreshold, beforeThreshold, }) @@ -257,7 +258,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('blockNumber', { + .addCaveat(CaveatType.BlockNumber, { afterThreshold, beforeThreshold, }) diff --git a/packages/delegator-e2e/test/caveats/caveatUtils.test.ts b/packages/delegator-e2e/test/caveats/caveatUtils.test.ts index 578b1c7..fac1fa3 100644 --- a/packages/delegator-e2e/test/caveats/caveatUtils.test.ts +++ b/packages/delegator-e2e/test/caveats/caveatUtils.test.ts @@ -3,6 +3,7 @@ import { encodeExecutionCalldatas, encodeDelegations, createCaveatBuilder, + CaveatType, } from '@metamask/smart-accounts-kit/utils'; import { createDelegation, @@ -623,7 +624,7 @@ describe('MultiTokenPeriodEnforcer', () => { delegator: aliceSmartAccount.address, authority: ROOT_AUTHORITY as Address, caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('multiTokenPeriod', { + .addCaveat(CaveatType.MultiTokenPeriod, { tokenConfigs: [ { token: erc20TokenAddress, @@ -721,7 +722,7 @@ describe('MultiTokenPeriodEnforcer', () => { delegator: aliceSmartAccount.address, authority: ROOT_AUTHORITY as Address, caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('multiTokenPeriod', { + .addCaveat(CaveatType.MultiTokenPeriod, { tokenConfigs: [ { token: erc20TokenAddress, @@ -809,7 +810,7 @@ describe('MultiTokenPeriodEnforcer', () => { delegator: aliceSmartAccount.address, authority: ROOT_AUTHORITY as Address, caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('multiTokenPeriod', { + .addCaveat(CaveatType.MultiTokenPeriod, { tokenConfigs: [ { token: erc20TokenAddress, @@ -1507,7 +1508,7 @@ describe('Individual action functions vs client extension methods', () => { delegator: aliceSmartAccount.address, authority: ROOT_AUTHORITY as Address, caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('multiTokenPeriod', { + .addCaveat(CaveatType.MultiTokenPeriod, { tokenConfigs: [ { token: erc20TokenAddress, diff --git a/packages/delegator-e2e/test/caveats/deployed.test.ts b/packages/delegator-e2e/test/caveats/deployed.test.ts index e2b62b9..ffe2106 100644 --- a/packages/delegator-e2e/test/caveats/deployed.test.ts +++ b/packages/delegator-e2e/test/caveats/deployed.test.ts @@ -10,6 +10,7 @@ import { } from '@metamask/smart-accounts-kit'; import { createCaveatBuilder, + CaveatType, encodeExecutionCalldatas, encodeDelegations, } from '@metamask/smart-accounts-kit/utils'; @@ -160,7 +161,7 @@ const runTest_expectSuccess = async (deployedAddress: Hex, salt: Hex) => { authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('deployed', { + .addCaveat(CaveatType.Deployed, { contractAddress: deployedAddress, salt, bytecode: CounterMetadata.bytecode.object as Hex, @@ -247,7 +248,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('deployed', { + .addCaveat(CaveatType.Deployed, { contractAddress: deployedAddress, salt, bytecode: CounterMetadata.bytecode.object as Hex, diff --git a/packages/delegator-e2e/test/caveats/erc20PeriodTransfer.test.ts b/packages/delegator-e2e/test/caveats/erc20PeriodTransfer.test.ts index 57ecaf9..09d5772 100644 --- a/packages/delegator-e2e/test/caveats/erc20PeriodTransfer.test.ts +++ b/packages/delegator-e2e/test/caveats/erc20PeriodTransfer.test.ts @@ -3,6 +3,7 @@ import { encodeExecutionCalldatas, encodeDelegations, createCaveatBuilder, + CaveatType, } from '@metamask/smart-accounts-kit/utils'; import { createExecution, @@ -111,7 +112,7 @@ const runTest_expectSuccess = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('erc20PeriodTransfer', { + .addCaveat(CaveatType.Erc20PeriodTransfer, { tokenAddress: erc20TokenAddress, periodAmount, periodDuration, @@ -196,7 +197,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('erc20PeriodTransfer', { + .addCaveat(CaveatType.Erc20PeriodTransfer, { tokenAddress: erc20TokenAddress, periodAmount, periodDuration, @@ -342,7 +343,7 @@ test('Bob attempts to redeem with invalid terms length', async () => { const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('erc20PeriodTransfer', { + .addCaveat(CaveatType.Erc20PeriodTransfer, { tokenAddress: erc20TokenAddress, periodAmount, periodDuration, @@ -414,7 +415,7 @@ test('Bob attempts to redeem with invalid execution length', async () => { const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('erc20PeriodTransfer', { + .addCaveat(CaveatType.Erc20PeriodTransfer, { tokenAddress: erc20TokenAddress, periodAmount, periodDuration, @@ -488,7 +489,7 @@ test('Bob attempts to redeem with invalid contract', async () => { const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('erc20PeriodTransfer', { + .addCaveat(CaveatType.Erc20PeriodTransfer, { tokenAddress: erc20TokenAddress, periodAmount, periodDuration, @@ -558,7 +559,7 @@ test('Bob attempts to redeem with invalid method', async () => { const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('erc20PeriodTransfer', { + .addCaveat(CaveatType.Erc20PeriodTransfer, { tokenAddress: erc20TokenAddress, periodAmount, periodDuration, @@ -628,7 +629,7 @@ test('Bob attempts to redeem with zero start date', async () => { const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('erc20PeriodTransfer', { + .addCaveat(CaveatType.Erc20PeriodTransfer, { tokenAddress: erc20TokenAddress, periodAmount, periodDuration, @@ -705,7 +706,7 @@ test('Bob attempts to redeem with zero period amount', async () => { const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('erc20PeriodTransfer', { + .addCaveat(CaveatType.Erc20PeriodTransfer, { tokenAddress: erc20TokenAddress, periodAmount: 1n, // we need a valid period amount to pass validation periodDuration, @@ -783,7 +784,7 @@ test('Bob attempts to redeem with zero period duration', async () => { const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('erc20PeriodTransfer', { + .addCaveat(CaveatType.Erc20PeriodTransfer, { tokenAddress: erc20TokenAddress, periodAmount, periodDuration: 1, // we need a valid period duration to pass validation @@ -861,7 +862,7 @@ test('Bob attempts to redeem before start date', async () => { const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('erc20PeriodTransfer', { + .addCaveat(CaveatType.Erc20PeriodTransfer, { tokenAddress: erc20TokenAddress, periodAmount, periodDuration, diff --git a/packages/delegator-e2e/test/caveats/erc20Streaming.test.ts b/packages/delegator-e2e/test/caveats/erc20Streaming.test.ts index 2a64ea2..dba6aad 100644 --- a/packages/delegator-e2e/test/caveats/erc20Streaming.test.ts +++ b/packages/delegator-e2e/test/caveats/erc20Streaming.test.ts @@ -14,6 +14,7 @@ import type { } from '@metamask/smart-accounts-kit'; import { createCaveatBuilder, + CaveatType, encodeExecutionCalldatas, encodeDelegations, } from '@metamask/smart-accounts-kit/utils'; @@ -393,7 +394,7 @@ test('Bob attempts to redeem with invalid terms length', async () => { const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('erc20Streaming', { + .addCaveat(CaveatType.Erc20Streaming, { tokenAddress: erc20TokenAddress, initialAmount, maxAmount, @@ -469,7 +470,7 @@ test('Bob attempts to redeem with maxAmount less than initialAmount', async () = const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('erc20Streaming', { + .addCaveat(CaveatType.Erc20Streaming, { tokenAddress: erc20TokenAddress, initialAmount, maxAmount: initialAmount + 1n, // we need a valid maxAmount @@ -551,7 +552,7 @@ test('Bob attempts to redeem with zero start time', async () => { const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('erc20Streaming', { + .addCaveat(CaveatType.Erc20Streaming, { tokenAddress: erc20TokenAddress, initialAmount, maxAmount, @@ -640,7 +641,7 @@ const runTest_expectSuccess = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('erc20Streaming', { + .addCaveat(CaveatType.Erc20Streaming, { tokenAddress: erc20TokenAddress, initialAmount, maxAmount, @@ -731,7 +732,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('erc20Streaming', { + .addCaveat(CaveatType.Erc20Streaming, { tokenAddress: erc20TokenAddress, initialAmount, maxAmount, diff --git a/packages/delegator-e2e/test/caveats/erc20TransferAmount.test.ts b/packages/delegator-e2e/test/caveats/erc20TransferAmount.test.ts index 145af69..6bda5a5 100644 --- a/packages/delegator-e2e/test/caveats/erc20TransferAmount.test.ts +++ b/packages/delegator-e2e/test/caveats/erc20TransferAmount.test.ts @@ -4,6 +4,7 @@ import { encodeDelegations, createCaveatBuilder, hashDelegation, + CaveatType, } from '@metamask/smart-accounts-kit/utils'; import { createExecution, @@ -99,7 +100,7 @@ const runTest_expectSuccess = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('erc20TransferAmount', { + .addCaveat(CaveatType.Erc20TransferAmount, { tokenAddress: erc20TokenAddress, maxAmount, }) @@ -194,7 +195,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('erc20TransferAmount', { + .addCaveat(CaveatType.Erc20TransferAmount, { tokenAddress: erc20TokenAddress, maxAmount, }) @@ -286,7 +287,7 @@ describe('ERC20TransferAmountEnforcer Utilities E2E Tests', () => { authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('erc20TransferAmount', { + .addCaveat(CaveatType.Erc20TransferAmount, { tokenAddress: erc20TokenAddress, maxAmount, }) @@ -341,7 +342,7 @@ describe('ERC20TransferAmountEnforcer Utilities E2E Tests', () => { authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('erc20TransferAmount', { + .addCaveat(CaveatType.Erc20TransferAmount, { tokenAddress: erc20TokenAddress, maxAmount, }) @@ -510,7 +511,7 @@ describe('ERC20TransferAmountEnforcer Utilities E2E Tests', () => { authority: ROOT_AUTHORITY, salt: '0x1', // Different salt to avoid conflicts caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('erc20TransferAmount', { + .addCaveat(CaveatType.Erc20TransferAmount, { tokenAddress: erc20TokenAddress, maxAmount, }) @@ -635,7 +636,7 @@ describe('ERC20TransferAmountEnforcer Utilities E2E Tests', () => { authority: ROOT_AUTHORITY, salt: '0x2', // Different salt caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('erc20TransferAmount', { + .addCaveat(CaveatType.Erc20TransferAmount, { tokenAddress: erc20TokenAddress, maxAmount, }) diff --git a/packages/delegator-e2e/test/caveats/erc721Transfer.test.ts b/packages/delegator-e2e/test/caveats/erc721Transfer.test.ts index b1f1de4..bf15b96 100644 --- a/packages/delegator-e2e/test/caveats/erc721Transfer.test.ts +++ b/packages/delegator-e2e/test/caveats/erc721Transfer.test.ts @@ -13,6 +13,7 @@ import type { } from '@metamask/smart-accounts-kit'; import { createCaveatBuilder, + CaveatType, encodeExecutionCalldatas, encodeDelegations, } from '@metamask/smart-accounts-kit/utils'; @@ -95,7 +96,7 @@ const runTest_expectSuccess = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('erc721Transfer', { + .addCaveat(CaveatType.Erc721Transfer, { tokenAddress, tokenId, }) @@ -195,7 +196,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('erc721Transfer', { + .addCaveat(CaveatType.Erc721Transfer, { tokenAddress, tokenId: allowedTokenId, }) diff --git a/packages/delegator-e2e/test/caveats/exactCalldata.test.ts b/packages/delegator-e2e/test/caveats/exactCalldata.test.ts index 1e29ba9..58ce832 100644 --- a/packages/delegator-e2e/test/caveats/exactCalldata.test.ts +++ b/packages/delegator-e2e/test/caveats/exactCalldata.test.ts @@ -12,6 +12,7 @@ import { createCaveatBuilder, encodeDelegations, encodeExecutionCalldatas, + CaveatType, } from '@metamask/smart-accounts-kit/utils'; import { gasPrice, @@ -81,7 +82,7 @@ const runTest_expectSuccess = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('exactCalldata', { calldata }) + .addCaveat(CaveatType.ExactCalldata, { calldata }) .build(), signature: '0x', }; @@ -141,7 +142,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('exactCalldata', { calldata: expectedCalldata }) + .addCaveat(CaveatType.ExactCalldata, { calldata: expectedCalldata }) .build(), signature: '0x', }; diff --git a/packages/delegator-e2e/test/caveats/exactCalldataBatch.test.ts b/packages/delegator-e2e/test/caveats/exactCalldataBatch.test.ts index ceb5549..37ceaa5 100644 --- a/packages/delegator-e2e/test/caveats/exactCalldataBatch.test.ts +++ b/packages/delegator-e2e/test/caveats/exactCalldataBatch.test.ts @@ -10,6 +10,7 @@ import { } from '@metamask/smart-accounts-kit'; import { createCaveatBuilder, + CaveatType, encodeExecutionCalldatas, encodeDelegations, } from '@metamask/smart-accounts-kit/utils'; @@ -84,7 +85,7 @@ const runTest_expectSuccess = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('exactCalldataBatch', { executions: expectedExecutions }) + .addCaveat(CaveatType.ExactCalldataBatch, { executions: expectedExecutions }) .build(), signature: '0x', }; @@ -139,7 +140,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('exactCalldataBatch', { executions: expectedExecutions }) + .addCaveat(CaveatType.ExactCalldataBatch, { executions: expectedExecutions }) .build(), signature: '0x', }; diff --git a/packages/delegator-e2e/test/caveats/exactExecution.test.ts b/packages/delegator-e2e/test/caveats/exactExecution.test.ts index e6ff3b4..ec1f890 100644 --- a/packages/delegator-e2e/test/caveats/exactExecution.test.ts +++ b/packages/delegator-e2e/test/caveats/exactExecution.test.ts @@ -10,6 +10,7 @@ import { } from '@metamask/smart-accounts-kit'; import { createCaveatBuilder, + CaveatType, encodeExecutionCalldatas, encodeDelegations, } from '@metamask/smart-accounts-kit/utils'; @@ -80,7 +81,7 @@ const runTest_expectSuccess = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('exactExecution', { execution }) + .addCaveat(CaveatType.ExactExecution, { execution }) .build(), signature: '0x', }; @@ -135,7 +136,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('exactExecution', { execution: expectedExecution }) + .addCaveat(CaveatType.ExactExecution, { execution: expectedExecution }) .build(), signature: '0x', }; diff --git a/packages/delegator-e2e/test/caveats/exactExecutionBatch.test.ts b/packages/delegator-e2e/test/caveats/exactExecutionBatch.test.ts index a844e26..8e8185a 100644 --- a/packages/delegator-e2e/test/caveats/exactExecutionBatch.test.ts +++ b/packages/delegator-e2e/test/caveats/exactExecutionBatch.test.ts @@ -10,6 +10,7 @@ import { } from '@metamask/smart-accounts-kit'; import { createCaveatBuilder, + CaveatType, encodeExecutionCalldatas, encodeDelegations, } from '@metamask/smart-accounts-kit/utils'; @@ -83,7 +84,7 @@ const runTest_expectSuccess = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('exactExecutionBatch', { executions }) + .addCaveat(CaveatType.ExactExecutionBatch, { executions }) .build(), signature: '0x', }; @@ -138,7 +139,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('exactExecutionBatch', { executions: expectedExecutions }) + .addCaveat(CaveatType.ExactExecutionBatch, { executions: expectedExecutions }) .build(), signature: '0x', }; diff --git a/packages/delegator-e2e/test/caveats/id.test.ts b/packages/delegator-e2e/test/caveats/id.test.ts index 9084246..d592434 100644 --- a/packages/delegator-e2e/test/caveats/id.test.ts +++ b/packages/delegator-e2e/test/caveats/id.test.ts @@ -10,6 +10,7 @@ import { } from '@metamask/smart-accounts-kit'; import { createCaveatBuilder, + CaveatType, encodeExecutionCalldatas, encodeDelegations, } from '@metamask/smart-accounts-kit/utils'; @@ -114,7 +115,7 @@ const runTest_expectSuccess = async (idValue: number) => { authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('id', { id: idValue }) + .addCaveat(CaveatType.Id, { id: idValue }) .build(), signature: '0x', }; @@ -187,7 +188,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('id', { id: idValue }) + .addCaveat(CaveatType.Id, { id: idValue }) .build(), signature: '0x', }; diff --git a/packages/delegator-e2e/test/caveats/idEnforcerContractRead.test.ts b/packages/delegator-e2e/test/caveats/idEnforcerContractRead.test.ts index 0798914..0a9947b 100644 --- a/packages/delegator-e2e/test/caveats/idEnforcerContractRead.test.ts +++ b/packages/delegator-e2e/test/caveats/idEnforcerContractRead.test.ts @@ -10,6 +10,7 @@ import { } from '@metamask/smart-accounts-kit'; import { createCaveatBuilder, + CaveatType, encodeExecutionCalldatas, encodeDelegations, } from '@metamask/smart-accounts-kit/utils'; @@ -145,7 +146,7 @@ describe('IdEnforcer Contract Read Methods', () => { authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('id', { id }) + .addCaveat(CaveatType.Id, { id }) .build(), signature: '0x', }; @@ -246,7 +247,7 @@ describe('IdEnforcer Contract Read Methods', () => { authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('id', { id }) + .addCaveat(CaveatType.Id, { id }) .build(), signature: '0x', }; @@ -360,7 +361,7 @@ describe('IdEnforcer Contract Read Methods', () => { authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('id', { id: id2 }) + .addCaveat(CaveatType.Id, { id: id2 }) .build(), signature: '0x', }; @@ -452,7 +453,7 @@ describe('IdEnforcer Contract Read Methods', () => { authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('id', { id }) + .addCaveat(CaveatType.Id, { id }) .build(), signature: '0x', }; @@ -520,7 +521,7 @@ describe('IdEnforcer Contract Read Methods', () => { authority: ROOT_AUTHORITY, salt: '0x1', // Different salt caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('id', { id }) + .addCaveat(CaveatType.Id, { id }) .build(), signature: '0x', }; diff --git a/packages/delegator-e2e/test/caveats/limitedCalls.test.ts b/packages/delegator-e2e/test/caveats/limitedCalls.test.ts index 56963f6..7596b83 100644 --- a/packages/delegator-e2e/test/caveats/limitedCalls.test.ts +++ b/packages/delegator-e2e/test/caveats/limitedCalls.test.ts @@ -10,6 +10,7 @@ import { } from '@metamask/smart-accounts-kit'; import { createCaveatBuilder, + CaveatType, encodeExecutionCalldatas, encodeDelegations, hashDelegation, @@ -111,7 +112,7 @@ const runTest = async (limit: number, runs: number) => { authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('limitedCalls', { limit }) + .addCaveat(CaveatType.LimitedCalls, { limit }) .build(), signature: '0x', }; @@ -203,7 +204,7 @@ describe('LimitedCallsEnforcer Contract Read Methods', () => { authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('limitedCalls', { limit }) + .addCaveat(CaveatType.LimitedCalls, { limit }) .build(), signature: '0x', }; @@ -231,7 +232,7 @@ describe('LimitedCallsEnforcer Contract Read Methods', () => { authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('limitedCalls', { limit }) + .addCaveat(CaveatType.LimitedCalls, { limit }) .build(), signature: '0x', }; @@ -318,7 +319,7 @@ describe('LimitedCallsEnforcer Contract Read Methods', () => { authority: ROOT_AUTHORITY, salt: '0x1', caveats: createCaveatBuilder(environment) - .addCaveat('limitedCalls', { limit }) + .addCaveat(CaveatType.LimitedCalls, { limit }) .build(), signature: '0x', }; @@ -329,7 +330,7 @@ describe('LimitedCallsEnforcer Contract Read Methods', () => { authority: ROOT_AUTHORITY, salt: '0x2', caveats: createCaveatBuilder(environment) - .addCaveat('limitedCalls', { limit }) + .addCaveat(CaveatType.LimitedCalls, { limit }) .build(), signature: '0x', }; @@ -412,7 +413,7 @@ describe('LimitedCallsEnforcer Contract Read Methods', () => { authority: ROOT_AUTHORITY, salt: '0x42', caveats: createCaveatBuilder(environment) - .addCaveat('limitedCalls', { limit }) + .addCaveat(CaveatType.LimitedCalls, { limit }) .build(), signature: '0x', }; diff --git a/packages/delegator-e2e/test/caveats/multiTokenPeriod.test.ts b/packages/delegator-e2e/test/caveats/multiTokenPeriod.test.ts index 240c3b6..f66efcc 100644 --- a/packages/delegator-e2e/test/caveats/multiTokenPeriod.test.ts +++ b/packages/delegator-e2e/test/caveats/multiTokenPeriod.test.ts @@ -3,6 +3,7 @@ import { encodeExecutionCalldatas, encodeDelegations, createCaveatBuilder, + CaveatType, } from '@metamask/smart-accounts-kit/utils'; import { createExecution, @@ -127,7 +128,7 @@ const runTest_expectSuccess = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('multiTokenPeriod', { tokenConfigs: configs }) + .addCaveat(CaveatType.MultiTokenPeriod, { tokenConfigs: configs }) .build(), signature: '0x', }; @@ -215,7 +216,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('multiTokenPeriod', { tokenConfigs: configs }) + .addCaveat(CaveatType.MultiTokenPeriod, { tokenConfigs: configs }) .build(), signature: '0x', }; diff --git a/packages/delegator-e2e/test/caveats/nativeBalanceChange.test.ts b/packages/delegator-e2e/test/caveats/nativeBalanceChange.test.ts index 72f9509..b3bfc19 100644 --- a/packages/delegator-e2e/test/caveats/nativeBalanceChange.test.ts +++ b/packages/delegator-e2e/test/caveats/nativeBalanceChange.test.ts @@ -11,6 +11,7 @@ import { } from '@metamask/smart-accounts-kit'; import { createCaveatBuilder, + CaveatType, encodeExecutionCalldatas, encodeDelegations, } from '@metamask/smart-accounts-kit/utils'; @@ -123,7 +124,7 @@ test('Bob attempts to redeem with invalid terms length', async () => { const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('nativeBalanceChange', { + .addCaveat(CaveatType.NativeBalanceChange, { recipient, balance: requiredIncrease, changeType: BalanceChangeType.Increase, @@ -200,7 +201,7 @@ const testRun_expectSuccess = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeBalanceChange', { + .addCaveat(CaveatType.NativeBalanceChange, { recipient: target, balance: requiredChange, changeType, @@ -290,7 +291,7 @@ const testRun_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeBalanceChange', { + .addCaveat(CaveatType.NativeBalanceChange, { recipient: target, balance: requiredChange, changeType, diff --git a/packages/delegator-e2e/test/caveats/nativeTokenPayment.test.ts b/packages/delegator-e2e/test/caveats/nativeTokenPayment.test.ts index 643d0ce..24434ad 100644 --- a/packages/delegator-e2e/test/caveats/nativeTokenPayment.test.ts +++ b/packages/delegator-e2e/test/caveats/nativeTokenPayment.test.ts @@ -4,6 +4,7 @@ import { encodeExecutionCalldatas, hashDelegation, createCaveatBuilder, + CaveatType, } from '@metamask/smart-accounts-kit/utils'; import { createExecution, @@ -84,7 +85,7 @@ test('maincase: Bob redeems the delegation with a permissions context allowing p authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeTokenPayment', { + .addCaveat(CaveatType.NativeTokenPayment, { recipient, amount: requiredValue, }) @@ -103,7 +104,7 @@ test('maincase: Bob redeems the delegation with a permissions context allowing p authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('argsEqualityCheck', { + .addCaveat(CaveatType.ArgsEqualityCheck, { args, }) .build(), @@ -137,7 +138,7 @@ test('Bob attempts to redeem the delegation without an argsEqualityCheckEnforcer authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeTokenPayment', { + .addCaveat(CaveatType.NativeTokenPayment, { recipient, amount: requiredValue, }) @@ -184,7 +185,7 @@ test('Bob attempts to redeem the delegation without providing a valid permission authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeTokenPayment', { + .addCaveat(CaveatType.NativeTokenPayment, { recipient, amount: requiredValue, }) @@ -208,7 +209,7 @@ test('Bob attempts to redeem with invalid terms length', async () => { const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('nativeTokenPayment', { + .addCaveat(CaveatType.NativeTokenPayment, { recipient, amount: requiredValue, }) @@ -237,7 +238,7 @@ test('Bob attempts to redeem with invalid terms length', async () => { authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('argsEqualityCheck', { + .addCaveat(CaveatType.ArgsEqualityCheck, { args, }) .build(), @@ -272,7 +273,7 @@ test('Bob attempts to redeem with empty allowance delegations', async () => { authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('nativeTokenPayment', { + .addCaveat(CaveatType.NativeTokenPayment, { recipient, amount: requiredValue, }) diff --git a/packages/delegator-e2e/test/caveats/nativeTokenPeriodTransfer.test.ts b/packages/delegator-e2e/test/caveats/nativeTokenPeriodTransfer.test.ts index 1474235..72b5605 100644 --- a/packages/delegator-e2e/test/caveats/nativeTokenPeriodTransfer.test.ts +++ b/packages/delegator-e2e/test/caveats/nativeTokenPeriodTransfer.test.ts @@ -3,6 +3,7 @@ import { encodeExecutionCalldatas, encodeDelegations, createCaveatBuilder, + CaveatType, } from '@metamask/smart-accounts-kit/utils'; import { Implementation, @@ -96,7 +97,7 @@ const runTest_expectSuccess = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('nativeTokenPeriodTransfer', { + .addCaveat(CaveatType.NativeTokenPeriodTransfer, { periodAmount, periodDuration, startDate, @@ -170,7 +171,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('nativeTokenPeriodTransfer', { + .addCaveat(CaveatType.NativeTokenPeriodTransfer, { periodAmount, periodDuration, startDate, @@ -301,7 +302,7 @@ test('Bob attempts to redeem with invalid terms length', async () => { const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('nativeTokenPeriodTransfer', { + .addCaveat(CaveatType.NativeTokenPeriodTransfer, { periodAmount, periodDuration, startDate, @@ -366,7 +367,7 @@ test('Bob attempts to redeem with zero start date', async () => { const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('nativeTokenPeriodTransfer', { + .addCaveat(CaveatType.NativeTokenPeriodTransfer, { periodAmount, periodDuration, startDate: currentTime, // valid start date @@ -435,7 +436,7 @@ test('Bob attempts to redeem with zero period amount', async () => { const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('nativeTokenPeriodTransfer', { + .addCaveat(CaveatType.NativeTokenPeriodTransfer, { periodAmount: 1n, // valid period amount periodDuration, startDate, @@ -504,7 +505,7 @@ test('Bob attempts to redeem with zero period duration', async () => { const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('nativeTokenPeriodTransfer', { + .addCaveat(CaveatType.NativeTokenPeriodTransfer, { periodAmount, periodDuration: 3600, // valid period duration startDate, @@ -573,7 +574,7 @@ test('Bob attempts to redeem before start date', async () => { const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('nativeTokenPeriodTransfer', { + .addCaveat(CaveatType.NativeTokenPeriodTransfer, { periodAmount, periodDuration, startDate, @@ -799,12 +800,12 @@ test('Caveat with exactCalldata: Bob successfully redeems with exact calldata ma authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeTokenPeriodTransfer', { + .addCaveat(CaveatType.NativeTokenPeriodTransfer, { periodAmount, periodDuration, startDate, }) - .addCaveat('exactCalldata', { calldata: exactCalldata }) + .addCaveat(CaveatType.ExactCalldata, { calldata: exactCalldata }) .build(), signature: '0x', }; @@ -891,12 +892,12 @@ test('Caveat with exactCalldata: Bob fails to redeem with wrong calldata', async authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeTokenPeriodTransfer', { + .addCaveat(CaveatType.NativeTokenPeriodTransfer, { periodAmount, periodDuration, startDate, }) - .addCaveat('exactCalldata', { calldata: exactCalldata }) + .addCaveat(CaveatType.ExactCalldata, { calldata: exactCalldata }) .build(), signature: '0x', }; @@ -956,12 +957,12 @@ test('Caveat with allowedCalldata: Bob successfully redeems with allowed calldat authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeTokenPeriodTransfer', { + .addCaveat(CaveatType.NativeTokenPeriodTransfer, { periodAmount, periodDuration, startDate, }) - .addCaveat('allowedCalldata', allowedCalldata) + .addCaveat(CaveatType.AllowedCalldata, allowedCalldata) .build(), signature: '0x', }; @@ -1047,12 +1048,12 @@ test('Caveat with allowedCalldata: Bob fails to redeem with disallowed calldata authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeTokenPeriodTransfer', { + .addCaveat(CaveatType.NativeTokenPeriodTransfer, { periodAmount, periodDuration, startDate, }) - .addCaveat('allowedCalldata', allowedCalldata) + .addCaveat(CaveatType.AllowedCalldata, allowedCalldata) .build(), signature: '0x', }; diff --git a/packages/delegator-e2e/test/caveats/nativeTokenStreaming.test.ts b/packages/delegator-e2e/test/caveats/nativeTokenStreaming.test.ts index cb75d60..72e02ee 100644 --- a/packages/delegator-e2e/test/caveats/nativeTokenStreaming.test.ts +++ b/packages/delegator-e2e/test/caveats/nativeTokenStreaming.test.ts @@ -3,6 +3,7 @@ import { encodeExecutionCalldatas, encodeDelegations, createCaveatBuilder, + CaveatType, } from '@metamask/smart-accounts-kit/utils'; import { createExecution, @@ -325,7 +326,7 @@ test('Bob attempts to redeem with invalid terms length', async () => { const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('nativeTokenStreaming', { + .addCaveat(CaveatType.NativeTokenStreaming, { initialAmount, maxAmount, amountPerSecond, @@ -394,7 +395,7 @@ test('Bob attempts to redeem with invalid max amount', async () => { const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('nativeTokenStreaming', { + .addCaveat(CaveatType.NativeTokenStreaming, { initialAmount, maxAmount: initialAmount + 1n, // we need a valid maxAmount amountPerSecond, @@ -467,7 +468,7 @@ test('Bob attempts to redeem with zero start time', async () => { const { environment } = aliceSmartAccount; const caveats = createCaveatBuilder(environment) - .addCaveat('nativeTokenStreaming', { + .addCaveat(CaveatType.NativeTokenStreaming, { initialAmount, maxAmount, amountPerSecond, @@ -548,7 +549,7 @@ const runTest_expectSuccess = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('nativeTokenStreaming', { + .addCaveat(CaveatType.NativeTokenStreaming, { initialAmount, maxAmount, amountPerSecond, @@ -630,7 +631,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('nativeTokenStreaming', { + .addCaveat(CaveatType.NativeTokenStreaming, { initialAmount, maxAmount, amountPerSecond, @@ -892,13 +893,13 @@ test('Caveat with exactCalldata: Bob successfully redeems with exact calldata ma authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeTokenStreaming', { + .addCaveat(CaveatType.NativeTokenStreaming, { initialAmount, maxAmount, amountPerSecond, startTime, }) - .addCaveat('exactCalldata', { calldata: exactCalldata }) + .addCaveat(CaveatType.ExactCalldata, { calldata: exactCalldata }) .build(), signature: '0x', }; @@ -986,13 +987,13 @@ test('Caveat with exactCalldata: Bob fails to redeem with wrong calldata', async authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeTokenStreaming', { + .addCaveat(CaveatType.NativeTokenStreaming, { initialAmount, maxAmount, amountPerSecond, startTime, }) - .addCaveat('exactCalldata', { calldata: exactCalldata }) + .addCaveat(CaveatType.ExactCalldata, { calldata: exactCalldata }) .build(), signature: '0x', }; @@ -1053,13 +1054,13 @@ test('Caveat with allowedCalldata: Bob successfully redeems with allowed calldat authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeTokenStreaming', { + .addCaveat(CaveatType.NativeTokenStreaming, { initialAmount, maxAmount, amountPerSecond, startTime, }) - .addCaveat('allowedCalldata', allowedCalldata) + .addCaveat(CaveatType.AllowedCalldata, allowedCalldata) .build(), signature: '0x', }; @@ -1146,13 +1147,13 @@ test('Caveat with allowedCalldata: Bob fails to redeem with disallowed calldata authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeTokenStreaming', { + .addCaveat(CaveatType.NativeTokenStreaming, { initialAmount, maxAmount, amountPerSecond, startTime, }) - .addCaveat('allowedCalldata', allowedCalldata) + .addCaveat(CaveatType.AllowedCalldata, allowedCalldata) .build(), signature: '0x', }; diff --git a/packages/delegator-e2e/test/caveats/nativeTokenTransferAmount.test.ts b/packages/delegator-e2e/test/caveats/nativeTokenTransferAmount.test.ts index 3c7c9c4..9110cfc 100644 --- a/packages/delegator-e2e/test/caveats/nativeTokenTransferAmount.test.ts +++ b/packages/delegator-e2e/test/caveats/nativeTokenTransferAmount.test.ts @@ -4,6 +4,7 @@ import { encodeDelegations, createCaveatBuilder, hashDelegation, + CaveatType, } from '@metamask/smart-accounts-kit/utils'; import { createExecution, @@ -105,7 +106,7 @@ const runTest_expectSuccess = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeTokenTransferAmount', { maxAmount: allowance }) + .addCaveat(CaveatType.NativeTokenTransferAmount, { maxAmount: allowance }) .build(), signature: '0x', }; @@ -177,7 +178,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeTokenTransferAmount', { maxAmount: allowance }) + .addCaveat(CaveatType.NativeTokenTransferAmount, { maxAmount: allowance }) .build(), signature: '0x', }; @@ -392,7 +393,7 @@ test('Utility: getTermsInfo should correctly decode terms from a real delegation authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeTokenTransferAmount', { + .addCaveat(CaveatType.NativeTokenTransferAmount, { maxAmount, }) .build(), @@ -459,7 +460,7 @@ test('Utility: getSpentAmount should track spending correctly before and after t authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeTokenTransferAmount', { maxAmount }) + .addCaveat(CaveatType.NativeTokenTransferAmount, { maxAmount }) .build(), signature: '0x', }; @@ -579,8 +580,8 @@ test('Caveat with exactCalldata: Bob successfully redeems with exact calldata ma authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeTokenTransferAmount', { maxAmount: allowance }) - .addCaveat('exactCalldata', { calldata: exactCalldata }) + .addCaveat(CaveatType.NativeTokenTransferAmount, { maxAmount: allowance }) + .addCaveat(CaveatType.ExactCalldata, { calldata: exactCalldata }) .build(), signature: '0x', }; @@ -665,8 +666,8 @@ test('Caveat with exactCalldata: Bob fails to redeem with wrong calldata', async authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeTokenTransferAmount', { maxAmount: allowance }) - .addCaveat('exactCalldata', { calldata: exactCalldata }) + .addCaveat(CaveatType.NativeTokenTransferAmount, { maxAmount: allowance }) + .addCaveat(CaveatType.ExactCalldata, { calldata: exactCalldata }) .build(), signature: '0x', }; @@ -724,8 +725,8 @@ test('Caveat with allowedCalldata: Bob successfully redeems with allowed calldat authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeTokenTransferAmount', { maxAmount: allowance }) - .addCaveat('allowedCalldata', { startIndex: 0, value: allowedCalldata }) + .addCaveat(CaveatType.NativeTokenTransferAmount, { maxAmount: allowance }) + .addCaveat(CaveatType.AllowedCalldata, { startIndex: 0, value: allowedCalldata }) .build(), signature: '0x', }; @@ -810,8 +811,8 @@ test('Caveat with allowedCalldata: Bob fails to redeem with disallowed calldata authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(aliceSmartAccount.environment) - .addCaveat('nativeTokenTransferAmount', { maxAmount: allowance }) - .addCaveat('allowedCalldata', { startIndex: 0, value: allowedCalldata }) + .addCaveat(CaveatType.NativeTokenTransferAmount, { maxAmount: allowance }) + .addCaveat(CaveatType.AllowedCalldata, { startIndex: 0, value: allowedCalldata }) .build(), signature: '0x', }; diff --git a/packages/delegator-e2e/test/caveats/nonce.test.ts b/packages/delegator-e2e/test/caveats/nonce.test.ts index 9c8681e..5e8ab13 100644 --- a/packages/delegator-e2e/test/caveats/nonce.test.ts +++ b/packages/delegator-e2e/test/caveats/nonce.test.ts @@ -11,6 +11,7 @@ import { } from '@metamask/smart-accounts-kit'; import { createCaveatBuilder, + CaveatType, encodeExecutionCalldatas, encodeDelegations, } from '@metamask/smart-accounts-kit/utils'; @@ -123,7 +124,7 @@ const runTest_expectSuccess = async (newCount: bigint, nonce: bigint) => { authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('nonce', { nonce: toHex(nonce) }) + .addCaveat(CaveatType.Nonce, { nonce: toHex(nonce) }) .build(), signature: '0x', }; @@ -197,7 +198,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('nonce', { nonce: toHex(nonce) }) + .addCaveat(CaveatType.Nonce, { nonce: toHex(nonce) }) .build(), signature: '0x', }; diff --git a/packages/delegator-e2e/test/caveats/redeemer.test.ts b/packages/delegator-e2e/test/caveats/redeemer.test.ts index e877ae9..ad43d0a 100644 --- a/packages/delegator-e2e/test/caveats/redeemer.test.ts +++ b/packages/delegator-e2e/test/caveats/redeemer.test.ts @@ -10,6 +10,7 @@ import { } from '@metamask/smart-accounts-kit'; import { createCaveatBuilder, + CaveatType, encodeExecutionCalldatas, encodeDelegations, } from '@metamask/smart-accounts-kit/utils'; @@ -99,7 +100,7 @@ const runTest_expectSuccess = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('redeemer', { redeemers: allowedRedeemers }) + .addCaveat(CaveatType.Redeemer, { redeemers: allowedRedeemers }) .build(), signature: '0x', }; @@ -180,7 +181,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('redeemer', { redeemers: allowedRedeemers }) + .addCaveat(CaveatType.Redeemer, { redeemers: allowedRedeemers }) .build(), signature: '0x', }; diff --git a/packages/delegator-e2e/test/caveats/specificActionERC20TransferBatch.test.ts b/packages/delegator-e2e/test/caveats/specificActionERC20TransferBatch.test.ts index 5b6df7a..273be26 100644 --- a/packages/delegator-e2e/test/caveats/specificActionERC20TransferBatch.test.ts +++ b/packages/delegator-e2e/test/caveats/specificActionERC20TransferBatch.test.ts @@ -4,6 +4,7 @@ import { encodeDelegations, createCaveatBuilder, hashDelegation, + CaveatType, } from '@metamask/smart-accounts-kit/utils'; import { Implementation, @@ -114,7 +115,7 @@ const runTest_expectSuccess = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('specificActionERC20TransferBatch', { + .addCaveat(CaveatType.SpecificActionERC20TransferBatch, { tokenAddress, recipient, amount, @@ -187,7 +188,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('specificActionERC20TransferBatch', { + .addCaveat(CaveatType.SpecificActionERC20TransferBatch, { tokenAddress, recipient, amount, @@ -665,7 +666,7 @@ describe('SpecificActionERC20TransferBatchEnforcer Contract Read Methods', () => authority: ROOT_AUTHORITY, salt: '0x123', caveats: createCaveatBuilder(environment) - .addCaveat('specificActionERC20TransferBatch', { + .addCaveat(CaveatType.SpecificActionERC20TransferBatch, { tokenAddress: erc20TokenAddress, recipient: bobSmartAccount.address, amount: parseEther('1'), @@ -703,7 +704,7 @@ describe('SpecificActionERC20TransferBatchEnforcer Contract Read Methods', () => authority: ROOT_AUTHORITY, salt: '0x456', caveats: createCaveatBuilder(environment) - .addCaveat('specificActionERC20TransferBatch', { + .addCaveat(CaveatType.SpecificActionERC20TransferBatch, { tokenAddress: erc20TokenAddress, recipient: bobSmartAccount.address, amount: transferAmount, @@ -799,7 +800,7 @@ describe('SpecificActionERC20TransferBatchEnforcer Contract Read Methods', () => authority: ROOT_AUTHORITY, salt: '0x111', caveats: createCaveatBuilder(environment) - .addCaveat('specificActionERC20TransferBatch', { + .addCaveat(CaveatType.SpecificActionERC20TransferBatch, { tokenAddress: erc20TokenAddress, recipient: bobSmartAccount.address, amount: parseEther('1'), @@ -816,7 +817,7 @@ describe('SpecificActionERC20TransferBatchEnforcer Contract Read Methods', () => authority: ROOT_AUTHORITY, salt: '0x222', // Different salt = different delegation hash caveats: createCaveatBuilder(environment) - .addCaveat('specificActionERC20TransferBatch', { + .addCaveat(CaveatType.SpecificActionERC20TransferBatch, { tokenAddress: erc20TokenAddress, recipient: bobSmartAccount.address, amount: parseEther('1'), diff --git a/packages/delegator-e2e/test/caveats/timestamp.test.ts b/packages/delegator-e2e/test/caveats/timestamp.test.ts index bfb349f..7a9e51a 100644 --- a/packages/delegator-e2e/test/caveats/timestamp.test.ts +++ b/packages/delegator-e2e/test/caveats/timestamp.test.ts @@ -10,6 +10,7 @@ import { } from '@metamask/smart-accounts-kit'; import { createCaveatBuilder, + CaveatType, encodeExecutionCalldatas, encodeDelegations, } from '@metamask/smart-accounts-kit/utils'; @@ -160,7 +161,7 @@ const runTest_expectSuccess = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('timestamp', { + .addCaveat(CaveatType.Timestamp, { afterThreshold, beforeThreshold, }) @@ -245,7 +246,7 @@ const runTest_expectFailure = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('timestamp', { + .addCaveat(CaveatType.Timestamp, { afterThreshold, beforeThreshold, }) diff --git a/packages/delegator-e2e/test/caveats/valueLte.test.ts b/packages/delegator-e2e/test/caveats/valueLte.test.ts index 8fb4b13..d714ea0 100644 --- a/packages/delegator-e2e/test/caveats/valueLte.test.ts +++ b/packages/delegator-e2e/test/caveats/valueLte.test.ts @@ -10,6 +10,7 @@ import { } from '@metamask/smart-accounts-kit'; import { createCaveatBuilder, + CaveatType, encodeExecutionCalldatas, encodeDelegations, } from '@metamask/smart-accounts-kit/utils'; @@ -125,7 +126,7 @@ const submitUserOperationForTest = async ( authority: ROOT_AUTHORITY, salt: '0x0', caveats: createCaveatBuilder(environment) - .addCaveat('valueLte', { maxValue }) + .addCaveat(CaveatType.ValueLte, { maxValue }) .build(), signature: '0x', }; diff --git a/packages/smart-accounts-kit/src/caveatBuilder/allowedCalldataBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/allowedCalldataBuilder.ts index fa565c1..22ed02e 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/allowedCalldataBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/allowedCalldataBuilder.ts @@ -2,8 +2,9 @@ import { createAllowedCalldataTerms } from '@metamask/delegation-core'; import { type Hex } from 'viem'; import type { SmartAccountsEnvironment, Caveat } from '../types'; +import { CaveatType } from './caveatType'; -export const allowedCalldata = 'allowedCalldata'; +export const allowedCalldata = CaveatType.AllowedCalldata; export type AllowedCalldataBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/allowedMethodsBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/allowedMethodsBuilder.ts index d9a1cfc..af06148 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/allowedMethodsBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/allowedMethodsBuilder.ts @@ -3,8 +3,9 @@ import { isHex, toFunctionSelector } from 'viem'; import type { AbiFunction, Hex } from 'viem'; import type { Caveat, SmartAccountsEnvironment } from '../types'; +import { CaveatType } from './caveatType'; -export const allowedMethods = 'allowedMethods'; +export const allowedMethods = CaveatType.AllowedMethods; export type MethodSelector = Hex | string | AbiFunction; diff --git a/packages/smart-accounts-kit/src/caveatBuilder/allowedTargetsBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/allowedTargetsBuilder.ts index fcd1e15..835c883 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/allowedTargetsBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/allowedTargetsBuilder.ts @@ -2,8 +2,9 @@ import { createAllowedTargetsTerms } from '@metamask/delegation-core'; import { isAddress, type Address } from 'viem'; import type { Caveat, SmartAccountsEnvironment } from '../types'; +import { CaveatType } from './caveatType'; -export const allowedTargets = 'allowedTargets'; +export const allowedTargets = CaveatType.AllowedTargets; export type AllowedTargetsBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/argsEqualityCheckBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/argsEqualityCheckBuilder.ts index 0234e40..2b8072f 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/argsEqualityCheckBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/argsEqualityCheckBuilder.ts @@ -2,8 +2,9 @@ import { createArgsEqualityCheckTerms } from '@metamask/delegation-core'; import { type Hex, isHex } from 'viem'; import type { SmartAccountsEnvironment, Caveat } from '../types'; +import { CaveatType } from './caveatType'; -export const argsEqualityCheck = 'argsEqualityCheck'; +export const argsEqualityCheck = CaveatType.ArgsEqualityCheck; export type ArgsEqualityCheckBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/blockNumberBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/blockNumberBuilder.ts index 99d3e03..4d4bfa7 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/blockNumberBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/blockNumberBuilder.ts @@ -1,8 +1,9 @@ import { createBlockNumberTerms } from '@metamask/delegation-core'; import type { SmartAccountsEnvironment, Caveat } from '../types'; +import { CaveatType } from './caveatType'; -export const blockNumber = 'blockNumber'; +export const blockNumber = CaveatType.BlockNumber; export type BlockNumberBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/caveatBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/caveatBuilder.ts index e9eda86..0bfb0f4 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/caveatBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/caveatBuilder.ts @@ -88,7 +88,12 @@ export class CaveatBuilder< /** * Adds a caveat using a named enforcer function. * - * @param name - The name of the enforcer function to use. + * Only accepts caveat types that are registered on this builder (keys of TCaveatBuilderMap). + * Supports both enum and string literal when the builder includes that enforcer, e.g.: + * - caveatBuilder.addCaveat(CaveatType.AllowedMethods, { ... }) + * - caveatBuilder.addCaveat('allowedMethods', { ... }) + * + * @param name - The name of the enforcer function to use (must be registered on this builder). * @param config - The configuration to pass to the enforcer function. * @returns The CaveatBuilder instance for chaining. */ diff --git a/packages/smart-accounts-kit/src/caveatBuilder/caveatType.ts b/packages/smart-accounts-kit/src/caveatBuilder/caveatType.ts new file mode 100644 index 0000000..2719711 --- /dev/null +++ b/packages/smart-accounts-kit/src/caveatBuilder/caveatType.ts @@ -0,0 +1,46 @@ +/** + * Caveat types for enforcer functions used in delegations. + * Can be used when defining caveats either via CaveatBuilder.addCaveat + * or in the caveats array in createDelegation. + */ +export enum CaveatType { + AllowedMethods = 'allowedMethods', + AllowedTargets = 'allowedTargets', + Deployed = 'deployed', + AllowedCalldata = 'allowedCalldata', + Erc20BalanceChange = 'erc20BalanceChange', + Erc721BalanceChange = 'erc721BalanceChange', + Erc1155BalanceChange = 'erc1155BalanceChange', + ValueLte = 'valueLte', + LimitedCalls = 'limitedCalls', + Id = 'id', + Nonce = 'nonce', + Timestamp = 'timestamp', + BlockNumber = 'blockNumber', + Erc20TransferAmount = 'erc20TransferAmount', + Erc20Streaming = 'erc20Streaming', + NativeTokenStreaming = 'nativeTokenStreaming', + Erc721Transfer = 'erc721Transfer', + NativeTokenTransferAmount = 'nativeTokenTransferAmount', + NativeBalanceChange = 'nativeBalanceChange', + Redeemer = 'redeemer', + NativeTokenPayment = 'nativeTokenPayment', + ArgsEqualityCheck = 'argsEqualityCheck', + SpecificActionERC20TransferBatch = 'specificActionERC20TransferBatch', + Erc20PeriodTransfer = 'erc20PeriodTransfer', + NativeTokenPeriodTransfer = 'nativeTokenPeriodTransfer', + ExactCalldataBatch = 'exactCalldataBatch', + ExactCalldata = 'exactCalldata', + ExactExecution = 'exactExecution', + ExactExecutionBatch = 'exactExecutionBatch', + MultiTokenPeriod = 'multiTokenPeriod', + OwnershipTransfer = 'ownershipTransfer', +} + +/** + * Represents a caveat type that can be either the enum value or its string representation. + * This allows both forms: + * - CaveatType.AllowedMethods (enum) + * - 'allowedMethods' (string literal) + */ +export type CaveatTypeParam = CaveatType | `${CaveatType}`; diff --git a/packages/smart-accounts-kit/src/caveatBuilder/coreCaveatBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/coreCaveatBuilder.ts index 963e2ce..d73136a 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/coreCaveatBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/coreCaveatBuilder.ts @@ -12,6 +12,7 @@ import { import { blockNumber, blockNumberBuilder } from './blockNumberBuilder'; import type { CaveatBuilderConfig } from './caveatBuilder'; import { CaveatBuilder } from './caveatBuilder'; +import type { CaveatType, CaveatTypeParam } from './caveatType'; import { deployed, deployedBuilder } from './deployedBuilder'; import { erc1155BalanceChange, @@ -89,45 +90,71 @@ import { valueLte, valueLteBuilder } from './valueLteBuilder'; // 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; + [CaveatType.AllowedMethods]: typeof allowedMethodsBuilder; + [CaveatType.AllowedTargets]: typeof allowedTargetsBuilder; + [CaveatType.Deployed]: typeof deployedBuilder; + [CaveatType.AllowedCalldata]: typeof allowedCalldataBuilder; + [CaveatType.Erc20BalanceChange]: typeof erc20BalanceChangeBuilder; + [CaveatType.Erc721BalanceChange]: typeof erc721BalanceChangeBuilder; + [CaveatType.Erc1155BalanceChange]: typeof erc1155BalanceChangeBuilder; + [CaveatType.ValueLte]: typeof valueLteBuilder; + [CaveatType.LimitedCalls]: typeof limitedCallsBuilder; + [CaveatType.Id]: typeof idBuilder; + [CaveatType.Nonce]: typeof nonceBuilder; + [CaveatType.Timestamp]: typeof timestampBuilder; + [CaveatType.BlockNumber]: typeof blockNumberBuilder; + [CaveatType.Erc20TransferAmount]: typeof erc20TransferAmountBuilder; + [CaveatType.Erc20Streaming]: typeof erc20StreamingBuilder; + [CaveatType.NativeTokenStreaming]: typeof nativeTokenStreamingBuilder; + [CaveatType.Erc721Transfer]: typeof erc721TransferBuilder; + [CaveatType.NativeTokenTransferAmount]: typeof nativeTokenTransferAmountBuilder; + [CaveatType.NativeBalanceChange]: typeof nativeBalanceChangeBuilder; + [CaveatType.Redeemer]: typeof redeemerBuilder; + [CaveatType.NativeTokenPayment]: typeof nativeTokenPaymentBuilder; + [CaveatType.ArgsEqualityCheck]: typeof argsEqualityCheckBuilder; + [CaveatType.SpecificActionERC20TransferBatch]: typeof specificActionERC20TransferBatchBuilder; + [CaveatType.Erc20PeriodTransfer]: typeof erc20PeriodTransferBuilder; + [CaveatType.NativeTokenPeriodTransfer]: typeof nativeTokenPeriodTransferBuilder; + [CaveatType.ExactCalldataBatch]: typeof exactCalldataBatchBuilder; + [CaveatType.ExactCalldata]: typeof exactCalldataBuilder; + [CaveatType.ExactExecution]: typeof exactExecutionBuilder; + [CaveatType.ExactExecutionBatch]: typeof exactExecutionBatchBuilder; + [CaveatType.MultiTokenPeriod]: typeof multiTokenPeriodBuilder; + [CaveatType.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. + * + * The addCaveat(name, config) overload is widened to accept CaveatTypeParam + * (enum or string literal) so that both CaveatType.AllowedMethods and + * 'allowedMethods' are accepted. Extended builders keep strict keyof Map typing. + */ +/** + * Maps each caveat type (enum and string literal) to its config type. + * Ensures addCaveat(name, config) is type-checked per caveat even when + * using string literals (e.g. 'allowedMethods'), preserving backward + * compatibility and preventing wrong-config-at-runtime regressions. */ -export type CoreCaveatBuilder = CaveatBuilder; +type CoreCaveatParamToConfig = { + [K in keyof CoreCaveatMap]: Parameters[1]; +} & { + [K in CaveatType as `${K}`]: K extends keyof CoreCaveatMap + ? Parameters[1] + : never; +}; + +export type CoreCaveatBuilder = CaveatBuilder & { + addCaveat( + name: TKey, + config: CoreCaveatParamToConfig[TKey], + ): CoreCaveatBuilder; +}; + +// Re-export CaveatType and related types for convenience +export { CaveatType, type CaveatTypeParam } from './caveatType'; type ExtractCaveatMapType> = TCaveatBuilder extends CaveatBuilder ? TCaveatMap : never; @@ -139,16 +166,25 @@ export type CaveatConfigurations = { } & Parameters[1]; }[keyof ExtractedCoreMap]; +// Convert a config type to accept both the enum value and its string representation, +// while preserving the discriminated union pattern. +type ConvertCaveatConfigToInputs = + TConfig extends { type: string } + ? Omit & { type: TConfig['type'] | `${TConfig['type']}` } + : never; + export type CaveatConfiguration< TCaveatBuilder extends CaveatBuilder, CaveatMap = ExtractCaveatMapType, > = CaveatMap extends Record any> - ? { - [TType in keyof CaveatMap]: { - type: TType; - } & Parameters[1]; - }[keyof CaveatMap] + ? ConvertCaveatConfigToInputs< + { + [TType in keyof CaveatMap]: { + type: TType extends string ? TType : never; + } & Parameters[1]; + }[keyof CaveatMap] + > : never; export type CoreCaveatConfiguration = CaveatConfiguration; diff --git a/packages/smart-accounts-kit/src/caveatBuilder/deployedBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/deployedBuilder.ts index e1a2d35..5eddd1b 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/deployedBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/deployedBuilder.ts @@ -2,8 +2,9 @@ import { createDeployedTerms } from '@metamask/delegation-core'; import { isAddress, isHex, type Address, type Hex } from 'viem'; import type { Caveat, SmartAccountsEnvironment } from '../types'; +import { CaveatType } from './caveatType'; -export const deployed = 'deployed'; +export const deployed = CaveatType.Deployed; export type DeployedBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/erc1155BalanceChangeBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/erc1155BalanceChangeBuilder.ts index c3746a4..7c00d6e 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/erc1155BalanceChangeBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/erc1155BalanceChangeBuilder.ts @@ -2,9 +2,10 @@ import { createERC1155BalanceChangeTerms } from '@metamask/delegation-core'; import { type Address, isAddress } from 'viem'; import type { SmartAccountsEnvironment, Caveat } from '../types'; +import { CaveatType } from './caveatType'; import { BalanceChangeType } from './types'; -export const erc1155BalanceChange = 'erc1155BalanceChange'; +export const erc1155BalanceChange = CaveatType.Erc1155BalanceChange; export type Erc1155BalanceChangeBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/erc20BalanceChangeBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/erc20BalanceChangeBuilder.ts index 5dcc982..fe46dd4 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/erc20BalanceChangeBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/erc20BalanceChangeBuilder.ts @@ -2,9 +2,10 @@ import { createERC20BalanceChangeTerms } from '@metamask/delegation-core'; import { type Address, isAddress } from 'viem'; import type { SmartAccountsEnvironment, Caveat } from '../types'; +import { CaveatType } from './caveatType'; import { BalanceChangeType } from './types'; -export const erc20BalanceChange = 'erc20BalanceChange'; +export const erc20BalanceChange = CaveatType.Erc20BalanceChange; export type Erc20BalanceChangeBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/erc20PeriodTransferBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/erc20PeriodTransferBuilder.ts index e63aea9..83087a7 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/erc20PeriodTransferBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/erc20PeriodTransferBuilder.ts @@ -2,8 +2,9 @@ import { createERC20TokenPeriodTransferTerms } from '@metamask/delegation-core'; import type { Address } from 'viem'; import type { Caveat, SmartAccountsEnvironment } from '../types'; +import { CaveatType } from './caveatType'; -export const erc20PeriodTransfer = 'erc20PeriodTransfer'; +export const erc20PeriodTransfer = CaveatType.Erc20PeriodTransfer; export type Erc20PeriodTransferBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/erc20StreamingBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/erc20StreamingBuilder.ts index 1b5db20..e0c1b80 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/erc20StreamingBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/erc20StreamingBuilder.ts @@ -2,8 +2,9 @@ import { createERC20StreamingTerms } from '@metamask/delegation-core'; import { type Address } from 'viem'; import type { SmartAccountsEnvironment, Caveat } from '../types'; +import { CaveatType } from './caveatType'; -export const erc20Streaming = 'erc20Streaming'; +export const erc20Streaming = CaveatType.Erc20Streaming; export type Erc20StreamingBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/erc20TransferAmountBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/erc20TransferAmountBuilder.ts index ca2f256..74cddb9 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/erc20TransferAmountBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/erc20TransferAmountBuilder.ts @@ -3,8 +3,9 @@ import type { Address } from 'viem'; import { isAddress } from 'viem'; import type { Caveat, SmartAccountsEnvironment } from '../types'; +import { CaveatType } from './caveatType'; -export const erc20TransferAmount = 'erc20TransferAmount'; +export const erc20TransferAmount = CaveatType.Erc20TransferAmount; export type Erc20TransferAmountBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/erc721BalanceChangeBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/erc721BalanceChangeBuilder.ts index 1509707..5541cee 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/erc721BalanceChangeBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/erc721BalanceChangeBuilder.ts @@ -2,9 +2,10 @@ import { createERC721BalanceChangeTerms } from '@metamask/delegation-core'; import { type Address, isAddress } from 'viem'; import type { SmartAccountsEnvironment, Caveat } from '../types'; +import { CaveatType } from './caveatType'; import { BalanceChangeType } from './types'; -export const erc721BalanceChange = 'erc721BalanceChange'; +export const erc721BalanceChange = CaveatType.Erc721BalanceChange; export type Erc721BalanceChangeBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/erc721TransferBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/erc721TransferBuilder.ts index 96ad918..36f1547 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/erc721TransferBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/erc721TransferBuilder.ts @@ -2,8 +2,9 @@ import { createERC721TransferTerms } from '@metamask/delegation-core'; import { type Address, isAddress } from 'viem'; import type { SmartAccountsEnvironment, Caveat } from '../types'; +import { CaveatType } from './caveatType'; -export const erc721Transfer = 'erc721Transfer'; +export const erc721Transfer = CaveatType.Erc721Transfer; export type Erc721TransferBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/exactCalldataBatchBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/exactCalldataBatchBuilder.ts index 0b294f3..7055085 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/exactCalldataBatchBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/exactCalldataBatchBuilder.ts @@ -3,8 +3,9 @@ import { isAddress } from 'viem'; import type { ExecutionStruct } from '../executions'; import type { Caveat, SmartAccountsEnvironment } from '../types'; +import { CaveatType } from './caveatType'; -export const exactCalldataBatch = 'exactCalldataBatch'; +export const exactCalldataBatch = CaveatType.ExactCalldataBatch; export type ExactCalldataBatchBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/exactCalldataBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/exactCalldataBuilder.ts index 85140d3..ad0b523 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/exactCalldataBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/exactCalldataBuilder.ts @@ -2,8 +2,9 @@ import { createExactCalldataTerms } from '@metamask/delegation-core'; import type { Hex } from 'viem'; import type { Caveat, SmartAccountsEnvironment } from '../types'; +import { CaveatType } from './caveatType'; -export const exactCalldata = 'exactCalldata'; +export const exactCalldata = CaveatType.ExactCalldata; export type ExactCalldataBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/exactExecutionBatchBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/exactExecutionBatchBuilder.ts index cf15aea..efdf3c6 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/exactExecutionBatchBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/exactExecutionBatchBuilder.ts @@ -3,8 +3,9 @@ import { isAddress } from 'viem'; import type { ExecutionStruct } from '../executions'; import type { Caveat, SmartAccountsEnvironment } from '../types'; +import { CaveatType } from './caveatType'; -export const exactExecutionBatch = 'exactExecutionBatch'; +export const exactExecutionBatch = CaveatType.ExactExecutionBatch; export type ExactExecutionBatchBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/exactExecutionBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/exactExecutionBuilder.ts index 4a87966..3ec81c9 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/exactExecutionBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/exactExecutionBuilder.ts @@ -3,8 +3,9 @@ import { isAddress } from 'viem'; import type { ExecutionStruct } from '../executions'; import type { Caveat, SmartAccountsEnvironment } from '../types'; +import { CaveatType } from './caveatType'; -export const exactExecution = 'exactExecution'; +export const exactExecution = CaveatType.ExactExecution; export type ExactExecutionBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/idBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/idBuilder.ts index c1b769a..f527ca3 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/idBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/idBuilder.ts @@ -2,6 +2,7 @@ import { createIdTerms } from '@metamask/delegation-core'; import { maxUint256 } from 'viem'; import type { SmartAccountsEnvironment, Caveat } from '../types'; +import { CaveatType } from './caveatType'; export type IdBuilderConfig = { /** @@ -10,7 +11,7 @@ export type IdBuilderConfig = { id: bigint | number; }; -export const id = 'id'; +export const id = CaveatType.Id; /** * Builds a caveat struct for the IdEnforcer. diff --git a/packages/smart-accounts-kit/src/caveatBuilder/index.ts b/packages/smart-accounts-kit/src/caveatBuilder/index.ts index 62a11b9..3350d7d 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/index.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/index.ts @@ -1,7 +1,7 @@ // Core Caveat Builder -export { createCaveatBuilder } from './coreCaveatBuilder'; +export { createCaveatBuilder, CaveatType } from './coreCaveatBuilder'; -export type { CoreCaveatBuilder } from './coreCaveatBuilder'; +export type { CoreCaveatBuilder, CaveatTypeParam } from './coreCaveatBuilder'; // Caveat Builder implementation export type { CaveatBuilderConfig } from './caveatBuilder'; diff --git a/packages/smart-accounts-kit/src/caveatBuilder/limitedCallsBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/limitedCallsBuilder.ts index eb71fa5..db76d36 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/limitedCallsBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/limitedCallsBuilder.ts @@ -1,8 +1,9 @@ import { createLimitedCallsTerms } from '@metamask/delegation-core'; import type { SmartAccountsEnvironment, Caveat } from '../types'; +import { CaveatType } from './caveatType'; -export const limitedCalls = 'limitedCalls'; +export const limitedCalls = CaveatType.LimitedCalls; export type LimitedCallsBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/multiTokenPeriodBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/multiTokenPeriodBuilder.ts index 32b9044..79457ee 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/multiTokenPeriodBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/multiTokenPeriodBuilder.ts @@ -3,6 +3,7 @@ import type { Hex } from 'viem'; import { isAddress } from 'viem'; import type { SmartAccountsEnvironment, Caveat } from '../types'; +import { CaveatType } from './caveatType'; export type TokenPeriodConfig = { /** @@ -27,7 +28,7 @@ export type MultiTokenPeriodBuilderConfig = { tokenConfigs: TokenPeriodConfig[]; }; -export const multiTokenPeriod = 'multiTokenPeriod'; +export const multiTokenPeriod = CaveatType.MultiTokenPeriod; /** * Creates a caveat for the MultiTokenPeriodEnforcer. diff --git a/packages/smart-accounts-kit/src/caveatBuilder/nativeBalanceChangeBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/nativeBalanceChangeBuilder.ts index 66fc889..4a1c564 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/nativeBalanceChangeBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/nativeBalanceChangeBuilder.ts @@ -2,9 +2,10 @@ import { createNativeBalanceChangeTerms } from '@metamask/delegation-core'; import { type Address, isAddress } from 'viem'; import type { SmartAccountsEnvironment, Caveat } from '../types'; +import { CaveatType } from './caveatType'; import { BalanceChangeType } from './types'; -export const nativeBalanceChange = 'nativeBalanceChange'; +export const nativeBalanceChange = CaveatType.NativeBalanceChange; export type NativeBalanceChangeBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/nativeTokenPaymentBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/nativeTokenPaymentBuilder.ts index 53e81b5..ef53efe 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/nativeTokenPaymentBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/nativeTokenPaymentBuilder.ts @@ -2,8 +2,9 @@ import { createNativeTokenPaymentTerms } from '@metamask/delegation-core'; import { type Address, isAddress } from 'viem'; import type { Caveat, SmartAccountsEnvironment } from '../types'; +import { CaveatType } from './caveatType'; -export const nativeTokenPayment = 'nativeTokenPayment'; +export const nativeTokenPayment = CaveatType.NativeTokenPayment; export type NativeTokenPaymentBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/nativeTokenPeriodTransferBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/nativeTokenPeriodTransferBuilder.ts index 5b202a0..4e97694 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/nativeTokenPeriodTransferBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/nativeTokenPeriodTransferBuilder.ts @@ -1,8 +1,9 @@ import { createNativeTokenPeriodTransferTerms } from '@metamask/delegation-core'; import type { Caveat, SmartAccountsEnvironment } from '../types'; +import { CaveatType } from './caveatType'; -export const nativeTokenPeriodTransfer = 'nativeTokenPeriodTransfer'; +export const nativeTokenPeriodTransfer = CaveatType.NativeTokenPeriodTransfer; export type NativeTokenPeriodTransferBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/nativeTokenStreamingBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/nativeTokenStreamingBuilder.ts index 0530512..1943661 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/nativeTokenStreamingBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/nativeTokenStreamingBuilder.ts @@ -1,8 +1,9 @@ import { createNativeTokenStreamingTerms } from '@metamask/delegation-core'; import type { SmartAccountsEnvironment, Caveat } from '../types'; +import { CaveatType } from './caveatType'; -export const nativeTokenStreaming = 'nativeTokenStreaming'; +export const nativeTokenStreaming = CaveatType.NativeTokenStreaming; export type NativeTokenStreamingBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/nativeTokenTransferAmountBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/nativeTokenTransferAmountBuilder.ts index 373e022..4e2c863 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/nativeTokenTransferAmountBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/nativeTokenTransferAmountBuilder.ts @@ -1,8 +1,9 @@ import { createNativeTokenTransferAmountTerms } from '@metamask/delegation-core'; import type { Caveat, SmartAccountsEnvironment } from '../types'; +import { CaveatType } from './caveatType'; -export const nativeTokenTransferAmount = 'nativeTokenTransferAmount'; +export const nativeTokenTransferAmount = CaveatType.NativeTokenTransferAmount; export type NativeTokenTransferAmountBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/nonceBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/nonceBuilder.ts index 1d7da0d..af89829 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/nonceBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/nonceBuilder.ts @@ -2,8 +2,9 @@ import { createNonceTerms } from '@metamask/delegation-core'; import { type Hex } from 'viem'; import type { SmartAccountsEnvironment, Caveat } from '../types'; +import { CaveatType } from './caveatType'; -export const nonce = 'nonce'; +export const nonce = CaveatType.Nonce; export type NonceBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/ownershipTransferBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/ownershipTransferBuilder.ts index 7a5de77..a7f1d95 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/ownershipTransferBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/ownershipTransferBuilder.ts @@ -2,8 +2,9 @@ import { createOwnershipTransferTerms } from '@metamask/delegation-core'; import { type Address, isAddress } from 'viem'; import type { SmartAccountsEnvironment, Caveat } from '../types'; +import { CaveatType } from './caveatType'; -export const ownershipTransfer = 'ownershipTransfer'; +export const ownershipTransfer = CaveatType.OwnershipTransfer; export type OwnershipTransferBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/redeemerBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/redeemerBuilder.ts index 2399554..dc5b552 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/redeemerBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/redeemerBuilder.ts @@ -2,8 +2,9 @@ import { createRedeemerTerms } from '@metamask/delegation-core'; import { type Address, isAddress } from 'viem'; import type { Caveat, SmartAccountsEnvironment } from '../types'; +import { CaveatType } from './caveatType'; -export const redeemer = 'redeemer'; +export const redeemer = CaveatType.Redeemer; export type RedeemerBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/resolveCaveats.ts b/packages/smart-accounts-kit/src/caveatBuilder/resolveCaveats.ts index 0bbeade..6fdc339 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/resolveCaveats.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/resolveCaveats.ts @@ -1,4 +1,5 @@ import type { CaveatBuilder } from './caveatBuilder'; +import type { CaveatTypeParam } from './caveatType'; import type { CoreCaveatConfiguration } from './coreCaveatBuilder'; import { createCaveatBuilderFromScope, type ScopeConfig } from './scope'; import type { Caveat, SmartAccountsEnvironment } from '../types'; @@ -31,16 +32,20 @@ export const resolveCaveats = ({ scopeCaveatBuilder.addCaveat(caveat); }); } else if (Array.isArray(caveats)) { - caveats.forEach((caveat) => { + caveats.forEach((caveat, index) => { try { if ('type' in caveat) { const { type, ...config } = caveat; - scopeCaveatBuilder.addCaveat(type, config); + // Safe type cast: CaveatTypeParam accepts both enum and string forms + // addCaveat validates at runtime and throws if enforcer doesn't exist + scopeCaveatBuilder.addCaveat(type as CaveatTypeParam, config); } else { scopeCaveatBuilder.addCaveat(caveat); } } catch (error) { - throw new Error(`Invalid caveat: ${(error as Error).message}`); + throw new Error( + `Error processing caveats[${index}]: ${(error as Error).message}`, + ); } }); } diff --git a/packages/smart-accounts-kit/src/caveatBuilder/scope/erc20PeriodicScope.ts b/packages/smart-accounts-kit/src/caveatBuilder/scope/erc20PeriodicScope.ts index 9f1a1fd..ab8ee51 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/scope/erc20PeriodicScope.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/scope/erc20PeriodicScope.ts @@ -1,6 +1,6 @@ import type { ScopeType } from '../../constants'; import type { SmartAccountsEnvironment } from '../../types'; -import { createCaveatBuilder } from '../coreCaveatBuilder'; +import { CaveatType, createCaveatBuilder } from '../coreCaveatBuilder'; import type { CoreCaveatBuilder } from '../coreCaveatBuilder'; import type { Erc20PeriodTransferBuilderConfig } from '../erc20PeriodTransferBuilder'; @@ -22,10 +22,10 @@ export function createErc20PeriodicCaveatBuilder( config: Erc20PeriodicScopeConfig, ): CoreCaveatBuilder { return createCaveatBuilder(environment) - .addCaveat('valueLte', { + .addCaveat(CaveatType.ValueLte, { maxValue: 0n, }) - .addCaveat('erc20PeriodTransfer', { + .addCaveat(CaveatType.Erc20PeriodTransfer, { tokenAddress: config.tokenAddress, periodAmount: config.periodAmount, periodDuration: config.periodDuration, diff --git a/packages/smart-accounts-kit/src/caveatBuilder/scope/erc20StreamingScope.ts b/packages/smart-accounts-kit/src/caveatBuilder/scope/erc20StreamingScope.ts index b333185..3597744 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/scope/erc20StreamingScope.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/scope/erc20StreamingScope.ts @@ -1,6 +1,6 @@ import type { ScopeType } from '../../constants'; import type { SmartAccountsEnvironment } from '../../types'; -import { createCaveatBuilder } from '../coreCaveatBuilder'; +import { CaveatType, createCaveatBuilder } from '../coreCaveatBuilder'; import type { CoreCaveatBuilder } from '../coreCaveatBuilder'; import type { Erc20StreamingBuilderConfig } from '../erc20StreamingBuilder'; @@ -22,10 +22,10 @@ export function createErc20StreamingCaveatBuilder( config: Erc20StreamingScopeConfig, ): CoreCaveatBuilder { return createCaveatBuilder(environment) - .addCaveat('valueLte', { + .addCaveat(CaveatType.ValueLte, { maxValue: 0n, }) - .addCaveat('erc20Streaming', { + .addCaveat(CaveatType.Erc20Streaming, { tokenAddress: config.tokenAddress, initialAmount: config.initialAmount, maxAmount: config.maxAmount, diff --git a/packages/smart-accounts-kit/src/caveatBuilder/scope/erc20TransferScope.ts b/packages/smart-accounts-kit/src/caveatBuilder/scope/erc20TransferScope.ts index fbb26b1..23b2477 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/scope/erc20TransferScope.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/scope/erc20TransferScope.ts @@ -1,6 +1,6 @@ import type { ScopeType } from '../../constants'; import type { SmartAccountsEnvironment } from '../../types'; -import { createCaveatBuilder } from '../coreCaveatBuilder'; +import { CaveatType, createCaveatBuilder } from '../coreCaveatBuilder'; import type { CoreCaveatBuilder } from '../coreCaveatBuilder'; import type { Erc20TransferAmountBuilderConfig } from '../erc20TransferAmountBuilder'; @@ -22,10 +22,10 @@ export function createErc20TransferCaveatBuilder( config: Erc20TransferScopeConfig, ): CoreCaveatBuilder { return createCaveatBuilder(environment) - .addCaveat('valueLte', { + .addCaveat(CaveatType.ValueLte, { maxValue: 0n, }) - .addCaveat('erc20TransferAmount', { + .addCaveat(CaveatType.Erc20TransferAmount, { tokenAddress: config.tokenAddress, maxAmount: config.maxAmount, }); diff --git a/packages/smart-accounts-kit/src/caveatBuilder/scope/erc721Scope.ts b/packages/smart-accounts-kit/src/caveatBuilder/scope/erc721Scope.ts index 19e1b9f..a7687c0 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/scope/erc721Scope.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/scope/erc721Scope.ts @@ -1,7 +1,7 @@ import type { ScopeType } from '../../constants'; import type { SmartAccountsEnvironment } from '../../types'; import { hasProperties } from '../../utils'; -import { createCaveatBuilder } from '../coreCaveatBuilder'; +import { CaveatType, createCaveatBuilder } from '../coreCaveatBuilder'; import type { CoreCaveatBuilder } from '../coreCaveatBuilder'; import type { Erc721TransferBuilderConfig } from '../erc721TransferBuilder'; @@ -38,7 +38,7 @@ export function createErc721CaveatBuilder( } const caveatBuilder = createCaveatBuilder(environment).addCaveat( - 'erc721Transfer', + CaveatType.Erc721Transfer, config, ); diff --git a/packages/smart-accounts-kit/src/caveatBuilder/scope/functionCallScope.ts b/packages/smart-accounts-kit/src/caveatBuilder/scope/functionCallScope.ts index 6bb0c4c..f9cedeb 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/scope/functionCallScope.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/scope/functionCallScope.ts @@ -4,7 +4,7 @@ import { hasProperties } from '../../utils'; import type { AllowedCalldataBuilderConfig } from '../allowedCalldataBuilder'; import type { AllowedMethodsBuilderConfig } from '../allowedMethodsBuilder'; import type { AllowedTargetsBuilderConfig } from '../allowedTargetsBuilder'; -import { createCaveatBuilder } from '../coreCaveatBuilder'; +import { CaveatType, createCaveatBuilder } from '../coreCaveatBuilder'; import type { CoreCaveatBuilder } from '../coreCaveatBuilder'; import type { ExactCalldataBuilderConfig } from '../exactCalldataBuilder'; import type { ValueLteBuilderConfig } from '../valueLteBuilder'; @@ -54,16 +54,16 @@ export function createFunctionCallCaveatBuilder( const valueLteConfig = config.valueLte ?? { maxValue: 0n }; const caveatBuilder = createCaveatBuilder(environment) - .addCaveat('allowedTargets', { targets }) - .addCaveat('allowedMethods', { selectors }) - .addCaveat('valueLte', valueLteConfig); + .addCaveat(CaveatType.AllowedTargets, { targets }) + .addCaveat(CaveatType.AllowedMethods, { selectors }) + .addCaveat(CaveatType.ValueLte, valueLteConfig); if (allowedCalldata && allowedCalldata.length > 0) { allowedCalldata.forEach((calldataConfig) => { - caveatBuilder.addCaveat('allowedCalldata', calldataConfig); + caveatBuilder.addCaveat(CaveatType.AllowedCalldata, calldataConfig); }); } else if (exactCalldata) { - caveatBuilder.addCaveat('exactCalldata', exactCalldata); + caveatBuilder.addCaveat(CaveatType.ExactCalldata, exactCalldata); } return caveatBuilder; diff --git a/packages/smart-accounts-kit/src/caveatBuilder/scope/index.ts b/packages/smart-accounts-kit/src/caveatBuilder/scope/index.ts index a53debb..4361987 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/scope/index.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/scope/index.ts @@ -42,9 +42,9 @@ import type { CoreCaveatBuilder } from '../coreCaveatBuilder'; // or the enum's string value this generic accepts a union of scope configs, and // converts them to an identical union except the `type` parameter is converted // to a union of `ScopeType.XXXX | `${ScopeType.XXXX}`. -export type ConvertScopeConfigsToInputs = - T extends { type: ScopeType } - ? Omit & { type: T['type'] | `${T['type']}` } +export type ConvertScopeConfigsToInputs = + TConfig extends { type: ScopeType } + ? Omit & { type: TConfig['type'] | `${TConfig['type']}` } : never; type ScopeConfigBase = diff --git a/packages/smart-accounts-kit/src/caveatBuilder/scope/nativeTokenPeriodicScope.ts b/packages/smart-accounts-kit/src/caveatBuilder/scope/nativeTokenPeriodicScope.ts index d72daaa..0325986 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/scope/nativeTokenPeriodicScope.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/scope/nativeTokenPeriodicScope.ts @@ -1,7 +1,7 @@ import type { ScopeType } from '../../constants'; import type { SmartAccountsEnvironment } from '../../types'; import type { AllowedCalldataBuilderConfig } from '../allowedCalldataBuilder'; -import { createCaveatBuilder } from '../coreCaveatBuilder'; +import { CaveatType, createCaveatBuilder } from '../coreCaveatBuilder'; import type { CoreCaveatBuilder } from '../coreCaveatBuilder'; import type { ExactCalldataBuilderConfig } from '../exactCalldataBuilder'; import type { NativeTokenPeriodTransferBuilderConfig } from '../nativeTokenPeriodTransferBuilder'; @@ -45,19 +45,19 @@ export function createNativeTokenPeriodicCaveatBuilder( // Add calldata restrictions if (allowedCalldata && allowedCalldata.length > 0) { allowedCalldata.forEach((calldataConfig) => { - caveatBuilder.addCaveat('allowedCalldata', calldataConfig); + caveatBuilder.addCaveat(CaveatType.AllowedCalldata, calldataConfig); }); } else if (exactCalldata) { - caveatBuilder.addCaveat('exactCalldata', exactCalldata); + caveatBuilder.addCaveat(CaveatType.ExactCalldata, exactCalldata); } else { // Default behavior: only allow empty calldata - caveatBuilder.addCaveat('exactCalldata', { + caveatBuilder.addCaveat(CaveatType.ExactCalldata, { calldata: '0x', }); } // Add native token period transfer restriction - caveatBuilder.addCaveat('nativeTokenPeriodTransfer', { + caveatBuilder.addCaveat(CaveatType.NativeTokenPeriodTransfer, { periodAmount, periodDuration, startDate, diff --git a/packages/smart-accounts-kit/src/caveatBuilder/scope/nativeTokenStreamingScope.ts b/packages/smart-accounts-kit/src/caveatBuilder/scope/nativeTokenStreamingScope.ts index 3139bab..7445318 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/scope/nativeTokenStreamingScope.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/scope/nativeTokenStreamingScope.ts @@ -1,7 +1,7 @@ import type { ScopeType } from '../../constants'; import type { SmartAccountsEnvironment } from '../../types'; import type { AllowedCalldataBuilderConfig } from '../allowedCalldataBuilder'; -import { createCaveatBuilder } from '../coreCaveatBuilder'; +import { CaveatType, createCaveatBuilder } from '../coreCaveatBuilder'; import type { CoreCaveatBuilder } from '../coreCaveatBuilder'; import type { ExactCalldataBuilderConfig } from '../exactCalldataBuilder'; import type { NativeTokenStreamingBuilderConfig } from '../nativeTokenStreamingBuilder'; @@ -46,19 +46,19 @@ export function createNativeTokenStreamingCaveatBuilder( // Add calldata restrictions if (allowedCalldata && allowedCalldata.length > 0) { allowedCalldata.forEach((calldataConfig) => { - caveatBuilder.addCaveat('allowedCalldata', calldataConfig); + caveatBuilder.addCaveat(CaveatType.AllowedCalldata, calldataConfig); }); } else if (exactCalldata) { - caveatBuilder.addCaveat('exactCalldata', exactCalldata); + caveatBuilder.addCaveat(CaveatType.ExactCalldata, exactCalldata); } else { // Default behavior: only allow empty calldata - caveatBuilder.addCaveat('exactCalldata', { + caveatBuilder.addCaveat(CaveatType.ExactCalldata, { calldata: '0x', }); } // Add native token streaming restriction - caveatBuilder.addCaveat('nativeTokenStreaming', { + caveatBuilder.addCaveat(CaveatType.NativeTokenStreaming, { initialAmount, maxAmount, amountPerSecond, diff --git a/packages/smart-accounts-kit/src/caveatBuilder/scope/nativeTokenTransferScope.ts b/packages/smart-accounts-kit/src/caveatBuilder/scope/nativeTokenTransferScope.ts index 8261852..d2fb82d 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/scope/nativeTokenTransferScope.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/scope/nativeTokenTransferScope.ts @@ -1,7 +1,7 @@ import type { ScopeType } from '../../constants'; import type { SmartAccountsEnvironment } from '../../types'; import type { AllowedCalldataBuilderConfig } from '../allowedCalldataBuilder'; -import { createCaveatBuilder } from '../coreCaveatBuilder'; +import { CaveatType, createCaveatBuilder } from '../coreCaveatBuilder'; import type { CoreCaveatBuilder } from '../coreCaveatBuilder'; import type { ExactCalldataBuilderConfig } from '../exactCalldataBuilder'; import type { NativeTokenTransferAmountBuilderConfig } from '../nativeTokenTransferAmountBuilder'; @@ -39,19 +39,19 @@ export function createNativeTokenTransferCaveatBuilder( // Add calldata restrictions if (allowedCalldata && allowedCalldata.length > 0) { allowedCalldata.forEach((calldataConfig) => { - caveatBuilder.addCaveat('allowedCalldata', calldataConfig); + caveatBuilder.addCaveat(CaveatType.AllowedCalldata, calldataConfig); }); } else if (exactCalldata) { - caveatBuilder.addCaveat('exactCalldata', exactCalldata); + caveatBuilder.addCaveat(CaveatType.ExactCalldata, exactCalldata); } else { // Default behavior: only allow empty calldata - caveatBuilder.addCaveat('exactCalldata', { + caveatBuilder.addCaveat(CaveatType.ExactCalldata, { calldata: '0x', }); } // Add native token transfer amount restriction - caveatBuilder.addCaveat('nativeTokenTransferAmount', { + caveatBuilder.addCaveat(CaveatType.NativeTokenTransferAmount, { maxAmount, }); diff --git a/packages/smart-accounts-kit/src/caveatBuilder/scope/ownershipScope.ts b/packages/smart-accounts-kit/src/caveatBuilder/scope/ownershipScope.ts index 2033d70..5b7450e 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/scope/ownershipScope.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/scope/ownershipScope.ts @@ -1,7 +1,7 @@ import type { ScopeType } from '../../constants'; import type { SmartAccountsEnvironment } from '../../types'; import { hasProperties } from '../../utils'; -import { createCaveatBuilder } from '../coreCaveatBuilder'; +import { CaveatType, createCaveatBuilder } from '../coreCaveatBuilder'; import type { CoreCaveatBuilder } from '../coreCaveatBuilder'; import type { OwnershipTransferBuilderConfig } from '../ownershipTransferBuilder'; @@ -38,7 +38,7 @@ export function createOwnershipCaveatBuilder( } const caveatBuilder = createCaveatBuilder(environment).addCaveat( - 'ownershipTransfer', + CaveatType.OwnershipTransfer, config, ); diff --git a/packages/smart-accounts-kit/src/caveatBuilder/specificActionERC20TransferBatchBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/specificActionERC20TransferBatchBuilder.ts index e32f7bc..a0f51d7 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/specificActionERC20TransferBatchBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/specificActionERC20TransferBatchBuilder.ts @@ -2,9 +2,10 @@ import { createSpecificActionERC20TransferBatchTerms } from '@metamask/delegatio import { isAddress, type Address, type Hex } from 'viem'; import type { Caveat, SmartAccountsEnvironment } from '../types'; +import { CaveatType } from './caveatType'; export const specificActionERC20TransferBatch = - 'specificActionERC20TransferBatch'; + CaveatType.SpecificActionERC20TransferBatch; export type SpecificActionErc20TransferBatchBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/timestampBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/timestampBuilder.ts index 5e44ea4..6642acc 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/timestampBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/timestampBuilder.ts @@ -1,8 +1,9 @@ import { createTimestampTerms } from '@metamask/delegation-core'; import type { Caveat, SmartAccountsEnvironment } from '../types'; +import { CaveatType } from './caveatType'; -export const timestamp = 'timestamp'; +export const timestamp = CaveatType.Timestamp; export type TimestampBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/caveatBuilder/valueLteBuilder.ts b/packages/smart-accounts-kit/src/caveatBuilder/valueLteBuilder.ts index 2031c31..7cf095d 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/valueLteBuilder.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/valueLteBuilder.ts @@ -1,8 +1,9 @@ import { createValueLteTerms } from '@metamask/delegation-core'; import type { Caveat, SmartAccountsEnvironment } from '../types'; +import { CaveatType } from './caveatType'; -export const valueLte = 'valueLte'; +export const valueLte = CaveatType.ValueLte; export type ValueLteBuilderConfig = { /** diff --git a/packages/smart-accounts-kit/src/index.ts b/packages/smart-accounts-kit/src/index.ts index 18aeab8..f845464 100644 --- a/packages/smart-accounts-kit/src/index.ts +++ b/packages/smart-accounts-kit/src/index.ts @@ -47,6 +47,8 @@ export type { Caveats } from './caveatBuilder'; export { createCaveat } from './caveats'; +export { CaveatType } from './caveatBuilder'; + export { BalanceChangeType } from './caveatBuilder/types'; export { aggregateSignature } from './signatures'; diff --git a/packages/smart-accounts-kit/src/utils/index.ts b/packages/smart-accounts-kit/src/utils/index.ts index 6ed7c10..2fcf2d9 100644 --- a/packages/smart-accounts-kit/src/utils/index.ts +++ b/packages/smart-accounts-kit/src/utils/index.ts @@ -42,4 +42,8 @@ export { export type { CoreCaveatBuilder, CaveatBuilderConfig } from '../caveatBuilder'; -export { createCaveatBuilder, CaveatBuilder } from '../caveatBuilder'; +export { + createCaveatBuilder, + CaveatBuilder, + CaveatType, +} from '../caveatBuilder'; diff --git a/packages/smart-accounts-kit/test/caveatBuilder/caveatTypeEnum.test.ts b/packages/smart-accounts-kit/test/caveatBuilder/caveatTypeEnum.test.ts new file mode 100644 index 0000000..3ab0c17 --- /dev/null +++ b/packages/smart-accounts-kit/test/caveatBuilder/caveatTypeEnum.test.ts @@ -0,0 +1,456 @@ +import { concat } from 'viem'; +import { describe, it, expect } from 'vitest'; + +import { createCaveatBuilder, CaveatType } from '../../src/caveatBuilder'; +import { resolveCaveats } from '../../src/caveatBuilder/resolveCaveats'; +import { ScopeType } from '../../src/constants'; +import { createDelegation } from '../../src/delegation'; +import type { SmartAccountsEnvironment } from '../../src/types'; +import { randomAddress, randomBytes } from '../utils'; + +/** + * This test file demonstrates the CaveatType enum usage patterns. + * These tests verify that both enum references and string literals work interchangeably. + */ +describe('CaveatType enum usage patterns', () => { + const environment: SmartAccountsEnvironment = { + caveatEnforcers: { + AllowedMethodsEnforcer: randomBytes(20), + AllowedTargetsEnforcer: randomBytes(20), + ValueLteEnforcer: randomBytes(20), + ERC20TransferAmountEnforcer: randomBytes(20), + BlockNumberEnforcer: randomBytes(20), + LimitedCallsEnforcer: randomBytes(20), + IdEnforcer: randomBytes(20), + NonceEnforcer: randomBytes(20), + TimestampEnforcer: randomBytes(20), + NativeTokenTransferAmountEnforcer: randomBytes(20), + NativeBalanceChangeEnforcer: randomBytes(20), + NativeTokenPaymentEnforcer: randomBytes(20), + ERC20BalanceChangeEnforcer: randomBytes(20), + ERC721TransferEnforcer: randomBytes(20), + DeployedEnforcer: randomBytes(20), + AllowedCalldataEnforcer: randomBytes(20), + RedeemerEnforcer: randomBytes(20), + ArgsEqualityCheckEnforcer: randomBytes(20), + ERC20StreamingEnforcer: randomBytes(20), + NativeTokenStreamingEnforcer: randomBytes(20), + ERC721BalanceChangeEnforcer: randomBytes(20), + ERC1155BalanceChangeEnforcer: randomBytes(20), + SpecificActionERC20TransferBatchEnforcer: randomBytes(20), + ERC20PeriodTransferEnforcer: randomBytes(20), + NativeTokenPeriodTransferEnforcer: randomBytes(20), + ExactCalldataBatchEnforcer: randomBytes(20), + ExactCalldataEnforcer: randomBytes(20), + ExactExecutionEnforcer: randomBytes(20), + ExactExecutionBatchEnforcer: randomBytes(20), + MultiTokenPeriodEnforcer: randomBytes(20), + OwnershipTransferEnforcer: randomBytes(20), + }, + } as unknown as SmartAccountsEnvironment; + + describe('using CaveatType enum in CaveatBuilder.addCaveat()', () => { + it('should add caveat using CaveatType.AllowedMethods enum', () => { + const builder = createCaveatBuilder(environment); + const selectors = [randomBytes(4), randomBytes(4)]; + + // Using enum reference + const caveats = builder + .addCaveat(CaveatType.AllowedMethods, { selectors }) + .build(); + + expect(caveats).to.have.lengthOf(1); + expect(caveats[0]?.enforcer).to.equal( + environment.caveatEnforcers.AllowedMethodsEnforcer, + ); + expect(caveats[0]?.terms).to.equal(concat(selectors)); + }); + + it('should add caveat using CaveatType.AllowedTargets enum', () => { + const builder = createCaveatBuilder(environment); + const targets = [randomAddress(), randomAddress()]; + + // Using enum reference + const caveats = builder + .addCaveat(CaveatType.AllowedTargets, { targets }) + .build(); + + expect(caveats).to.have.lengthOf(1); + expect(caveats[0]?.enforcer).to.equal( + environment.caveatEnforcers.AllowedTargetsEnforcer, + ); + }); + + it('should add caveat using CaveatType.ValueLte enum', () => { + const builder = createCaveatBuilder(environment); + const maxValue = 1000n; + + // Using enum reference + const caveats = builder + .addCaveat(CaveatType.ValueLte, { maxValue }) + .build(); + + expect(caveats).to.have.lengthOf(1); + expect(caveats[0]?.enforcer).to.equal( + environment.caveatEnforcers.ValueLteEnforcer, + ); + }); + + it('should add caveat using CaveatType.LimitedCalls enum', () => { + const builder = createCaveatBuilder(environment); + const limit = 10; + + // Using enum reference + const caveats = builder + .addCaveat(CaveatType.LimitedCalls, { limit }) + .build(); + + expect(caveats).to.have.lengthOf(1); + expect(caveats[0]?.enforcer).to.equal( + environment.caveatEnforcers.LimitedCallsEnforcer, + ); + }); + + it('should add caveat using CaveatType.Erc20TransferAmount enum', () => { + const builder = createCaveatBuilder(environment); + const tokenAddress = randomAddress(); + const maxAmount = 1000n; + + // Using enum reference + const caveats = builder + .addCaveat(CaveatType.Erc20TransferAmount, { + tokenAddress, + maxAmount, + }) + .build(); + + expect(caveats).to.have.lengthOf(1); + expect(caveats[0]?.enforcer).to.equal( + environment.caveatEnforcers.ERC20TransferAmountEnforcer, + ); + }); + + it('should work identically with string literal (existing pattern)', () => { + const builderWithEnum = createCaveatBuilder(environment); + const builderWithString = createCaveatBuilder(environment); + const selectors = [randomBytes(4)]; + + const enumResult = builderWithEnum + .addCaveat(CaveatType.AllowedMethods, { selectors }) + .build(); + + const stringResult = builderWithString + .addCaveat('allowedMethods', { selectors }) + .build(); + + // Both should produce the same result + expect(enumResult).to.deep.equal(stringResult); + }); + }); + + describe('using CaveatType enum in createDelegation caveats array', () => { + const mockDelegator = randomAddress(); + const mockDelegate = randomAddress(); + + const smartAccountEnvironment: SmartAccountsEnvironment = { + caveatEnforcers: { + ValueLteEnforcer: randomAddress(), + ERC20TransferAmountEnforcer: randomAddress(), + AllowedMethodsEnforcer: randomAddress(), + BlockNumberEnforcer: randomAddress(), + AllowedTargetsEnforcer: randomAddress(), + LimitedCallsEnforcer: randomAddress(), + }, + } as unknown as SmartAccountsEnvironment; + + it('should create delegation with CaveatType enum in caveats array', () => { + const scope = { + type: ScopeType.Erc20TransferAmount as const, + tokenAddress: randomAddress(), + maxAmount: 100n, + }; + + const result = createDelegation({ + environment: smartAccountEnvironment, + scope, + to: mockDelegate, + from: mockDelegator, + caveats: [ + { + type: CaveatType.LimitedCalls, + limit: 5, + }, + ], + }); + + // Should have scope caveats (valueLte + erc20TransferAmount) + 1 additional caveat + expect(result.caveats.length).to.be.greaterThan(2); + }); + + it('should create delegation with string literal in caveats array', () => { + const scope = { + type: 'erc20TransferAmount' as const, + tokenAddress: randomAddress(), + maxAmount: 100n, + }; + + const result = createDelegation({ + environment: smartAccountEnvironment, + scope, + to: mockDelegate, + from: mockDelegator, + caveats: [ + { + type: 'limitedCalls', + limit: 5, + }, + ], + }); + + expect(result.caveats.length).to.be.greaterThan(2); + }); + + it('should mix CaveatType enum and string literals in caveats array', () => { + const scope = { + type: ScopeType.Erc20TransferAmount as const, + tokenAddress: randomAddress(), + maxAmount: 100n, + }; + + const result = createDelegation({ + environment: smartAccountEnvironment, + scope, + to: mockDelegate, + from: mockDelegator, + caveats: [ + { type: CaveatType.LimitedCalls, limit: 5 }, + { type: 'allowedMethods', selectors: ['0x12345678'] }, + ], + }); + + // Should have scope caveats + 2 additional caveats + expect(result.caveats.length).to.be.greaterThan(3); + }); + + it('should create delegation with CaveatType.ValueLte enum', () => { + const scope = { + type: ScopeType.FunctionCall as const, + targets: [randomAddress()], + selectors: ['0x12345678'], + }; + + const result = createDelegation({ + environment: smartAccountEnvironment, + scope, + to: mockDelegate, + from: mockDelegator, + caveats: [ + { + type: CaveatType.ValueLte, + maxValue: 1000n, + }, + ], + }); + + expect(result.caveats.length).to.be.greaterThan(0); + }); + }); + + describe('using CaveatType enum in resolveCaveats', () => { + const envWithCaveats: SmartAccountsEnvironment = { + caveatEnforcers: { + ValueLteEnforcer: randomAddress(), + ERC20TransferAmountEnforcer: randomAddress(), + AllowedMethodsEnforcer: randomAddress(), + BlockNumberEnforcer: randomAddress(), + AllowedTargetsEnforcer: randomAddress(), + }, + } as unknown as SmartAccountsEnvironment; + + it('should resolve caveats with CaveatType enum', () => { + const scope = { + type: ScopeType.Erc20TransferAmount as const, + tokenAddress: randomAddress(), + maxAmount: 100n, + }; + + const result = resolveCaveats({ + environment: envWithCaveats, + scope, + caveats: [ + { + type: CaveatType.AllowedMethods, + selectors: ['0xaabbccdd'], + }, + ], + }); + + expect(result).to.be.an('array'); + expect(result.length).to.be.greaterThan(2); // scope caveats + additional + }); + + it('should resolve caveats with string literal', () => { + const scope = { + type: 'erc20TransferAmount' as const, + tokenAddress: randomAddress(), + maxAmount: 100n, + }; + + const result = resolveCaveats({ + environment: envWithCaveats, + scope, + caveats: [ + { + type: 'allowedMethods', + selectors: ['0xaabbccdd'], + }, + ], + }); + + expect(result).to.be.an('array'); + expect(result.length).to.be.greaterThan(2); + }); + + it('should resolve caveats with mixed enum and string', () => { + const scope = { + type: ScopeType.Erc20TransferAmount as const, + tokenAddress: randomAddress(), + maxAmount: 100n, + }; + + const result = resolveCaveats({ + environment: envWithCaveats, + scope, + caveats: [ + { type: CaveatType.AllowedMethods, selectors: ['0xaabbccdd'] }, + { type: 'allowedTargets', targets: [randomAddress()] }, + { + type: CaveatType.BlockNumber, + afterThreshold: 0n, + beforeThreshold: 1000n, + }, + ], + }); + + expect(result).to.be.an('array'); + expect(result.length).to.be.greaterThan(4); + }); + }); + + describe('using ScopeType enum in scope config', () => { + it('should create delegation with ScopeType enum reference', () => { + const smartAccountEnvironment: SmartAccountsEnvironment = { + caveatEnforcers: { + ValueLteEnforcer: randomAddress(), + ERC20TransferAmountEnforcer: randomAddress(), + }, + } as unknown as SmartAccountsEnvironment; + + // Using enum reference for scope type + const result = createDelegation({ + environment: smartAccountEnvironment, + scope: { + type: ScopeType.Erc20TransferAmount as const, + tokenAddress: randomAddress(), + maxAmount: 100n, + }, + to: randomAddress(), + from: randomAddress(), + }); + + expect(result.caveats.length).to.be.greaterThan(0); + }); + + it('should create delegation with string literal scope type', () => { + const smartAccountEnvironment: SmartAccountsEnvironment = { + caveatEnforcers: { + ValueLteEnforcer: randomAddress(), + ERC20TransferAmountEnforcer: randomAddress(), + }, + } as unknown as SmartAccountsEnvironment; + + // Using string literal for scope type + const result = createDelegation({ + environment: smartAccountEnvironment, + scope: { + type: 'erc20TransferAmount' as const, + tokenAddress: randomAddress(), + maxAmount: 100n, + }, + to: randomAddress(), + from: randomAddress(), + }); + + expect(result.caveats.length).to.be.greaterThan(0); + }); + }); + + describe('TypeScript type inference verification', () => { + // These tests verify TypeScript types are correctly inferred + // If TypeScript compilation passes, the types are correct + + it('should allow CaveatType enum in addCaveat', () => { + const builder = createCaveatBuilder(environment); + + // This should compile without errors if types are correct + builder.addCaveat(CaveatType.AllowedMethods, { + selectors: ['0x12345678'], + }); + builder.addCaveat(CaveatType.ValueLte, { maxValue: 1000n }); + builder.addCaveat(CaveatType.AllowedTargets, { + targets: [randomAddress()], + }); + + const caveats = builder.build(); + expect(caveats).to.have.lengthOf(3); + }); + + it('should allow string literals in addCaveat', () => { + const builder = createCaveatBuilder(environment); + + // String literals (backward compatibility): addCaveat accepts CaveatTypeParam + builder.addCaveat('allowedMethods', { + selectors: ['0x12345678'], + }); + builder.addCaveat('valueLte', { maxValue: 1000n }); + builder.addCaveat('allowedTargets', { + targets: [randomAddress()], + }); + + const caveats = builder.build(); + expect(caveats).to.have.lengthOf(3); + }); + + it('should reject wrong config for string literal caveat type at compile time', () => { + const builder = createCaveatBuilder(environment); + + // Type-only assertion: wrong config must be a compile error (never executed). + if (false as boolean) { + // @ts-expect-error - wrong config for 'allowedMethods' (expects selectors, not maxValue) + builder.addCaveat('allowedMethods', { maxValue: 1000n }); + } + }); + + it('should allow CaveatType enum in caveats array', () => { + const scope = { + type: ScopeType.Erc20TransferAmount as const, + tokenAddress: randomAddress(), + maxAmount: 100n, + }; + + // This should compile if types are correct + const result = createDelegation({ + environment, + scope, + to: randomAddress(), + from: randomAddress(), + caveats: [ + { type: CaveatType.LimitedCalls, limit: 10 }, + { type: CaveatType.ValueLte, maxValue: 500n }, + ], + }); + + expect(result.caveats.length).to.be.greaterThan(2); + }); + }); +}); diff --git a/packages/smart-accounts-kit/test/caveatBuilder/createCaveatBuilder.test.ts b/packages/smart-accounts-kit/test/caveatBuilder/createCaveatBuilder.test.ts index 7006e38..26a683b 100644 --- a/packages/smart-accounts-kit/test/caveatBuilder/createCaveatBuilder.test.ts +++ b/packages/smart-accounts-kit/test/caveatBuilder/createCaveatBuilder.test.ts @@ -2,7 +2,11 @@ import { concat, encodePacked, isAddress, pad, toHex } from 'viem'; import type { Address } from 'viem/accounts'; import { expect, describe, it } from 'vitest'; -import { createCaveatBuilder, CaveatBuilder } from '../../src/caveatBuilder'; +import { + createCaveatBuilder, + CaveatBuilder, + CaveatType, +} from '../../src/caveatBuilder'; import { BalanceChangeType } from '../../src/caveatBuilder/types'; import type { SmartAccountsEnvironment } from '../../src/types'; import { randomAddress, randomBytes } from '../utils'; @@ -61,7 +65,7 @@ describe('createCaveatBuilder()', () => { const selectors = [randomBytes(4), randomBytes(4)]; const caveats = builder - .addCaveat('allowedMethods', { selectors }) + .addCaveat(CaveatType.AllowedMethods, { selectors }) .build(); expect(caveats).to.deep.equal([ @@ -84,7 +88,9 @@ describe('createCaveatBuilder()', () => { const targets: [Address, Address] = [randomAddress(), randomAddress()]; - const caveats = builder.addCaveat('allowedTargets', { targets }).build(); + const caveats = builder + .addCaveat(CaveatType.AllowedTargets, { targets }) + .build(); expect(caveats).to.deep.equal([ { @@ -110,7 +116,7 @@ describe('createCaveatBuilder()', () => { const bytecode = randomBytes(256); const caveats = builder - .addCaveat('deployed', { contractAddress, salt, bytecode }) + .addCaveat(CaveatType.Deployed, { contractAddress, salt, bytecode }) .build(); expect(caveats).to.deep.equal([ @@ -136,7 +142,7 @@ describe('createCaveatBuilder()', () => { const startIndex = Math.floor(Math.random() * 2 ** 32); const caveats = builder - .addCaveat('allowedCalldata', { startIndex, value }) + .addCaveat(CaveatType.AllowedCalldata, { startIndex, value }) .build(); expect(caveats).to.deep.equal([ @@ -165,7 +171,7 @@ describe('createCaveatBuilder()', () => { ); const caveats = builder - .addCaveat('erc20BalanceChange', { + .addCaveat(CaveatType.Erc20BalanceChange, { tokenAddress, recipient, balance, @@ -198,7 +204,9 @@ describe('createCaveatBuilder()', () => { Math.floor(Math.random() * Number.MAX_SAFE_INTEGER), ); - const caveats = builder.addCaveat('valueLte', { maxValue }).build(); + const caveats = builder + .addCaveat(CaveatType.ValueLte, { maxValue }) + .build(); expect(caveats).to.deep.equal([ { @@ -219,7 +227,9 @@ describe('createCaveatBuilder()', () => { const builder = createCaveatBuilder(environment); const limit = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER); - const caveats = builder.addCaveat('limitedCalls', { limit }).build(); + const caveats = builder + .addCaveat(CaveatType.LimitedCalls, { limit }) + .build(); expect(caveats).to.deep.equal([ { @@ -240,7 +250,7 @@ describe('createCaveatBuilder()', () => { const builder = createCaveatBuilder(environment); const idValue = BigInt(Math.floor(Math.random() * 2 ** 32)); - const caveats = builder.addCaveat('id', { id: idValue }).build(); + const caveats = builder.addCaveat(CaveatType.Id, { id: idValue }).build(); expect(caveats).to.deep.equal([ { @@ -261,7 +271,7 @@ describe('createCaveatBuilder()', () => { const builder = createCaveatBuilder(environment); const nonce = randomBytes(16); - const caveats = builder.addCaveat('nonce', { nonce }).build(); + const caveats = builder.addCaveat(CaveatType.Nonce, { nonce }).build(); expect(caveats).to.deep.equal([ { @@ -285,7 +295,7 @@ describe('createCaveatBuilder()', () => { const beforeThreshold = 2000; const caveats = builder - .addCaveat('timestamp', { + .addCaveat(CaveatType.Timestamp, { afterThreshold, beforeThreshold, }) @@ -316,7 +326,7 @@ describe('createCaveatBuilder()', () => { const beforeThreshold = 2000n; const caveats = builder - .addCaveat('blockNumber', { + .addCaveat(CaveatType.BlockNumber, { afterThreshold, beforeThreshold, }) @@ -345,7 +355,7 @@ describe('createCaveatBuilder()', () => { const maxAmount = 1000000000000000000n; // 1 ETH in wei const caveats = builder - .addCaveat('nativeTokenTransferAmount', { maxAmount }) + .addCaveat(CaveatType.NativeTokenTransferAmount, { maxAmount }) .build(); expect(caveats).to.deep.equal([ @@ -371,7 +381,7 @@ describe('createCaveatBuilder()', () => { const minBalance = 500000000000000000n; // 0.5 ETH in wei const caveats = builder - .addCaveat('nativeBalanceChange', { + .addCaveat(CaveatType.NativeBalanceChange, { recipient, balance: minBalance, changeType: BalanceChangeType.Increase, @@ -402,7 +412,7 @@ describe('createCaveatBuilder()', () => { const recipient = randomAddress('lowercase'); const caveats = builder - .addCaveat('nativeTokenPayment', { recipient, amount }) + .addCaveat(CaveatType.NativeTokenPayment, { recipient, amount }) .build(); expect(caveats).to.deep.equal([ @@ -427,7 +437,7 @@ describe('createCaveatBuilder()', () => { const maxAmount = 2000n; const caveats = builder - .addCaveat('erc20TransferAmount', { tokenAddress, maxAmount }) + .addCaveat(CaveatType.Erc20TransferAmount, { tokenAddress, maxAmount }) .build(); expect(caveats).to.deep.equal([ @@ -451,7 +461,7 @@ describe('createCaveatBuilder()', () => { const redeemerAddress = randomAddress(); const caveats = builder - .addCaveat('redeemer', { redeemers: [redeemerAddress] }) + .addCaveat(CaveatType.Redeemer, { redeemers: [redeemerAddress] }) .build(); expect(caveats).to.deep.equal([ @@ -473,7 +483,9 @@ describe('createCaveatBuilder()', () => { const builder = createCaveatBuilder(environment); const args = '0x1234567890'; - const caveats = builder.addCaveat('argsEqualityCheck', { args }).build(); + const caveats = builder + .addCaveat(CaveatType.ArgsEqualityCheck, { args }) + .build(); expect(caveats).to.deep.equal([ { @@ -489,4 +501,334 @@ describe('createCaveatBuilder()', () => { expect(isAddress(caveat.enforcer)).to.equal(true); }); + + describe('string literal caveat names', () => { + it("should add an 'allowedMethods' caveat using string literal", () => { + const builder = createCaveatBuilder(environment); + + const selectors = [randomBytes(4), randomBytes(4)]; + + const caveats = builder + .addCaveat('allowedMethods', { selectors }) + .build(); + + expect(caveats).to.deep.equal([ + { + enforcer: environment.caveatEnforcers.AllowedMethodsEnforcer, + terms: concat(selectors), + args: '0x00', + }, + ]); + }); + + it("should add an 'allowedTargets' caveat using string literal", () => { + const builder = createCaveatBuilder(environment); + + const targets: [Address, Address] = [randomAddress(), randomAddress()]; + + const caveats = builder.addCaveat('allowedTargets', { targets }).build(); + + expect(caveats).to.deep.equal([ + { + enforcer: environment.caveatEnforcers.AllowedTargetsEnforcer, + terms: targets[0] + targets[1]?.slice(2), + args: '0x00', + }, + ]); + }); + + it("should add a 'deployed' caveat using string literal", () => { + const builder = createCaveatBuilder(environment); + + const contractAddress = randomAddress(); + const salt = randomBytes(32); + const bytecode = randomBytes(256); + + const caveats = builder + .addCaveat('deployed', { contractAddress, salt, bytecode }) + .build(); + + expect(caveats).to.deep.equal([ + { + enforcer: environment.caveatEnforcers.DeployedEnforcer, + terms: concat([contractAddress, pad(salt, { size: 32 }), bytecode]), + args: '0x00', + }, + ]); + }); + + it("should add an 'allowedCalldata' caveat using string literal", () => { + const builder = createCaveatBuilder(environment); + + const value = randomBytes(128); + const startIndex = Math.floor(Math.random() * 2 ** 32); + + const caveats = builder + .addCaveat('allowedCalldata', { startIndex, value }) + .build(); + + expect(caveats).to.deep.equal([ + { + enforcer: environment.caveatEnforcers.AllowedCalldataEnforcer, + terms: concat([toHex(startIndex, { size: 32 }), value]), + args: '0x00', + }, + ]); + }); + + it("should add an 'erc20BalanceChange' caveat using string literal", () => { + const builder = createCaveatBuilder(environment); + + const tokenAddress = randomAddress(); + const recipient = randomAddress(); + const balance = BigInt( + Math.floor(Math.random() * Number.MAX_SAFE_INTEGER), + ); + + const caveats = builder + .addCaveat('erc20BalanceChange', { + tokenAddress, + recipient, + balance, + changeType: BalanceChangeType.Increase, + }) + .build(); + + expect(caveats).to.deep.equal([ + { + enforcer: environment.caveatEnforcers.ERC20BalanceChangeEnforcer, + terms: encodePacked( + ['uint8', 'address', 'address', 'uint256'], + [BalanceChangeType.Increase, tokenAddress, recipient, balance], + ), + args: '0x00', + }, + ]); + }); + + it("should add a 'valueLte' caveat using string literal", () => { + const builder = createCaveatBuilder(environment); + + const maxValue = BigInt( + Math.floor(Math.random() * Number.MAX_SAFE_INTEGER), + ); + + const caveats = builder.addCaveat('valueLte', { maxValue }).build(); + + expect(caveats).to.deep.equal([ + { + enforcer: environment.caveatEnforcers.ValueLteEnforcer, + terms: toHex(maxValue, { size: 32 }), + args: '0x00', + }, + ]); + }); + + it("should add a 'limitedCalls' caveat using string literal", () => { + const builder = createCaveatBuilder(environment); + + const limit = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER); + const caveats = builder.addCaveat('limitedCalls', { limit }).build(); + + expect(caveats).to.deep.equal([ + { + enforcer: environment.caveatEnforcers.LimitedCallsEnforcer, + terms: toHex(limit, { size: 32 }), + args: '0x00', + }, + ]); + }); + + it("should add an 'id' caveat using string literal", () => { + const builder = createCaveatBuilder(environment); + + const idValue = BigInt(Math.floor(Math.random() * 2 ** 32)); + const caveats = builder.addCaveat('id', { id: idValue }).build(); + + expect(caveats).to.deep.equal([ + { + enforcer: environment.caveatEnforcers.IdEnforcer, + terms: toHex(idValue, { size: 32 }), + args: '0x00', + }, + ]); + }); + + it("should add a 'nonce' caveat using string literal", () => { + const builder = createCaveatBuilder(environment); + + const nonce = randomBytes(16); + const caveats = builder.addCaveat('nonce', { nonce }).build(); + + expect(caveats).to.deep.equal([ + { + enforcer: environment.caveatEnforcers.NonceEnforcer, + terms: pad(nonce, { size: 32 }), + args: '0x00', + }, + ]); + }); + + it("should add a 'timestamp' caveat using string literal", () => { + const builder = createCaveatBuilder(environment); + + const afterThreshold = 1000; + const beforeThreshold = 2000; + + const caveats = builder + .addCaveat('timestamp', { + afterThreshold, + beforeThreshold, + }) + .build(); + + expect(caveats).to.deep.equal([ + { + enforcer: environment.caveatEnforcers.TimestampEnforcer, + terms: concat([ + toHex(afterThreshold, { size: 16 }), + toHex(beforeThreshold, { size: 16 }), + ]), + args: '0x00', + }, + ]); + }); + + it("should add a 'blockNumber' caveat using string literal", () => { + const builder = createCaveatBuilder(environment); + + const afterThreshold = 1000n; + const beforeThreshold = 2000n; + + const caveats = builder + .addCaveat('blockNumber', { + afterThreshold, + beforeThreshold, + }) + .build(); + + expect(caveats).to.deep.equal([ + { + enforcer: environment.caveatEnforcers.BlockNumberEnforcer, + terms: concat([ + toHex(afterThreshold, { size: 16 }), + toHex(beforeThreshold, { size: 16 }), + ]), + args: '0x00', + }, + ]); + }); + + it("should add a 'nativeTokenTransferAmount' caveat using string literal", () => { + const builder = createCaveatBuilder(environment); + const maxAmount = 1000000000000000000n; // 1 ETH in wei + + const caveats = builder + .addCaveat('nativeTokenTransferAmount', { maxAmount }) + .build(); + + expect(caveats).to.deep.equal([ + { + enforcer: + environment.caveatEnforcers.NativeTokenTransferAmountEnforcer, + terms: toHex(maxAmount, { size: 32 }), + args: '0x00', + }, + ]); + }); + + it("should add a 'nativeBalanceChange' caveat using string literal", () => { + const builder = createCaveatBuilder(environment); + const recipient = randomAddress(); + const minBalance = 500000000000000000n; // 0.5 ETH in wei + + const caveats = builder + .addCaveat('nativeBalanceChange', { + recipient, + balance: minBalance, + changeType: BalanceChangeType.Increase, + }) + .build(); + + expect(caveats).to.deep.equal([ + { + enforcer: environment.caveatEnforcers.NativeBalanceChangeEnforcer, + terms: encodePacked( + ['uint8', 'address', 'uint256'], + [BalanceChangeType.Increase, recipient, minBalance], + ), + args: '0x00', + }, + ]); + }); + + it("should add a 'nativeTokenPayment' caveat using string literal", () => { + const builder = createCaveatBuilder(environment); + const amount = 1000000000000000000n; // 1 ETH in wei + const recipient = randomAddress('lowercase'); + + const caveats = builder + .addCaveat('nativeTokenPayment', { recipient, amount }) + .build(); + + expect(caveats).to.deep.equal([ + { + enforcer: environment.caveatEnforcers.NativeTokenPaymentEnforcer, + terms: concat([recipient, toHex(amount, { size: 32 })]), + args: '0x00', + }, + ]); + }); + + it("should add an 'erc20TransferAmount' caveat using string literal", () => { + const builder = createCaveatBuilder(environment); + + const tokenAddress = randomAddress(); + const maxAmount = 2000n; + + const caveats = builder + .addCaveat('erc20TransferAmount', { tokenAddress, maxAmount }) + .build(); + + expect(caveats).to.deep.equal([ + { + enforcer: environment.caveatEnforcers.ERC20TransferAmountEnforcer, + terms: concat([tokenAddress, toHex(maxAmount, { size: 32 })]), + args: '0x00', + }, + ]); + }); + + it("should add a 'redeemer' caveat using string literal", () => { + const builder = createCaveatBuilder(environment); + const redeemerAddress = randomAddress(); + + const caveats = builder + .addCaveat('redeemer', { redeemers: [redeemerAddress] }) + .build(); + + expect(caveats).to.deep.equal([ + { + enforcer: environment.caveatEnforcers.RedeemerEnforcer, + terms: redeemerAddress, + args: '0x00', + }, + ]); + }); + + it("should add an 'argsEqualityCheck' caveat using string literal", () => { + const builder = createCaveatBuilder(environment); + const args = '0x1234567890'; + + const caveats = builder.addCaveat('argsEqualityCheck', { args }).build(); + + expect(caveats).to.deep.equal([ + { + enforcer: environment.caveatEnforcers.ArgsEqualityCheckEnforcer, + terms: args, + args: '0x00', + }, + ]); + }); + }); }); diff --git a/packages/smart-accounts-kit/test/caveatBuilder/resolveCaveats.test.ts b/packages/smart-accounts-kit/test/caveatBuilder/resolveCaveats.test.ts index 871952b..8b24607 100644 --- a/packages/smart-accounts-kit/test/caveatBuilder/resolveCaveats.test.ts +++ b/packages/smart-accounts-kit/test/caveatBuilder/resolveCaveats.test.ts @@ -2,7 +2,10 @@ import { describe, it, expect } from 'vitest'; import { CaveatBuilder } from '../../src/caveatBuilder/caveatBuilder'; import type { CoreCaveatConfiguration } from '../../src/caveatBuilder/coreCaveatBuilder'; -import { createCaveatBuilder } from '../../src/caveatBuilder/coreCaveatBuilder'; +import { + createCaveatBuilder, + CaveatType, +} from '../../src/caveatBuilder/coreCaveatBuilder'; import { resolveCaveats } from '../../src/caveatBuilder/resolveCaveats'; import type { ScopeConfig } from '../../src/caveatBuilder/scope'; import { ScopeType } from '../../src/constants'; @@ -71,10 +74,29 @@ describe('resolveCaveats', () => { expect(result.length).to.be.greaterThan(0); // Should have scope caveats }); - it('should handle CoreCaveatBuilder with named caveats', () => { + it('should handle CoreCaveatBuilder with named caveats using enum', () => { const caveatBuilder = createCaveatBuilder(environment, { allowInsecureUnrestrictedDelegation: true, }); + caveatBuilder.addCaveat(CaveatType.AllowedMethods, { + selectors: ['0x12345678'], + }); + + const result = resolveCaveats({ + environment, + scope: erc20Scope, + caveats: caveatBuilder as any, + }); + + expect(result).to.be.an('array'); + expect(result.length).to.be.greaterThan(1); // Should have scope caveats + our added caveat + }); + + it('should handle CoreCaveatBuilder with named caveats using string literal', () => { + const caveatBuilder = createCaveatBuilder(environment, { + allowInsecureUnrestrictedDelegation: true, + }); + // Use string literal instead of enum caveatBuilder.addCaveat('allowedMethods', { selectors: ['0x12345678'], }); @@ -108,7 +130,7 @@ describe('resolveCaveats', () => { expect(result).to.deep.include(mockCaveat2); }); - it('should resolve caveats from an array of CaveatConfiguration objects', () => { + it('should resolve caveats from an array of CaveatConfiguration objects with string types', () => { const caveatConfigs: CoreCaveatConfiguration[] = [ { type: 'allowedMethods', @@ -139,6 +161,37 @@ describe('resolveCaveats', () => { expect(result.length).to.be.greaterThan(scopeOnlyResult.length); }); + it('should resolve caveats from an array of CaveatConfiguration objects with enum types', () => { + const caveatConfigs: CoreCaveatConfiguration[] = [ + { + type: CaveatType.AllowedMethods, + selectors: ['0x12345678'], + }, + { + type: CaveatType.BlockNumber, + afterThreshold: 0n, + beforeThreshold: 1000n, + }, + ]; + + const result = resolveCaveats({ + environment, + scope: erc20Scope, + caveats: caveatConfigs, + }); + + expect(result).to.be.an('array'); + expect(result.length).to.be.greaterThan(2); // Should have scope caveats + our added caveats + + // Verify that the caveats were added by checking the result contains more than just scope caveats + const scopeOnlyResult = resolveCaveats({ + environment, + scope: erc20Scope, + caveats: [], + }); + expect(result.length).to.be.greaterThan(scopeOnlyResult.length); + }); + it('should resolve caveats from a mixed array of Caveat and CaveatConfiguration objects', () => { const mixedCaveats = [ mockCaveat1, @@ -237,7 +290,7 @@ describe('resolveCaveats', () => { scope: erc20Scope, caveats: [invalidType as any], }); - }).to.throw('Invalid caveat'); + }).to.throw('does not exist'); }); }); });