From a9547c561f885cc343da8c4a018ba95d1dc91179 Mon Sep 17 00:00:00 2001 From: gregfromstl Date: Thu, 2 Jan 2025 01:36:46 +0000 Subject: [PATCH] [SDK] Fix: Use transaction-specified chain in smart account (#5865) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## PR-Codex overview This PR focuses on fixing chain switching in smart account transactions within the `thirdweb` SDK and adding tests for sending transactions across different chains. ### Detailed summary - Updated the logic for `accountContract` in `packages/thirdweb/src/wallets/smart/index.ts` to handle chain switching. - Added a new test in `packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts` to verify sending transactions on another chain. - Introduced similar test functionality in `packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts`. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` --- .changeset/fair-planes-doubt.md | 5 +++++ packages/thirdweb/src/wallets/smart/index.ts | 17 ++++++++++++++++- .../smart/smart-wallet-integration-v07.test.ts | 17 +++++++++++++++++ .../smart/smart-wallet-integration.test.ts | 15 +++++++++++++++ 4 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 .changeset/fair-planes-doubt.md diff --git a/.changeset/fair-planes-doubt.md b/.changeset/fair-planes-doubt.md new file mode 100644 index 00000000000..d3ca2bda5dc --- /dev/null +++ b/.changeset/fair-planes-doubt.md @@ -0,0 +1,5 @@ +--- +"thirdweb": patch +--- + +SDK: Fix chain switching in smart account transactions diff --git a/packages/thirdweb/src/wallets/smart/index.ts b/packages/thirdweb/src/wallets/smart/index.ts index f97d8fb386c..2ae82742f55 100644 --- a/packages/thirdweb/src/wallets/smart/index.ts +++ b/packages/thirdweb/src/wallets/smart/index.ts @@ -240,8 +240,22 @@ async function createSmartAccount( } else { paymasterOverride = options.overrides?.paymaster; } + + const accountContractForTransaction = (() => { + // If this transaction is for a different chain than the initial one, get the account contract for that chain + if (transaction.chainId !== accountContract.chain.id) { + return getContract({ + address: account.address, + chain: getCachedChain(transaction.chainId), + client: options.client, + }); + } + // Default to the existing account contract + return accountContract; + })(); + const executeTx = prepareExecute({ - accountContract, + accountContract: accountContractForTransaction, transaction, executeOverride: options.overrides?.execute, }); @@ -249,6 +263,7 @@ async function createSmartAccount( executeTx, options: { ...options, + chain: getCachedChain(transaction.chainId), overrides: { ...options.overrides, paymaster: paymasterOverride, 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 015bb6cf8b2..a71ac72593f 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 @@ -5,7 +5,9 @@ import { verifySignature } from "../../auth/verify-signature.js"; import { type ThirdwebContract, getContract } from "../../contract/contract.js"; import { parseEventLogs } from "../../event/actions/parse-logs.js"; +import { TEST_WALLET_A } from "~test/addresses.js"; import { verifyTypedData } from "../../auth/verify-typed-data.js"; +import { baseSepolia } from "../../chains/chain-definitions/base-sepolia.js"; import { sepolia } from "../../chains/chain-definitions/sepolia.js"; import { addAdmin, @@ -18,6 +20,7 @@ import { estimateGasCost } from "../../transaction/actions/estimate-gas-cost.js" import { sendAndConfirmTransaction } from "../../transaction/actions/send-and-confirm-transaction.js"; import { sendBatchTransaction } from "../../transaction/actions/send-batch-transaction.js"; import { waitForReceipt } from "../../transaction/actions/wait-for-tx-receipt.js"; +import { prepareTransaction } from "../../transaction/prepare-transaction.js"; import { getAddress } from "../../utils/address.js"; import { isContractDeployed } from "../../utils/bytecode/is-contract-deployed.js"; import { sleep } from "../../utils/sleep.js"; @@ -107,6 +110,20 @@ describe.runIf(process.env.TW_SECRET_KEY)( expect(isValid).toEqual(true); }); + it("can send a transaction on another chain", async () => { + const tx = await sendAndConfirmTransaction({ + transaction: prepareTransaction({ + to: TEST_WALLET_A, + client: TEST_CLIENT, + chain: baseSepolia, + value: 0n, + }), + // biome-ignore lint/style/noNonNullAssertion: Just trust me + account: wallet.getAccount()!, + }); + expect(tx.transactionHash).toHaveLength(66); + }); + it("should revert on unsuccessful transactions", async () => { const tx = sendAndConfirmTransaction({ transaction: setContractURI({ 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 012b936d319..c6801c4ec9f 100644 --- a/packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts +++ b/packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts @@ -1,4 +1,5 @@ import { beforeAll, describe, expect, it } from "vitest"; +import { TEST_WALLET_A } from "~test/addresses.js"; import { TEST_CLIENT } from "../../../test/src/test-clients.js"; import { typedData } from "../../../test/src/typed-data.js"; import { verifySignature } from "../../auth/verify-signature.js"; @@ -309,6 +310,20 @@ describe.runIf(process.env.TW_SECRET_KEY).sequential( expect(wallet.getChain()?.id).toEqual(baseSepolia.id); }); + it("can send a transaction on another chain", async () => { + const tx = await sendAndConfirmTransaction({ + transaction: prepareTransaction({ + to: TEST_WALLET_A, + client: TEST_CLIENT, + chain: baseSepolia, + value: 0n, + }), + // biome-ignore lint/style/noNonNullAssertion: Just trust me + account: wallet.getAccount()!, + }); + expect(tx.transactionHash).toHaveLength(66); + }); + it("can execute 2 tx in parallel", async () => { const newSmartWallet = smartWallet({ chain,