thirdweb 5.105.2 → 5.105.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 (76) hide show
  1. package/dist/cjs/engine/server-wallet.js +64 -19
  2. package/dist/cjs/engine/server-wallet.js.map +1 -1
  3. package/dist/cjs/engine/wait-for-tx-hash.js +1 -1
  4. package/dist/cjs/engine/wait-for-tx-hash.js.map +1 -1
  5. package/dist/cjs/exports/wallets/in-app.js +5 -1
  6. package/dist/cjs/exports/wallets/in-app.js.map +1 -1
  7. package/dist/cjs/exports/wallets/in-app.native.js +5 -1
  8. package/dist/cjs/exports/wallets/in-app.native.js.map +1 -1
  9. package/dist/cjs/extensions/erc7702/account/createSessionKey.js +127 -0
  10. package/dist/cjs/extensions/erc7702/account/createSessionKey.js.map +1 -0
  11. package/dist/cjs/extensions/erc7702/account/types.js +57 -0
  12. package/dist/cjs/extensions/erc7702/account/types.js.map +1 -0
  13. package/dist/cjs/react/web/ui/Bridge/payment-details/PaymentDetails.js +1 -1
  14. package/dist/cjs/react/web/ui/Bridge/payment-details/PaymentDetails.js.map +1 -1
  15. package/dist/cjs/react/web/ui/ConnectWallet/ConnectButton.js +7 -1
  16. package/dist/cjs/react/web/ui/ConnectWallet/ConnectButton.js.map +1 -1
  17. package/dist/cjs/version.js +1 -1
  18. package/dist/cjs/wallets/defaultWallets.js +3 -1
  19. package/dist/cjs/wallets/defaultWallets.js.map +1 -1
  20. package/dist/cjs/wallets/in-app/core/authentication/backend.js +2 -1
  21. package/dist/cjs/wallets/in-app/core/authentication/backend.js.map +1 -1
  22. package/dist/cjs/wallets/in-app/core/eip7702/minimal-account.js +1 -1
  23. package/dist/esm/engine/server-wallet.js +65 -20
  24. package/dist/esm/engine/server-wallet.js.map +1 -1
  25. package/dist/esm/engine/wait-for-tx-hash.js +1 -1
  26. package/dist/esm/engine/wait-for-tx-hash.js.map +1 -1
  27. package/dist/esm/exports/wallets/in-app.js +2 -0
  28. package/dist/esm/exports/wallets/in-app.js.map +1 -1
  29. package/dist/esm/exports/wallets/in-app.native.js +2 -0
  30. package/dist/esm/exports/wallets/in-app.native.js.map +1 -1
  31. package/dist/esm/extensions/erc7702/account/createSessionKey.js +123 -0
  32. package/dist/esm/extensions/erc7702/account/createSessionKey.js.map +1 -0
  33. package/dist/esm/extensions/erc7702/account/types.js +54 -0
  34. package/dist/esm/extensions/erc7702/account/types.js.map +1 -0
  35. package/dist/esm/react/web/ui/Bridge/payment-details/PaymentDetails.js +1 -1
  36. package/dist/esm/react/web/ui/Bridge/payment-details/PaymentDetails.js.map +1 -1
  37. package/dist/esm/react/web/ui/ConnectWallet/ConnectButton.js +7 -1
  38. package/dist/esm/react/web/ui/ConnectWallet/ConnectButton.js.map +1 -1
  39. package/dist/esm/version.js +1 -1
  40. package/dist/esm/wallets/defaultWallets.js +3 -1
  41. package/dist/esm/wallets/defaultWallets.js.map +1 -1
  42. package/dist/esm/wallets/in-app/core/authentication/backend.js +2 -1
  43. package/dist/esm/wallets/in-app/core/authentication/backend.js.map +1 -1
  44. package/dist/esm/wallets/in-app/core/eip7702/minimal-account.js +1 -1
  45. package/dist/types/engine/server-wallet.d.ts +5 -2
  46. package/dist/types/engine/server-wallet.d.ts.map +1 -1
  47. package/dist/types/exports/wallets/in-app.d.ts +2 -0
  48. package/dist/types/exports/wallets/in-app.d.ts.map +1 -1
  49. package/dist/types/exports/wallets/in-app.native.d.ts +2 -0
  50. package/dist/types/exports/wallets/in-app.native.d.ts.map +1 -1
  51. package/dist/types/extensions/erc7702/account/createSessionKey.d.ts +69 -0
  52. package/dist/types/extensions/erc7702/account/createSessionKey.d.ts.map +1 -0
  53. package/dist/types/extensions/erc7702/account/types.d.ts +107 -0
  54. package/dist/types/extensions/erc7702/account/types.d.ts.map +1 -0
  55. package/dist/types/react/web/ui/Bridge/payment-details/PaymentDetails.d.ts.map +1 -1
  56. package/dist/types/react/web/ui/ConnectWallet/ConnectButton.d.ts.map +1 -1
  57. package/dist/types/version.d.ts +1 -1
  58. package/dist/types/wallets/defaultWallets.d.ts +2 -0
  59. package/dist/types/wallets/defaultWallets.d.ts.map +1 -1
  60. package/dist/types/wallets/in-app/core/authentication/backend.d.ts.map +1 -1
  61. package/package.json +2 -2
  62. package/src/engine/server-wallet.test.ts +23 -28
  63. package/src/engine/server-wallet.ts +80 -26
  64. package/src/engine/wait-for-tx-hash.ts +1 -1
  65. package/src/exports/wallets/in-app.native.ts +10 -0
  66. package/src/exports/wallets/in-app.ts +10 -0
  67. package/src/extensions/erc7702/account/createSessionKey.ts +181 -0
  68. package/src/extensions/erc7702/account/sessionkey.test.ts +132 -0
  69. package/src/extensions/erc7702/account/types.ts +94 -0
  70. package/src/react/web/ui/Bridge/payment-details/PaymentDetails.tsx +3 -7
  71. package/src/react/web/ui/ConnectWallet/ConnectButton.tsx +7 -1
  72. package/src/version.ts +1 -1
  73. package/src/wallets/defaultWallets.ts +5 -1
  74. package/src/wallets/in-app/core/authentication/backend.ts +2 -1
  75. package/src/wallets/in-app/core/eip7702/minimal-account.ts +1 -1
  76. package/src/wallets/in-app/web/lib/in-app-gateway.test.ts +126 -0
