thirdweb 5.97.1 → 5.97.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/dist/cjs/contract/verification/constructor-params.js +1 -1
  2. package/dist/cjs/contract/verification/constructor-params.js.map +1 -1
  3. package/dist/cjs/engine/get-status.js +110 -0
  4. package/dist/cjs/engine/get-status.js.map +1 -0
  5. package/dist/cjs/engine/index.js +9 -0
  6. package/dist/cjs/engine/index.js.map +1 -0
  7. package/dist/cjs/engine/server-wallet.js +214 -0
  8. package/dist/cjs/engine/server-wallet.js.map +1 -0
  9. package/dist/cjs/exports/engine.js +5 -0
  10. package/dist/cjs/exports/engine.js.map +1 -0
  11. package/dist/cjs/exports/thirdweb.js +6 -2
  12. package/dist/cjs/exports/thirdweb.js.map +1 -1
  13. package/dist/cjs/extensions/prebuilts/get-required-transactions.js +5 -5
  14. package/dist/cjs/extensions/prebuilts/get-required-transactions.js.map +1 -1
  15. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js +1 -1
  16. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js.map +1 -1
  17. package/dist/cjs/react/web/ui/prebuilt/NFT/utils.js +1 -0
  18. package/dist/cjs/react/web/ui/prebuilt/NFT/utils.js.map +1 -1
  19. package/dist/cjs/react/web/wallets/in-app/InAppWalletConnectUI.js +1 -1
  20. package/dist/cjs/react/web/wallets/in-app/InAppWalletConnectUI.js.map +1 -1
  21. package/dist/cjs/storage/upload/mobile.js +1 -1
  22. package/dist/cjs/storage/upload/mobile.js.map +1 -1
  23. package/dist/cjs/utils/domains.js +3 -0
  24. package/dist/cjs/utils/domains.js.map +1 -1
  25. package/dist/cjs/utils/fetch.js +7 -3
  26. package/dist/cjs/utils/fetch.js.map +1 -1
  27. package/dist/cjs/version.js +1 -1
  28. package/dist/cjs/wallets/engine/index.js +1 -0
  29. package/dist/cjs/wallets/engine/index.js.map +1 -1
  30. package/dist/cjs/wallets/smart/lib/calls.js +13 -6
  31. package/dist/cjs/wallets/smart/lib/calls.js.map +1 -1
  32. package/dist/cjs/wallets/smart/lib/paymaster.js +2 -2
  33. package/dist/cjs/wallets/smart/lib/paymaster.js.map +1 -1
  34. package/dist/esm/contract/verification/constructor-params.js +1 -1
  35. package/dist/esm/contract/verification/constructor-params.js.map +1 -1
  36. package/dist/esm/engine/get-status.js +106 -0
  37. package/dist/esm/engine/get-status.js.map +1 -0
  38. package/dist/esm/engine/index.js +3 -0
  39. package/dist/esm/engine/index.js.map +1 -0
  40. package/dist/esm/engine/server-wallet.js +211 -0
  41. package/dist/esm/engine/server-wallet.js.map +1 -0
  42. package/dist/esm/exports/engine.js +2 -0
  43. package/dist/esm/exports/engine.js.map +1 -0
  44. package/dist/esm/exports/thirdweb.js +4 -0
  45. package/dist/esm/exports/thirdweb.js.map +1 -1
  46. package/dist/esm/extensions/prebuilts/get-required-transactions.js +5 -5
  47. package/dist/esm/extensions/prebuilts/get-required-transactions.js.map +1 -1
  48. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js +1 -1
  49. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js.map +1 -1
  50. package/dist/esm/react/web/ui/prebuilt/NFT/utils.js +1 -0
  51. package/dist/esm/react/web/ui/prebuilt/NFT/utils.js.map +1 -1
  52. package/dist/esm/react/web/wallets/in-app/InAppWalletConnectUI.js +1 -1
  53. package/dist/esm/react/web/wallets/in-app/InAppWalletConnectUI.js.map +1 -1
  54. package/dist/esm/storage/upload/mobile.js +1 -1
  55. package/dist/esm/storage/upload/mobile.js.map +1 -1
  56. package/dist/esm/utils/domains.js +3 -0
  57. package/dist/esm/utils/domains.js.map +1 -1
  58. package/dist/esm/utils/fetch.js +7 -3
  59. package/dist/esm/utils/fetch.js.map +1 -1
  60. package/dist/esm/version.js +1 -1
  61. package/dist/esm/wallets/engine/index.js +1 -0
  62. package/dist/esm/wallets/engine/index.js.map +1 -1
  63. package/dist/esm/wallets/smart/lib/calls.js +13 -6
  64. package/dist/esm/wallets/smart/lib/calls.js.map +1 -1
  65. package/dist/esm/wallets/smart/lib/paymaster.js +2 -2
  66. package/dist/esm/wallets/smart/lib/paymaster.js.map +1 -1
  67. package/dist/types/engine/get-status.d.ts +81 -0
  68. package/dist/types/engine/get-status.d.ts.map +1 -0
  69. package/dist/types/engine/index.d.ts +3 -0
  70. package/dist/types/engine/index.d.ts.map +1 -0
  71. package/dist/types/engine/server-wallet.d.ts +95 -0
  72. package/dist/types/engine/server-wallet.d.ts.map +1 -0
  73. package/dist/types/exports/engine.d.ts +2 -0
  74. package/dist/types/exports/engine.d.ts.map +1 -0
  75. package/dist/types/exports/thirdweb.d.ts +4 -0
  76. package/dist/types/exports/thirdweb.d.ts.map +1 -1
  77. package/dist/types/react/native/ui/prebuilt/Account/balance.d.ts +1 -1
  78. package/dist/types/react/native/ui/prebuilt/Wallet/name.d.ts +1 -1
  79. package/dist/types/react/web/ui/prebuilt/Account/balance.d.ts +1 -1
  80. package/dist/types/react/web/ui/prebuilt/Chain/name.d.ts +1 -1
  81. package/dist/types/react/web/ui/prebuilt/NFT/utils.d.ts.map +1 -1
  82. package/dist/types/react/web/ui/prebuilt/Token/name.d.ts +1 -1
  83. package/dist/types/react/web/ui/prebuilt/Token/symbol.d.ts +1 -1
  84. package/dist/types/react/web/ui/prebuilt/Wallet/name.d.ts +1 -1
  85. package/dist/types/utils/domains.d.ts +6 -0
  86. package/dist/types/utils/domains.d.ts.map +1 -1
  87. package/dist/types/utils/fetch.d.ts.map +1 -1
  88. package/dist/types/version.d.ts +1 -1
  89. package/dist/types/wallets/engine/index.d.ts +1 -0
  90. package/dist/types/wallets/engine/index.d.ts.map +1 -1
  91. package/dist/types/wallets/smart/lib/calls.d.ts.map +1 -1
  92. package/package.json +7 -1
  93. package/src/contract/verification/constructor-params.ts +1 -1
  94. package/src/engine/get-status.ts +180 -0
  95. package/src/engine/index.ts +11 -0
  96. package/src/engine/server-wallet.test.ts +196 -0
  97. package/src/engine/server-wallet.ts +284 -0
  98. package/src/exports/engine.ts +1 -0
  99. package/src/exports/thirdweb.ts +5 -0
  100. package/src/extensions/erc721/read/getNFT.test.ts +2 -2
  101. package/src/extensions/prebuilts/get-required-transactions.ts +5 -5
  102. package/src/react/native/ui/prebuilt/Account/balance.tsx +1 -1
  103. package/src/react/native/ui/prebuilt/Wallet/name.tsx +1 -1
  104. package/src/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.tsx +2 -2
  105. package/src/react/web/ui/prebuilt/Account/balance.tsx +1 -1
  106. package/src/react/web/ui/prebuilt/Chain/name.tsx +1 -1
  107. package/src/react/web/ui/prebuilt/NFT/utils.ts +1 -0
  108. package/src/react/web/ui/prebuilt/Token/name.tsx +1 -1
  109. package/src/react/web/ui/prebuilt/Token/symbol.tsx +1 -1
  110. package/src/react/web/ui/prebuilt/Wallet/name.tsx +1 -1
  111. package/src/react/web/wallets/in-app/InAppWalletConnectUI.tsx +1 -1
  112. package/src/storage/upload/mobile.ts +1 -1
  113. package/src/utils/domain.test.ts +1 -0
  114. package/src/utils/domains.ts +9 -0
  115. package/src/utils/fetch.ts +11 -3
  116. package/src/version.ts +1 -1
  117. package/src/wallets/engine/index.ts +1 -0
  118. package/src/wallets/smart/lib/calls.ts +13 -6
  119. package/src/wallets/smart/lib/paymaster.ts +2 -2
