diff --git a/packages/delegation-deployments/src/index.ts b/packages/delegation-deployments/src/index.ts index 3edbcb57..a64f791d 100644 --- a/packages/delegation-deployments/src/index.ts +++ b/packages/delegation-deployments/src/index.ts @@ -1,3 +1,4 @@ +import type { Address } from 'viem'; import { deployments_1_3_0, deployments_1_1_0, @@ -39,7 +40,7 @@ export const CHAIN_ID = { type DeployedContracts = Record< string, - Record> + Record> >; export const DELEGATOR_CONTRACTS: DeployedContracts = { diff --git a/packages/delegation-toolkit/src/actions/signDelegation.ts b/packages/delegation-toolkit/src/actions/signDelegation.ts index 95dc2f93..2ccb69e0 100644 --- a/packages/delegation-toolkit/src/actions/signDelegation.ts +++ b/packages/delegation-toolkit/src/actions/signDelegation.ts @@ -3,6 +3,7 @@ import type { Address, Chain, Client, + Hex, Transport, WalletClient, } from 'viem'; @@ -29,7 +30,7 @@ export type SignDelegationParameters = { allowInsecureUnrestrictedDelegation?: boolean; }; -export type SignDelegationReturnType = `0x${string}`; +export type SignDelegationReturnType = Hex; /** * Signs a delegation using a wallet client. diff --git a/packages/delegation-toolkit/src/actions/signUserOperation.ts b/packages/delegation-toolkit/src/actions/signUserOperation.ts index 9a70851e..94cee0f3 100644 --- a/packages/delegation-toolkit/src/actions/signUserOperation.ts +++ b/packages/delegation-toolkit/src/actions/signUserOperation.ts @@ -3,6 +3,7 @@ import type { Address, Chain, Client, + Hex, Transport, WalletClient, } from 'viem'; @@ -29,7 +30,7 @@ export type SignUserOperationParameters = { version?: string; }; -export type SignUserOperationReturnType = `0x${string}`; +export type SignUserOperationReturnType = Hex; /** * Signs a user operation using a wallet client. diff --git a/packages/delegation-toolkit/src/userOp.ts b/packages/delegation-toolkit/src/userOp.ts index 77f4e9ae..20a24cf3 100644 --- a/packages/delegation-toolkit/src/userOp.ts +++ b/packages/delegation-toolkit/src/userOp.ts @@ -327,7 +327,7 @@ export const signUserOperation = async ({ address, version = '1', }: { - privateKey: `0x${string}`; + privateKey: Hex; userOperation: Omit; entryPoint: { address: Address }; chainId: number; diff --git a/packages/delegation-toolkit/test/actions/signUserOperation.test.ts b/packages/delegation-toolkit/test/actions/signUserOperation.test.ts index 4d3c2acf..4fb9f31e 100644 --- a/packages/delegation-toolkit/test/actions/signUserOperation.test.ts +++ b/packages/delegation-toolkit/test/actions/signUserOperation.test.ts @@ -1,4 +1,4 @@ -import type { Account, Address } from 'viem'; +import type { Account, Address, Hex } from 'viem'; import { createWalletClient, custom, isHex } from 'viem'; import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; import { sepolia } from 'viem/chains'; @@ -51,7 +51,7 @@ describe('signUserOperation Action', () => { userOperation = { sender: randomAddress(), nonce: 0n, - callData: '0x', + callData: '0x' as Hex, callGasLimit: 1000000n, verificationGasLimit: 1000000n, preVerificationGas: 21000n, @@ -177,7 +177,7 @@ describe('signUserOperation Action', () => { paymaster: randomAddress(), paymasterVerificationGasLimit: 50000n, paymasterPostOpGasLimit: 50000n, - paymasterData: '0x1234' as `0x${string}`, + paymasterData: '0x1234' as Hex, }; const parameters: SignUserOperationParameters = { @@ -196,7 +196,7 @@ describe('signUserOperation Action', () => { const userOpWithFactory = { ...userOperation, factory: randomAddress(), - factoryData: '0x5678' as `0x${string}`, + factoryData: '0x5678' as Hex, }; const parameters: SignUserOperationParameters = { diff --git a/packages/delegation-toolkit/test/caveatBuilder/exactExecutionBatchBuilder.test.ts b/packages/delegation-toolkit/test/caveatBuilder/exactExecutionBatchBuilder.test.ts index d0c223d9..5918d8dd 100644 --- a/packages/delegation-toolkit/test/caveatBuilder/exactExecutionBatchBuilder.test.ts +++ b/packages/delegation-toolkit/test/caveatBuilder/exactExecutionBatchBuilder.test.ts @@ -30,7 +30,7 @@ describe('exactExecutionBatchBuilder()', () => { }); it('should fail with an invalid target address', () => { - const invalidAddress = 'invalid-address' as Address; + const invalidAddress = 'invalid-address' as any; expect(() => buildWithParams([ { @@ -60,7 +60,7 @@ describe('exactExecutionBatchBuilder()', () => { { target: randomAddress(), value: 0n, - callData: 'invalid' as Hex, + callData: 'invalid' as any, }, ]), ).to.throw('Invalid calldata: must be a hex string starting with 0x'); diff --git a/packages/delegation-toolkit/test/delegation.test.ts b/packages/delegation-toolkit/test/delegation.test.ts index 96023069..41ebecda 100644 --- a/packages/delegation-toolkit/test/delegation.test.ts +++ b/packages/delegation-toolkit/test/delegation.test.ts @@ -17,8 +17,8 @@ import { } from '../src/delegation'; import type { Caveat, Delegation, DeleGatorEnvironment } from '../src/types'; -const mockDelegate = '0x1234567890123456789012345678901234567890' as const; -const mockDelegator = '0x0987654321098765432109876543210987654321' as const; +const mockDelegate: Address = '0x1234567890123456789012345678901234567890'; +const mockDelegator: Address = '0x0987654321098765432109876543210987654321'; const mockSignature = '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890' as const; @@ -62,9 +62,9 @@ describe('toDelegationStruct', () => { const delegation: Delegation = { delegate: mockDelegate, delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [mockCaveat], - salt: '0x123', + salt: '0x123' as Hex, signature: mockSignature, }; @@ -72,7 +72,7 @@ describe('toDelegationStruct', () => { expect(result).to.deep.equal({ delegate: mockDelegate, delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [{ ...mockCaveat, enforcer: getAddress(mockCaveat.enforcer) }], salt: 291n, signature: mockSignature, @@ -83,7 +83,7 @@ describe('toDelegationStruct', () => { const delegation: Delegation = { delegate: mockDelegate, delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [ { enforcer: '0x1111111111111111111111111111111111111111', @@ -91,7 +91,7 @@ describe('toDelegationStruct', () => { args: '0x', }, ], - salt: '0x123', + salt: '0x123' as Hex, signature: mockSignature, }; @@ -99,7 +99,7 @@ describe('toDelegationStruct', () => { expect(result).to.deep.equal({ delegate: mockDelegate, delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [ { enforcer: '0x1111111111111111111111111111111111111111', @@ -116,7 +116,7 @@ describe('toDelegationStruct', () => { const delegationStruct: DelegationStruct = { delegate: mockDelegate, delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [ { enforcer: '0x1111111111111111111111111111111111111111', @@ -148,9 +148,9 @@ describe('resolveAuthority', () => { const parentDelegation: Delegation = { delegate: mockDelegate, delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [mockCaveat], - salt: '0x', + salt: '0x' as Hex, signature: '0x', }; const result = resolveAuthority(parentDelegation); @@ -172,9 +172,9 @@ describe('createDelegation', () => { expect(result).to.deep.equal({ delegate: mockDelegate, delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [...erc20ScopeCaveats, mockCaveat], - salt: '0x', + salt: '0x' as Hex, signature: '0x', }); }); @@ -196,7 +196,7 @@ describe('createDelegation', () => { delegator: mockDelegator, authority: parentHash, caveats: [...erc20ScopeCaveats, mockCaveat], - salt: '0x', + salt: '0x' as Hex, signature: '0x', }); }); @@ -221,7 +221,7 @@ describe('createDelegation', () => { expect(result).to.deep.equal({ delegate: mockDelegate, delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [ ...erc20ScopeCaveats, { @@ -230,7 +230,7 @@ describe('createDelegation', () => { args: '0x', }, ], - salt: '0x', + salt: '0x' as Hex, signature: '0x', }); }); @@ -246,9 +246,9 @@ describe('createDelegation', () => { expect(result).to.deep.equal({ delegate: mockDelegate, delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [...erc20ScopeCaveats], - salt: '0x', + salt: '0x' as Hex, signature: '0x', }); }); @@ -266,7 +266,7 @@ describe('createDelegation', () => { expect(result).to.deep.equal({ delegate: mockDelegate, delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [...erc20ScopeCaveats, mockCaveat], salt: customSalt, signature: '0x', @@ -284,9 +284,9 @@ describe('createDelegation', () => { expect(result).to.deep.equal({ delegate: mockDelegate, delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [...erc20ScopeCaveats], - salt: '0x', + salt: '0x' as Hex, signature: '0x', }); }); @@ -303,9 +303,9 @@ describe('createDelegation', () => { expect(result).to.deep.equal({ delegate: mockDelegate, delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [...erc20ScopeCaveats], - salt: '0x', + salt: '0x' as Hex, signature: '0x', }); }); @@ -322,9 +322,9 @@ describe('createDelegation', () => { expect(result).to.deep.equal({ delegate: mockDelegate, delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [...erc20ScopeCaveats], - salt: '0x', + salt: '0x' as Hex, signature: '0x', }); }); @@ -342,9 +342,9 @@ describe('createOpenDelegation', () => { expect(result).to.deep.equal({ delegate: '0x0000000000000000000000000000000000000a11', delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [...erc20ScopeCaveats, mockCaveat], - salt: '0x', + salt: '0x' as Hex, signature: '0x', }); }); @@ -365,7 +365,7 @@ describe('createOpenDelegation', () => { delegator: mockDelegator, authority: parentHash, caveats: [...erc20ScopeCaveats, mockCaveat], - salt: '0x', + salt: '0x' as Hex, signature: '0x', }); }); @@ -389,7 +389,7 @@ describe('createOpenDelegation', () => { expect(result).to.deep.equal({ delegate: '0x0000000000000000000000000000000000000a11', delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [ ...erc20ScopeCaveats, { @@ -398,7 +398,7 @@ describe('createOpenDelegation', () => { args: '0x', }, ], - salt: '0x', + salt: '0x' as Hex, signature: '0x', }); }); @@ -415,7 +415,7 @@ describe('createOpenDelegation', () => { expect(result).to.deep.equal({ delegate: '0x0000000000000000000000000000000000000a11', delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [...erc20ScopeCaveats, mockCaveat], salt: customSalt, signature: '0x', @@ -432,9 +432,9 @@ describe('createOpenDelegation', () => { expect(result).to.deep.equal({ delegate: '0x0000000000000000000000000000000000000a11', delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [...erc20ScopeCaveats], - salt: '0x', + salt: '0x' as Hex, signature: '0x', }); }); @@ -450,9 +450,9 @@ describe('createOpenDelegation', () => { expect(result).to.deep.equal({ delegate: '0x0000000000000000000000000000000000000a11', delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [...erc20ScopeCaveats], - salt: '0x', + salt: '0x' as Hex, signature: '0x', }); }); @@ -468,9 +468,9 @@ describe('createOpenDelegation', () => { expect(result).to.deep.equal({ delegate: '0x0000000000000000000000000000000000000a11', delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [...erc20ScopeCaveats], - salt: '0x', + salt: '0x' as Hex, signature: '0x', }); }); @@ -480,16 +480,16 @@ describe('encodeDelegations', () => { const mockDelegation1: Delegation = { delegate: mockDelegate, delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [mockCaveat], - salt: '0x123', + salt: '0x123' as Hex, signature: mockSignature, }; const mockDelegation2: Delegation = { delegate: '0x2222222222222222222222222222222222222222', delegator: '0x3333333333333333333333333333333333333333', - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [ { enforcer: '0x1111111111111111111111111111111111111111', @@ -497,7 +497,7 @@ describe('encodeDelegations', () => { args: '0x', }, ], - salt: '0x456', + salt: '0x456' as Hex, signature: mockSignature, }; @@ -532,16 +532,16 @@ describe('decodeDelegations', () => { const mockDelegation1: Delegation = { delegate: mockDelegate, delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [mockCaveat], - salt: '0x123', + salt: '0x123' as Hex, signature: mockSignature, }; const mockDelegation2: Delegation = { delegate: '0x2222222222222222222222222222222222222222', delegator: '0x3333333333333333333333333333333333333333', - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [ { enforcer: '0x1111111111111111111111111111111111111111', @@ -549,7 +549,7 @@ describe('decodeDelegations', () => { args: '0x', }, ], - salt: '0x456', + salt: '0x456' as Hex, signature: mockSignature, }; @@ -584,16 +584,16 @@ describe('encodePermissionContexts', () => { const mockDelegation1: Delegation = { delegate: mockDelegate, delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [mockCaveat], - salt: '0x123', + salt: '0x123' as Hex, signature: mockSignature, }; const mockDelegation2: Delegation = { delegate: '0x2222222222222222222222222222222222222222', delegator: '0x3333333333333333333333333333333333333333', - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [ { enforcer: '0x1111111111111111111111111111111111111111', @@ -601,7 +601,7 @@ describe('encodePermissionContexts', () => { args: '0x', }, ], - salt: '0x456', + salt: '0x456' as Hex, signature: mockSignature, }; @@ -645,16 +645,16 @@ describe('decodePermissionContexts', () => { const mockDelegation1: Delegation = { delegate: mockDelegate, delegator: mockDelegator, - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [mockCaveat], - salt: '0x123', + salt: '0x123' as Hex, signature: mockSignature, }; const mockDelegation2: Delegation = { delegate: '0x2222222222222222222222222222222222222222', delegator: '0x3333333333333333333333333333333333333333', - authority: ROOT_AUTHORITY, + authority: ROOT_AUTHORITY as Hex, caveats: [ { enforcer: '0x1111111111111111111111111111111111111111', @@ -662,7 +662,7 @@ describe('decodePermissionContexts', () => { args: '0x', }, ], - salt: '0x456', + salt: '0x456' as Hex, signature: mockSignature, }; @@ -703,19 +703,19 @@ describe('decodePermissionContexts', () => { }); describe('signDelegation', () => { - const mockPrivateKey = - '0x1234567890123456789012345678901234567890123456789012345678901234' as `0x${string}`; + const mockPrivateKey: Hex = + '0x1234567890123456789012345678901234567890123456789012345678901234'; const mockDelegation = { delegate: mockDelegate, delegator: mockDelegator, - authority: ROOT_AUTHORITY as Address, + authority: ROOT_AUTHORITY as Hex, caveats: [mockCaveat], salt: '0x123' as Hex, }; - const delegationManager = - '0x1234567890123456789012345678901234567890' as Address; + const delegationManager: Address = + '0x1234567890123456789012345678901234567890'; const chainId = 1; it('should sign a delegation successfully', async () => { diff --git a/packages/delegator-e2e/test/caveats/ownershipTransfer.test.ts b/packages/delegator-e2e/test/caveats/ownershipTransfer.test.ts index 10b75468..c93a1e83 100644 --- a/packages/delegator-e2e/test/caveats/ownershipTransfer.test.ts +++ b/packages/delegator-e2e/test/caveats/ownershipTransfer.test.ts @@ -38,6 +38,13 @@ describe('Ownership Transfer Caveat', () => { let bobSmartAccount: MetaMaskSmartAccount; let contractAddress: Address; + /** + * These tests verify the OwnershipTransferEnforcer behavior: + * - Allows ownership transfer ONLY to the specific contract address in the delegation terms + * - Allows transfer to the requested newOwner address (does NOT force transfer to redeemer) + * - Rejects attempts to transfer ownership of unauthorized contracts + */ + beforeEach(async () => { // Create Alice's smart account const alicePrivateKey = generatePrivateKey(); @@ -92,6 +99,9 @@ describe('Ownership Transfer Caveat', () => { const environment = delegator.environment; const delegatorAddress = delegator.address; + // Store initial owner to verify transfer happened + const initialOwner = await getContractOwner(contractAddress); + const delegation = createDelegation({ to: delegate, from: delegatorAddress, @@ -140,9 +150,17 @@ describe('Ownership Transfer Caveat', () => { await expectUserOperationToSucceed(userOpHash); - // Verify ownership was transferred + // Verify ownership was transferred successfully const finalOwner = await getContractOwner(contractAddress); + + // The ownership should have changed from the initial owner + expect(finalOwner).not.toBe(initialOwner); + + // The OwnershipTransferEnforcer allows transfer to the requested newOwner address expect(finalOwner).toBe(newOwner); + + // Additional validation: ensure it's a valid Ethereum address + expect(finalOwner).toMatch(/^0x[a-fA-F0-9]{40}$/); }; const runTest_expectFailure = async ( @@ -238,6 +256,9 @@ describe('Ownership Transfer Caveat', () => { contractAddress: Address, newOwner: Address, ) => { + // Store initial owner to verify transfer happened + const initialOwner = await getContractOwner(contractAddress); + const delegation = createDelegation({ environment: aliceSmartAccount.environment, to: bobSmartAccount.address, @@ -285,9 +306,17 @@ describe('Ownership Transfer Caveat', () => { await expectUserOperationToSucceed(userOpHash); - // Verify ownership was transferred + // Verify ownership was transferred successfully const finalOwner = await getContractOwner(contractAddress); + + // The ownership should have changed from the initial owner + expect(finalOwner).not.toBe(initialOwner); + + // The OwnershipTransferEnforcer allows transfer to the requested newOwner address expect(finalOwner).toBe(newOwner); + + // Additional validation: ensure it's a valid Ethereum address + expect(finalOwner).toMatch(/^0x[a-fA-F0-9]{40}$/); }; const runScopeTest_expectFailure = async ( diff --git a/packages/delegator-e2e/test/execute-multisig.test.ts b/packages/delegator-e2e/test/execute-multisig.test.ts index 59421795..357acfe0 100644 --- a/packages/delegator-e2e/test/execute-multisig.test.ts +++ b/packages/delegator-e2e/test/execute-multisig.test.ts @@ -23,7 +23,7 @@ import { } from '@metamask/delegation-toolkit'; import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; -import { Account, encodeFunctionData, parseEther } from 'viem'; +import { Account, encodeFunctionData, parseEther, type Hex } from 'viem'; import { chain } from '../src/config'; import { sponsoredBundlerClient } from './utils/helpers'; import CounterMetadata from './utils/counter/metadata.json'; @@ -31,7 +31,7 @@ import CounterMetadata from './utils/counter/metadata.json'; let aliceSmartAccount: MetaMaskSmartAccount; let signers: Account[]; -let privateKeys: `0x${string}`[]; +let privateKeys: Hex[]; beforeEach(async () => { privateKeys = [ diff --git a/packages/delegator-e2e/test/experimental/erc7710sendTransactionWithDelegation.test.ts b/packages/delegator-e2e/test/experimental/erc7710sendTransactionWithDelegation.test.ts index 56cfbd5f..5bd2de3e 100644 --- a/packages/delegator-e2e/test/experimental/erc7710sendTransactionWithDelegation.test.ts +++ b/packages/delegator-e2e/test/experimental/erc7710sendTransactionWithDelegation.test.ts @@ -19,6 +19,7 @@ import { } from '@metamask/delegation-toolkit'; import { erc7710WalletActions } from '@metamask/delegation-toolkit/experimental'; import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; +import type { Hex } from 'viem'; import { Address, createWalletClient, @@ -36,7 +37,7 @@ import CounterMetadata from '../utils/counter/metadata.json'; let aliceSmartAccount: MetaMaskSmartAccount; let bob: Account; -let bobPrivateKey: `0x${string}`; +let bobPrivateKey: Hex; let aliceCounterContractAddress: Address; let permissionsContext: Hex; let signedDelegation: Delegation;