@@ -1,5 +1,15 @@
1
1
  // --- KEEEP IN SYNC with exports/wallets/in-app.native.ts ---
2
2
 
3
+ //ACCOUNT
4
+ export {
5
+ type CreateSessionKeyOptions,
6
+ createSessionKey,
7
+ isCreateSessionKeySupported,
8
+ } from "../../extensions/erc7702/account/createSessionKey.js";
9
+ export type {
10
+ Condition,
11
+ LimitType,
12
+ } from "../../extensions/erc7702/account/types.js";
3
13
  export {
4
14
  getSocialIcon,
5
15
  socialIcons,
@@ -0,0 +1,181 @@
1
+ import type { BaseTransactionOptions } from "../../../transaction/types.js";
2
+ import { randomBytesHex } from "../../../utils/random.js";
3
+ import type { Account } from "../../../wallets/interfaces/wallet.js";
4
+ import {
5
+ createSessionWithSig,
6
+ isCreateSessionWithSigSupported,
7
+ } from "../__generated__/MinimalAccount/write/createSessionWithSig.js";
8
+ import {
9
+ type CallSpecInput,
10
+ CallSpecRequest,
11
+ ConstraintRequest,
12
+ SessionSpecRequest,
13
+ type TransferSpecInput,
14
+ TransferSpecRequest,
15
+ UsageLimitRequest,
16
+ } from "./types.js";
17
+
18
+ /**
19
+ * @extension ERC7702
20
+ */
21
+ export type CreateSessionKeyOptions = {
22
+ /**
23
+ * The admin account that will perform the operation.
24
+ */
25
+ account: Account;
26
+ /**
27
+ * The address to add as a session key.
28
+ */
29
+ sessionKeyAddress: string;
30
+ /**
31
+ * How long the session key should be valid for, in seconds.
32
+ */
33
+ durationInSeconds: number;
34
+ /**
35
+ * Whether to grant full execution permissions to the session key.
36
+ */
37
+ grantFullPermissions?: boolean;
38
+ /**
39
+ * Smart contract interaction policies to apply to the session key, ignored if grantFullPermissions is true.
40
+ */
41
+ callPolicies?: CallSpecInput[];
42
+ /**
43
+ * Value transfer policies to apply to the session key, ignored if grantFullPermissions is true.
44
+ */
45
+ transferPolicies?: TransferSpecInput[];
46
+ };
47
+
48
+ /**
49
+ * Creates session key permissions for a specified address.
50
+ * @param options - The options for the createSessionKey function.
51
+ * @param {Contract} options.contract - The EIP-7702 smart EOA contract to create the session key from
52
+ * @returns The transaction object to be sent.
53
+ * @example
54
+ * ```ts
55
+ * import { createSessionKey } from 'thirdweb/extensions/7702';
56
+ * import { sendTransaction } from 'thirdweb';
57
+ *
58
+ * const transaction = createSessionKey({
59
+ * account: account,
60
+ * contract: accountContract,
61
+ * sessionKeyAddress: TEST_ACCOUNT_A.address,
62
+ * durationInSeconds: 86400, // 1 day
63
+ * grantFullPermissions: true
64
+ *})
65
+ *
66
+ * await sendTransaction({ transaction, account });
67
+ * ```
68
+ * @extension ERC7702
69
+ */
70
+ export function createSessionKey(
71
+ options: BaseTransactionOptions<CreateSessionKeyOptions>,
72
+ ) {
73
+ const {
74
+ contract,
75
+ account,
76
+ sessionKeyAddress,
77
+ durationInSeconds,
78
+ grantFullPermissions,
79
+ callPolicies,
80
+ transferPolicies,
81
+ } = options;
82
+
83
+ if (durationInSeconds <= 0) {
84
+ throw new Error("durationInSeconds must be positive");
85
+ }
86
+
87
+ return createSessionWithSig({
88
+ async asyncParams() {
89
+ const req = {
90
+ callPolicies: (callPolicies || []).map((policy) => ({
91
+ constraints: (policy.constraints || []).map((constraint) => ({
92
+ condition: Number(constraint.condition),
93
+ index: constraint.index || BigInt(0),
94
+ limit: constraint.limit
95
+ ? {
96
+ limit: constraint.limit.limit,
97
+ limitType: Number(constraint.limit.limitType),
98
+ period: constraint.limit.period,
99
+ }
100
+ : {
101
+ limit: BigInt(0),
102
+ limitType: 0,
103
+ period: BigInt(0),
104
+ },
105
+ refValue: constraint.refValue || "0x",
106
+ })),
107
+ maxValuePerUse: policy.maxValuePerUse || BigInt(0),
108
+ selector: policy.selector,
109
+ target: policy.target,
110
+ valueLimit: policy.valueLimit
111
+ ? {
112
+ limit: policy.valueLimit.limit,
113
+ limitType: Number(policy.valueLimit.limitType),
114
+ period: policy.valueLimit.period,
115
+ }
116
+ : {
117
+ limit: BigInt(0),
118
+ limitType: 0,
119
+ period: BigInt(0),
120
+ },
121
+ })),
122
+ expiresAt: BigInt(Math.floor(Date.now() / 1000) + durationInSeconds),
123
+ isWildcard: grantFullPermissions ?? true,
124
+ signer: sessionKeyAddress,
125
+ transferPolicies: (transferPolicies || []).map((policy) => ({
126
+ maxValuePerUse: policy.maxValuePerUse || BigInt(0),
127
+ target: policy.target,
128
+ valueLimit: policy.valueLimit
129
+ ? {
130
+ limit: policy.valueLimit.limit,
131
+ limitType: Number(policy.valueLimit.limitType),
132
+ period: policy.valueLimit.period,
133
+ }
134
+ : {
135
+ limit: BigInt(0),
136
+ limitType: 0,
137
+ period: BigInt(0),
138
+ },
139
+ })),
140
+ uid: await randomBytesHex(),
141
+ };
142
+
143
+ const signature = await account.signTypedData({
144
+ domain: {
145
+ chainId: contract.chain.id,
146
+ name: "MinimalAccount",
147
+ verifyingContract: contract.address,
148
+ version: "1",
149
+ },
150
+ message: req,
151
+ primaryType: "SessionSpec",
152
+ types: {
153
+ CallSpec: CallSpecRequest,
154
+ Constraint: ConstraintRequest,
155
+ SessionSpec: SessionSpecRequest,
156
+ TransferSpec: TransferSpecRequest,
157
+ UsageLimit: UsageLimitRequest,
158
+ },
159
+ });
160
+
161
+ return { sessionSpec: req, signature };
162
+ },
163
+ contract,
164
+ });
165
+ }
166
+
167
+ /**
168
+ * Checks if the `isCreateSessionKeySupported` method is supported by the given contract.
169
+ * @param availableSelectors An array of 4byte function selectors of the contract. You can get this in various ways, such as using "whatsabi" or if you have the ABI of the contract available you can use it to generate the selectors.
170
+ * @returns A boolean indicating if the `isAddSessionKeySupported` method is supported.
171
+ * @extension ERC7702
172
+ * @example
173
+ * ```ts
174
+ * import { isCreateSessionKeySupported } from "thirdweb/extensions/erc7702";
175
+ *
176
+ * const supported = isCreateSessionKeySupported(["0x..."]);
177
+ * ```
178
+ */
179
+ export function isCreateSessionKeySupported(availableSelectors: string[]) {
180
+ return isCreateSessionWithSigSupported(availableSelectors);
181
+ }
@@ -0,0 +1,132 @@
1
+ import { defineChain } from "src/chains/utils.js";
2
+ import { prepareTransaction } from "src/transaction/prepare-transaction.js";
3
+ import { inAppWallet } from "src/wallets/in-app/web/in-app.js";
4
+ import type { Account } from "src/wallets/interfaces/wallet.js";
5
+ import { beforeAll, describe, expect, it } from "vitest";
6
+ import { TEST_CLIENT } from "../../../../test/src/test-clients.js";
7
+ import { TEST_ACCOUNT_A } from "../../../../test/src/test-wallets.js";
8
+ import { ZERO_ADDRESS } from "../../../constants/addresses.js";
9
+ import {
10
+ getContract,
11
+ type ThirdwebContract,
12
+ } from "../../../contract/contract.js";
13
+ import { parseEventLogs } from "../../../event/actions/parse-logs.js";
14
+ import { sendAndConfirmTransaction } from "../../../transaction/actions/send-and-confirm-transaction.js";
15
+ import { sessionCreatedEvent } from "../__generated__/MinimalAccount/events/SessionCreated.js";
16
+ import { createSessionKey } from "./createSessionKey.js";
17
+ import { Condition, LimitType } from "./types.js";
18
+
19
+ describe.runIf(process.env.TW_SECRET_KEY)(
20
+ "Session Key Behavior",
21
+ {
22
+ retry: 0,
23
+ timeout: 240_000,
24
+ },
25
+ () => {
26
+ const chainId = 11155111;
27
+ let account: Account;
28
+ let accountContract: ThirdwebContract;
29
+
30
+ beforeAll(async () => {
31
+ // Create 7702 Smart EOA
32
+ const wallet = inAppWallet({
33
+ executionMode: {
34
+ mode: "EIP7702",
35
+ sponsorGas: true,
36
+ },
37
+ });
38
+ account = await wallet.connect({
39
+ chain: defineChain(chainId),
40
+ client: TEST_CLIENT,
41
+ strategy: "guest",
42
+ });
43
+
44
+ // Send a null tx to trigger deploy/upgrade
45
+ await sendAndConfirmTransaction({
46
+ account: account,
47
+ transaction: prepareTransaction({
48
+ chain: defineChain(chainId),
49
+ client: TEST_CLIENT,
50
+ to: account.address,
51
+ value: 0n,
52
+ }),
53
+ });
54
+
55
+ // Will auto resolve abi since it's deployed
56
+ accountContract = getContract({
57
+ address: account.address,
58
+ chain: defineChain(chainId),
59
+ client: TEST_CLIENT,
60
+ });
61
+ }, 120_000);
62
+
63
+ it("should allow adding adminlike session keys", async () => {
64
+ const receipt = await sendAndConfirmTransaction({
65
+ account: account,
66
+ transaction: createSessionKey({
67
+ account: account,
68
+ contract: accountContract,
69
+ durationInSeconds: 86400,
70
+ grantFullPermissions: true, // 1 day
71
+ sessionKeyAddress: TEST_ACCOUNT_A.address,
72
+ }),
73
+ });
74
+ const logs = parseEventLogs({
75
+ events: [sessionCreatedEvent()],
76
+ logs: receipt.logs,
77
+ });
78
+ expect(logs[0]?.args.signer).toBe(TEST_ACCOUNT_A.address);
79
+ });
80
+
81
+ it("should allow adding granular session keys", async () => {
82
+ const receipt = await sendAndConfirmTransaction({
83
+ account: account,
84
+ transaction: createSessionKey({
85
+ account: account,
86
+ callPolicies: [
87
+ {
88
+ constraints: [
89
+ {
90
+ condition: Condition.Unconstrained,
91
+ index: 0n,
92
+ refValue:
93
+ "0x0000000000000000000000000000000000000000000000000000000000000000",
94
+ },
95
+ ],
96
+ maxValuePerUse: 0n,
97
+ selector: "0x00000000",
98
+ target: ZERO_ADDRESS,
99
+ valueLimit: {
100
+ limit: 0n,
101
+ limitType: LimitType.Unlimited,
102
+ period: 0n,
103
+ },
104
+ },
105
+ ],
106
+ contract: accountContract,
107
+ durationInSeconds: 86400, // 1 day
108
+ grantFullPermissions: false,
109
+ sessionKeyAddress: TEST_ACCOUNT_A.address,
110
+ transferPolicies: [
111
+ {
112
+ maxValuePerUse: 0n,
113
+ target: ZERO_ADDRESS,
114
+ valueLimit: {
115
+ limit: 0n,
116
+ limitType: 0,
117
+ period: 0n,
118
+ },
119
+ },
120
+ ],
121
+ }),
122
+ });
123
+ const logs = parseEventLogs({
124
+ events: [sessionCreatedEvent()],
125
+ logs: receipt.logs,
126
+ });
127
+ expect(logs[0]?.args.signer).toBe(TEST_ACCOUNT_A.address);
128
+ expect(logs[0]?.args.sessionSpec.callPolicies).toHaveLength(1);
129
+ expect(logs[0]?.args.sessionSpec.transferPolicies).toHaveLength(1);
130
+ });
131
+ },
132
+ );
@@ -0,0 +1,94 @@
1
+ /* ────────────────────────────────
2
+ Enums
3
+ ──────────────────────────────── */
4
+
5
+ export enum LimitType {
6
+ Unlimited = 0,
7
+ Lifetime = 1,
8
+ Allowance = 2,
9
+ }
10
+
11
+ export enum Condition {
12
+ Unconstrained = 0,
13
+ Equal = 1,
14
+ Greater = 2,
15
+ Less = 3,
16
+ GreaterOrEqual = 4,
17
+ LessOrEqual = 5,
18
+ NotEqual = 6,
19
+ }
20
+
21
+ /* ────────────────────────────────
22
+ Input types
23
+ ──────────────────────────────── */
24
+
25
+ /* ---------- UsageLimit ---------- */
26
+ interface UsageLimitInput {
27
+ limitType: LimitType;
28
+ limit: bigint;
29
+ period: bigint;
30
+ }
31
+
32
+ /* ---------- Constraint ---------- */
33
+ interface ConstraintInput {
34
+ condition: Condition;
35
+ index: bigint;
36
+ refValue: `0x${string}`;
37
+ limit?: UsageLimitInput;
38
+ }
39
+
40
+ /* ---------- CallSpec ---------- */
41
+ export interface CallSpecInput {
42
+ target: `0x${string}`;
43
+ selector: `0x${string}`;
44
+ maxValuePerUse?: bigint;
45
+ valueLimit?: UsageLimitInput;
46
+ constraints?: ConstraintInput[];
47
+ }
48
+
49
+ /* ---------- TransferSpec ---------- */
50
+ export interface TransferSpecInput {
51
+ target: `0x${string}`;
52
+ maxValuePerUse?: bigint;
53
+ valueLimit?: UsageLimitInput;
54
+ }
55
+
56
+ /* ────────────────────────────────
57
+ EIP-712 structs
58
+ ──────────────────────────────── */
59
+
60
+ export const UsageLimitRequest = [
61
+ { name: "limitType", type: "uint8" },
62
+ { name: "limit", type: "uint256" },
63
+ { name: "period", type: "uint256" },
64
+ ] as const;
65
+
66
+ export const ConstraintRequest = [
67
+ { name: "condition", type: "uint8" },
68
+ { name: "index", type: "uint64" },
69
+ { name: "refValue", type: "bytes32" },
70
+ { name: "limit", type: "UsageLimit" },
71
+ ] as const;
72
+
73
+ export const CallSpecRequest = [
74
+ { name: "target", type: "address" },
75
+ { name: "selector", type: "bytes4" },
76
+ { name: "maxValuePerUse", type: "uint256" },
77
+ { name: "valueLimit", type: "UsageLimit" },
78
+ { name: "constraints", type: "Constraint[]" },
79
+ ] as const;
80
+
81
+ export const TransferSpecRequest = [
82
+ { name: "target", type: "address" },
83
+ { name: "maxValuePerUse", type: "uint256" },
84
+ { name: "valueLimit", type: "UsageLimit" },
85
+ ] as const;
86
+
87
+ export const SessionSpecRequest = [
88
+ { name: "signer", type: "address" },
89
+ { name: "isWildcard", type: "bool" },
90
+ { name: "expiresAt", type: "uint256" },
91
+ { name: "callPolicies", type: "CallSpec[]" },
92
+ { name: "transferPolicies", type: "TransferSpec[]" },
93
+ { name: "uid", type: "bytes32" },
94
+ ] as const;
@@ -370,13 +370,9 @@ export function PaymentDetails({
370
370
  }
371
371
  </>
372
372
  ) : (
373
- <>
374
- {
375
- chainsMetadata.find(
376
- (c) => c.chainId === step.originToken.chainId,
377
- )?.name
378
- }
379
- </>
373
+ chainsMetadata.find(
374
+ (c) => c.chainId === step.originToken.chainId,
375
+ )?.name
380
376
  )}
