diff --git a/src/abstractionkit.ts b/src/abstractionkit.ts index 82f7830..e582dd3 100644 --- a/src/abstractionkit.ts +++ b/src/abstractionkit.ts @@ -16,6 +16,7 @@ export { } from "./account/Safe/modules/AllowanceModule"; export { SafeAccountV0_2_0 } from "./account/Safe/SafeAccountV0_2_0"; export { SafeAccountV0_3_0 } from "./account/Safe/SafeAccountV0_3_0"; +export { SafeAccountV1_5_0_M_0_3_0 } from "./account/Safe/SafeAccountV1_5_0_M_0_3_0"; export { SendUseroperationResponse } from "./account/SendUseroperationResponse"; diff --git a/src/account/Safe/SafeAccount.ts b/src/account/Safe/SafeAccount.ts index b283414..1313011 100644 --- a/src/account/Safe/SafeAccount.ts +++ b/src/account/Safe/SafeAccount.ts @@ -58,6 +58,7 @@ import { BaseInitOverrides, WebauthnDummySignerSignaturePair, WebauthnPublicKey, + SafeAccountSingleton, } from "./types"; import { decodeMultiSendCallData, encodeMultiSendCallData } from "./multisend"; import { AbstractionKitError, ensureError } from "src/errors"; @@ -67,8 +68,6 @@ import { SafeAccountFactory } from "src/factory/SafeAccountFactory"; import { getSafeMessageEip712Data, SafeMessageTypedDataDomain, SafeMessageTypedMessageValue } from "./safeMessage"; export class SafeAccount extends SmartAccount { - static readonly DEFAULT_SAFE_SINGLETON = Safe_L2_V1_4_1; - static readonly DEFAULT_WEB_AUTHN_SHARED_SIGNER: string = "0xfD90FAd33ee8b58f32c00aceEad1358e4AFC23f9"; static readonly DEFAULT_WEB_AUTHN_SIGNER_SINGLETON: string = @@ -110,6 +109,7 @@ export class SafeAccount extends SmartAccount { protected x: bigint | null = null; protected y: bigint | null = null; + readonly safeAccountSingleton:SafeAccountSingleton; readonly entrypointAddress: string; readonly safe4337ModuleAddress: string; protected factoryAddress: string | null; @@ -124,6 +124,7 @@ export class SafeAccount extends SmartAccount { overrides: { onChainIdentifierParams?: OnChainIdentifierParamsType; onChainIdentifier?: string; + safeAccountSingleton?: SafeAccountSingleton; } = {} ) { super(accountAddress); @@ -160,6 +161,7 @@ export class SafeAccount extends SmartAccount { }else{ this.onChainIdentifier = null; } + this.safeAccountSingleton = overrides.safeAccountSingleton?? Safe_L2_V1_4_1; } /** @@ -172,7 +174,7 @@ export class SafeAccount extends SmartAccount { * SafeAccountFactory.DEFAULT_FACTORY_ADDRESS * @param overrides.singletonInitHash - a hash that includes the singleton address and thr proxy bytecode * keccak256(solidityPacked(["bytes", "bytes"], [proxyByteCode, abiCoder.encode(["uint256"], [singletonAddress])])) - * defaults to SafeAccount.DEFAULT_SAFE_SINGLETON.singletonInitHash + * defaults to SafeAccount.safeAccountSingleton.singletonInitHash * @returns proxy/account address */ public static createProxyAddress( @@ -191,8 +193,7 @@ export class SafeAccount extends SmartAccount { overrides.safeFactoryAddress ?? SafeAccountFactory.DEFAULT_FACTORY_ADDRESS; const singletonInitHash = - overrides.singletonInitHash ?? - SafeAccount.DEFAULT_SAFE_SINGLETON.singletonInitHash; + overrides.singletonInitHash ?? Safe_L2_V1_4_1.singletonInitHash; const salt = keccak256( solidityPacked( ["bytes32", "uint256"], @@ -914,9 +915,8 @@ export class SafeAccount extends SmartAccount { } else { safeAccountFactory = new SafeAccountFactory(); } - const safeSingleton = - overrides.safeAccountSingleton ?? SafeAccount.DEFAULT_SAFE_SINGLETON; + overrides.safeAccountSingleton ?? Safe_L2_V1_4_1; const sender = this.createProxyAddress(initializerCallData, { c2Nonce: overrides.c2Nonce ?? 0n, safeFactoryAddress: safeAccountFactory.address, @@ -1118,7 +1118,7 @@ export class SafeAccount extends SmartAccount { } const safeSingleton = - overrides.safeAccountSingleton ?? SafeAccount.DEFAULT_SAFE_SINGLETON; + overrides.safeAccountSingleton ?? Safe_L2_V1_4_1; const generatorFunctionInputParameters = [ safeSingleton.singletonAddress, diff --git a/src/account/Safe/SafeAccountV0_3_0.ts b/src/account/Safe/SafeAccountV0_3_0.ts index 7fdf0d9..2ed3a59 100644 --- a/src/account/Safe/SafeAccountV0_3_0.ts +++ b/src/account/Safe/SafeAccountV0_3_0.ts @@ -5,10 +5,11 @@ import { CreateUserOperationV7Overrides, SafeUserOperationTypedDataDomain, SafeUserOperationV7TypedMessageValue, + SafeAccountSingleton, } from "./types"; import { UserOperationV7, MetaTransaction, OnChainIdentifierParamsType } from "../../types"; -import { ENTRYPOINT_V7 } from "src/constants"; +import { ENTRYPOINT_V7, Safe_L2_V1_4_1 } from "src/constants"; export class SafeAccountV0_3_0 extends SafeAccount { static readonly DEFAULT_ENTRYPOINT_ADDRESS = ENTRYPOINT_V7; @@ -24,6 +25,7 @@ export class SafeAccountV0_3_0 extends SafeAccount { entrypointAddress?: string; onChainIdentifierParams?: OnChainIdentifierParamsType; onChainIdentifier?: string + safeAccountSingleton?: SafeAccountSingleton; } = {}, ) { const safe4337ModuleAddress = @@ -37,7 +39,8 @@ export class SafeAccountV0_3_0 extends SafeAccount { accountAddress, safe4337ModuleAddress, entrypointAddress, { onChainIdentifierParams: overrides.onChainIdentifierParams, - onChainIdentifier: overrides.onChainIdentifier + onChainIdentifier: overrides.onChainIdentifier, + safeAccountSingleton: overrides.safeAccountSingleton } ); } @@ -100,7 +103,7 @@ export class SafeAccountV0_3_0 extends SafeAccount { } } const [accountAddress, factoryAddress, factoryData] = - SafeAccountV0_3_0.createAccountAddressAndFactoryAddressAndData( + SafeAccount.createAccountAddressAndFactoryAddressAndData( owners, overrides, overrides.safe4337ModuleAddress ?? @@ -298,3 +301,6 @@ export class SafeAccountV0_3_0 extends SafeAccount { return userOperationV7; } } + +export class SafeAccountV1_4_1_M_0_3_0 extends SafeAccountV0_3_0 { +} diff --git a/src/account/Safe/SafeAccountV1_5_0_M_0_3_0.ts b/src/account/Safe/SafeAccountV1_5_0_M_0_3_0.ts new file mode 100644 index 0000000..7fa2147 --- /dev/null +++ b/src/account/Safe/SafeAccountV1_5_0_M_0_3_0.ts @@ -0,0 +1,105 @@ +import { OnChainIdentifierParamsType } from "src/types"; +import { SafeAccountV0_3_0 } from "./SafeAccountV0_3_0"; +import { Signer, InitCodeOverrides } from "./types"; +import { Safe_L2_V1_5_0 } from "src/constants"; +import { AbiCoder, keccak256, solidityPacked } from "ethers"; +import { SafeAccount } from "./SafeAccount"; + +export class SafeAccountV1_5_0_M_0_3_0 extends SafeAccountV0_3_0 { + constructor( + accountAddress: string, + overrides: { + safe4337ModuleAddress?: string; + entrypointAddress?: string; + onChainIdentifierParams?: OnChainIdentifierParamsType; + onChainIdentifier?: string + } = {}, + ) { + super( + accountAddress, + { + onChainIdentifierParams: overrides.onChainIdentifierParams, + onChainIdentifier: overrides.onChainIdentifier, + safeAccountSingleton: Safe_L2_V1_5_0 + } + ); + } + + public static createProxyAddress( + initializerCallData: string, + overrides: { + c2Nonce?: bigint; + safeFactoryAddress?: string; + singletonInitHash?: string; + } = {}, + ): string { + const modOverrides = overrides; + modOverrides.singletonInitHash = + overrides.singletonInitHash??Safe_L2_V1_5_0.singletonInitHash; + return SafeAccountV0_3_0.createProxyAddress( + initializerCallData, + modOverrides + ); + } + + /** + * To create and initialize a SafeAccount object from its + * initial owners + * @remarks + * initializeNewAccount only needed when the smart account + * have not been deployed yet and the account address is unknown. + * @param owners - list of account owners signers + * @param overrides - override values to change the initialization default values + * @returns a SafeAccount object + */ + public static initializeNewAccount( + owners: Signer[], + overrides: InitCodeOverrides = {}, + ): SafeAccountV1_5_0_M_0_3_0 { + const modOverrides = overrides; + modOverrides.safeAccountSingleton = + overrides.safeAccountSingleton??Safe_L2_V1_5_0; + return SafeAccountV0_3_0.initializeNewAccount( + owners, + overrides + ); + } + + /** + * calculate account addressfrom initial owners signers + * @param owners - list of account owners addresses + * @param overrides - override values to change the initialization default values + * @returns account address + */ + public static createAccountAddress( + owners: Signer[], + overrides: InitCodeOverrides = {}, + ): string { + const modOverrides = overrides; + modOverrides.safeAccountSingleton = + overrides.safeAccountSingleton??Safe_L2_V1_5_0; + return SafeAccountV0_3_0.createAccountAddress( + owners, + modOverrides + ); + } + + /** + * create account factory address and factory data + * @param owners - list of account owners signers + * @param overrides - override values to change the initialization default values + * @returns factoryAddress and factoryData + */ + public static createFactoryAddressAndData( + owners: Signer[], + overrides: InitCodeOverrides = {}, + ): [string, string] { + const modOverrides = overrides; + modOverrides.safeAccountSingleton = + overrides.safeAccountSingleton??Safe_L2_V1_5_0; + return SafeAccountV0_3_0.createFactoryAddressAndData( + owners, + overrides + ); + } +} diff --git a/src/constants.ts b/src/constants.ts index 2c2df67..fe8761c 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -6,6 +6,12 @@ export const ENTRYPOINT_V8 = "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"; export const ENTRYPOINT_V7 = "0x0000000071727De22E5E9d8BAf0edAc6f37da032"; export const ENTRYPOINT_V6 = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; +export const Safe_L2_V1_5_0: SafeAccountSingleton = { + singletonAddress: "0xEdd160fEBBD92E350D4D398fb636302fccd67C7e", + singletonInitHash: + "0x1b94aebb5a7df6dff11d93589204a6bbc99b4b8c9014bf1d386d006c2c17a881", +}; + export const Safe_L2_V1_4_1: SafeAccountSingleton = { singletonAddress: "0x29fcB43b46531BcA003ddC8FCB67FFE91900C762", singletonInitHash: