diff --git a/packages/smart-accounts-kit/src/caveatBuilder/scope/index.ts b/packages/smart-accounts-kit/src/caveatBuilder/scope/index.ts index 64b22f36..a09a3805 100644 --- a/packages/smart-accounts-kit/src/caveatBuilder/scope/index.ts +++ b/packages/smart-accounts-kit/src/caveatBuilder/scope/index.ts @@ -37,7 +37,16 @@ import { import { ScopeType } from '../../constants'; import type { SmartAccountsEnvironment } from '../../types'; -export type ScopeConfig = +// We want to allow the scope `type` to be passed as either an enum reference, +// 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']}` } + : never; + +type ScopeConfigBase = | Erc20TransferScopeConfig | Erc20StreamingScopeConfig | Erc20PeriodicScopeConfig @@ -48,32 +57,64 @@ export type ScopeConfig = | OwnershipScopeConfig | FunctionCallScopeConfig; +export type ScopeConfig = ConvertScopeConfigsToInputs; + +const normalizeScopeConfig = (config: ScopeConfig): ScopeConfigBase => { + return { + ...config, + type: config.type as ScopeType, + } as ScopeConfigBase; +}; + export const createCaveatBuilderFromScope = ( environment: SmartAccountsEnvironment, scopeConfig: ScopeConfig, ) => { - switch (scopeConfig.type) { + const normalizedScopeConfig = normalizeScopeConfig(scopeConfig); + + switch (normalizedScopeConfig.type) { case ScopeType.Erc20TransferAmount: - return createErc20TransferCaveatBuilder(environment, scopeConfig); + return createErc20TransferCaveatBuilder( + environment, + normalizedScopeConfig, + ); case ScopeType.Erc20Streaming: - return createErc20StreamingCaveatBuilder(environment, scopeConfig); + return createErc20StreamingCaveatBuilder( + environment, + normalizedScopeConfig, + ); case ScopeType.Erc20PeriodTransfer: - return createErc20PeriodicCaveatBuilder(environment, scopeConfig); + return createErc20PeriodicCaveatBuilder( + environment, + normalizedScopeConfig, + ); case ScopeType.NativeTokenTransferAmount: - return createNativeTokenTransferCaveatBuilder(environment, scopeConfig); + return createNativeTokenTransferCaveatBuilder( + environment, + normalizedScopeConfig, + ); case ScopeType.NativeTokenStreaming: - return createNativeTokenStreamingCaveatBuilder(environment, scopeConfig); + return createNativeTokenStreamingCaveatBuilder( + environment, + normalizedScopeConfig, + ); case ScopeType.NativeTokenPeriodTransfer: - return createNativeTokenPeriodicCaveatBuilder(environment, scopeConfig); + return createNativeTokenPeriodicCaveatBuilder( + environment, + normalizedScopeConfig, + ); case ScopeType.Erc721Transfer: - return createErc721CaveatBuilder(environment, scopeConfig); + return createErc721CaveatBuilder(environment, normalizedScopeConfig); case ScopeType.OwnershipTransfer: - return createOwnershipCaveatBuilder(environment, scopeConfig); + return createOwnershipCaveatBuilder(environment, normalizedScopeConfig); case ScopeType.FunctionCall: - return createFunctionCallCaveatBuilder(environment, scopeConfig); + return createFunctionCallCaveatBuilder( + environment, + normalizedScopeConfig, + ); default: // eslint-disable-next-line no-case-declarations - const exhaustivenessCheck: never = scopeConfig; + const exhaustivenessCheck: never = normalizedScopeConfig; throw new Error( `Invalid scope type: ${(exhaustivenessCheck as { type: string }).type}`, ); diff --git a/packages/smart-accounts-kit/test/delegation.test.ts b/packages/smart-accounts-kit/test/delegation.test.ts index 55d0a926..7e98e5e4 100644 --- a/packages/smart-accounts-kit/test/delegation.test.ts +++ b/packages/smart-accounts-kit/test/delegation.test.ts @@ -166,6 +166,24 @@ describe('resolveAuthority', () => { }); describe('createDelegation', () => { + it('creates a delegation with a scope type as a string', () => { + const result = createDelegation({ + environment: smartAccountEnvironment, + scope: { ...erc20Scope, type: 'erc20TransferAmount' }, + to: mockDelegate, + from: mockDelegator, + }); + + expect(result).to.deep.equal({ + delegate: mockDelegate, + delegator: mockDelegator, + authority: ROOT_AUTHORITY, + caveats: [...erc20ScopeCaveats], + salt: '0x', + signature: '0x', + }); + }); + it('should create a basic delegation with root authority', () => { const result = createDelegation({ environment: smartAccountEnvironment, @@ -178,9 +196,9 @@ describe('createDelegation', () => { expect(result).to.deep.equal({ delegate: mockDelegate, delegator: mockDelegator, - authority: ROOT_AUTHORITY as Hex, + authority: ROOT_AUTHORITY, caveats: [...erc20ScopeCaveats, mockCaveat], - salt: '0x' as Hex, + salt: '0x', signature: '0x', }); });