381
377
  </Text>
382
378
  </Container>
@@ -292,8 +292,14 @@ export function ConnectButton(props: ConnectButtonProps) {
292
292
  getDefaultWallets({
293
293
  appMetadata: props.appMetadata,
294
294
  chains: props.chains,
295
+ executionMode: props.accountAbstraction
296
+ ? {
297
+ mode: "EIP4337",
298
+ smartAccount: props.accountAbstraction,
299
+ }
300
+ : undefined,
295
301
  }),
296
- [props.wallets, props.appMetadata, props.chains],
302
+ [props.wallets, props.appMetadata, props.chains, props.accountAbstraction],
297
303
  );
298
304
  const localeQuery = useConnectLocale(props.locale || "en_US");
299
305
  const connectionManager = useConnectionManager();
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = "5.105.2";
1
+ export const version = "5.105.3";
@@ -1,6 +1,7 @@
1
1
  import type { Chain } from "../chains/types.js";
2
2
  import { COINBASE, METAMASK, RAINBOW, ZERION } from "./constants.js";
3
3
  import { createWallet } from "./create-wallet.js";
4
+ import type { ExecutionModeOptions } from "./in-app/core/wallet/types.js";
4
5
  import type { Wallet } from "./interfaces/wallet.js";
5
6
  import type { AppMetadata } from "./types.js";
