From 6d807f4451bec73ba072846adc361f4f44250a27 Mon Sep 17 00:00:00 2001 From: RanaBug Date: Mon, 17 Jun 2024 17:22:54 +0100 Subject: [PATCH 1/6] add modular sdk, update default sdk to modular sdk, add install and uninstall modules --- CHANGELOG.md | 13 ++ __mocks__/@etherspot/modular-sdk.js | 143 ++++++++++++++++++ .../EtherspotTokenTransferTransaction.test.js | 5 +- __tests__/hooks/useEtherspotModules.test.js | 76 ++++++++++ .../hooks/useEtherspotTransactions.test.js | 3 +- __tests__/hooks/useWalletAddress.test.js | 18 ++- example/src/App.tsx | 22 ++- package-lock.json | 24 ++- package.json | 3 +- rollup.config.js | 1 + src/components/EtherspotTransactionKit.tsx | 44 +++++- src/contexts/EtherspotContext.tsx | 6 +- src/hooks/useEtherspotBalances.ts | 4 +- src/hooks/useEtherspotHistory.ts | 4 +- src/hooks/useEtherspotModules.ts | 102 +++++++++++++ src/hooks/useEtherspotNfts.ts | 4 +- src/hooks/useEtherspotSwaps.ts | 8 +- src/hooks/useWalletAddress.ts | 8 +- src/index.ts | 1 + src/providers/EtherspotContextProvider.tsx | 81 ++++++++-- ...EtherspotTransactionKitContextProvider.tsx | 21 +-- src/types/EtherspotTransactionKit.ts | 3 +- 22 files changed, 536 insertions(+), 58 deletions(-) create mode 100644 __mocks__/@etherspot/modular-sdk.js create mode 100644 __tests__/hooks/useEtherspotModules.test.js create mode 100644 src/hooks/useEtherspotModules.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 51680fc..b785556 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## [0.13.0] - 2024-06-17 + +### Added Changes +- `getSDK` include a param to choose to instantiate the Prime SDK instead of the Modular SDK +- Added Etherspot Modular SDK `installModule` and `uninstallModule` to hook `useEtherspotModules` +- `EtherspotContextProvider` updated with choice of instantiatiating the Prime SDK or Modular SDK +- Added `isModular` to context `EtherspotContextProvider` +- + +### Breaking Changes +- Etherspot Modular SDK implemented to Transaction Kit as the default SDK +- The account template in the `EtherspotTransactionKit` component, can only be 'etherspot' if `moddular` is true. + ## [0.12.1] - 2024-05-22 ### Added Changes diff --git a/__mocks__/@etherspot/modular-sdk.js b/__mocks__/@etherspot/modular-sdk.js new file mode 100644 index 0000000..bed7755 --- /dev/null +++ b/__mocks__/@etherspot/modular-sdk.js @@ -0,0 +1,143 @@ +import * as EtherspotModular from '@etherspot/modular-sdk'; +import { ethers } from 'ethers'; + +export const defaultAccountAddress = '0x7F30B1960D5556929B03a0339814fE903c55a347'; +export const otherFactoryDefaultAccountAddress = '0xe383724e3bDC4753746dEC781809f8CD82010914'; +export const otherAccountAddress = '0xAb4C67d8D7B248B2fA6B638C645466065fE8F1F1'; + +export class ModularSdk { + sdkChainId; + userOps = []; + nonce = ethers.BigNumber.from(1); + factoryWallet; + + constructor(provider, config) { + this.sdkChainId = config.chainId; + this.factoryWallet = config.factoryWallet; + } + + getCounterFactualAddress() { + if (this.factoryWallet === Factory.ETHERSPOT) { + return defaultAccountAddress; + } + return otherFactoryDefaultAccountAddress; + } + + async clearUserOpsFromBatch() { + this.userOps = []; + } + + async addUserOpsToBatch(userOp) { + this.userOps.push(userOp); + } + + async estimate({ paymasterDetails: paymaster }) { + let maxFeePerGas = ethers.utils.parseUnits('1', 'gwei'); + let maxPriorityFeePerGas = ethers.utils.parseUnits('1', 'gwei'); + let callGasLimit = ethers.BigNumber.from('50000'); + let signature = '0x004'; + + if (paymaster?.url === 'someUrl') { + maxFeePerGas = ethers.utils.parseUnits('2', 'gwei'); + maxPriorityFeePerGas = ethers.utils.parseUnits('3', 'gwei'); + callGasLimit = ethers.BigNumber.from('75000'); + } + + if (paymaster?.url === 'someUnstableUrl') { + signature = '0x0'; + } + + let finalGasLimit = ethers.BigNumber.from(callGasLimit); + + if (this.sdkChainId === 420) { + throw new Error('Transaction reverted: chain too high'); + } + + this.userOps.forEach((userOp) => { + if (userOp.to === '0xDEADBEEF') { + throw new Error('Transaction reverted: invalid address'); + } + finalGasLimit = finalGasLimit.add(callGasLimit); + if (userOp.data && userOp.data !== '0x0' && userOp.data !== '0xFFF') { + finalGasLimit = finalGasLimit.add(callGasLimit); + } + }); + + return { + sender: defaultAccountAddress, + nonce: this.nonce, + initCode: '0x001', + callData: '0x002', + callGasLimit: finalGasLimit, + verificationGasLimit: ethers.BigNumber.from('25000'), + preVerificationGas: ethers.BigNumber.from('75000'), + maxFeePerGas, + maxPriorityFeePerGas, + paymasterAndData: '0x003', + signature, + }; + } + + totalGasEstimated({ callGasLimit, verificationGasLimit, preVerificationGas }) { + return callGasLimit.add(verificationGasLimit).add(preVerificationGas); + } + + async send(userOp) { + if (this.sdkChainId === 696969) { + throw new Error('Transaction reverted: chain too hot'); + } + + if (userOp.signature === '0x0') { + throw new Error('Transaction reverted: invalid signature'); + } + + /** + * provide fake userOp hash by increasing nonce on each send + * and add SDK chain ID to make it more unique per userOp + */ + const userOpHash = this.nonce.add(this.sdkChainId).toHexString(); + this.nonce = this.nonce.add(1); + + return userOpHash; + } + + async installModule(moduleType, module, initData, accountAddress) { + if (!accountAddress && !defaultAccountAddress) { + return 'No account address provided!' + } + + if (!moduleType || !module) { + return 'installModule props missing' + } + + if (module === '0x222') { + return 'module is already installed' + } + + return '0x123'; + } + + async uninstallModule(moduleType, module, deinitData, accountAddress) { + if (module === '0x222') { + return 'module is not installed' + } + + if (!accountAddress && !defaultAccountAddress) { + return 'No account address provided!' + } + + if (!moduleType || !module || !deinitData) { + return 'uninstallModule props missing' + } + + return '0x456'; + } +} + +export const isWalletProvider = EtherspotModular.isWalletProvider; + +export const Factory = EtherspotModular.Factory; + +export const EtherspotBundler = jest.fn(); + +export default EtherspotModular; diff --git a/__tests__/components/EtherspotTokenTransferTransaction.test.js b/__tests__/components/EtherspotTokenTransferTransaction.test.js index 7f6b05e..433b758 100644 --- a/__tests__/components/EtherspotTokenTransferTransaction.test.js +++ b/__tests__/components/EtherspotTokenTransferTransaction.test.js @@ -1,4 +1,5 @@ -import { renderHook, render, waitFor, act } from '@testing-library/react'; +import { renderHook, render, waitFor } from '@testing-library/react'; +import { act } from 'react'; import { ethers } from 'ethers'; import { useEtherspotTransactions, EtherspotTransactionKit, EtherspotBatches, EtherspotBatch, EtherspotTokenTransferTransaction } from '../../src'; @@ -24,7 +25,7 @@ describe('EtherspotTokenTransferTransaction', () => { it('throws error if wrong receiver address provided', async () => { await expect(async () => { - await act(() => { + await act(() => { render( diff --git a/__tests__/hooks/useEtherspotModules.test.js b/__tests__/hooks/useEtherspotModules.test.js new file mode 100644 index 0000000..ed8e489 --- /dev/null +++ b/__tests__/hooks/useEtherspotModules.test.js @@ -0,0 +1,76 @@ +import { renderHook, waitFor } from '@testing-library/react'; +import { ethers } from 'ethers'; + +// hooks +import { useEtherspotModules, EtherspotTransactionKit } from '../../src'; +import { MODULE_TYPE } from '@etherspot/modular-sdk/dist/sdk/common'; + +const ethersProvider = new ethers.providers.JsonRpcProvider('http://localhost:8545', 'sepolia'); // replace with your node's RPC URL +const provider = new ethers.Wallet.createRandom().connect(ethersProvider); + +const moduleAddress = '0x111'; +const initData = ethers.utils.defaultAbiCoder.encode( + ["address", "bytes"], + ['0x0000000000000000000000000000000000000001', '0x00'] + ); + const deInitData = ethers.utils.defaultAbiCoder.encode( + ["address", "bytes"], + ['0x0000000000000000000000000000000000000001', '0x00'] + ); + +describe('useEtherspotModules()', () => { + it('install one module', async () => { + const wrapper = ({ children }) => ( + + {children} + + ); + + const { result } = renderHook(({ chainId }) => useEtherspotModules(chainId), { + initialProps: { chainId: 1 }, + wrapper, + }); + + + // wait for balances to be fetched for chain ID 1 + await waitFor(() => expect(result.current).not.toBeNull()); + + const installOneModuleProps = await result.current.installModule(MODULE_TYPE.VALIDATOR); + expect(installOneModuleProps).toBe('installModule props missing') + + const installOneModuleAlreadyInstalled = await result.current.installModule(MODULE_TYPE.VALIDATOR, '0x222'); + expect(installOneModuleAlreadyInstalled).toBe('module is already installed') + + const installOneModule = await result.current.installModule(MODULE_TYPE.VALIDATOR, moduleAddress, initData); + expect(installOneModule).toBe('0x123') + }); + + it('uninstall one module', async () => { + const wrapper = ({ children }) => ( + + {children} + + ); + + const { result } = renderHook(({ chainId }) => useEtherspotModules(chainId), { + initialProps: { chainId: 1 }, + wrapper, + }); + + // wait for balances to be fetched for chain ID 1 + await waitFor(() => expect(result.current).not.toBeNull()); + + const uninstallOneModuleNotInstalled = await result.current.uninstallModule(MODULE_TYPE.VALIDATOR, '0x222', deInitData); + expect(uninstallOneModuleNotInstalled).toBe('module is not installed'); + + const installOneModule = await result.current.installModule(MODULE_TYPE.VALIDATOR, moduleAddress, initData); + expect(installOneModule).toBe('0x123'); + + const uninstallOneModuleProps = await result.current.uninstallModule(moduleAddress); + expect(uninstallOneModuleProps).toBe('uninstallModule props missing'); + + const uninstallOneModule = await result.current.uninstallModule(MODULE_TYPE.VALIDATOR, moduleAddress, deInitData); + expect(uninstallOneModule).toBe('0x456'); + + }); +}) diff --git a/__tests__/hooks/useEtherspotTransactions.test.js b/__tests__/hooks/useEtherspotTransactions.test.js index 28ae131..15a253f 100644 --- a/__tests__/hooks/useEtherspotTransactions.test.js +++ b/__tests__/hooks/useEtherspotTransactions.test.js @@ -1,4 +1,5 @@ -import { renderHook, render, act, waitFor } from '@testing-library/react'; +import { renderHook, render, waitFor } from '@testing-library/react'; +import { act } from 'react'; import { ethers } from 'ethers'; // hooks diff --git a/__tests__/hooks/useWalletAddress.test.js b/__tests__/hooks/useWalletAddress.test.js index 7d134ea..1f07aff 100644 --- a/__tests__/hooks/useWalletAddress.test.js +++ b/__tests__/hooks/useWalletAddress.test.js @@ -1,9 +1,13 @@ import { renderHook, waitFor } from '@testing-library/react'; import { ethers } from 'ethers'; +import { Factory as ModularFactory } from '@etherspot/modular-sdk'; import { Factory } from '@etherspot/prime-sdk'; // hooks import { EtherspotTransactionKit, useWalletAddress } from '../../src'; +import { + defaultAccountAddress as modularDefaultAccountAddress, +} from '../../__mocks__/@etherspot/modular-sdk'; import { defaultAccountAddress, otherFactoryDefaultAccountAddress, @@ -17,7 +21,7 @@ const providerWalletAddress = provider.address; describe('useWalletAddress()', () => { it('returns default type wallet address if no provided type', async () => { const wrapper = ({ children }) => ( - + {children} ); @@ -41,10 +45,10 @@ describe('useWalletAddress()', () => { }); await waitFor(() => expect(result.current).not.toBe(undefined)); - expect(result.current).toEqual(defaultAccountAddress); + expect(result.current).toEqual(modularDefaultAccountAddress); rerender({ providerType: 'provider' }); - await waitFor(() => expect(result.current).not.toBe(defaultAccountAddress)); + await waitFor(() => expect(result.current).not.toBe(modularDefaultAccountAddress)); expect(result.current).toEqual(providerWalletAddress); }); @@ -61,7 +65,7 @@ describe('useWalletAddress()', () => { }); await waitFor(() => expect(result.current).not.toBe(undefined)); - expect(result.current).toEqual(defaultAccountAddress); + expect(result.current).toEqual(modularDefaultAccountAddress); rerender({ providerType: 'whatever' }); await waitFor(() => expect(result.current).toBe(undefined)); @@ -69,19 +73,19 @@ describe('useWalletAddress()', () => { it('returns different wallet address when account template provided', async () => { const createWrapper = ({ accountTemplate } = {}) => ({ children }) => ( - + {children} ); - const { result: resultNoAccountTemplate } = renderHook(() => useWalletAddress(), { + const { result: resultNoAccountTemplate } = renderHook(() => useWalletAddress(undefined, undefined, false), { wrapper: createWrapper(), }); await waitFor(() => expect(resultNoAccountTemplate.current).not.toBe(undefined)); expect(resultNoAccountTemplate.current).toEqual(defaultAccountAddress); - const { result: resultWithAccountTemplate } = renderHook(() => useWalletAddress(), { + const { result: resultWithAccountTemplate } = renderHook(() => useWalletAddress(undefined, undefined, false), { wrapper: createWrapper({ accountTemplate: Factory.SIMPLE_ACCOUNT }), }); diff --git a/example/src/App.tsx b/example/src/App.tsx index d0e3ea8..016a687 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,3 +1,4 @@ +import { MODULE_TYPE } from '@etherspot/modular-sdk/dist/sdk/common'; import { EstimatedBatch, EtherspotBatch, @@ -8,6 +9,7 @@ import { useEtherspot, useEtherspotTransactions, useWalletAddress, + useEtherspotModules, } from '@etherspot/transaction-kit'; import TreeItem from '@mui/lab/TreeItem'; import TreeView from '@mui/lab/TreeView'; @@ -79,6 +81,7 @@ const App = () => { const { batches, estimate, send } = useEtherspotTransactions(); // eslint-disable-next-line @typescript-eslint/no-unused-vars const { getDataService, chainId: etherspotChainId } = useEtherspot(); + const { installModule, uninstallModule } = useEtherspotModules(); const [balancePerAddress, setBalancePerAddress] = useState({ [walletAddressByName.Alice]: '', [walletAddressByName.Bob]: '', @@ -154,6 +157,19 @@ const App = () => { setExpanded(batchesTreeViewExpandedIds); }; + const deInitData = ethers.utils.defaultAbiCoder.encode( + ["address", "bytes"], + ['0x0000000000000000000000000000000000000001', '0x00'] + ); + + const onInstallModuleClick = async () => { + await installModule(MODULE_TYPE.VALIDATOR, '0x6a00da4DEEf677Ad854B7c14F17Ed9312c2B5fDf'); + } + + const onUninstallModuleClick = async () => { + await uninstallModule(MODULE_TYPE.VALIDATOR, '0x6a00da4DEEf677Ad854B7c14F17Ed9312c2B5fDf', deInitData) + } + useEffect(() => { let expired = false; @@ -237,6 +253,8 @@ const App = () => { )} + + setActiveTab(id)}> @@ -290,7 +308,7 @@ const App = () => { {!!estimatedBatch?.cost && ( - Batch estimated: {ethers.utils.formatEther(estimatedBatch.cost)} MATIC + Batch estimated: {ethers.utils.formatEther(estimatedBatch.cost)} ETH )} {!!estimatedBatch?.errorMessage && ( @@ -324,7 +342,7 @@ const App = () => { key={transaction.treeNodeId} > To: {transaction.to} - Value: {transactionValue} MATIC + Value: {transactionValue} ETH Data: {transaction.data ?? 'None'} ); diff --git a/package-lock.json b/package-lock.json index ab55231..5c487da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,16 @@ { "name": "@etherspot/transaction-kit", - "version": "0.12.0", + "version": "0.12.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@etherspot/transaction-kit", - "version": "0.12.0", + "version": "0.12.1", "license": "MIT", "dependencies": { "@etherspot/eip1271-verification-util": "0.1.2", + "@etherspot/modular-sdk": "1.0.1", "@etherspot/prime-sdk": "1.8.1", "buffer": "^6.0.3", "ethers": "^5.6.9", @@ -2684,6 +2685,25 @@ } } }, + "node_modules/@etherspot/modular-sdk": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@etherspot/modular-sdk/-/modular-sdk-1.0.1.tgz", + "integrity": "sha512-NCAgsvJobfYmWhNs4GIzapvVLQGGdtGHvOJVMaFj1OFdIRTMoco1BqDC0H4fNoZK3zQPrGhVBGUUJSc7q1wQEA==", + "dependencies": { + "@lifi/sdk": "2.5.0", + "@thehubbleproject/bls": "0.5.1", + "@walletconnect/universal-provider": "2.10.0", + "buffer": "^6.0.3", + "class-transformer": "0.5.1", + "class-validator": "0.14.1", + "commander": "10.0.1", + "cross-fetch": "3.1.8", + "ethers": "5.7.2", + "prettier": "2.8.8", + "reflect-metadata": "0.1.14", + "rxjs": "6.6.7" + } + }, "node_modules/@etherspot/prime-sdk": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/@etherspot/prime-sdk/-/prime-sdk-1.8.1.tgz", diff --git a/package.json b/package.json index 3a53489..9cb6f0b 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "homepage": "https://github.com/etherspot/transaction-kit#readme", "dependencies": { "@etherspot/eip1271-verification-util": "0.1.2", + "@etherspot/modular-sdk": "1.0.1", "@etherspot/prime-sdk": "1.8.1", "buffer": "^6.0.3", "ethers": "^5.6.9", @@ -61,4 +62,4 @@ "peerDependencies": { "react": ">=16.13.0" } -} \ No newline at end of file +} diff --git a/rollup.config.js b/rollup.config.js index 154ed48..09a8347 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -10,6 +10,7 @@ const packageJson = require('./package.json'); const external = [ 'etherspot', '@etherspot/prime-sdk', + '@etherspot/modular-sdk', 'ethers', 'react', 'buffer', diff --git a/src/components/EtherspotTransactionKit.tsx b/src/components/EtherspotTransactionKit.tsx index 65ba599..feecd52 100644 --- a/src/components/EtherspotTransactionKit.tsx +++ b/src/components/EtherspotTransactionKit.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { WalletProviderLike, Factory } from '@etherspot/prime-sdk'; +import { WalletProviderLike as WalletProviderLikeModular, Factory as ModularFactory } from '@etherspot/modular-sdk'; // types import { AccountTemplate } from '../types/EtherspotTransactionKit'; @@ -10,27 +11,59 @@ import ProviderWalletContextProvider from '../providers/ProviderWalletContextPro import EtherspotContextProvider from '../providers/EtherspotContextProvider'; interface EtherspotTransactionKitProps extends React.PropsWithChildren { - provider: WalletProviderLike; + provider: WalletProviderLike | WalletProviderLikeModular; chainId?: number; accountTemplate?: AccountTemplate; dataApiKey?: string; bundlerApiKey?: string; + modular?: boolean; } const EtherspotTransactionKit = ({ children, provider, chainId = 1, - accountTemplate = Factory.ETHERSPOT, + accountTemplate, dataApiKey, bundlerApiKey, -}: EtherspotTransactionKitProps) => ( + modular = true, +}: EtherspotTransactionKitProps) => { + let accountTemp; + + if (accountTemplate) { + switch (accountTemplate) { + case 'zeroDev': + if (!modular) { + accountTemp = Factory.ZERO_DEV; + } else { + console.warn('You cannot use a ZeroDev Account template with the modular functionality.'); + } + break; + case 'simpleAccount': + if (!modular) { + accountTemp = Factory.SIMPLE_ACCOUNT; + } else { + console.warn('You cannot use a Simple Account template with the modular functionality.'); + } + break; + case 'etherspot': + accountTemp = modular ? ModularFactory.ETHERSPOT : Factory.ETHERSPOT; + break; + default: + console.warn('This account template cannot be used:', accountTemplate); + } + } else { + accountTemp = modular ? ModularFactory.ETHERSPOT : Factory.ETHERSPOT; + } + + return ( @@ -38,6 +71,7 @@ const EtherspotTransactionKit = ({ -); + ) +}; export default EtherspotTransactionKit; diff --git a/src/contexts/EtherspotContext.tsx b/src/contexts/EtherspotContext.tsx index 947bf8c..cb8b065 100644 --- a/src/contexts/EtherspotContext.tsx +++ b/src/contexts/EtherspotContext.tsx @@ -1,12 +1,14 @@ import { createContext } from 'react'; import { DataUtils, PrimeSdk, WalletProviderLike } from '@etherspot/prime-sdk'; +import { ModularSdk, WalletProviderLike as WalletProviderLikeModular } from '@etherspot/modular-sdk'; export interface EtherspotContextData { data: { - getSdk: (chainId?: number, forceNewInstance?: boolean) => Promise; + getSdk: (modular?: boolean, chainId?: number, forceNewInstance?: boolean) => Promise; getDataService: () => DataUtils; - provider: WalletProviderLike | null | undefined; + provider: WalletProviderLike | WalletProviderLikeModular | null | undefined; chainId: number; + isModular: boolean; } } diff --git a/src/hooks/useEtherspotBalances.ts b/src/hooks/useEtherspotBalances.ts index de947e2..0cca924 100644 --- a/src/hooks/useEtherspotBalances.ts +++ b/src/hooks/useEtherspotBalances.ts @@ -13,7 +13,7 @@ interface IEtherspotBalancesHook { * @param chainId {number | undefined} - Chain ID * @returns {IEtherspotBalancesHook} - hook method to fetch Etherspot account balances */ -const useEtherspotBalances = (chainId?: number): IEtherspotBalancesHook => { +const useEtherspotBalances = (chainId?: number, modular: boolean = true): IEtherspotBalancesHook => { const { getDataService, getSdk, chainId: etherspotChainId } = useEtherspot(); const defaultChainId = useMemo(() => { @@ -25,7 +25,7 @@ const useEtherspotBalances = (chainId?: number): IEtherspotBalancesHook => { accountAddress?: string, balancesChainId: number = defaultChainId, ) => { - const sdkForChainId = await getSdk(balancesChainId); + const sdkForChainId = await getSdk(modular, balancesChainId); const balancesForAccount = accountAddress ?? await sdkForChainId.getCounterFactualAddress(); if (!balancesForAccount) { diff --git a/src/hooks/useEtherspotHistory.ts b/src/hooks/useEtherspotHistory.ts index d689acf..1c61902 100644 --- a/src/hooks/useEtherspotHistory.ts +++ b/src/hooks/useEtherspotHistory.ts @@ -23,7 +23,7 @@ interface IEtherspotHistoryHook { * @param chainId {number | undefined} - Chain ID * @returns {IEtherspotHistoryHook} - hook methods to fetch Etherspot transactions history */ -const useEtherspotHistory = (chainId?: number): IEtherspotHistoryHook => { +const useEtherspotHistory = (chainId?: number, modular: boolean = true): IEtherspotHistoryHook => { const { getDataService, getSdk, chainId: etherspotChainId } = useEtherspot(); const defaultChainId = useMemo(() => { @@ -35,7 +35,7 @@ const useEtherspotHistory = (chainId?: number): IEtherspotHistoryHook => { accountAddress?: string, historyChainId: number = defaultChainId ): Promise => { - const sdkForChainId = await getSdk(historyChainId); + const sdkForChainId = await getSdk(modular, historyChainId); let transactions: UserOpTransaction[] = []; diff --git a/src/hooks/useEtherspotModules.ts b/src/hooks/useEtherspotModules.ts new file mode 100644 index 0000000..429dddb --- /dev/null +++ b/src/hooks/useEtherspotModules.ts @@ -0,0 +1,102 @@ +import { useMemo } from 'react'; + +// hooks +import useEtherspot from './useEtherspot'; + +// types +import { MODULE_TYPE } from '@etherspot/modular-sdk/dist/sdk/common'; +import { ModularSdk } from '@etherspot/modular-sdk'; + +interface IEtherspotModulesHook { + installModule: (moduleType: MODULE_TYPE, module: string, initData?: string, accountAddress?: string, chainId?: number) => Promise; + uninstallModule: (moduleType: MODULE_TYPE, module: string, deinitData: string, accountAddress?: string, chainId?: number) => Promise; +} + +/** + * Hook to fetch account balances + * @param chainId {number | undefined} - Chain ID + * @returns {IEtherspotModulesHook} - hook method to fetch Etherspot account balances + */ +const useEtherspotModules = (chainId?: number): IEtherspotModulesHook => { + const { getSdk, chainId: etherspotChainId, isModular } = useEtherspot(); + + const defaultChainId = useMemo(() => { + if (chainId) return chainId; + return etherspotChainId; + }, [chainId, etherspotChainId]); + + const installModule = async ( + moduleType: MODULE_TYPE, + module: string, + initData?: string, + accountAddress?: string, + modulesChainId: number = defaultChainId, + ) => { + // this hook can only be used is the sdk is using the modular functionality + if (!isModular) { + console.warn(`The component is not using the modular functionality. Please make sure to use the modular functionality to install and uninstall modules.`); + return ''; + } + + const sdkForChainId = await getSdk(isModular, modulesChainId) as ModularSdk; + + const modulesForAccount = accountAddress ?? await sdkForChainId.getCounterFactualAddress(); + if (!modulesForAccount) { + console.warn(`No account address provided!`); + return ''; + } + + try { + const getInstallModule = await sdkForChainId.installModule(moduleType, module, initData) + return getInstallModule; + } catch (e) { + console.warn( + `Sorry, an error occurred whilst trying to install the new module` + + ` ${module}` + + ` for ${modulesForAccount}. Please try again. Error:`, + e, + ); + return ''; + } + } + + const uninstallModule = async ( + moduleType: MODULE_TYPE, + module: string, + deinitData: string, + accountAddress?: string, + modulesChainId: number = defaultChainId, + ) => { + // this hook can only be used is the sdk is using the modular functionality + if (!isModular) { + console.warn(`The component is not using the modular functionality. Please make sure to use the modular functionality to install and uninstall modules.`); + return ''; + } + + const sdkForChainId = await getSdk(isModular, modulesChainId) as ModularSdk; + + const modulesForAccount = accountAddress ?? await sdkForChainId.getCounterFactualAddress(); + if (!modulesForAccount) { + console.warn(`No account address provided!`); + return ''; + } + + try { + const getUninstallModule = await sdkForChainId.uninstallModule(moduleType, module, deinitData); + return getUninstallModule; + } catch (e) { + console.warn( + `Sorry, an error occurred whilst trying to uninstall the module` + + ` ${module}` + + ` for ${modulesForAccount}. Please try again. Error:`, + e, + ); + return ''; + } + } + + return { installModule, uninstallModule }; +}; + +export default useEtherspotModules; + diff --git a/src/hooks/useEtherspotNfts.ts b/src/hooks/useEtherspotNfts.ts index 9b3c7ca..41aba96 100644 --- a/src/hooks/useEtherspotNfts.ts +++ b/src/hooks/useEtherspotNfts.ts @@ -13,7 +13,7 @@ interface IEtherspotNftsHook { * @param chainId {number | undefined} - Chain ID * @returns {IEtherspotNftsHook} - hook methods to fetch Etherspot account NFTs */ -const useEtherspotNfts = (chainId?: number): IEtherspotNftsHook => { +const useEtherspotNfts = (chainId?: number, modular: boolean = true): IEtherspotNftsHook => { const { getDataService, getSdk, chainId: etherspotChainId } = useEtherspot(); const defaultChainId = useMemo(() => { @@ -25,7 +25,7 @@ const useEtherspotNfts = (chainId?: number): IEtherspotNftsHook => { accountAddress?: string, nftsChainId: number = defaultChainId, ) => { - const sdkForChainId = await getSdk(nftsChainId); + const sdkForChainId = await getSdk(modular, nftsChainId); const nftsForAccount = accountAddress ?? await sdkForChainId.getCounterFactualAddress(); if (!nftsForAccount) { diff --git a/src/hooks/useEtherspotSwaps.ts b/src/hooks/useEtherspotSwaps.ts index 46d10e7..0608412 100644 --- a/src/hooks/useEtherspotSwaps.ts +++ b/src/hooks/useEtherspotSwaps.ts @@ -39,7 +39,7 @@ interface IEtherspotSwapsHook { * @param chainId {number | undefined} - Source Chain ID * @returns {IEtherspotSwapsHook} - hook method to fetch Etherspot aggregated offers for same-chain and cross-chain swaps */ -const useEtherspotSwaps = (chainId?: number): IEtherspotSwapsHook => { +const useEtherspotSwaps = (chainId?: number, modular: boolean = true): IEtherspotSwapsHook => { const { getDataService, getSdk, chainId: defaultChainId } = useEtherspot(); const swapsChainId = useMemo(() => { @@ -51,7 +51,7 @@ const useEtherspotSwaps = (chainId?: number): IEtherspotSwapsHook => { offer: Route, accountAddress?: string ): Promise => { - const sdkForChainId = await getSdk(swapsChainId); + const sdkForChainId = await getSdk(modular, swapsChainId); const forAccount = accountAddress ?? (await sdkForChainId.getCounterFactualAddress()); if (!forAccount) { @@ -81,7 +81,7 @@ const useEtherspotSwaps = (chainId?: number): IEtherspotSwapsHook => { toChainId?: number, fromAccountAddress?: string ): Promise => { - const sdkForChainId = await getSdk(swapsChainId); + const sdkForChainId = await getSdk(modular, swapsChainId); const fromAccount = fromAccountAddress ?? (await sdkForChainId.getCounterFactualAddress()); if (!fromAccount) { @@ -138,7 +138,7 @@ const useEtherspotSwaps = (chainId?: number): IEtherspotSwapsHook => { fromAccountAddress?: string, provider?: BridgingProvider ): Promise => { - const sdkForChainId = await getSdk(swapsChainId); + const sdkForChainId = await getSdk(modular, swapsChainId); const fromAccount = fromAccountAddress ?? (await sdkForChainId.getCounterFactualAddress()); if (!fromAccount) { diff --git a/src/hooks/useWalletAddress.ts b/src/hooks/useWalletAddress.ts index 02ece24..53ad00b 100644 --- a/src/hooks/useWalletAddress.ts +++ b/src/hooks/useWalletAddress.ts @@ -12,7 +12,7 @@ import useEtherspot from './useEtherspot'; * @param chainId {number} - Chain ID * @returns {string | undefined} - wallet address by its type */ -const useWalletAddress = (walletType: IWalletType = 'etherspot-prime', chainId?: number): string | undefined => { +const useWalletAddress = (walletType: IWalletType = 'etherspot-prime', chainId?: number, modular: boolean = true): string | undefined => { const [accountAddress, setAccountAddress] = useState<(string | undefined)>(undefined); const { getSdk, chainId: defaultChainId, provider } = useEtherspot(); @@ -25,7 +25,7 @@ const useWalletAddress = (walletType: IWalletType = 'etherspot-prime', chainId?: let shouldUpdate = true; const updateAccountAddress = async () => { - const etherspotPrimeSdk = await getSdk(walletAddressChainId); + const etherspotModularOrPrimeSdk = await getSdk(modular, walletAddressChainId); let newAccountAddress; @@ -35,7 +35,7 @@ const useWalletAddress = (walletType: IWalletType = 'etherspot-prime', chainId?: * Reference – https://github.com/etherspot/etherspot-prime-sdk/blob/master/src/sdk/sdk.ts#L31 */ // @ts-ignore - newAccountAddress = etherspotPrimeSdk?.etherspotWallet?.accountAddress; + newAccountAddress = etherspotModularOrPrimeSdk?.etherspotWallet?.accountAddress; } catch (e) { console.warn(`Unable to get wallet address from SDK state for etherspot-prime type for chainId ID ${walletAddressChainId}.`, e); } @@ -43,7 +43,7 @@ const useWalletAddress = (walletType: IWalletType = 'etherspot-prime', chainId?: // if were unable to get wallet address from SDK state, try to get using getCounterFactualAddress if (!newAccountAddress) { try { - newAccountAddress = await etherspotPrimeSdk.getCounterFactualAddress(); + newAccountAddress = await etherspotModularOrPrimeSdk.getCounterFactualAddress(); } catch (e) { console.warn(`Unable to get wallet address for etherspot-prime type for chainId ID ${walletAddressChainId}.`, e); } diff --git a/src/index.ts b/src/index.ts index c087ac4..dd1df53 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,6 +21,7 @@ export { default as useEtherspotPrices } from './hooks/useEtherspotPrices'; export { default as useEtherspotSwaps } from './hooks/useEtherspotSwaps'; export { default as useWalletAddress } from './hooks/useWalletAddress'; export { default as useEtherspot } from './hooks/useEtherspot'; +export { default as useEtherspotModules } from './hooks/useEtherspotModules'; export * from './types/EtherspotTransactionKit'; diff --git a/src/providers/EtherspotContextProvider.tsx b/src/providers/EtherspotContextProvider.tsx index 28bfed6..f69c400 100644 --- a/src/providers/EtherspotContextProvider.tsx +++ b/src/providers/EtherspotContextProvider.tsx @@ -15,6 +15,7 @@ import React, { useMemo, } from 'react'; import isEqual from 'lodash/isEqual'; +import { ModularSdk, WalletProviderLike as WalletProviderLikeModular, isWalletProvider as isWalletProviderModular, Web3WalletProvider as Web3WalletModularProvider, EtherspotBundler as EtherspotBundlerModular, Factory as FactoryModular } from '@etherspot/modular-sdk'; // contexts import EtherspotContext from '../contexts/EtherspotContext'; @@ -28,6 +29,9 @@ let prevAccountTemplate: AccountTemplate | undefined; let dataService: DataUtils; +let sdkPerChainModular: { [chainId: number]: ModularSdk | Promise } = {}; +let prevProviderModular: WalletProviderLikeModular; + const EtherspotContextProvider = ({ children, provider, @@ -35,13 +39,15 @@ const EtherspotContextProvider = ({ accountTemplate, dataApiKey, bundlerApiKey, + isModular, }: { children: ReactNode; - provider: WalletProviderLike; + provider: WalletProviderLike | WalletProviderLikeModular; chainId: number; accountTemplate?: AccountTemplate; dataApiKey?: string; bundlerApiKey?: string; + isModular: boolean; }) => { const context = useContext(EtherspotContext); @@ -53,24 +59,31 @@ const EtherspotContextProvider = ({ return () => { // reset on unmount sdkPerChain = {}; + sdkPerChainModular = {}; } }, []); - const getSdk = useCallback(async (sdkChainId: number = chainId, forceNewInstance: boolean = false) => { - const accountTemplateOrProviderChanged = (prevProvider && !isEqual(prevProvider, provider)) + const getSdk = useCallback(async (modular: boolean = isModular, sdkChainId: number = chainId, forceNewInstance: boolean = false) => { + if (modular) { + + const accountTemplateOrProviderChanged = (prevProvider && !isEqual(prevProviderModular, provider as WalletProviderLikeModular)) || (prevAccountTemplate && prevAccountTemplate !== accountTemplate); + + if (sdkPerChainModular[sdkChainId] && !forceNewInstance && !accountTemplateOrProviderChanged) { + return sdkPerChainModular[sdkChainId]; + } - if (sdkPerChain[sdkChainId] && !forceNewInstance && !accountTemplateOrProviderChanged) { - return sdkPerChain[sdkChainId]; - } + if (accountTemplate !== 'etherspot') { + throw new Error('Invalid account template: to use the modular functionality you must use the etherspot account template'); + } - sdkPerChain[sdkChainId] = (async () => { + sdkPerChainModular[sdkChainId] = (async () => { let mappedProvider; - if (!isWalletProvider(provider)) { + if (!isWalletProviderModular(provider as WalletProviderLikeModular)) { try { // @ts-ignore - mappedProvider = new Web3WalletProvider(provider); + mappedProvider = new Web3WalletModularProvider(provider as WalletProviderLikeModular); await mappedProvider.refresh(); } catch (e) { // no need to log, this is an attempt @@ -81,7 +94,50 @@ const EtherspotContextProvider = ({ } } - const etherspotPrimeSdk = new PrimeSdk(mappedProvider ?? provider, { + const etherspotModularSdk = new ModularSdk(mappedProvider as Web3WalletModularProvider ?? provider as WalletProviderLikeModular, { + chainId: +sdkChainId, + bundlerProvider: new EtherspotBundlerModular(+sdkChainId, bundlerApiKey ?? ('__ETHERSPOT_BUNDLER_API_KEY__' || undefined)), + factoryWallet: accountTemplate as FactoryModular, + }); + + // load the address into SDK state + await etherspotModularSdk.getCounterFactualAddress(); + + prevProviderModular = provider as WalletProviderLikeModular; + prevAccountTemplate = accountTemplate; + + return etherspotModularSdk; + })(); + + return sdkPerChainModular[sdkChainId]; + + } else { + + const accountTemplateOrProviderChanged = (prevProvider && !isEqual(prevProvider, provider as WalletProviderLike)) + || (prevAccountTemplate && prevAccountTemplate !== accountTemplate); + + if (sdkPerChain[sdkChainId] && !forceNewInstance && !accountTemplateOrProviderChanged) { + return sdkPerChain[sdkChainId]; + } + + sdkPerChain[sdkChainId] = (async () => { + let mappedProvider; + + if (!isWalletProvider(provider as WalletProviderLike)) { + try { + // @ts-ignore + mappedProvider = new Web3WalletProvider(provider as WalletProviderLike); + await mappedProvider.refresh(); + } catch (e) { + // no need to log, this is an attempt + } + + if (!mappedProvider) { + throw new Error('Invalid provider!'); + } + } + + const etherspotPrimeSdk = new PrimeSdk(mappedProvider as Web3WalletProvider ?? provider as WalletProviderLike, { chainId: +sdkChainId, bundlerProvider: new EtherspotBundler(+sdkChainId, bundlerApiKey ?? ('__ETHERSPOT_BUNDLER_API_KEY__' || undefined)), factoryWallet: accountTemplate as Factory, @@ -90,13 +146,14 @@ const EtherspotContextProvider = ({ // load the address into SDK state await etherspotPrimeSdk.getCounterFactualAddress(); - prevProvider = provider; + prevProvider = provider as WalletProviderLike; prevAccountTemplate = accountTemplate; return etherspotPrimeSdk; })(); return sdkPerChain[sdkChainId]; + } }, [provider, chainId, accountTemplate, bundlerApiKey]); const getDataService = useCallback(() => { @@ -110,11 +167,13 @@ const EtherspotContextProvider = ({ getDataService, provider, chainId, + isModular, }), [ getSdk, getDataService, provider, chainId, + isModular, ]); return ( diff --git a/src/providers/EtherspotTransactionKitContextProvider.tsx b/src/providers/EtherspotTransactionKitContextProvider.tsx index 8950a12..a49728c 100644 --- a/src/providers/EtherspotTransactionKitContextProvider.tsx +++ b/src/providers/EtherspotTransactionKitContextProvider.tsx @@ -33,6 +33,7 @@ const EtherspotTransactionKitContextProvider = ({ children }: EtherspotTransacti const estimate = async ( batchesIds?: string[], + modular: boolean = true, forSending: boolean = false, ): Promise => { if (!forSending) { @@ -65,17 +66,17 @@ const EtherspotTransactionKitContextProvider = ({ children }: EtherspotTransacti } // force new instance for each batch to not mix up user ops added to SDK state batch - const etherspotPrimeSdk = await getSdk(batchChainId, true); + const etherspotModularOrPrimeSdk = await getSdk(modular, batchChainId, true); try { - if (!forSending) await etherspotPrimeSdk.clearUserOpsFromBatch(); + if (!forSending) await etherspotModularOrPrimeSdk.clearUserOpsFromBatch(); await Promise.all(batch.transactions.map(async ({ to, value, data }) => { - await etherspotPrimeSdk.addUserOpsToBatch(({ to, value, data })); + await etherspotModularOrPrimeSdk.addUserOpsToBatch(({ to, value, data })); })); - const userOp = await etherspotPrimeSdk.estimate({ paymasterDetails: groupedBatch.paymaster }); - const totalGas = await etherspotPrimeSdk.totalGasEstimated(userOp); + const userOp = await etherspotModularOrPrimeSdk.estimate({ paymasterDetails: groupedBatch.paymaster }); + const totalGas = await etherspotModularOrPrimeSdk.totalGasEstimated(userOp); estimatedBatches.push({ ...batch, cost: totalGas.mul(userOp.maxFeePerGas as BigNumber), userOp }); } catch (e) { const errorMessage = parseEtherspotErrorMessage(e, 'Failed to estimate!'); @@ -97,7 +98,7 @@ const EtherspotTransactionKitContextProvider = ({ children }: EtherspotTransacti return result; } - const send = async (batchesIds?: string[]): Promise => { + const send = async (batchesIds?: string[], modular: boolean = true): Promise => { setIsSending(true); setContainsSendingError(false); @@ -110,9 +111,9 @@ const EtherspotTransactionKitContextProvider = ({ children }: EtherspotTransacti }) => Promise.all(batches.map(async (batch) => { const batchChainId = batch.chainId ?? chainId; - const etherspotPrimeSdk = await getSdk(batchChainId); + const etherspotModularOrPrimeSdk = await getSdk(modular, batchChainId); - await etherspotPrimeSdk.clearUserOpsFromBatch(); + await etherspotModularOrPrimeSdk.clearUserOpsFromBatch(); })))); const estimated = await estimate(batchesIds, true); @@ -130,7 +131,7 @@ const EtherspotTransactionKitContextProvider = ({ children }: EtherspotTransacti continue; } - const etherspotPrimeSdk = await getSdk(batchChainId); + const etherspotModularOrPrimeSdk = await getSdk(modular, batchChainId); if (!estimatedBatch.userOp) { sentBatches.push({ ...estimatedBatch, errorMessage: 'Failed to get estimated UserOp!' }); @@ -138,7 +139,7 @@ const EtherspotTransactionKitContextProvider = ({ children }: EtherspotTransacti } try { - const userOpHash = await etherspotPrimeSdk.send(estimatedBatch.userOp); + const userOpHash = await etherspotModularOrPrimeSdk.send(estimatedBatch.userOp); sentBatches.push({ ...estimatedBatch, userOpHash }); } catch (e) { const errorMessage = parseEtherspotErrorMessage(e, 'Failed to send!'); diff --git a/src/types/EtherspotTransactionKit.ts b/src/types/EtherspotTransactionKit.ts index ff85e85..0a1b97b 100644 --- a/src/types/EtherspotTransactionKit.ts +++ b/src/types/EtherspotTransactionKit.ts @@ -4,6 +4,7 @@ import { Route } from '@lifi/types'; import { PaymasterApi } from '@etherspot/prime-sdk'; import { ExchangeOffer } from '@etherspot/prime-sdk/dist/sdk/data'; import { TransactionStatuses } from '@etherspot/prime-sdk/dist/sdk/data/constants'; +import { PaymasterApi as PaymasterApiModular } from '@etherspot/modular-sdk'; export interface ITransaction { id?: string; @@ -43,7 +44,7 @@ export interface IBatches { onEstimated?: (estimated: EstimatedBatch[]) => void; onSent?: (sent: SentBatch[]) => void; skip?: boolean; - paymaster?: PaymasterApi, + paymaster?: PaymasterApi | PaymasterApiModular, } export type IEstimatedBatches = IBatches & { From 1cada862a34d358868c37a1ac8e1ee3129330ad1 Mon Sep 17 00:00:00 2001 From: RanaBug Date: Mon, 17 Jun 2024 17:30:00 +0100 Subject: [PATCH 2/6] minor fix --- CHANGELOG.md | 1 - __tests__/hooks/useWalletAddress.test.js | 1 - 2 files changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b785556..90435bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,6 @@ - Added Etherspot Modular SDK `installModule` and `uninstallModule` to hook `useEtherspotModules` - `EtherspotContextProvider` updated with choice of instantiatiating the Prime SDK or Modular SDK - Added `isModular` to context `EtherspotContextProvider` -- ### Breaking Changes - Etherspot Modular SDK implemented to Transaction Kit as the default SDK diff --git a/__tests__/hooks/useWalletAddress.test.js b/__tests__/hooks/useWalletAddress.test.js index 1f07aff..4be5a5a 100644 --- a/__tests__/hooks/useWalletAddress.test.js +++ b/__tests__/hooks/useWalletAddress.test.js @@ -1,6 +1,5 @@ import { renderHook, waitFor } from '@testing-library/react'; import { ethers } from 'ethers'; -import { Factory as ModularFactory } from '@etherspot/modular-sdk'; import { Factory } from '@etherspot/prime-sdk'; // hooks From bef96fea62cef85a50fc8d5ae0f31aa545dff812 Mon Sep 17 00:00:00 2001 From: RanaBug Date: Mon, 17 Jun 2024 17:31:01 +0100 Subject: [PATCH 3/6] updated version in package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9cb6f0b..ed88d16 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@etherspot/transaction-kit", "description": "React Etherspot Transaction Kit", - "version": "0.12.1", + "version": "0.13.0", "main": "dist/cjs/index.js", "scripts": { "rollup:build": "NODE_OPTIONS=--max-old-space-size=8192 rollup -c", From 041206d4e8cf04c09f53339f1a031bf9e72e4c66 Mon Sep 17 00:00:00 2001 From: RanaBug Date: Tue, 18 Jun 2024 15:01:57 +0100 Subject: [PATCH 4/6] update of accountTemplate indicating if the modular or prime sdk should be used, updated tests --- CHANGELOG.md | 3 +- __mocks__/@etherspot/modular-sdk.js | 30 +++++------ __tests__/hooks/useEtherspotModules.test.js | 37 +++++++++---- __tests__/hooks/useWalletAddress.test.js | 18 +++---- example/src/App.tsx | 6 ++- package-lock.json | 4 +- src/components/EtherspotTransactionKit.tsx | 53 ++++++++----------- src/contexts/EtherspotContext.tsx | 2 +- src/hooks/useEtherspotBalances.ts | 4 +- src/hooks/useEtherspotHistory.ts | 4 +- src/hooks/useEtherspotModules.ts | 24 ++++----- src/hooks/useEtherspotNfts.ts | 4 +- src/hooks/useEtherspotSwaps.ts | 8 +-- src/hooks/useWalletAddress.ts | 4 +- src/providers/EtherspotContextProvider.tsx | 14 +++-- ...EtherspotTransactionKitContextProvider.tsx | 9 ++-- src/types/EtherspotTransactionKit.ts | 2 +- 17 files changed, 114 insertions(+), 112 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90435bc..f320909 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,10 @@ ### Added Changes - `getSDK` include a param to choose to instantiate the Prime SDK instead of the Modular SDK - Added Etherspot Modular SDK `installModule` and `uninstallModule` to hook `useEtherspotModules` -- `EtherspotContextProvider` updated with choice of instantiatiating the Prime SDK or Modular SDK - Added `isModular` to context `EtherspotContextProvider` ### Breaking Changes -- Etherspot Modular SDK implemented to Transaction Kit as the default SDK +- Etherspot Modular SDK implemented to Transaction Kit as the default `accountTemplate` - The account template in the `EtherspotTransactionKit` component, can only be 'etherspot' if `moddular` is true. ## [0.12.1] - 2024-05-22 diff --git a/__mocks__/@etherspot/modular-sdk.js b/__mocks__/@etherspot/modular-sdk.js index bed7755..e9a97b6 100644 --- a/__mocks__/@etherspot/modular-sdk.js +++ b/__mocks__/@etherspot/modular-sdk.js @@ -1,9 +1,9 @@ import * as EtherspotModular from '@etherspot/modular-sdk'; import { ethers } from 'ethers'; -export const defaultAccountAddress = '0x7F30B1960D5556929B03a0339814fE903c55a347'; -export const otherFactoryDefaultAccountAddress = '0xe383724e3bDC4753746dEC781809f8CD82010914'; -export const otherAccountAddress = '0xAb4C67d8D7B248B2fA6B638C645466065fE8F1F1'; +export const defaultAccountAddressModular = '0x7F30B1960D5556929B03a0339814fE903c55a347'; +export const otherFactoryDefaultAccountAddressModular = '0xe383724e3bDC4753746dEC781809f8CD82010914'; +export const otherAccountAddressModular = '0xAb4C67d8D7B248B2fA6B638C645466065fE8F1F1'; export class ModularSdk { sdkChainId; @@ -17,10 +17,10 @@ export class ModularSdk { } getCounterFactualAddress() { - if (this.factoryWallet === Factory.ETHERSPOT) { - return defaultAccountAddress; + if (this.factoryWallet === 'etherspotModular') { + return defaultAccountAddressModular; } - return otherFactoryDefaultAccountAddress; + return otherFactoryDefaultAccountAddressModular; } async clearUserOpsFromBatch() { @@ -64,7 +64,7 @@ export class ModularSdk { }); return { - sender: defaultAccountAddress, + sender: defaultAccountAddressModular, nonce: this.nonce, initCode: '0x001', callData: '0x002', @@ -102,16 +102,16 @@ export class ModularSdk { } async installModule(moduleType, module, initData, accountAddress) { - if (!accountAddress && !defaultAccountAddress) { - return 'No account address provided!' + if (!accountAddress && !defaultAccountAddressModular) { + throw new Error('No account address provided!') } if (!moduleType || !module) { - return 'installModule props missing' + throw new Error('installModule props missing') } if (module === '0x222') { - return 'module is already installed' + throw new Error('module is already installed') } return '0x123'; @@ -119,15 +119,15 @@ export class ModularSdk { async uninstallModule(moduleType, module, deinitData, accountAddress) { if (module === '0x222') { - return 'module is not installed' + throw new Error('module is not installed') } - if (!accountAddress && !defaultAccountAddress) { - return 'No account address provided!' + if (!accountAddress && !defaultAccountAddressModular) { + throw new Error('No account address provided!') } if (!moduleType || !module || !deinitData) { - return 'uninstallModule props missing' + throw new Error('uninstallModule props missing') } return '0x456'; diff --git a/__tests__/hooks/useEtherspotModules.test.js b/__tests__/hooks/useEtherspotModules.test.js index ed8e489..40c1ce0 100644 --- a/__tests__/hooks/useEtherspotModules.test.js +++ b/__tests__/hooks/useEtherspotModules.test.js @@ -35,11 +35,20 @@ describe('useEtherspotModules()', () => { // wait for balances to be fetched for chain ID 1 await waitFor(() => expect(result.current).not.toBeNull()); - const installOneModuleProps = await result.current.installModule(MODULE_TYPE.VALIDATOR); - expect(installOneModuleProps).toBe('installModule props missing') + const installModuleMissingProps = await result.current.installModule(MODULE_TYPE.VALIDATOR) + .catch((e) => { + console.error(e); + return `${e}` + }) + expect(installModuleMissingProps).toBe('Error: Failed to install module: Error: installModule props missing'); - const installOneModuleAlreadyInstalled = await result.current.installModule(MODULE_TYPE.VALIDATOR, '0x222'); - expect(installOneModuleAlreadyInstalled).toBe('module is already installed') + const installModuleAlreadyInstalled = await result.current.installModule(MODULE_TYPE.VALIDATOR, '0x222') + .catch((e) => { + console.error(e); + return `${e}` + }) + + expect(installModuleAlreadyInstalled).toBe('Error: Failed to install module: Error: module is already installed'); const installOneModule = await result.current.installModule(MODULE_TYPE.VALIDATOR, moduleAddress, initData); expect(installOneModule).toBe('0x123') @@ -60,15 +69,25 @@ describe('useEtherspotModules()', () => { // wait for balances to be fetched for chain ID 1 await waitFor(() => expect(result.current).not.toBeNull()); - const uninstallOneModuleNotInstalled = await result.current.uninstallModule(MODULE_TYPE.VALIDATOR, '0x222', deInitData); - expect(uninstallOneModuleNotInstalled).toBe('module is not installed'); + const uninstallModuleNotInstalled = await result.current.uninstallModule(MODULE_TYPE.VALIDATOR, '0x222', deInitData) + .catch((e) => { + console.error(e); + return `${e}` + }) + + expect(uninstallModuleNotInstalled).toBe('Error: Failed to uninstall module: Error: module is not installed'); const installOneModule = await result.current.installModule(MODULE_TYPE.VALIDATOR, moduleAddress, initData); expect(installOneModule).toBe('0x123'); - const uninstallOneModuleProps = await result.current.uninstallModule(moduleAddress); - expect(uninstallOneModuleProps).toBe('uninstallModule props missing'); - + const uninstallModulePropsMissing = await result.current.uninstallModule(moduleAddress) + .catch((e) => { + console.error(e); + return `${e}` + }) + expect(uninstallModulePropsMissing).toBe('Error: Failed to uninstall module: Error: uninstallModule props missing'); + + const uninstallOneModule = await result.current.uninstallModule(MODULE_TYPE.VALIDATOR, moduleAddress, deInitData); expect(uninstallOneModule).toBe('0x456'); diff --git a/__tests__/hooks/useWalletAddress.test.js b/__tests__/hooks/useWalletAddress.test.js index 4be5a5a..f011dd3 100644 --- a/__tests__/hooks/useWalletAddress.test.js +++ b/__tests__/hooks/useWalletAddress.test.js @@ -5,7 +5,7 @@ import { Factory } from '@etherspot/prime-sdk'; // hooks import { EtherspotTransactionKit, useWalletAddress } from '../../src'; import { - defaultAccountAddress as modularDefaultAccountAddress, + defaultAccountAddressModular, } from '../../__mocks__/@etherspot/modular-sdk'; import { defaultAccountAddress, @@ -20,7 +20,7 @@ const providerWalletAddress = provider.address; describe('useWalletAddress()', () => { it('returns default type wallet address if no provided type', async () => { const wrapper = ({ children }) => ( - + {children} ); @@ -44,10 +44,10 @@ describe('useWalletAddress()', () => { }); await waitFor(() => expect(result.current).not.toBe(undefined)); - expect(result.current).toEqual(modularDefaultAccountAddress); + expect(result.current).toEqual(defaultAccountAddressModular); rerender({ providerType: 'provider' }); - await waitFor(() => expect(result.current).not.toBe(modularDefaultAccountAddress)); + await waitFor(() => expect(result.current).not.toBe(defaultAccountAddressModular)); expect(result.current).toEqual(providerWalletAddress); }); @@ -64,7 +64,7 @@ describe('useWalletAddress()', () => { }); await waitFor(() => expect(result.current).not.toBe(undefined)); - expect(result.current).toEqual(modularDefaultAccountAddress); + expect(result.current).toEqual(defaultAccountAddressModular); rerender({ providerType: 'whatever' }); await waitFor(() => expect(result.current).toBe(undefined)); @@ -72,19 +72,19 @@ describe('useWalletAddress()', () => { it('returns different wallet address when account template provided', async () => { const createWrapper = ({ accountTemplate } = {}) => ({ children }) => ( - + {children} ); - const { result: resultNoAccountTemplate } = renderHook(() => useWalletAddress(undefined, undefined, false), { + const { result: resultNoAccountTemplate } = renderHook(() => useWalletAddress(), { wrapper: createWrapper(), }); await waitFor(() => expect(resultNoAccountTemplate.current).not.toBe(undefined)); - expect(resultNoAccountTemplate.current).toEqual(defaultAccountAddress); + expect(resultNoAccountTemplate.current).toEqual(defaultAccountAddressModular); - const { result: resultWithAccountTemplate } = renderHook(() => useWalletAddress(undefined, undefined, false), { + const { result: resultWithAccountTemplate } = renderHook(() => useWalletAddress(), { wrapper: createWrapper({ accountTemplate: Factory.SIMPLE_ACCOUNT }), }); diff --git a/example/src/App.tsx b/example/src/App.tsx index 016a687..7a55607 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -29,6 +29,8 @@ const tabs = { MULTIPLE_TRANSACTIONS: 'MULTIPLE_TRANSACTIONS', }; +const testModuleSepoliaTestnet = '0x6a00da4DEEf677Ad854B7c14F17Ed9312c2B5fDf'; + const CodePreview = ({ code }: { code: string }) => (
@@ -163,11 +165,11 @@ const App = () => {
   );
 
   const onInstallModuleClick = async () => {
-    await installModule(MODULE_TYPE.VALIDATOR, '0x6a00da4DEEf677Ad854B7c14F17Ed9312c2B5fDf');
+    await installModule(MODULE_TYPE.VALIDATOR, testModuleSepoliaTestnet);
   }
 
   const onUninstallModuleClick = async () => {
-    await uninstallModule(MODULE_TYPE.VALIDATOR, '0x6a00da4DEEf677Ad854B7c14F17Ed9312c2B5fDf', deInitData)
+    await uninstallModule(MODULE_TYPE.VALIDATOR, testModuleSepoliaTestnet, deInitData)
   }
 
   useEffect(() => {
diff --git a/package-lock.json b/package-lock.json
index 5c487da..badc4a9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "@etherspot/transaction-kit",
-  "version": "0.12.1",
+  "version": "0.13.0",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "@etherspot/transaction-kit",
-      "version": "0.12.1",
+      "version": "0.13.0",
       "license": "MIT",
       "dependencies": {
         "@etherspot/eip1271-verification-util": "0.1.2",
diff --git a/src/components/EtherspotTransactionKit.tsx b/src/components/EtherspotTransactionKit.tsx
index feecd52..f09f7fa 100644
--- a/src/components/EtherspotTransactionKit.tsx
+++ b/src/components/EtherspotTransactionKit.tsx
@@ -1,6 +1,6 @@
 import React from 'react';
-import { WalletProviderLike, Factory } from '@etherspot/prime-sdk';
-import { WalletProviderLike as WalletProviderLikeModular, Factory as ModularFactory } from '@etherspot/modular-sdk';
+import { WalletProviderLike } from '@etherspot/prime-sdk';
+import { WalletProviderLike as WalletProviderLikeModular} from '@etherspot/modular-sdk';
 
 // types
 import { AccountTemplate } from '../types/EtherspotTransactionKit';
@@ -9,14 +9,12 @@ import { AccountTemplate } from '../types/EtherspotTransactionKit';
 import EtherspotTransactionKitContextProvider from '../providers/EtherspotTransactionKitContextProvider';
 import ProviderWalletContextProvider from '../providers/ProviderWalletContextProvider';
 import EtherspotContextProvider from '../providers/EtherspotContextProvider';
-
 interface EtherspotTransactionKitProps extends React.PropsWithChildren {
   provider: WalletProviderLike | WalletProviderLikeModular;
   chainId?: number;
   accountTemplate?: AccountTemplate;
   dataApiKey?: string;
   bundlerApiKey?: string;
-  modular?: boolean;
 }
 
 const EtherspotTransactionKit = ({
@@ -26,36 +24,27 @@ const EtherspotTransactionKit = ({
   accountTemplate,
   dataApiKey,
   bundlerApiKey,
-  modular = true,
 }: EtherspotTransactionKitProps) => {
-  let accountTemp;
+  let accountTemp: AccountTemplate;
 
-  if (accountTemplate) {
-    switch (accountTemplate) {
-      case 'zeroDev':
-        if (!modular) {
-          accountTemp = Factory.ZERO_DEV;
-        } else {
-          console.warn('You cannot use a ZeroDev Account template with the modular functionality.');
-        }
-        break;
-      case 'simpleAccount':
-        if (!modular) {
-          accountTemp = Factory.SIMPLE_ACCOUNT;
-        } else {
-          console.warn('You cannot use a Simple Account template with the modular functionality.');
-        }
-        break;
-      case 'etherspot':
-        accountTemp = modular ? ModularFactory.ETHERSPOT : Factory.ETHERSPOT;
-        break;
-      default:
-        console.warn('This account template cannot be used:', accountTemplate);
-    }
-  } else {
-    accountTemp = modular ? ModularFactory.ETHERSPOT : Factory.ETHERSPOT;
+  switch (accountTemplate) {
+    case 'etherspotModular':
+      accountTemp = 'etherspotModular';
+      break;
+    case 'etherspot':
+      accountTemp = 'etherspot';
+      break;
+    case 'simpleAccount':
+      accountTemp = 'simpleAccount';
+      break;
+    case 'zeroDev':
+      accountTemp = 'zeroDev';
+      break;
+    default:
+      accountTemp = 'etherspotModular';
+      break;
   }
-  
+
   return (
   
     
       
diff --git a/src/contexts/EtherspotContext.tsx b/src/contexts/EtherspotContext.tsx
index cb8b065..8137213 100644
--- a/src/contexts/EtherspotContext.tsx
+++ b/src/contexts/EtherspotContext.tsx
@@ -4,7 +4,7 @@ import { ModularSdk, WalletProviderLike as WalletProviderLikeModular } from '@et
 
 export interface EtherspotContextData {
   data: {
-    getSdk: (modular?: boolean, chainId?: number, forceNewInstance?: boolean) => Promise;
+    getSdk: (chainId?: number, forceNewInstance?: boolean) => Promise;
     getDataService: () => DataUtils;
     provider: WalletProviderLike | WalletProviderLikeModular | null | undefined;
     chainId: number;
diff --git a/src/hooks/useEtherspotBalances.ts b/src/hooks/useEtherspotBalances.ts
index 0cca924..de947e2 100644
--- a/src/hooks/useEtherspotBalances.ts
+++ b/src/hooks/useEtherspotBalances.ts
@@ -13,7 +13,7 @@ interface IEtherspotBalancesHook {
  * @param chainId {number | undefined} - Chain ID
  * @returns {IEtherspotBalancesHook} - hook method to fetch Etherspot account balances
  */
-const useEtherspotBalances = (chainId?: number, modular: boolean = true): IEtherspotBalancesHook => {
+const useEtherspotBalances = (chainId?: number): IEtherspotBalancesHook => {
   const { getDataService, getSdk, chainId: etherspotChainId } = useEtherspot();
 
   const defaultChainId = useMemo(() => {
@@ -25,7 +25,7 @@ const useEtherspotBalances = (chainId?: number, modular: boolean = true): IEther
     accountAddress?: string,
     balancesChainId: number = defaultChainId,
   ) => {
-    const sdkForChainId = await getSdk(modular, balancesChainId);
+    const sdkForChainId = await getSdk(balancesChainId);
 
     const balancesForAccount = accountAddress ?? await sdkForChainId.getCounterFactualAddress();
     if (!balancesForAccount) {
diff --git a/src/hooks/useEtherspotHistory.ts b/src/hooks/useEtherspotHistory.ts
index 1c61902..d689acf 100644
--- a/src/hooks/useEtherspotHistory.ts
+++ b/src/hooks/useEtherspotHistory.ts
@@ -23,7 +23,7 @@ interface IEtherspotHistoryHook {
  * @param chainId {number | undefined} - Chain ID
  * @returns {IEtherspotHistoryHook} - hook methods to fetch Etherspot transactions history
  */
-const useEtherspotHistory = (chainId?: number, modular: boolean = true): IEtherspotHistoryHook => {
+const useEtherspotHistory = (chainId?: number): IEtherspotHistoryHook => {
   const { getDataService, getSdk, chainId: etherspotChainId } = useEtherspot();
 
   const defaultChainId = useMemo(() => {
@@ -35,7 +35,7 @@ const useEtherspotHistory = (chainId?: number, modular: boolean = true): IEthers
     accountAddress?: string,
     historyChainId: number = defaultChainId
   ): Promise => {
-    const sdkForChainId = await getSdk(modular, historyChainId);
+    const sdkForChainId = await getSdk(historyChainId);
 
     let transactions: UserOpTransaction[] = [];
 
diff --git a/src/hooks/useEtherspotModules.ts b/src/hooks/useEtherspotModules.ts
index 429dddb..b016504 100644
--- a/src/hooks/useEtherspotModules.ts
+++ b/src/hooks/useEtherspotModules.ts
@@ -34,29 +34,27 @@ const useEtherspotModules = (chainId?: number): IEtherspotModulesHook => {
   ) => {
     // this hook can only be used is the sdk is using the modular functionality
     if (!isModular) {
-      console.warn(`The  component is not using the modular functionality. Please make sure to use the modular functionality to install and uninstall modules.`);
-      return '';
+      throw new Error(`The  component is not using the modular functionality. Please make sure to use the modular functionality to install and uninstall modules.`);
     }
 
-    const sdkForChainId = await getSdk(isModular, modulesChainId) as ModularSdk;
+    const sdkForChainId = await getSdk(modulesChainId) as ModularSdk;
 
     const modulesForAccount = accountAddress ?? await sdkForChainId.getCounterFactualAddress();
     if (!modulesForAccount) {
-      console.warn(`No account address provided!`);
-      return '';
+      throw new Error(`No account address provided!`);
     }
 
     try {
         const getInstallModule = await sdkForChainId.installModule(moduleType, module, initData)
         return getInstallModule;
     } catch (e) {
-      console.warn(
+      console.error(
         `Sorry, an error occurred whilst trying to install the new module`
         + ` ${module}`
         + ` for ${modulesForAccount}. Please try again. Error:`,
         e,
       );
-      return '';
+      throw new Error(`Failed to install module: ${e}`)
     }
   }
 
@@ -69,29 +67,27 @@ const useEtherspotModules = (chainId?: number): IEtherspotModulesHook => {
   ) => {
     // this hook can only be used is the sdk is using the modular functionality
     if (!isModular) {
-      console.warn(`The  component is not using the modular functionality. Please make sure to use the modular functionality to install and uninstall modules.`);
-      return '';
+      throw new Error(`The  component is not using the modular functionality. Please make sure to use the modular functionality to install and uninstall modules.`);
     }
 
-    const sdkForChainId = await getSdk(isModular, modulesChainId) as ModularSdk;
+    const sdkForChainId = await getSdk(modulesChainId) as ModularSdk;
 
     const modulesForAccount = accountAddress ?? await sdkForChainId.getCounterFactualAddress();
     if (!modulesForAccount) {
-      console.warn(`No account address provided!`);
-      return '';
+      throw new Error(`No account address provided!`);
     }
 
     try {
         const getUninstallModule = await sdkForChainId.uninstallModule(moduleType, module, deinitData);
         return getUninstallModule;
     } catch (e) {
-      console.warn(
+      console.error(
         `Sorry, an error occurred whilst trying to uninstall the module`
         + ` ${module}`
         + ` for ${modulesForAccount}. Please try again. Error:`,
         e,
       );
-      return '';
+      throw new Error(`Failed to uninstall module: ${e}`)
     }
   }
 
diff --git a/src/hooks/useEtherspotNfts.ts b/src/hooks/useEtherspotNfts.ts
index 41aba96..9b3c7ca 100644
--- a/src/hooks/useEtherspotNfts.ts
+++ b/src/hooks/useEtherspotNfts.ts
@@ -13,7 +13,7 @@ interface IEtherspotNftsHook {
  * @param chainId {number | undefined} - Chain ID
  * @returns {IEtherspotNftsHook} - hook methods to fetch Etherspot account NFTs
  */
-const useEtherspotNfts = (chainId?: number, modular: boolean = true): IEtherspotNftsHook => {
+const useEtherspotNfts = (chainId?: number): IEtherspotNftsHook => {
   const { getDataService, getSdk, chainId: etherspotChainId } = useEtherspot();
 
   const defaultChainId = useMemo(() => {
@@ -25,7 +25,7 @@ const useEtherspotNfts = (chainId?: number, modular: boolean = true): IEtherspot
     accountAddress?: string,
     nftsChainId: number = defaultChainId,
   ) => {
-    const sdkForChainId = await getSdk(modular, nftsChainId);
+    const sdkForChainId = await getSdk(nftsChainId);
 
     const nftsForAccount = accountAddress ?? await sdkForChainId.getCounterFactualAddress();
     if (!nftsForAccount) {
diff --git a/src/hooks/useEtherspotSwaps.ts b/src/hooks/useEtherspotSwaps.ts
index 0608412..46d10e7 100644
--- a/src/hooks/useEtherspotSwaps.ts
+++ b/src/hooks/useEtherspotSwaps.ts
@@ -39,7 +39,7 @@ interface IEtherspotSwapsHook {
  * @param chainId {number | undefined} - Source Chain ID
  * @returns {IEtherspotSwapsHook} - hook method to fetch Etherspot aggregated offers for same-chain and cross-chain swaps
  */
-const useEtherspotSwaps = (chainId?: number, modular: boolean = true): IEtherspotSwapsHook => {
+const useEtherspotSwaps = (chainId?: number): IEtherspotSwapsHook => {
   const { getDataService, getSdk, chainId: defaultChainId } = useEtherspot();
 
   const swapsChainId = useMemo(() => {
@@ -51,7 +51,7 @@ const useEtherspotSwaps = (chainId?: number, modular: boolean = true): IEtherspo
     offer: Route,
     accountAddress?: string
   ): Promise => {
-    const sdkForChainId = await getSdk(modular, swapsChainId);
+    const sdkForChainId = await getSdk(swapsChainId);
 
     const forAccount = accountAddress ?? (await sdkForChainId.getCounterFactualAddress());
     if (!forAccount) {
@@ -81,7 +81,7 @@ const useEtherspotSwaps = (chainId?: number, modular: boolean = true): IEtherspo
     toChainId?: number,
     fromAccountAddress?: string
   ): Promise => {
-    const sdkForChainId = await getSdk(modular, swapsChainId);
+    const sdkForChainId = await getSdk(swapsChainId);
 
     const fromAccount = fromAccountAddress ?? (await sdkForChainId.getCounterFactualAddress());
     if (!fromAccount) {
@@ -138,7 +138,7 @@ const useEtherspotSwaps = (chainId?: number, modular: boolean = true): IEtherspo
     fromAccountAddress?: string,
     provider?: BridgingProvider
   ): Promise => {
-    const sdkForChainId = await getSdk(modular, swapsChainId);
+    const sdkForChainId = await getSdk(swapsChainId);
 
     const fromAccount = fromAccountAddress ?? (await sdkForChainId.getCounterFactualAddress());
     if (!fromAccount) {
diff --git a/src/hooks/useWalletAddress.ts b/src/hooks/useWalletAddress.ts
index 53ad00b..e1a2e55 100644
--- a/src/hooks/useWalletAddress.ts
+++ b/src/hooks/useWalletAddress.ts
@@ -12,7 +12,7 @@ import useEtherspot from './useEtherspot';
  * @param chainId {number} - Chain ID
  * @returns {string | undefined} - wallet address by its type
  */
-const useWalletAddress = (walletType: IWalletType = 'etherspot-prime', chainId?: number, modular: boolean = true): string | undefined => {
+const useWalletAddress = (walletType: IWalletType = 'etherspot-prime', chainId?: number): string | undefined => {
   const [accountAddress, setAccountAddress] = useState<(string | undefined)>(undefined);
   const { getSdk, chainId: defaultChainId, provider } = useEtherspot();
 
@@ -25,7 +25,7 @@ const useWalletAddress = (walletType: IWalletType = 'etherspot-prime', chainId?:
     let shouldUpdate = true;
 
     const updateAccountAddress = async () => {
-      const etherspotModularOrPrimeSdk = await getSdk(modular, walletAddressChainId);
+      const etherspotModularOrPrimeSdk = await getSdk(walletAddressChainId);
 
       let newAccountAddress;
 
diff --git a/src/providers/EtherspotContextProvider.tsx b/src/providers/EtherspotContextProvider.tsx
index f69c400..18dedd2 100644
--- a/src/providers/EtherspotContextProvider.tsx
+++ b/src/providers/EtherspotContextProvider.tsx
@@ -15,7 +15,7 @@ import React, {
   useMemo,
 } from 'react';
 import isEqual from 'lodash/isEqual';
-import { ModularSdk, WalletProviderLike as WalletProviderLikeModular, isWalletProvider as isWalletProviderModular, Web3WalletProvider as Web3WalletModularProvider, EtherspotBundler as EtherspotBundlerModular, Factory as FactoryModular } from '@etherspot/modular-sdk';
+import { ModularSdk, WalletProviderLike as WalletProviderLikeModular, isWalletProvider as isWalletProviderModular, Web3WalletProvider as Web3WalletModularProvider, EtherspotBundler as EtherspotBundlerModular, Factory as ModularFactory } from '@etherspot/modular-sdk';
 
 // contexts
 import EtherspotContext from '../contexts/EtherspotContext';
@@ -63,8 +63,10 @@ const EtherspotContextProvider = ({
     }
   }, []);
 
-  const getSdk = useCallback(async (modular: boolean = isModular, sdkChainId: number = chainId, forceNewInstance: boolean = false) => {
-    if (modular) {
+  console.log('PROUT', accountTemplate)
+
+  const getSdk = useCallback(async (sdkChainId: number = chainId, forceNewInstance: boolean = false) => {
+    if (isModular) {
 
       const accountTemplateOrProviderChanged = (prevProvider && !isEqual(prevProviderModular, provider as WalletProviderLikeModular))
       || (prevAccountTemplate && prevAccountTemplate !== accountTemplate);
@@ -73,10 +75,6 @@ const EtherspotContextProvider = ({
         return sdkPerChainModular[sdkChainId];
       }
 
-      if (accountTemplate !== 'etherspot') {
-        throw new Error('Invalid account template: to use the modular functionality you must use the etherspot account template');
-      }
-
       sdkPerChainModular[sdkChainId] = (async () => {
       let mappedProvider;
 
@@ -97,7 +95,7 @@ const EtherspotContextProvider = ({
       const etherspotModularSdk = new ModularSdk(mappedProvider as Web3WalletModularProvider ?? provider as WalletProviderLikeModular, {
         chainId: +sdkChainId,
         bundlerProvider: new EtherspotBundlerModular(+sdkChainId, bundlerApiKey ?? ('__ETHERSPOT_BUNDLER_API_KEY__' || undefined)),
-        factoryWallet: accountTemplate as FactoryModular,
+        factoryWallet: accountTemplate as ModularFactory,
       });
 
       // load the address into SDK state
diff --git a/src/providers/EtherspotTransactionKitContextProvider.tsx b/src/providers/EtherspotTransactionKitContextProvider.tsx
index a49728c..b1012c7 100644
--- a/src/providers/EtherspotTransactionKitContextProvider.tsx
+++ b/src/providers/EtherspotTransactionKitContextProvider.tsx
@@ -33,7 +33,6 @@ const EtherspotTransactionKitContextProvider = ({ children }: EtherspotTransacti
 
   const estimate = async (
     batchesIds?: string[],
-    modular: boolean = true,
     forSending: boolean = false,
   ): Promise => {
     if (!forSending) {
@@ -66,7 +65,7 @@ const EtherspotTransactionKitContextProvider = ({ children }: EtherspotTransacti
         }
 
         // force new instance for each batch to not mix up user ops added to SDK state batch
-        const etherspotModularOrPrimeSdk = await getSdk(modular, batchChainId, true);
+        const etherspotModularOrPrimeSdk = await getSdk(batchChainId, true);
 
         try {
           if (!forSending) await etherspotModularOrPrimeSdk.clearUserOpsFromBatch();
@@ -98,7 +97,7 @@ const EtherspotTransactionKitContextProvider = ({ children }: EtherspotTransacti
     return result;
   }
 
-  const send = async (batchesIds?: string[], modular: boolean = true): Promise => {
+  const send = async (batchesIds?: string[]): Promise => {
     setIsSending(true);
     setContainsSendingError(false);
 
@@ -111,7 +110,7 @@ const EtherspotTransactionKitContextProvider = ({ children }: EtherspotTransacti
     }) => Promise.all(batches.map(async (batch) => {
       const batchChainId = batch.chainId ?? chainId;
 
-      const etherspotModularOrPrimeSdk = await getSdk(modular, batchChainId);
+      const etherspotModularOrPrimeSdk = await getSdk(batchChainId);
 
       await etherspotModularOrPrimeSdk.clearUserOpsFromBatch();
     }))));
@@ -131,7 +130,7 @@ const EtherspotTransactionKitContextProvider = ({ children }: EtherspotTransacti
           continue;
         }
 
-        const etherspotModularOrPrimeSdk = await getSdk(modular, batchChainId);
+        const etherspotModularOrPrimeSdk = await getSdk(batchChainId);
 
         if (!estimatedBatch.userOp) {
           sentBatches.push({ ...estimatedBatch, errorMessage: 'Failed to get estimated UserOp!' });
diff --git a/src/types/EtherspotTransactionKit.ts b/src/types/EtherspotTransactionKit.ts
index 0a1b97b..a19ee45 100644
--- a/src/types/EtherspotTransactionKit.ts
+++ b/src/types/EtherspotTransactionKit.ts
@@ -183,4 +183,4 @@ export interface UserOpTransaction {
   nftTransfers?: EtherspotNftTransfersEntity[];
 }
 
-export type AccountTemplate = 'etherspot' | 'zeroDev' | 'simpleAccount';
+export type AccountTemplate = 'etherspot' | 'etherspotModular' | 'zeroDev' | 'simpleAccount';

From b9d27cf074fc7fc0a127bacb061d46db779e068c Mon Sep 17 00:00:00 2001
From: RanaBug 
Date: Tue, 18 Jun 2024 15:59:51 +0100
Subject: [PATCH 5/6] changed wallet type to etherspot instead of
 etehrspot-prime

---
 CHANGELOG.md                                         | 1 +
 __tests__/hooks/useWalletAddress.test.js             | 4 ++--
 src/components/EtherspotTokenTransferTransaction.tsx | 2 +-
 src/components/EtherspotTransactionKit.tsx           | 2 +-
 src/hooks/useWalletAddress.ts                        | 8 ++++----
 src/providers/EtherspotContextProvider.tsx           | 2 --
 src/types/EtherspotTransactionKit.ts                 | 2 +-
 7 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index f320909..828983c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@
 ### Breaking Changes
 - Etherspot Modular SDK implemented to Transaction Kit as the default `accountTemplate`
 - The account template in the `EtherspotTransactionKit` component, can only be 'etherspot' if `moddular` is true.
+- Changed the `etherspot-prime` wallet type to `etherpot` wallet type
 
 ## [0.12.1] - 2024-05-22
 
diff --git a/__tests__/hooks/useWalletAddress.test.js b/__tests__/hooks/useWalletAddress.test.js
index f011dd3..fa26839 100644
--- a/__tests__/hooks/useWalletAddress.test.js
+++ b/__tests__/hooks/useWalletAddress.test.js
@@ -39,7 +39,7 @@ describe('useWalletAddress()', () => {
     );
 
     const { result, rerender } = renderHook(({ providerType }) => useWalletAddress(providerType), {
-      initialProps: { providerType: 'etherspot-prime' },
+      initialProps: { providerType: 'etherspot' },
       wrapper,
     });
 
@@ -59,7 +59,7 @@ describe('useWalletAddress()', () => {
     );
 
     const { result, rerender } = renderHook(({ providerType }) => useWalletAddress(providerType), {
-      initialProps: { providerType: 'etherspot-prime' },
+      initialProps: { providerType: 'etherspot' },
       wrapper,
     });
 
diff --git a/src/components/EtherspotTokenTransferTransaction.tsx b/src/components/EtherspotTokenTransferTransaction.tsx
index cf601f9..abc1a26 100644
--- a/src/components/EtherspotTokenTransferTransaction.tsx
+++ b/src/components/EtherspotTokenTransferTransaction.tsx
@@ -34,7 +34,7 @@ const EtherspotTokenTransferTransaction = ({
 }: EtherspotTokenTransferTransactionProps): JSX.Element => {
   const context = useContext(EtherspotBatchContext);
   const componentId = useId();
-  const senderAddress = useWalletAddress('etherspot-prime', context?.chainId);
+  const senderAddress = useWalletAddress('etherspot', context?.chainId);
 
   if (context === null) {
     throw new Error('No parent ');
diff --git a/src/components/EtherspotTransactionKit.tsx b/src/components/EtherspotTransactionKit.tsx
index f09f7fa..3bd9db2 100644
--- a/src/components/EtherspotTransactionKit.tsx
+++ b/src/components/EtherspotTransactionKit.tsx
@@ -52,7 +52,7 @@ const EtherspotTransactionKit = ({
     accountTemplate={accountTemp}
     dataApiKey={dataApiKey}
     bundlerApiKey={bundlerApiKey}
-    isModular={accountTemp === 'etherspotModular' && true}
+    isModular={accountTemp === 'etherspotModular'}
   >
     
       
diff --git a/src/hooks/useWalletAddress.ts b/src/hooks/useWalletAddress.ts
index e1a2e55..485d3bf 100644
--- a/src/hooks/useWalletAddress.ts
+++ b/src/hooks/useWalletAddress.ts
@@ -12,7 +12,7 @@ import useEtherspot from './useEtherspot';
  * @param chainId {number} - Chain ID
  * @returns {string | undefined} - wallet address by its type
  */
-const useWalletAddress = (walletType: IWalletType = 'etherspot-prime', chainId?: number): string | undefined => {
+const useWalletAddress = (walletType: IWalletType = 'etherspot', chainId?: number): string | undefined => {
   const [accountAddress, setAccountAddress] = useState<(string | undefined)>(undefined);
   const { getSdk, chainId: defaultChainId, provider } = useEtherspot();
 
@@ -37,7 +37,7 @@ const useWalletAddress = (walletType: IWalletType = 'etherspot-prime', chainId?:
         // @ts-ignore
         newAccountAddress = etherspotModularOrPrimeSdk?.etherspotWallet?.accountAddress;
       } catch (e) {
-        console.warn(`Unable to get wallet address from SDK state for etherspot-prime type for chainId ID ${walletAddressChainId}.`, e);
+        console.warn(`Unable to get wallet address from SDK state for etherspot type for chainId ID ${walletAddressChainId}.`, e);
       }
 
       // if were unable to get wallet address from SDK state, try to get using getCounterFactualAddress
@@ -45,7 +45,7 @@ const useWalletAddress = (walletType: IWalletType = 'etherspot-prime', chainId?:
         try {
           newAccountAddress = await etherspotModularOrPrimeSdk.getCounterFactualAddress();
         } catch (e) {
-          console.warn(`Unable to get wallet address for etherspot-prime type for chainId ID ${walletAddressChainId}.`, e);
+          console.warn(`Unable to get wallet address for etherspot type for chainId ID ${walletAddressChainId}.`, e);
         }
       }
 
@@ -60,7 +60,7 @@ const useWalletAddress = (walletType: IWalletType = 'etherspot-prime', chainId?:
   }, [getSdk, walletAddressChainId]);
 
   return useMemo(() => {
-    if (walletType === 'etherspot-prime') {
+    if (walletType === 'etherspot') {
       return accountAddress;
     }
 
diff --git a/src/providers/EtherspotContextProvider.tsx b/src/providers/EtherspotContextProvider.tsx
index 18dedd2..2c441bf 100644
--- a/src/providers/EtherspotContextProvider.tsx
+++ b/src/providers/EtherspotContextProvider.tsx
@@ -63,8 +63,6 @@ const EtherspotContextProvider = ({
     }
   }, []);
 
-  console.log('PROUT', accountTemplate)
-
   const getSdk = useCallback(async (sdkChainId: number = chainId, forceNewInstance: boolean = false) => {
     if (isModular) {
 
diff --git a/src/types/EtherspotTransactionKit.ts b/src/types/EtherspotTransactionKit.ts
index a19ee45..b1260d8 100644
--- a/src/types/EtherspotTransactionKit.ts
+++ b/src/types/EtherspotTransactionKit.ts
@@ -100,7 +100,7 @@ export interface IProviderWalletTransactionSent {
   errorMessage?: string;
 }
 
-export type IWalletType = 'provider' | 'etherspot-prime';
+export type IWalletType = 'provider' | 'etherspot';
 
 type EtherspotPromiseOrValue = T | Promise;
 

From b7bdeaed7a2a798529f415abbfd714f681bff551 Mon Sep 17 00:00:00 2001
From: RanaBug 
Date: Tue, 18 Jun 2024 16:15:49 +0100
Subject: [PATCH 6/6] update ChangeLog

---
 CHANGELOG.md | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 828983c..e71b1e3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,9 +8,8 @@
 - Added `isModular` to context `EtherspotContextProvider`
 
 ### Breaking Changes
-- Etherspot Modular SDK implemented to Transaction Kit as the default `accountTemplate`
-- The account template in the `EtherspotTransactionKit` component, can only be 'etherspot' if `moddular` is true.
-- Changed the `etherspot-prime` wallet type to `etherpot` wallet type
+- Etherspot Modular SDK implemented to TransactionKit as the default `accountTemplate`
+- Changed the `etherspot-prime` wallet type to `etherspot` wallet type
 
 ## [0.12.1] - 2024-05-22