From c9837e56062925f6d2da0c089cc054c465098517 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Wed, 19 Mar 2025 20:45:42 +1300 Subject: [PATCH] [thirdweb] feat: Support account overrides in engineAccount() --- .changeset/fifty-hoops-build.md | 5 +++ .../src/wallets/engine/engine-account.test.ts | 42 +++++++++++++++++++ packages/thirdweb/src/wallets/engine/index.ts | 32 ++++++++++++-- 3 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 .changeset/fifty-hoops-build.md diff --git a/.changeset/fifty-hoops-build.md b/.changeset/fifty-hoops-build.md new file mode 100644 index 00000000000..24fe924ac12 --- /dev/null +++ b/.changeset/fifty-hoops-build.md @@ -0,0 +1,5 @@ +--- +"thirdweb": patch +--- + +Support account overrides in engineAccount() diff --git a/packages/thirdweb/src/wallets/engine/engine-account.test.ts b/packages/thirdweb/src/wallets/engine/engine-account.test.ts index 1c6faeb26b6..a2c92a2a188 100644 --- a/packages/thirdweb/src/wallets/engine/engine-account.test.ts +++ b/packages/thirdweb/src/wallets/engine/engine-account.test.ts @@ -6,6 +6,8 @@ import { sepolia } from "../../chains/chain-definitions/sepolia.js"; import { getContract } from "../../contract/contract.js"; import { claimTo } from "../../extensions/erc1155/drops/write/claimTo.js"; import { sendTransaction } from "../../transaction/actions/send-transaction.js"; +import { smartWallet } from "../smart/smart-wallet.js"; +import { generateAccount } from "../utils/generateAccount.js"; import { engineAccount } from "./index.js"; describe.runIf( @@ -66,4 +68,44 @@ describe.runIf( }); expect(tx).toBeDefined(); }); + + it.skip("should send a session key tx", async () => { + const personalAccount = await generateAccount({ + client: TEST_CLIENT, + }); + const smart = smartWallet({ + chain: sepolia, + sponsorGas: true, + sessionKey: { + address: process.env.ENGINE_WALLET_ADDRESS_EOA as string, + permissions: { + approvedTargets: "*", + }, + }, + }); + const smartAccount = await smart.connect({ + client: TEST_CLIENT, + personalAccount, + }); + + const engineAcc = engineAccount({ + engineUrl: process.env.ENGINE_URL as string, + authToken: process.env.ENGINE_AUTH_TOKEN as string, + walletAddress: process.env.ENGINE_WALLET_ADDRESS_EOA as string, + chain: sepolia, + overrides: { + accountAddress: smartAccount.address, + }, + }); + const tx = await sendTransaction({ + account: engineAcc, + transaction: { + client: TEST_CLIENT, + chain: sepolia, + to: TEST_ACCOUNT_B.address, + value: 0n, + }, + }); + expect(tx).toBeDefined(); + }); }); diff --git a/packages/thirdweb/src/wallets/engine/index.ts b/packages/thirdweb/src/wallets/engine/index.ts index 1d139859bc5..7b29d9c1d89 100644 --- a/packages/thirdweb/src/wallets/engine/index.ts +++ b/packages/thirdweb/src/wallets/engine/index.ts @@ -19,6 +19,20 @@ export type EngineAccountOptions = { * The backend wallet to use for sending transactions inside engine. */ walletAddress: string; + overrides?: { + /** + * The address of the smart account to act on behalf of. Requires your backend wallet to be a valid signer on that smart account. + */ + accountAddress?: string; + /** + * The address of the smart account factory to use for creating smart accounts. + */ + accountFactoryAddress?: string; + /** + * The salt to use for creating the smart account. + */ + accountSalt?: string; + }; /** * The chain to use for signing messages and typed data (smart backend wallet only). */ @@ -55,7 +69,7 @@ export type EngineAccountOptions = { * ``` */ export function engineAccount(options: EngineAccountOptions): Account { - const { engineUrl, authToken, walletAddress, chain } = options; + const { engineUrl, authToken, walletAddress, chain, overrides } = options; // these are shared across all methods const headers: HeadersInit = { @@ -64,6 +78,16 @@ export function engineAccount(options: EngineAccountOptions): Account { "Content-Type": "application/json", }; + if (overrides?.accountAddress) { + headers["x-account-address"] = overrides.accountAddress; + } + if (overrides?.accountFactoryAddress) { + headers["x-account-factory-address"] = overrides.accountFactoryAddress; + } + if (overrides?.accountSalt) { + headers["x-account-salt"] = overrides.accountSalt; + } + return { address: walletAddress, sendTransaction: async (transaction: SendTransactionOption) => { @@ -181,12 +205,14 @@ export function engineAccount(options: EngineAccountOptions): Account { domain: _typedData.domain, types: _typedData.types, value: _typedData.message, + primaryType: _typedData.primaryType, + chainId: chain?.id, }), }); if (!engineRes.ok) { - engineRes.body?.cancel(); + const body = await engineRes.text(); throw new Error( - `Engine request failed with status ${engineRes.status}`, + `Engine request failed with status ${engineRes.status} - ${body}`, ); } const engineJson = (await engineRes.json()) as {