6
7
 
@@ -10,9 +11,12 @@ import type { AppMetadata } from "./types.js";
10
11
  export function getDefaultWallets(options?: {
11
12
  appMetadata?: AppMetadata;
12
13
  chains?: Chain[];
14
+ executionMode?: ExecutionModeOptions;
13
15
  }): Wallet[] {
14
16
  return [
15
- createWallet("inApp"),
17
+ createWallet("inApp", {
18
+ executionMode: options?.executionMode,
19
+ }),
16
20
  createWallet(METAMASK),
17
21
  createWallet(COINBASE, {
18
22
  appMetadata: options?.appMetadata,
@@ -31,7 +31,8 @@ export async function backendAuthenticate(args: {
31
31
  });
32
32
 
33
33
  if (!res.ok) {
34
- throw new Error("Failed to generate backend account");
34
+ const error = await res.text();
35
+ throw new Error(`Failed to generate backend account: ${error}`);
35
36
  }
36
37
 
37
38
  return (await res.json()) satisfies AuthStoredTokenWithCookieReturnType;
@@ -24,7 +24,7 @@ import {
24
24
  import type { BundlerOptions } from "../../../smart/types.js";
25
25
 
26
26
  const MINIMAL_ACCOUNT_IMPLEMENTATION_ADDRESS =
27
- "0xbaC7e770af15d130Cd72838ff386f14FBF3e9a3D";
27
+ "0xD6999651Fc0964B9c6B444307a0ab20534a66560";
28
28
 
29
29
  export const create7702MinimalAccount = (args: {
30
30
  client: ThirdwebClient;
@@ -0,0 +1,126 @@
1
+ import { sendTransaction, signMessage } from "@thirdweb-dev/engine";
2
+ import { beforeAll, describe, expect, it } from "vitest";
3
+ import { TEST_CLIENT } from "~test/test-clients.js";
4
+ import { sepolia } from "../../../../chains/chain-definitions/sepolia.js";
5
+ import { createThirdwebClient } from "../../../../client/client.js";
6
+ import { waitForTransactionHash } from "../../../../engine/wait-for-tx-hash.js";
7
+ import {
8
+ getThirdwebBaseUrl,
9
+ setThirdwebDomains,
10
+ } from "../../../../utils/domains.js";
11
+ import { getClientFetch } from "../../../../utils/fetch.js";
12
+ import { stringify } from "../../../../utils/json.js";
13
+ import type { Account } from "../../../interfaces/wallet.js";
14
+ import { inAppWallet } from "../in-app.js";
15
+
16
+ // TODO: productionize this test
17
+ describe
18
+ .runIf(process.env.TW_SECRET_KEY)
19
+ .skip("InAppWallet Gateway Tests", () => {
20
+ let account: Account;
21
+ let authToken: string | null | undefined;
22
+ const clientIdFetch = getClientFetch(
23
+ createThirdwebClient({
24
+ clientId: TEST_CLIENT.clientId,
25
+ }),
26
+ );
27
+
28
+ beforeAll(async () => {
29
+ setThirdwebDomains({
30
+ bundler: "bundler.thirdweb-dev.com",
31
+ engineCloud: "engine.thirdweb-dev.com",
32
+ inAppWallet: "embedded-wallet.thirdweb-dev.com",
33
+ rpc: "rpc.thirdweb-dev.com",
34
+ });
35
+ const wallet = inAppWallet();
36
+ account = await wallet.connect({
37
+ client: TEST_CLIENT,
38
+ strategy: "backend",
39
+ walletSecret: "test-secret",
40
+ });
41
+ authToken = wallet.getAuthToken?.();
42
+ expect(authToken).toBeDefined();
43
+ });
44
+
45
+ it("should sign a message with backend strategy", async () => {
46
+ const rawSignature = await account.signMessage({
47
+ message: "Hello, world!",
48
+ });
49
+
50
+ // sign via api
51
+ const signResult = await signMessage({
52
+ baseUrl: getThirdwebBaseUrl("engineCloud"),
53
+ body: {
54
+ params: [
55
+ {
56
+ format: "text",
57
+ message: "Hello, world!",
58
+ },
59
+ ],
60
+ signingOptions: {
61
+ from: account.address,
62
+ type: "eoa",
63
+ },
64
+ },
65
+ bodySerializer: stringify,
66
+ fetch: clientIdFetch,
67
+ headers: {
68
+ "x-wallet-access-token": authToken,
69
+ },
70
+ });
71
+
72
+ const signatureResult = signResult.data?.result?.results[0];
73
+ if (signatureResult && "result" in signatureResult) {
74
+ expect(signatureResult.result.signature).toEqual(rawSignature);
75
+ } else {
76
+ throw new Error(
77
+ `Failed to sign message: ${stringify(signatureResult?.error) || "Unknown error"}`,
78
+ );
79
+ }
80
+ });
81
+
82
+ it("should queue a 4337 transaction", async () => {
83
+ const body = {
84
+ executionOptions: {
85
+ chainId: sepolia.id,
86
+ from: account.address,
87
+ type: "auto" as const,
88
+ },
89
+ params: [
90
+ {
91
+ data: "0x",
92
+ to: account.address,
93
+ value: "0",
94
+ },
95
+ ],
96
+ };
97
+ const result = await sendTransaction({
98
+ baseUrl: getThirdwebBaseUrl("engineCloud"),
99
+ body,
100
+ bodySerializer: stringify,
101
+ fetch: clientIdFetch,
102
+ headers: {
103
+ "x-wallet-access-token": authToken,
104
+ },
105
+ });
106
+ if (result.error) {
107
+ throw new Error(
108
+ `Error sending transaction: ${stringify(result.error)}`,
109
+ );
110
+ }
111
+
112
+ const txId = result.data?.result.transactions[0]?.id;
113
+ console.log(txId);
114
+ if (!txId) {
115
+ throw new Error("No transaction ID found");
116
+ }
117
+
118
+ const tx = await waitForTransactionHash({
119
+ client: TEST_CLIENT,
120
+ transactionId: txId,
121
+ });
122
+
123
+ console.log(tx);
124
+ expect(tx.transactionHash).toBeDefined();
125
+ });
126
+ });