diff --git a/.changeset/early-shoes-applaud.md b/.changeset/early-shoes-applaud.md new file mode 100644 index 00000000000..439dae02669 --- /dev/null +++ b/.changeset/early-shoes-applaud.md @@ -0,0 +1,5 @@ +--- +"thirdweb": patch +--- + +Respect custom bundler URL for getting gas fees + better DX for `predictSmartAccountAddress()` diff --git a/apps/portal/src/app/typescript/v5/sidebar.tsx b/apps/portal/src/app/typescript/v5/sidebar.tsx index 44e199443eb..12418f76cd2 100644 --- a/apps/portal/src/app/typescript/v5/sidebar.tsx +++ b/apps/portal/src/app/typescript/v5/sidebar.tsx @@ -139,7 +139,7 @@ export const sidebar: SideBar = { }, ...[ "smartWallet", - "predictAddress", + "predictSmartAccountAddress", "createAndSignUserOp", "createUnsignedUserOp", "signUserOp", diff --git a/packages/thirdweb/src/exports/wallets/smart.ts b/packages/thirdweb/src/exports/wallets/smart.ts index aa01c4007af..7a5f0acb2cd 100644 --- a/packages/thirdweb/src/exports/wallets/smart.ts +++ b/packages/thirdweb/src/exports/wallets/smart.ts @@ -15,7 +15,10 @@ export { estimateUserOpGas, } from "../../wallets/smart/lib/bundler.js"; -export { predictAddress } from "../../wallets/smart/lib/calls.js"; +export { + predictAddress, + predictSmartAccountAddress, +} from "../../wallets/smart/lib/calls.js"; export { getPaymasterAndData } from "../../wallets/smart/lib/paymaster.js"; diff --git a/packages/thirdweb/src/transaction/prepare-contract-call.ts b/packages/thirdweb/src/transaction/prepare-contract-call.ts index 4a95fa0e4c8..27971613493 100644 --- a/packages/thirdweb/src/transaction/prepare-contract-call.ts +++ b/packages/thirdweb/src/transaction/prepare-contract-call.ts @@ -92,6 +92,29 @@ export type PrepareContractCallOptions< * }); * ``` * + * ### Usage with ERC20 value: + * + * For transactions that transfer ERC20 tokens, you can specify the value as the amount of tokens to transfer. + * + * You can use this in conjuction with the [`getApprovalForTransaction`](https://portal.thirdweb.com/references/typescript/v5/getApprovalForTransaction) function to easily create approval transactions for ERC20 tokens. + * + * This value will also be read by the react hooks and UI components to present to total cost to the user. + * + * ```ts + * import { prepareContractCall } from "thirdweb"; + * import { toWei } from "thirdweb/utils"; + * + * const transaction = prepareContractCall({ + * contract, + * method: "function payWithCoin()", + * params: [], + * erc20Value: { + * tokenAddress: "0x...", // the address of the ERC20 token + * amountWei: toWei("0.1"), // the amount of tokens to transfer in wei + * }, + * }); + * ``` + * * ### Usage with a JSON ABI function object: * * ```ts diff --git a/packages/thirdweb/src/wallets/smart/lib/calls.ts b/packages/thirdweb/src/wallets/smart/lib/calls.ts index b2cbf430012..259de48b5a0 100644 --- a/packages/thirdweb/src/wallets/smart/lib/calls.ts +++ b/packages/thirdweb/src/wallets/smart/lib/calls.ts @@ -1,9 +1,49 @@ -import type { ThirdwebContract } from "../../../contract/contract.js"; +import type { Chain } from "../../../chains/types.js"; +import type { ThirdwebClient } from "../../../client/client.js"; +import { + type ThirdwebContract, + getContract, +} from "../../../contract/contract.js"; import { prepareContractCall } from "../../../transaction/prepare-contract-call.js"; import type { PreparedTransaction } from "../../../transaction/prepare-transaction.js"; import { readContract } from "../../../transaction/read-contract.js"; import { isHex, stringToHex } from "../../../utils/encoding/hex.js"; import type { SendTransactionOption } from "../../interfaces/wallet.js"; +import { DEFAULT_ACCOUNT_FACTORY_V0_6 } from "./constants.js"; + +/** + * Predict the address of a smart account. + * @param args - The options for predicting the address of a smart account. + * @returns The predicted address of the smart account. + * @example + * ```ts + * import { predictSmartAccountAddress } from "thirdweb/wallets/smart"; + * + * const predictedAddress = await predictSmartAccountAddress({ + * client, + * chain, + * adminAddress, + * }); + * ``` + * @walletUtils + */ +export async function predictSmartAccountAddress(args: { + client: ThirdwebClient; + chain: Chain; + adminAddress: string; + factoryAddress?: string; + accountSalt?: string; +}): Promise { + return predictAddress({ + adminAddress: args.adminAddress, + accountSalt: args.accountSalt, + factoryContract: getContract({ + address: args.factoryAddress ?? DEFAULT_ACCOUNT_FACTORY_V0_6, + chain: args.chain, + client: args.client, + }), + }); +} /** * Predict the address of a smart account. @@ -20,6 +60,7 @@ import type { SendTransactionOption } from "../../interfaces/wallet.js"; * }); * ``` * @walletUtils + * @deprecated Use `predictSmartAccountAddress` instead. */ export async function predictAddress(args: { factoryContract: ThirdwebContract; diff --git a/packages/thirdweb/src/wallets/smart/lib/userop.ts b/packages/thirdweb/src/wallets/smart/lib/userop.ts index 87f86a43556..755cc0fbde9 100644 --- a/packages/thirdweb/src/wallets/smart/lib/userop.ts +++ b/packages/thirdweb/src/wallets/smart/lib/userop.ts @@ -149,6 +149,7 @@ export async function createUnsignedUserOp(args: { const bundlerOptions = { client, chain, + bundlerUrl: overrides?.bundlerUrl, entrypointAddress: overrides?.entrypointAddress, }; diff --git a/packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts b/packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts index fe025500457..1e2f0630ce7 100644 --- a/packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts +++ b/packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts @@ -23,6 +23,7 @@ import { isContractDeployed } from "../../utils/bytecode/is-contract-deployed.js import { sleep } from "../../utils/sleep.js"; import type { Account, Wallet } from "../interfaces/wallet.js"; import { generateAccount } from "../utils/generateAccount.js"; +import { predictSmartAccountAddress } from "./lib/calls.js"; import { DEFAULT_ACCOUNT_FACTORY_V0_7 } from "./lib/constants.js"; import { smartWallet } from "./smart-wallet.js"; @@ -70,6 +71,13 @@ describe.runIf(process.env.TW_SECRET_KEY).sequential( it("can connect", async () => { expect(smartWalletAddress).toHaveLength(42); + const predictedAddress = await predictSmartAccountAddress({ + client, + chain, + adminAddress: personalAccount.address, + factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_7, + }); + expect(predictedAddress).toEqual(smartWalletAddress); }); it("should revert on unsuccessful transactions", async () => { diff --git a/packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts b/packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts index 2b164024aed..5a731ce71c1 100644 --- a/packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts +++ b/packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts @@ -23,6 +23,7 @@ import { isContractDeployed } from "../../utils/bytecode/is-contract-deployed.js import { sleep } from "../../utils/sleep.js"; import type { Account, Wallet } from "../interfaces/wallet.js"; import { generateAccount } from "../utils/generateAccount.js"; +import { predictSmartAccountAddress } from "./lib/calls.js"; import { smartWallet } from "./smart-wallet.js"; let wallet: Wallet; @@ -69,6 +70,12 @@ describe.runIf(process.env.TW_SECRET_KEY).sequential( it("can connect", async () => { expect(smartWalletAddress).toHaveLength(42); + const predictedAddress = await predictSmartAccountAddress({ + client, + chain, + adminAddress: personalAccount.address, + }); + expect(predictedAddress).toEqual(smartWalletAddress); }); it("should revert on unsuccessful transactions", async () => {