Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/early-shoes-applaud.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"thirdweb": patch
---

Respect custom bundler URL for getting gas fees + better DX for `predictSmartAccountAddress()`
2 changes: 1 addition & 1 deletion apps/portal/src/app/typescript/v5/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ export const sidebar: SideBar = {
},
...[
"smartWallet",
"predictAddress",
"predictSmartAccountAddress",
"createAndSignUserOp",
"createUnsignedUserOp",
"signUserOp",
Expand Down
5 changes: 4 additions & 1 deletion packages/thirdweb/src/exports/wallets/smart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down
23 changes: 23 additions & 0 deletions packages/thirdweb/src/transaction/prepare-contract-call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
43 changes: 42 additions & 1 deletion packages/thirdweb/src/wallets/smart/lib/calls.ts
Original file line number Diff line number Diff line change
@@ -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<string> {
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.
Expand All @@ -20,6 +60,7 @@ import type { SendTransactionOption } from "../../interfaces/wallet.js";
* });
* ```
* @walletUtils
* @deprecated Use `predictSmartAccountAddress` instead.
*/
export async function predictAddress(args: {
factoryContract: ThirdwebContract;
Expand Down
1 change: 1 addition & 0 deletions packages/thirdweb/src/wallets/smart/lib/userop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ export async function createUnsignedUserOp(args: {
const bundlerOptions = {
client,
chain,
bundlerUrl: overrides?.bundlerUrl,
entrypointAddress: overrides?.entrypointAddress,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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 () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 () => {
Expand Down