@@ -0,0 +1,180 @@
1
+ import { searchTransactions } from "@thirdweb-dev/engine";
2
+ import type { Chain } from "../chains/types.js";
3
+ import { getCachedChain } from "../chains/utils.js";
4
+ import type { ThirdwebClient } from "../client/client.js";
5
+ import type { WaitForReceiptOptions } from "../transaction/actions/wait-for-tx-receipt.js";
6
+ import { getThirdwebBaseUrl } from "../utils/domains.js";
7
+ import type { Hex } from "../utils/encoding/hex.js";
8
+ import { getClientFetch } from "../utils/fetch.js";
9
+ import { stringify } from "../utils/json.js";
10
+ import type { Prettify } from "../utils/type-utils.js";
11
+
12
+ export type RevertData = {
13
+ errorName: string;
14
+ errorArgs: Record<string, unknown>;
15
+ };
16
+
17
+ type ExecutionResult4337Serialized =
18
+ | {
19
+ status: "QUEUED";
20
+ }
21
+ | {
22
+ status: "FAILED";
23
+ error: string;
24
+ }
25
+ | {
26
+ status: "SUBMITTED";
27
+ monitoringStatus: "WILL_MONITOR" | "CANNOT_MONITOR";
28
+ userOpHash: string;
29
+ }
30
+ | ({
31
+ status: "CONFIRMED";
32
+ userOpHash: Hex;
33
+ transactionHash: Hex;
34
+ actualGasCost: string;
35
+ actualGasUsed: string;
36
+ nonce: string;
37
+ } & (
38
+ | {
39
+ onchainStatus: "SUCCESS";
40
+ }
41
+ | {
42
+ onchainStatus: "REVERTED";
43
+ revertData?: RevertData;
44
+ }
45
+ ));
46
+
47
+ export type ExecutionResult = Prettify<
48
+ ExecutionResult4337Serialized & {
49
+ chain: Chain;
50
+ from: string | undefined;
51
+ id: string;
52
+ }
53
+ >;
54
+
55
+ /**
56
+ * Get the execution status of a transaction.
57
+ * @param args - The arguments for the transaction.
58
+ * @param args.client - The thirdweb client to use.
59
+ * @param args.transactionId - The id of the transaction to get the status of.
60
+ * @engine
61
+ * @example
62
+ * ```ts
63
+ * import { Engine } from "thirdweb";
64
+ *
65
+ * const executionResult = await Engine.getTransactionStatus({
66
+ * client,
67
+ * transactionId,
68
+ * });
69
+ * console.log(executionResult.status);
70
+ * ```
71
+ */
72
+ export async function getTransactionStatus(args: {
73
+ client: ThirdwebClient;
74
+ transactionId: string;
75
+ }): Promise<ExecutionResult> {
76
+ const { client, transactionId } = args;
77
+ const searchResult = await searchTransactions({
78
+ baseUrl: getThirdwebBaseUrl("engineCloud"),
79
+ fetch: getClientFetch(client),
80
+ body: {
81
+ filters: [
82
+ {
83
+ field: "id",
84
+ values: [transactionId],
85
+ operation: "OR",
86
+ },
87
+ ],
88
+ },
89
+ });
90
+
91
+ if (searchResult.error) {
92
+ throw new Error(
93
+ `Error searching for transaction ${transactionId}: ${stringify(
94
+ searchResult.error,
95
+ )}`,
96
+ );
97
+ }
98
+
99
+ const data = searchResult.data?.result?.transactions?.[0];
100
+
101
+ if (!data) {
102
+ throw new Error(`Transaction ${transactionId} not found`);
103
+ }
104
+
105
+ const executionResult = data.executionResult as ExecutionResult4337Serialized;
106
+ return {
107
+ ...executionResult,
108
+ chain: getCachedChain(Number(data.chainId)),
109
+ from: data.from ?? undefined,
110
+ id: data.id,
111
+ };
112
+ }
113
+
114
+ /**
115
+ * Wait for a transaction to be submitted onchain and return the transaction hash.
116
+ * @param args - The arguments for the transaction.
117
+ * @param args.client - The thirdweb client to use.
118
+ * @param args.transactionId - The id of the transaction to wait for.
119
+ * @param args.timeoutInSeconds - The timeout in seconds.
120
+ * @engine
121
+ * @example
122
+ * ```ts
123
+ * import { Engine } from "thirdweb";
124
+ *
125
+ * const { transactionHash } = await Engine.waitForTransactionHash({
126
+ * client,
127
+ * transactionId, // the transaction id returned from enqueueTransaction
128
+ * });
129
+ * ```
130
+ */
131
+ export async function waitForTransactionHash(args: {
132
+ client: ThirdwebClient;
133
+ transactionId: string;
134
+ timeoutInSeconds?: number;
135
+ }): Promise<WaitForReceiptOptions> {
136
+ const startTime = Date.now();
137
+ const TIMEOUT_IN_MS = args.timeoutInSeconds
138
+ ? args.timeoutInSeconds * 1000
139
+ : 5 * 60 * 1000; // 5 minutes in milliseconds
140
+
141
+ while (Date.now() - startTime < TIMEOUT_IN_MS) {
142
+ const executionResult = await getTransactionStatus(args);
143
+ const status = executionResult.status;
144
+
145
+ switch (status) {
146
+ case "FAILED": {
147
+ throw new Error(
148
+ `Transaction failed: ${executionResult.error || "Unknown error"}`,
149
+ );
150
+ }
151
+ case "CONFIRMED": {
152
+ const onchainStatus =
153
+ executionResult && "onchainStatus" in executionResult
154
+ ? executionResult.onchainStatus
155
+ : null;
156
+ if (onchainStatus === "REVERTED") {
157
+ const revertData =
158
+ "revertData" in executionResult
159
+ ? executionResult.revertData
160
+ : undefined;
161
+ throw new Error(
162
+ `Transaction reverted: ${revertData?.errorName || ""} ${revertData?.errorArgs ? stringify(revertData.errorArgs) : ""}`,
163
+ );
164
+ }
165
+ return {
166
+ transactionHash: executionResult.transactionHash as Hex,
167
+ client: args.client,
168
+ chain: executionResult.chain,
169
+ };
170
+ }
171
+ default: {
172
+ // wait for the transaction to be confirmed
173
+ await new Promise((resolve) => setTimeout(resolve, 1000));
174
+ }
175
+ }
176
+ }
177
+ throw new Error(
178
+ `Transaction timed out after ${TIMEOUT_IN_MS / 1000} seconds`,
179
+ );
180
+ }
@@ -0,0 +1,11 @@
1
+ export {
2
+ serverWallet,
3
+ type ServerWalletOptions,
4
+ type ServerWallet,
5
+ } from "./server-wallet.js";
6
+ export {
7
+ getTransactionStatus,
8
+ waitForTransactionHash,
9
+ type ExecutionResult,
10
+ type RevertData,
11
+ } from "./get-status.js";
@@ -0,0 +1,196 @@
1
+ import { beforeAll, describe, expect, it } from "vitest";
2
+ import { TEST_CLIENT } from "../../test/src/test-clients.js";
3
+ import { TEST_ACCOUNT_B } from "../../test/src/test-wallets.js";
4
+ import { typedData } from "../../test/src/typed-data.js";
5
+ import { arbitrumSepolia } from "../chains/chain-definitions/arbitrum-sepolia.js";
6
+ import { sepolia } from "../chains/chain-definitions/sepolia.js";
7
+ import { getContract } from "../contract/contract.js";
8
+ import { setContractURI } from "../extensions/common/__generated__/IContractMetadata/write/setContractURI.js";
9
+ import { claimTo } from "../extensions/erc1155/drops/write/claimTo.js";
10
+ import { getAllActiveSigners } from "../extensions/erc4337/__generated__/IAccountPermissions/read/getAllActiveSigners.js";
11
+ import { sendTransaction } from "../transaction/actions/send-transaction.js";
12
+ import { setThirdwebDomains } from "../utils/domains.js";
13
+ import {
14
+ DEFAULT_ACCOUNT_FACTORY_V0_6,
15
+ ENTRYPOINT_ADDRESS_v0_6,
16
+ } from "../wallets/smart/lib/constants.js";
17
+ import { smartWallet } from "../wallets/smart/smart-wallet.js";
18
+ import { generateAccount } from "../wallets/utils/generateAccount.js";
19
+ import * as Engine from "./index.js";
20
+
21
+ describe.runIf(
22
+ process.env.TW_SECRET_KEY &&
23
+ process.env.VAULT_TOKEN &&
24
+ process.env.ENGINE_CLOUD_WALLET_ADDRESS &&
25
+ process.env.ENGINE_CLOUD_WALLET_ADDRESS_EOA,
26
+ )(
27
+ "Engine Cloud",
28
+ {
29
+ retry: 0,
30
+ },
31
+ () => {
32
+ let serverWallet: Engine.ServerWallet;
33
+
34
+ beforeAll(async () => {
35
+ setThirdwebDomains({
36
+ rpc: "rpc.thirdweb-dev.com",
37
+ storage: "storage.thirdweb-dev.com",
38
+ bundler: "bundler.thirdweb-dev.com",
39
+ engineCloud: "engine.thirdweb-dev.com",
40
+ });
41
+ serverWallet = Engine.serverWallet({
42
+ client: TEST_CLIENT,
43
+ vaultAccessToken: process.env.VAULT_TOKEN as string,
44
+ address: process.env.ENGINE_CLOUD_WALLET_ADDRESS as string,
45
+ chain: arbitrumSepolia,
46
+ });
47
+ });
48
+
49
+ it("should sign a message", async () => {
50
+ const signature = await serverWallet.signMessage({
51
+ message: "hello",
52
+ });
53
+ expect(signature).toBeDefined();
54
+ });
55
+
56
+ it("should sign typed data", async () => {
57
+ const signature = await serverWallet.signTypedData({
58
+ ...typedData.basic,
59
+ });
60
+ expect(signature).toBeDefined();
61
+ });
62
+
63
+ it("should send a tx with regular API", async () => {
64
+ const tx = await sendTransaction({
65
+ account: serverWallet,
66
+ transaction: {
67
+ client: TEST_CLIENT,
68
+ chain: arbitrumSepolia,
69
+ to: TEST_ACCOUNT_B.address,
70
+ value: 0n,
71
+ },
72
+ });
73
+ expect(tx).toBeDefined();
74
+ });
75
+
76
+ it("should enqueue a tx", async () => {
77
+ const nftContract = getContract({
78
+ client: TEST_CLIENT,
79
+ chain: sepolia,
80
+ address: "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8",
81
+ });
82
+ const claimTx = claimTo({
83
+ contract: nftContract,
84
+ to: TEST_ACCOUNT_B.address,
85
+ tokenId: 0n,
86
+ quantity: 1n,
87
+ });
88
+ const result = await serverWallet.enqueueTransaction({
89
+ transaction: claimTx,
90
+ });
91
+ expect(result.transactionId).toBeDefined();
92
+ const txHash = await Engine.waitForTransactionHash({
93
+ client: TEST_CLIENT,
94
+ transactionId: result.transactionId,
95
+ });
96
+ expect(txHash.transactionHash).toBeDefined();
97
+ });
98
+
99
+ it("should send a extension tx", async () => {
100
+ const nftContract = getContract({
101
+ client: TEST_CLIENT,
102
+ chain: sepolia,
103
+ address: "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8",
104
+ });
105
+ const claimTx = claimTo({
106
+ contract: nftContract,
107
+ to: TEST_ACCOUNT_B.address,
108
+ tokenId: 0n,
109
+ quantity: 1n,
110
+ });
111
+ const tx = await sendTransaction({
112
+ account: serverWallet,
113
+ transaction: claimTx,
114
+ });
115
+ expect(tx).toBeDefined();
116
+ });
117
+
118
+ it("should get revert reason", async () => {
119
+ const nftContract = getContract({
120
+ client: TEST_CLIENT,
121
+ chain: sepolia,
122
+ address: "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8",
123
+ });
124
+ const transaction = setContractURI({
125
+ contract: nftContract,
126
+ uri: "https://example.com",
127
+ overrides: {
128
+ gas: 1000000n, // skip simulation
129
+ },
130
+ });
131
+ await expect(
132
+ sendTransaction({
133
+ account: serverWallet,
134
+ transaction,
135
+ }),
136
+ ).rejects.toThrow();
137
+ });
138
+
139
+ it("should send a session key tx", async () => {
140
+ const sessionKeyAccountAddress = process.env
141
+ .ENGINE_CLOUD_WALLET_ADDRESS_EOA as string;
142
+ const personalAccount = await generateAccount({
143
+ client: TEST_CLIENT,
144
+ });
145
+ const smart = smartWallet({
146
+ chain: sepolia,
147
+ sponsorGas: true,
148
+ sessionKey: {
149
+ address: sessionKeyAccountAddress,
150
+ permissions: {
151
+ approvedTargets: "*",
152
+ },
153
+ },
154
+ });
155
+ const smartAccount = await smart.connect({
156
+ client: TEST_CLIENT,
157
+ personalAccount,
158
+ });
159
+ expect(smartAccount.address).toBeDefined();
160
+
161
+ const signers = await getAllActiveSigners({
162
+ contract: getContract({
163
+ client: TEST_CLIENT,
164
+ chain: sepolia,
165
+ address: smartAccount.address,
166
+ }),
167
+ });
168
+ expect(signers.map((s) => s.signer)).toContain(sessionKeyAccountAddress);
169
+
170
+ const serverWallet = Engine.serverWallet({
171
+ client: TEST_CLIENT,
172
+ vaultAccessToken: process.env.VAULT_TOKEN as string,
173
+ address: sessionKeyAccountAddress,
174
+ chain: sepolia,
175
+ executionOptions: {
176
+ type: "ERC4337",
177
+ signerAddress: sessionKeyAccountAddress,
178
+ smartAccountAddress: smartAccount.address,
179
+ factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6,
180
+ entrypointAddress: ENTRYPOINT_ADDRESS_v0_6,
181
+ },
182
+ });
183
+
184
+ const tx = await sendTransaction({
185
+ account: serverWallet,
186
+ transaction: {
187
+ client: TEST_CLIENT,
188
+ chain: sepolia,
189
+ to: TEST_ACCOUNT_B.address,
190
+ value: 0n,
191
+ },
192
+ });
193
+ expect(tx).toBeDefined();
194
+ });
195
+ },
196
+ );
@@ -0,0 +1,284 @@
1
+ import {
2
+ type AaExecutionOptions,
3
+ type AaZksyncExecutionOptions,
4
+ sendTransaction,
5
+ signMessage,
6
+ signTypedData,
7
+ } from "@thirdweb-dev/engine";
8
+ import type { Chain } from "../chains/types.js";
9
+ import type { ThirdwebClient } from "../client/client.js";
10
+ import { encode } from "../transaction/actions/encode.js";
11
+ import { toSerializableTransaction } from "../transaction/actions/to-serializable-transaction.js";
12
+ import type { PreparedTransaction } from "../transaction/prepare-transaction.js";
13
+ import { getThirdwebBaseUrl } from "../utils/domains.js";
14
+ import { type Hex, toHex } from "../utils/encoding/hex.js";
15
+ import { getClientFetch } from "../utils/fetch.js";
16
+ import { stringify } from "../utils/json.js";
17
+ import { resolvePromisedValue } from "../utils/promise/resolve-promised-value.js";
18
+ import type {
19
+ Account,
20
+ SendTransactionOption,
21
+ } from "../wallets/interfaces/wallet.js";
22
+ import { waitForTransactionHash } from "./get-status.js";
23
+
24
+ /**
25
+ * Options for creating an server wallet.
26
+ */
27
+ export type ServerWalletOptions = {
28
+ /**
29
+ * The thirdweb client to use for authentication to thirdweb services.
30
+ */
31
+ client: ThirdwebClient;
32
+ /**
33
+ * The vault access token to use your server wallet.
34
+ */
35
+ vaultAccessToken: string;
36
+ /**
37
+ * The server wallet address to use for sending transactions inside engine.
38
+ */
39
+ address: string;
40
+ /**
41
+ * The chain to use for signing messages and typed data (smart server wallet only).
42
+ */
43
+ chain?: Chain;
44
+ /**
45
+ * Optional custom execution options to use for sending transactions and signing data.
46
+ */
47
+ executionOptions?:
48
+ | Omit<AaExecutionOptions, "chainId">
49
+ | Omit<AaZksyncExecutionOptions, "chainId">;
50
+ };
51
+
52
+ export type ServerWallet = Account & {
53
+ enqueueTransaction: (args: {
54
+ transaction: PreparedTransaction;
55
+ simulate?: boolean;
56
+ }) => Promise<{ transactionId: string }>;
57
+ };
58
+
59
+ /**
60
+ * Create a server wallet for sending transactions and signing messages via engine (v3+).
61
+ * @param options - The server wallet options.
62
+ * @returns An account object that can be used to send transactions and sign messages.
63
+ * @engine
64
+ * @example
65
+ * ### Creating a server wallet
66
+ * ```ts
67
+ * import { Engine } from "thirdweb";
68
+ *
69
+ * const client = createThirdwebClient({
70
+ * secretKey: "<your-project-secret-key>",
71
+ * });
72
+ *
73
+ * const myServerWallet = Engine.serverWallet({
74
+ * client,
75
+ * address: "<your-server-wallet-address>",
76
+ * vaultAccessToken: "<your-vault-access-token>",
77
+ * });
78
+ * ```
79
+ *
80
+ * ### Sending a transaction
81
+ * ```ts
82
+ * // prepare the transaction
83
+ * const transaction = claimTo({
84
+ * contract,
85
+ * to: "0x...",
86
+ * quantity: 1n,
87
+ * });
88
+ *
89
+ * // enqueue the transaction
90
+ * const { transactionId } = await myServerWallet.enqueueTransaction({
91
+ * transaction,
92
+ * });
93
+ * ```
94
+ *
95
+ * ### Polling for the transaction to be submitted onchain
96
+ * ```ts
97
+ * // optionally poll for the transaction to be submitted onchain
98
+ * const { transactionHash } = await Engine.waitForTransactionHash({
99
+ * client,
100
+ * transactionId,
101
+ * });
102
+ * console.log("Transaction sent:", transactionHash);
103
+ * ```
104
+ *
105
+ * ### Getting the execution status of a transaction
106
+ * ```ts
107
+ * const executionResult = await Engine.getTransactionStatus({
108
+ * client,
109
+ * transactionId,
110
+ * });
111
+ * console.log("Transaction status:", executionResult.status);
112
+ * ```
113
+ */
114
+ export function serverWallet(options: ServerWalletOptions): ServerWallet {
115
+ const { client, vaultAccessToken, address, chain, executionOptions } =
116
+ options;
117
+ const headers: HeadersInit = {
118
+ "x-vault-access-token": vaultAccessToken,
119
+ };
120
+
121
+ const getExecutionOptions = (chainId: number) => {
122
+ return executionOptions
123
+ ? {
124
+ ...executionOptions,
125
+ chainId: chainId.toString(),
126
+ }
127
+ : {
128
+ from: address,
129
+ chainId: chainId.toString(),
130
+ };
131
+ };
132
+
133
+ const enqueueTx = async (transaction: SendTransactionOption) => {
134
+ const body = {
135
+ executionOptions: getExecutionOptions(transaction.chainId),
136
+ params: [
137
+ {
138
+ to: transaction.to ?? undefined,
139
+ data: transaction.data,
140
+ value: transaction.value?.toString(),
141
+ },
142
+ ],
143
+ };
144
+
145
+ const result = await sendTransaction({
146
+ baseUrl: getThirdwebBaseUrl("engineCloud"),
147
+ fetch: getClientFetch(client),
148
+ headers,
149
+ body,
150
+ });
151
+
152
+ if (result.error) {
153
+ throw new Error(`Error sending transaction: ${result.error}`);
154
+ }
155
+
156
+ const data = result.data?.result;
157
+ if (!data) {
158
+ throw new Error("No data returned from engine");
159
+ }
160
+ const transactionId = data.transactions?.[0]?.id;
161
+ if (!transactionId) {
162
+ throw new Error("No transactionId returned from engine");
163
+ }
164
+ return transactionId;
165
+ };
166
+
167
+ return {
168
+ address,
169
+ enqueueTransaction: async (args: {
170
+ transaction: PreparedTransaction;
171
+ simulate?: boolean;
172
+ }) => {
173
+ let serializedTransaction: SendTransactionOption;
174
+ if (args.simulate) {
175
+ serializedTransaction = await toSerializableTransaction({
176
+ transaction: args.transaction,
177
+ });
178
+ } else {
179
+ const [to, data, value] = await Promise.all([
180
+ args.transaction.to
181
+ ? resolvePromisedValue(args.transaction.to)
182
+ : null,
183
+ encode(args.transaction),
184
+ args.transaction.value
185
+ ? resolvePromisedValue(args.transaction.value)
186
+ : null,
187
+ ]);
188
+ serializedTransaction = {
189
+ chainId: args.transaction.chain.id,
190
+ data,
191
+ to: to ?? undefined,
192
+ value: value ?? undefined,
193
+ };
194
+ }
195
+ const transactionId = await enqueueTx(serializedTransaction);
196
+ return { transactionId };
197
+ },
198
+ sendTransaction: async (transaction: SendTransactionOption) => {
199
+ const transactionId = await enqueueTx(transaction);
200
+ return waitForTransactionHash({
201
+ client,
202
+ transactionId,
203
+ });
204
+ },
205
+ signMessage: async (data) => {
206
+ const { message, chainId } = data;
207
+ let engineMessage: string | Hex;
208
+ let isBytes = false;
209
+ if (typeof message === "string") {
210
+ engineMessage = message;
211
+ } else {
212
+ engineMessage = toHex(message.raw);
213
+ isBytes = true;
214
+ }
215
+
216
+ const signingChainId = chainId || chain?.id;
217
+ if (!signingChainId) {
218
+ throw new Error("Chain ID is required for signing messages");
219
+ }
220
+
221
+ const signResult = await signMessage({
222
+ baseUrl: getThirdwebBaseUrl("engineCloud"),
223
+ fetch: getClientFetch(client),
224
+ headers,
225
+ body: {
226
+ executionOptions: getExecutionOptions(signingChainId),
227
+ params: [
228
+ {
229
+ message: engineMessage,
230
+ messageFormat: isBytes ? "hex" : "text",
231
+ },
232
+ ],
233
+ },
234
+ });
235
+
236
+ if (signResult.error) {
237
+ throw new Error(
238
+ `Error signing message: ${stringify(signResult.error)}`,
239
+ );
240
+ }
241
+
242
+ const signatureResult = signResult.data?.result.results[0];
243
+ if (signatureResult?.success) {
244
+ return signatureResult.result.signature as Hex;
245
+ }
246
+
247
+ throw new Error(
248
+ `Failed to sign message: ${signatureResult?.error?.message || "Unknown error"}`,
249
+ );
250
+ },
251
+ signTypedData: async (typedData) => {
252
+ const signingChainId = chain?.id;
253
+ if (!signingChainId) {
254
+ throw new Error("Chain ID is required for signing messages");
255
+ }
256
+
257
+ const signResult = await signTypedData({
258
+ baseUrl: getThirdwebBaseUrl("engineCloud"),
259
+ fetch: getClientFetch(client),
260
+ headers,
261
+ body: {
262
+ executionOptions: getExecutionOptions(signingChainId),
263
+ // biome-ignore lint/suspicious/noExplicitAny: TODO: fix ts / hey-api type clash
264
+ params: [typedData as any],
265
+ },
266
+ });
267
+
268
+ if (signResult.error) {
269
+ throw new Error(
270
+ `Error signing message: ${stringify(signResult.error)}`,
271
+ );
272
+ }
273
+
274
+ const signatureResult = signResult.data?.result.results[0];
275
+ if (signatureResult?.success) {
276
+ return signatureResult.result.signature as Hex;
277
+ }
278
+
279
+ throw new Error(
280
+ `Failed to sign message: ${signatureResult?.error?.message || "Unknown error"}`,
281
+ );
282
+ },
283
+ };
284
+ }
@@ -0,0 +1 @@
1
+ export * from "../engine/index.js";
@@ -81,6 +81,11 @@ export * as Bridge from "../bridge/index.js";
81
81
  */
