diff --git a/packages/thirdweb/src/wallets/smart/lib/calls.ts b/packages/thirdweb/src/wallets/smart/lib/calls.ts index f90c5582e43..b8730bd33cd 100644 --- a/packages/thirdweb/src/wallets/smart/lib/calls.ts +++ b/packages/thirdweb/src/wallets/smart/lib/calls.ts @@ -8,6 +8,7 @@ import { prepareContractCall } from "../../../transaction/prepare-contract-call. import type { PreparedTransaction } from "../../../transaction/prepare-transaction.js"; import { readContract } from "../../../transaction/read-contract.js"; import { isHex, stringToHex } from "../../../utils/encoding/hex.js"; +import { withCache } from "../../../utils/promise/withCache.js"; import type { SendTransactionOption } from "../../interfaces/wallet.js"; import { DEFAULT_ACCOUNT_FACTORY_V0_6 } from "./constants.js"; @@ -90,15 +91,23 @@ export async function predictAddress(args: { "Account address is required to predict the smart wallet address.", ); } - const saltHex = - accountSalt && isHex(accountSalt) - ? accountSalt - : stringToHex(accountSalt ?? ""); - return readContract({ - contract: factoryContract, - method: "function getAddress(address, bytes) returns (address)", - params: [adminAddress, saltHex], - }); + return withCache( + async () => { + const saltHex = + accountSalt && isHex(accountSalt) + ? accountSalt + : stringToHex(accountSalt ?? ""); + return readContract({ + contract: factoryContract, + method: "function getAddress(address, bytes) returns (address)", + params: [adminAddress, saltHex], + }); + }, + { + cacheKey: `${args.factoryContract.chain.id}-${args.factoryContract.address}-${args.adminAddress}-${args.accountSalt}`, + cacheTime: 1000 * 60 * 60 * 24, // 1 day + }, + ); } /** diff --git a/packages/thirdweb/src/wallets/smart/lib/userop.ts b/packages/thirdweb/src/wallets/smart/lib/userop.ts index db00983de90..77f11c98825 100644 --- a/packages/thirdweb/src/wallets/smart/lib/userop.ts +++ b/packages/thirdweb/src/wallets/smart/lib/userop.ts @@ -136,6 +136,7 @@ export async function createUnsignedUserOp(args: { adminAddress: string; sponsorGas: boolean; waitForDeployment?: boolean; + isDeployedOverride?: boolean; overrides?: SmartWalletOptions["overrides"]; }): Promise { const { @@ -146,6 +147,7 @@ export async function createUnsignedUserOp(args: { overrides, sponsorGas, waitForDeployment = true, + isDeployedOverride, } = args; const chain = executeTx.chain; const client = executeTx.client; @@ -163,7 +165,11 @@ export async function createUnsignedUserOp(args: { const [isDeployed, callData, callGasLimit, gasFees, nonce] = await Promise.all([ - isContractDeployed(accountContract), + typeof isDeployedOverride === "boolean" + ? isDeployedOverride + : isContractDeployed(accountContract).then( + (isDeployed) => isDeployed || isAccountDeploying(accountContract), + ), encode(executeTx), resolvePromisedValue(executeTx.gas), getGasFees({ @@ -299,7 +305,7 @@ async function populateUserOp_v0_7(args: { let factory: string | undefined; let factoryData: Hex; - if (isDeployed || isAccountDeploying(accountContract)) { + if (isDeployed) { factoryData = "0x"; if (waitForDeployment) { // lock until account is deployed if needed to avoid 'sender already created' errors when sending multiple transactions in parallel @@ -462,7 +468,7 @@ async function populateUserOp_v0_6(args: { const { chain, client } = bundlerOptions; let initCode: Hex; - if (isDeployed || isAccountDeploying(accountContract)) { + if (isDeployed) { initCode = "0x"; if (waitForDeployment) { // lock until account is deployed if needed to avoid 'sender already created' errors when sending multiple transactions in parallel @@ -699,6 +705,7 @@ export async function createAndSignUserOp(options: { client: ThirdwebClient; smartWalletOptions: SmartWalletOptions; waitForDeployment?: boolean; + isDeployedOverride?: boolean; }) { const config = options.smartWalletOptions; const factoryContract = getContract({ @@ -757,6 +764,7 @@ export async function createAndSignUserOp(options: { sponsorGas: "sponsorGas" in config ? config.sponsorGas : config.gasless, overrides: config.overrides, waitForDeployment: options.waitForDeployment, + isDeployedOverride: options.isDeployedOverride, }); const signedUserOp = await signUserOp({ client: options.client,