82
82
  export * as Insight from "../insight/index.js";
83
83
 
84
+ /**
85
+ * ENGINE
86
+ */
87
+ export * as Engine from "../engine/index.js";
88
+
84
89
  /**
85
90
  * WALLETS
86
91
  */
@@ -58,7 +58,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("erc721.getNFT", () => {
58
58
  includeOwner: true,
59
59
  });
60
60
  expect(nft.metadata.name).toBe("Doodle #1");
61
- expect(nft.owner).toBe("0xbE9936FCFC50666f5425FDE4A9decC59cEF73b24");
61
+ expect(nft.owner).toBeDefined();
62
62
  expect(nft).toMatchInlineSnapshot(`
63
63
  {
64
64
  "chainId": 1,
@@ -92,7 +92,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("erc721.getNFT", () => {
92
92
  "name": "Doodle #1",
93
93
  "uri": "ipfs://QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/1",
94
94
  },
95
- "owner": "0xbE9936FCFC50666f5425FDE4A9decC59cEF73b24",
95
+ "owner": "0x620b70123fB810F6C653DA7644b5dD0b6312e4D8",
96
96
  "tokenAddress": "0x8a90cab2b38dba80c64b7734e58ee1db38b8992e",
97
97
  "tokenURI": "ipfs://QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/1",
98
98
  "type": "ERC721",