thirdweb 5.73.1-nightly-33c23e789e577bd6463e135cec4e25cfcfc9964a-20241205000340 → 5.74.0
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.
- package/dist/cjs/exports/wallets/smart.js +2 -1
- package/dist/cjs/exports/wallets/smart.js.map +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/screens/SignatureScreen.js +12 -10
- package/dist/cjs/react/web/ui/ConnectWallet/screens/SignatureScreen.js.map +1 -1
- package/dist/cjs/react/web/wallets/shared/ConnectWalletSocialOptions.js +1 -1
- package/dist/cjs/react/web/wallets/shared/ConnectWalletSocialOptions.js.map +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/version.js.map +1 -1
- package/dist/cjs/wallets/ecosystem/is-ecosystem-wallet.js +1 -1
- package/dist/cjs/wallets/in-app/core/wallet/in-app-core.js +8 -4
- package/dist/cjs/wallets/in-app/core/wallet/in-app-core.js.map +1 -1
- package/dist/cjs/wallets/in-app/web/ecosystem.js +1 -1
- package/dist/cjs/wallets/in-app/web/in-app.js +2 -2
- package/dist/cjs/wallets/smart/index.js +19 -12
- package/dist/cjs/wallets/smart/index.js.map +1 -1
- package/dist/cjs/wallets/smart/lib/bundler.js +2 -1
- package/dist/cjs/wallets/smart/lib/bundler.js.map +1 -1
- package/dist/cjs/wallets/smart/lib/constants.js +21 -1
- package/dist/cjs/wallets/smart/lib/constants.js.map +1 -1
- package/dist/cjs/wallets/smart/lib/userop.js +19 -4
- package/dist/cjs/wallets/smart/lib/userop.js.map +1 -1
- package/dist/cjs/wallets/smart/smart-wallet.js +1 -1
- package/dist/cjs/wallets/smart/types.js.map +1 -1
- package/dist/esm/exports/wallets/smart.js +1 -1
- package/dist/esm/exports/wallets/smart.js.map +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/screens/SignatureScreen.js +12 -10
- package/dist/esm/react/web/ui/ConnectWallet/screens/SignatureScreen.js.map +1 -1
- package/dist/esm/react/web/wallets/shared/ConnectWalletSocialOptions.js +1 -1
- package/dist/esm/react/web/wallets/shared/ConnectWalletSocialOptions.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/version.js.map +1 -1
- package/dist/esm/wallets/ecosystem/is-ecosystem-wallet.js +1 -1
- package/dist/esm/wallets/in-app/core/wallet/in-app-core.js +9 -5
- package/dist/esm/wallets/in-app/core/wallet/in-app-core.js.map +1 -1
- package/dist/esm/wallets/in-app/web/ecosystem.js +1 -1
- package/dist/esm/wallets/in-app/web/in-app.js +2 -2
- package/dist/esm/wallets/smart/index.js +20 -13
- package/dist/esm/wallets/smart/index.js.map +1 -1
- package/dist/esm/wallets/smart/lib/bundler.js +2 -1
- package/dist/esm/wallets/smart/lib/bundler.js.map +1 -1
- package/dist/esm/wallets/smart/lib/constants.js +20 -0
- package/dist/esm/wallets/smart/lib/constants.js.map +1 -1
- package/dist/esm/wallets/smart/lib/userop.js +20 -5
- package/dist/esm/wallets/smart/lib/userop.js.map +1 -1
- package/dist/esm/wallets/smart/smart-wallet.js +1 -1
- package/dist/esm/wallets/smart/types.js.map +1 -1
- package/dist/types/exports/wallets/smart.d.ts +1 -1
- package/dist/types/exports/wallets/smart.d.ts.map +1 -1
- package/dist/types/react/web/ui/ConnectWallet/screens/SignatureScreen.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/types/version.d.ts.map +1 -1
- package/dist/types/wallets/ecosystem/get-ecosystem-wallet-auth-options.d.ts +1 -1
- package/dist/types/wallets/ecosystem/get-ecosystem-wallet-auth-options.d.ts.map +1 -1
- package/dist/types/wallets/in-app/core/wallet/in-app-core.d.ts.map +1 -1
- package/dist/types/wallets/in-app/web/ecosystem.d.ts +1 -1
- package/dist/types/wallets/in-app/web/in-app.d.ts +2 -2
- package/dist/types/wallets/smart/index.d.ts.map +1 -1
- package/dist/types/wallets/smart/lib/bundler.d.ts +6 -0
- package/dist/types/wallets/smart/lib/bundler.d.ts.map +1 -1
- package/dist/types/wallets/smart/lib/constants.d.ts +4 -0
- package/dist/types/wallets/smart/lib/constants.d.ts.map +1 -1
- package/dist/types/wallets/smart/lib/userop.d.ts.map +1 -1
- package/dist/types/wallets/smart/smart-wallet.d.ts +1 -1
- package/dist/types/wallets/smart/types.d.ts +7 -4
- package/dist/types/wallets/smart/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/exports/wallets/smart.ts +1 -0
- package/src/react/web/ui/ConnectWallet/screens/SignatureScreen.test.tsx +287 -0
- package/src/react/web/ui/ConnectWallet/screens/SignatureScreen.tsx +13 -5
- package/src/react/web/wallets/shared/ConnectWalletSocialOptions.test.tsx +87 -0
- package/src/react/web/wallets/shared/ConnectWalletSocialOptions.tsx +1 -1
- package/src/version.ts +1 -1
- package/src/wallets/ecosystem/get-ecosystem-wallet-auth-options.ts +1 -1
- package/src/wallets/ecosystem/is-ecosystem-wallet.ts +1 -1
- package/src/wallets/in-app/core/wallet/in-app-core.test.ts +270 -0
- package/src/wallets/in-app/core/wallet/in-app-core.ts +16 -5
- package/src/wallets/in-app/web/ecosystem.ts +1 -1
- package/src/wallets/in-app/web/in-app.ts +2 -2
- package/src/wallets/smart/index.ts +37 -17
- package/src/wallets/smart/lib/bundler.ts +14 -4
- package/src/wallets/smart/lib/constants.ts +23 -0
- package/src/wallets/smart/lib/userop.ts +31 -8
- package/src/wallets/smart/smart-wallet-tokenpaymaster.test.ts +117 -0
- package/src/wallets/smart/smart-wallet.ts +1 -1
- package/src/wallets/smart/types.ts +8 -4
@@ -0,0 +1,270 @@
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
2
|
+
import { baseSepolia } from "../../../../chains/chain-definitions/base-sepolia.js";
|
3
|
+
import { createThirdwebClient } from "../../../../client/client.js";
|
4
|
+
import { getEcosystemInfo } from "../../../ecosystem/get-ecosystem-wallet-auth-options.js";
|
5
|
+
import type { Account } from "../../../interfaces/wallet.js";
|
6
|
+
import type { InAppConnector } from "../interfaces/connector.js";
|
7
|
+
import { createInAppWallet } from "./in-app-core.js";
|
8
|
+
import { autoConnectInAppWallet, connectInAppWallet } from "./index.js";
|
9
|
+
|
10
|
+
vi.mock("../../../../analytics/track/connect.js", () => ({
|
11
|
+
trackConnect: vi.fn(),
|
12
|
+
}));
|
13
|
+
|
14
|
+
vi.mock("./index.js", () => ({
|
15
|
+
autoConnectInAppWallet: vi.fn(),
|
16
|
+
connectInAppWallet: vi.fn(),
|
17
|
+
}));
|
18
|
+
|
19
|
+
vi.mock("../../../ecosystem/get-ecosystem-wallet-auth-options.js", () => ({
|
20
|
+
getEcosystemInfo: vi.fn(),
|
21
|
+
}));
|
22
|
+
|
23
|
+
describe("createInAppWallet", () => {
|
24
|
+
const mockClient = createThirdwebClient({
|
25
|
+
clientId: "test-client",
|
26
|
+
});
|
27
|
+
const mockChain = baseSepolia;
|
28
|
+
const mockAccount = { address: "0x123" } as Account;
|
29
|
+
|
30
|
+
const mockConnectorFactory = vi.fn(() =>
|
31
|
+
Promise.resolve({
|
32
|
+
connect: vi.fn(),
|
33
|
+
logout: vi.fn(() => Promise.resolve({ success: true })),
|
34
|
+
authenticate: vi.fn(),
|
35
|
+
getAccounts: vi.fn(),
|
36
|
+
getAccount: vi.fn(),
|
37
|
+
getProfiles: vi.fn(),
|
38
|
+
getUser: vi.fn(),
|
39
|
+
linkProfile: vi.fn(),
|
40
|
+
preAuthenticate: vi.fn(),
|
41
|
+
} as InAppConnector),
|
42
|
+
);
|
43
|
+
|
44
|
+
beforeEach(() => {
|
45
|
+
vi.clearAllMocks();
|
46
|
+
});
|
47
|
+
|
48
|
+
it("should connect successfully", async () => {
|
49
|
+
vi.mocked(connectInAppWallet).mockResolvedValue([mockAccount, mockChain]);
|
50
|
+
|
51
|
+
const wallet = createInAppWallet({
|
52
|
+
connectorFactory: mockConnectorFactory,
|
53
|
+
});
|
54
|
+
|
55
|
+
const result = await wallet.connect({
|
56
|
+
client: mockClient,
|
57
|
+
chain: mockChain,
|
58
|
+
strategy: "email",
|
59
|
+
email: "",
|
60
|
+
verificationCode: "",
|
61
|
+
});
|
62
|
+
|
63
|
+
expect(result).toBe(mockAccount);
|
64
|
+
expect(connectInAppWallet).toHaveBeenCalledWith(
|
65
|
+
expect.objectContaining({
|
66
|
+
client: mockClient,
|
67
|
+
chain: mockChain,
|
68
|
+
}),
|
69
|
+
undefined,
|
70
|
+
expect.any(Object),
|
71
|
+
);
|
72
|
+
});
|
73
|
+
|
74
|
+
it("should auto connect successfully", async () => {
|
75
|
+
vi.mocked(autoConnectInAppWallet).mockResolvedValue([
|
76
|
+
mockAccount,
|
77
|
+
mockChain,
|
78
|
+
]);
|
79
|
+
|
80
|
+
const wallet = createInAppWallet({
|
81
|
+
connectorFactory: mockConnectorFactory,
|
82
|
+
});
|
83
|
+
|
84
|
+
const result = await wallet.autoConnect({
|
85
|
+
client: mockClient,
|
86
|
+
chain: mockChain,
|
87
|
+
});
|
88
|
+
|
89
|
+
expect(result).toBe(mockAccount);
|
90
|
+
expect(autoConnectInAppWallet).toHaveBeenCalledWith(
|
91
|
+
expect.objectContaining({
|
92
|
+
client: mockClient,
|
93
|
+
chain: mockChain,
|
94
|
+
}),
|
95
|
+
undefined,
|
96
|
+
expect.any(Object),
|
97
|
+
);
|
98
|
+
});
|
99
|
+
|
100
|
+
it("should handle ecosystem wallet connection with smart account settings", async () => {
|
101
|
+
vi.mocked(getEcosystemInfo).mockResolvedValue({
|
102
|
+
smartAccountOptions: {
|
103
|
+
defaultChainId: mockChain.id,
|
104
|
+
sponsorGas: true,
|
105
|
+
accountFactoryAddress: "0x456",
|
106
|
+
},
|
107
|
+
authOptions: [],
|
108
|
+
name: "hello world",
|
109
|
+
slug: "test-ecosystem",
|
110
|
+
});
|
111
|
+
|
112
|
+
vi.mocked(connectInAppWallet).mockResolvedValue([mockAccount, mockChain]);
|
113
|
+
|
114
|
+
const wallet = createInAppWallet({
|
115
|
+
connectorFactory: mockConnectorFactory,
|
116
|
+
ecosystem: { id: "ecosystem.test-ecosystem" },
|
117
|
+
});
|
118
|
+
|
119
|
+
const result = await wallet.connect({
|
120
|
+
client: mockClient,
|
121
|
+
chain: mockChain,
|
122
|
+
strategy: "email",
|
123
|
+
email: "",
|
124
|
+
verificationCode: "",
|
125
|
+
});
|
126
|
+
|
127
|
+
expect(result).toBe(mockAccount);
|
128
|
+
expect(connectInAppWallet).toHaveBeenCalledWith(
|
129
|
+
expect.objectContaining({
|
130
|
+
client: mockClient,
|
131
|
+
chain: mockChain,
|
132
|
+
}),
|
133
|
+
expect.objectContaining({
|
134
|
+
smartAccount: expect.objectContaining({
|
135
|
+
chain: mockChain,
|
136
|
+
sponsorGas: true,
|
137
|
+
factoryAddress: "0x456",
|
138
|
+
}),
|
139
|
+
}),
|
140
|
+
expect.any(Object),
|
141
|
+
);
|
142
|
+
});
|
143
|
+
it("should handle ecosystem wallet connection with smart account settings even when no chain is set", async () => {
|
144
|
+
vi.mocked(getEcosystemInfo).mockResolvedValue({
|
145
|
+
smartAccountOptions: {
|
146
|
+
defaultChainId: mockChain.id,
|
147
|
+
sponsorGas: true,
|
148
|
+
accountFactoryAddress: "0x456",
|
149
|
+
},
|
150
|
+
authOptions: [],
|
151
|
+
name: "hello world",
|
152
|
+
slug: "test-ecosystem",
|
153
|
+
});
|
154
|
+
|
155
|
+
vi.mocked(connectInAppWallet).mockResolvedValue([mockAccount, mockChain]);
|
156
|
+
|
157
|
+
const wallet = createInAppWallet({
|
158
|
+
connectorFactory: mockConnectorFactory,
|
159
|
+
ecosystem: { id: "ecosystem.test-ecosystem" },
|
160
|
+
});
|
161
|
+
|
162
|
+
const result = await wallet.connect({
|
163
|
+
client: mockClient,
|
164
|
+
strategy: "email",
|
165
|
+
email: "",
|
166
|
+
verificationCode: "",
|
167
|
+
});
|
168
|
+
|
169
|
+
expect(result).toBe(mockAccount);
|
170
|
+
expect(connectInAppWallet).toHaveBeenCalledWith(
|
171
|
+
expect.objectContaining({
|
172
|
+
client: mockClient,
|
173
|
+
}),
|
174
|
+
expect.objectContaining({
|
175
|
+
smartAccount: expect.objectContaining({
|
176
|
+
chain: mockChain,
|
177
|
+
sponsorGas: true,
|
178
|
+
factoryAddress: "0x456",
|
179
|
+
}),
|
180
|
+
}),
|
181
|
+
expect.any(Object),
|
182
|
+
);
|
183
|
+
});
|
184
|
+
|
185
|
+
it("should handle ecosystem wallet auto connection with smart account settings", async () => {
|
186
|
+
vi.mocked(getEcosystemInfo).mockResolvedValue({
|
187
|
+
smartAccountOptions: {
|
188
|
+
defaultChainId: mockChain.id,
|
189
|
+
sponsorGas: true,
|
190
|
+
accountFactoryAddress: "0x456",
|
191
|
+
},
|
192
|
+
authOptions: [],
|
193
|
+
name: "hello world",
|
194
|
+
slug: "test-ecosystem",
|
195
|
+
});
|
196
|
+
|
197
|
+
vi.mocked(autoConnectInAppWallet).mockResolvedValue([
|
198
|
+
mockAccount,
|
199
|
+
mockChain,
|
200
|
+
]);
|
201
|
+
|
202
|
+
const wallet = createInAppWallet({
|
203
|
+
connectorFactory: mockConnectorFactory,
|
204
|
+
ecosystem: { id: "ecosystem.test-ecosystem" },
|
205
|
+
});
|
206
|
+
|
207
|
+
const result = await wallet.autoConnect({
|
208
|
+
client: mockClient,
|
209
|
+
chain: mockChain,
|
210
|
+
});
|
211
|
+
|
212
|
+
expect(result).toBe(mockAccount);
|
213
|
+
expect(autoConnectInAppWallet).toHaveBeenCalledWith(
|
214
|
+
expect.objectContaining({
|
215
|
+
client: mockClient,
|
216
|
+
chain: mockChain,
|
217
|
+
}),
|
218
|
+
expect.objectContaining({
|
219
|
+
smartAccount: expect.objectContaining({
|
220
|
+
chain: mockChain,
|
221
|
+
sponsorGas: true,
|
222
|
+
factoryAddress: "0x456",
|
223
|
+
}),
|
224
|
+
}),
|
225
|
+
expect.any(Object),
|
226
|
+
);
|
227
|
+
});
|
228
|
+
|
229
|
+
it("should handle ecosystem wallet auto connection with smart account settings even when no chain is set", async () => {
|
230
|
+
vi.mocked(getEcosystemInfo).mockResolvedValue({
|
231
|
+
smartAccountOptions: {
|
232
|
+
defaultChainId: mockChain.id,
|
233
|
+
sponsorGas: true,
|
234
|
+
accountFactoryAddress: "0x456",
|
235
|
+
},
|
236
|
+
authOptions: [],
|
237
|
+
name: "hello world",
|
238
|
+
slug: "test-ecosystem",
|
239
|
+
});
|
240
|
+
|
241
|
+
vi.mocked(autoConnectInAppWallet).mockResolvedValue([
|
242
|
+
mockAccount,
|
243
|
+
mockChain,
|
244
|
+
]);
|
245
|
+
|
246
|
+
const wallet = createInAppWallet({
|
247
|
+
connectorFactory: mockConnectorFactory,
|
248
|
+
ecosystem: { id: "ecosystem.test-ecosystem" },
|
249
|
+
});
|
250
|
+
|
251
|
+
const result = await wallet.autoConnect({
|
252
|
+
client: mockClient,
|
253
|
+
});
|
254
|
+
|
255
|
+
expect(result).toBe(mockAccount);
|
256
|
+
expect(autoConnectInAppWallet).toHaveBeenCalledWith(
|
257
|
+
expect.objectContaining({
|
258
|
+
client: mockClient,
|
259
|
+
}),
|
260
|
+
expect.objectContaining({
|
261
|
+
smartAccount: expect.objectContaining({
|
262
|
+
chain: mockChain,
|
263
|
+
sponsorGas: true,
|
264
|
+
factoryAddress: "0x456",
|
265
|
+
}),
|
266
|
+
}),
|
267
|
+
expect.any(Object),
|
268
|
+
);
|
269
|
+
});
|
270
|
+
});
|
@@ -1,6 +1,9 @@
|
|
1
1
|
import { trackConnect } from "../../../../analytics/track/connect.js";
|
2
2
|
import type { Chain } from "../../../../chains/types.js";
|
3
|
-
import {
|
3
|
+
import {
|
4
|
+
getCachedChain,
|
5
|
+
getCachedChainIfExists,
|
6
|
+
} from "../../../../chains/utils.js";
|
4
7
|
import type { ThirdwebClient } from "../../../../client/client.js";
|
5
8
|
import { stringify } from "../../../../utils/json.js";
|
6
9
|
import { getEcosystemInfo } from "../../../ecosystem/get-ecosystem-wallet-auth-options.js";
|
@@ -74,12 +77,16 @@ export function createInAppWallet(args: {
|
|
74
77
|
const ecosystemOptions = await getEcosystemInfo(ecosystem.id);
|
75
78
|
const smartAccountOptions = ecosystemOptions?.smartAccountOptions;
|
76
79
|
if (smartAccountOptions) {
|
77
|
-
const
|
80
|
+
const { defaultChainId } = ecosystemOptions.smartAccountOptions;
|
81
|
+
const preferredChain =
|
82
|
+
options.chain ??
|
83
|
+
(defaultChainId ? getCachedChain(defaultChainId) : undefined);
|
78
84
|
if (!preferredChain) {
|
79
85
|
throw new Error(
|
80
|
-
|
86
|
+
`A chain must be provided either via 'chain' in connect options or 'defaultChainId' in ecosystem configuration. Please pass it via connect() or update the ecosystem configuration.`,
|
81
87
|
);
|
82
88
|
}
|
89
|
+
|
83
90
|
createOptions = {
|
84
91
|
...createOptions,
|
85
92
|
smartAccount: {
|
@@ -123,12 +130,16 @@ export function createInAppWallet(args: {
|
|
123
130
|
const ecosystemOptions = await getEcosystemInfo(ecosystem.id);
|
124
131
|
const smartAccountOptions = ecosystemOptions?.smartAccountOptions;
|
125
132
|
if (smartAccountOptions) {
|
126
|
-
const
|
133
|
+
const { defaultChainId } = ecosystemOptions.smartAccountOptions;
|
134
|
+
const preferredChain =
|
135
|
+
options.chain ??
|
136
|
+
(defaultChainId ? getCachedChain(defaultChainId) : undefined);
|
127
137
|
if (!preferredChain) {
|
128
138
|
throw new Error(
|
129
|
-
|
139
|
+
`A chain must be provided either via 'chain' in connect options or 'defaultChainId' in ecosystem configuration. Please pass it via connect() or update the ecosystem configuration.`,
|
130
140
|
);
|
131
141
|
}
|
142
|
+
|
132
143
|
createOptions = {
|
133
144
|
...createOptions,
|
134
145
|
smartAccount: {
|
@@ -7,7 +7,7 @@ import type {
|
|
7
7
|
import { createInAppWallet } from "../core/wallet/in-app-core.js";
|
8
8
|
|
9
9
|
/**
|
10
|
-
* Creates an [Ecosystem Wallet](https://portal.thirdweb.com/connect/
|
10
|
+
* Creates an [Ecosystem Wallet](https://portal.thirdweb.com/connect/wallet/overview) based on various authentication methods. Full list of available authentication methods [here](/connect/wallet/sign-in-methods/configure).
|
11
11
|
*
|
12
12
|
* Can also be configured to use Account Abstraction to directly connect to a ERC4337 smart account based on those authentication methods.
|
13
13
|
*
|
@@ -4,7 +4,7 @@ import type { CreateWalletArgs } from "../../wallet-types.js";
|
|
4
4
|
import { createInAppWallet } from "../core/wallet/in-app-core.js";
|
5
5
|
|
6
6
|
/**
|
7
|
-
* Creates an app scoped wallet for users based on various authentication methods. Full list of available authentication methods [here](https://portal.thirdweb.com/connect/wallet/sign-in-methods/
|
7
|
+
* Creates an app scoped wallet for users based on various authentication methods. Full list of available authentication methods [here](https://portal.thirdweb.com/connect/wallet/sign-in-methods/configure).
|
8
8
|
*
|
9
9
|
* Can also be configured to use Account Abstraction to directly connect to a ERC4337 smart account based on those authentication methods.
|
10
10
|
*
|
@@ -27,7 +27,7 @@ import { createInAppWallet } from "../core/wallet/in-app-core.js";
|
|
27
27
|
* });
|
28
28
|
* ```
|
29
29
|
*
|
30
|
-
* [View all available social auth methods](https://portal.thirdweb.com/connect/wallet/sign-in-methods/
|
30
|
+
* [View all available social auth methods](https://portal.thirdweb.com/connect/wallet/sign-in-methods/configure)
|
31
31
|
*
|
32
32
|
* ### Login with email
|
33
33
|
*
|
@@ -22,7 +22,6 @@ import type { PreparedTransaction } from "../../transaction/prepare-transaction.
|
|
22
22
|
import { readContract } from "../../transaction/read-contract.js";
|
23
23
|
import { getAddress } from "../../utils/address.js";
|
24
24
|
import { isZkSyncChain } from "../../utils/any-evm/zksync/isZkSyncChain.js";
|
25
|
-
import { concatHex } from "../../utils/encoding/helpers/concat-hex.js";
|
26
25
|
import type { Hex } from "../../utils/encoding/hex.js";
|
27
26
|
import { parseTypedData } from "../../utils/signatures/helpers/parseTypedData.js";
|
28
27
|
import type {
|
@@ -45,7 +44,12 @@ import {
|
|
45
44
|
prepareBatchExecute,
|
46
45
|
prepareExecute,
|
47
46
|
} from "./lib/calls.js";
|
48
|
-
import {
|
47
|
+
import {
|
48
|
+
ENTRYPOINT_ADDRESS_v0_6,
|
49
|
+
ENTRYPOINT_ADDRESS_v0_7,
|
50
|
+
getDefaultAccountFactory,
|
51
|
+
getEntryPointVersion,
|
52
|
+
} from "./lib/constants.js";
|
49
53
|
import {
|
50
54
|
clearAccountDeploying,
|
51
55
|
createUnsignedUserOp,
|
@@ -58,6 +62,7 @@ import type {
|
|
58
62
|
SmartAccountOptions,
|
59
63
|
SmartWalletConnectionOptions,
|
60
64
|
SmartWalletOptions,
|
65
|
+
TokenPaymasterConfig,
|
61
66
|
UserOperationV06,
|
62
67
|
UserOperationV07,
|
63
68
|
} from "./types.js";
|
@@ -116,6 +121,17 @@ export async function connectSmartWallet(
|
|
116
121
|
}
|
117
122
|
}
|
118
123
|
|
124
|
+
if (
|
125
|
+
options.overrides?.tokenPaymaster &&
|
126
|
+
!options.overrides?.entrypointAddress
|
127
|
+
) {
|
128
|
+
// if token paymaster is set, but no entrypoint address, set the entrypoint address to v0.7
|
129
|
+
options.overrides = {
|
130
|
+
...options.overrides,
|
131
|
+
entrypointAddress: ENTRYPOINT_ADDRESS_v0_7,
|
132
|
+
};
|
133
|
+
}
|
134
|
+
|
119
135
|
const factoryAddress =
|
120
136
|
options.factoryAddress ??
|
121
137
|
getDefaultAccountFactory(options.overrides?.entrypointAddress);
|
@@ -196,12 +212,24 @@ export async function disconnectSmartWallet(
|
|
196
212
|
async function createSmartAccount(
|
197
213
|
options: SmartAccountOptions,
|
198
214
|
): Promise<Account> {
|
215
|
+
const erc20Paymaster = options.overrides?.tokenPaymaster;
|
216
|
+
if (erc20Paymaster) {
|
217
|
+
if (
|
218
|
+
getEntryPointVersion(
|
219
|
+
options.overrides?.entrypointAddress || ENTRYPOINT_ADDRESS_v0_6,
|
220
|
+
) !== "v0.7"
|
221
|
+
) {
|
222
|
+
throw new Error(
|
223
|
+
"Token paymaster is only supported for entrypoint version v0.7",
|
224
|
+
);
|
225
|
+
}
|
226
|
+
}
|
227
|
+
|
199
228
|
const { accountContract } = options;
|
200
229
|
const account: Account = {
|
201
230
|
address: getAddress(accountContract.address),
|
202
231
|
async sendTransaction(transaction: SendTransactionOption) {
|
203
232
|
// if erc20 paymaster - check allowance and approve if needed
|
204
|
-
const erc20Paymaster = options.overrides?.erc20Paymaster;
|
205
233
|
let paymasterOverride:
|
206
234
|
| undefined
|
207
235
|
| ((
|
@@ -215,12 +243,7 @@ async function createSmartAccount(
|
|
215
243
|
});
|
216
244
|
const paymasterCallback = async (): Promise<PaymasterResult> => {
|
217
245
|
return {
|
218
|
-
|
219
|
-
erc20Paymaster.address as Hex,
|
220
|
-
erc20Paymaster?.token as Hex,
|
221
|
-
]),
|
222
|
-
// for 0.7 compatibility
|
223
|
-
paymaster: erc20Paymaster.address as Hex,
|
246
|
+
paymaster: erc20Paymaster.paymasterAddress as Hex,
|
224
247
|
paymasterData: "0x",
|
225
248
|
};
|
226
249
|
};
|
@@ -436,13 +459,10 @@ async function createSmartAccount(
|
|
436
459
|
async function approveERC20(args: {
|
437
460
|
accountContract: ThirdwebContract;
|
438
461
|
options: SmartAccountOptions;
|
439
|
-
erc20Paymaster:
|
440
|
-
address: string;
|
441
|
-
token: string;
|
442
|
-
};
|
462
|
+
erc20Paymaster: TokenPaymasterConfig;
|
443
463
|
}) {
|
444
464
|
const { accountContract, erc20Paymaster, options } = args;
|
445
|
-
const tokenAddress = erc20Paymaster.
|
465
|
+
const tokenAddress = erc20Paymaster.tokenAddress;
|
446
466
|
const tokenContract = getContract({
|
447
467
|
address: tokenAddress,
|
448
468
|
chain: accountContract.chain,
|
@@ -451,7 +471,7 @@ async function approveERC20(args: {
|
|
451
471
|
const accountAllowance = await allowance({
|
452
472
|
contract: tokenContract,
|
453
473
|
owner: accountContract.address,
|
454
|
-
spender: erc20Paymaster.
|
474
|
+
spender: erc20Paymaster.paymasterAddress,
|
455
475
|
});
|
456
476
|
|
457
477
|
if (accountAllowance > 0n) {
|
@@ -460,7 +480,7 @@ async function approveERC20(args: {
|
|
460
480
|
|
461
481
|
const approveTx = approve({
|
462
482
|
contract: tokenContract,
|
463
|
-
spender: erc20Paymaster.
|
483
|
+
spender: erc20Paymaster.paymasterAddress,
|
464
484
|
amountWei: maxUint96 - 1n,
|
465
485
|
});
|
466
486
|
const transaction = await toSerializableTransaction({
|
@@ -478,7 +498,7 @@ async function approveERC20(args: {
|
|
478
498
|
...options,
|
479
499
|
overrides: {
|
480
500
|
...options.overrides,
|
481
|
-
|
501
|
+
tokenPaymaster: undefined,
|
482
502
|
},
|
483
503
|
},
|
484
504
|
});
|
@@ -67,16 +67,26 @@ export async function bundleUserOp(args: {
|
|
67
67
|
* ```
|
68
68
|
* @walletUtils
|
69
69
|
*/
|
70
|
-
export async function estimateUserOpGas(
|
71
|
-
|
72
|
-
|
73
|
-
|
70
|
+
export async function estimateUserOpGas(
|
71
|
+
args: {
|
72
|
+
userOp: UserOperationV06 | UserOperationV07;
|
73
|
+
options: BundlerOptions;
|
74
|
+
},
|
75
|
+
stateOverrides?: {
|
76
|
+
[x: string]: {
|
77
|
+
stateDiff: {
|
78
|
+
[x: string]: `0x${string}`;
|
79
|
+
};
|
80
|
+
};
|
81
|
+
},
|
82
|
+
): Promise<EstimationResult> {
|
74
83
|
const res = await sendBundlerRequest({
|
75
84
|
...args,
|
76
85
|
operation: "eth_estimateUserOperationGas",
|
77
86
|
params: [
|
78
87
|
hexlifyUserOp(args.userOp),
|
79
88
|
args.options.entrypointAddress ?? ENTRYPOINT_ADDRESS_v0_6,
|
89
|
+
stateOverrides,
|
80
90
|
],
|
81
91
|
});
|
82
92
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import type { Chain } from "../../../chains/types.js";
|
2
2
|
import { getAddress } from "../../../utils/address.js";
|
3
3
|
import { getThirdwebDomains } from "../../../utils/domains.js";
|
4
|
+
import type { TokenPaymasterConfig } from "../types.js";
|
4
5
|
|
5
6
|
export const DUMMY_SIGNATURE =
|
6
7
|
"0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c";
|
@@ -17,6 +18,28 @@ export const ENTRYPOINT_ADDRESS_v0_7 =
|
|
17
18
|
|
18
19
|
export const MANAGED_ACCOUNT_GAS_BUFFER = 50000n;
|
19
20
|
|
21
|
+
type PAYMASTERS = "BASE_USDC" | "CELO_CUSD" | "LISK_LSK";
|
22
|
+
export const TokenPaymaster: Record<PAYMASTERS, TokenPaymasterConfig> = {
|
23
|
+
BASE_USDC: {
|
24
|
+
chainId: 8453,
|
25
|
+
paymasterAddress: "0x2222f2738BE6bB7aA0Bfe4AEeAf2908172CF5539",
|
26
|
+
tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
27
|
+
balanceStorageSlot: 9n,
|
28
|
+
},
|
29
|
+
CELO_CUSD: {
|
30
|
+
chainId: 42220,
|
31
|
+
paymasterAddress: "0x3feA3c5744D715ff46e91C4e5C9a94426DfF2aF9",
|
32
|
+
tokenAddress: "0x765DE816845861e75A25fCA122bb6898B8B1282a",
|
33
|
+
balanceStorageSlot: 9n,
|
34
|
+
},
|
35
|
+
LISK_LSK: {
|
36
|
+
chainId: 1135,
|
37
|
+
paymasterAddress: "0x9eb8cf7fBa5ed9EeDCC97a0d52254cc0e9B1AC25",
|
38
|
+
tokenAddress: "0xac485391EB2d7D88253a7F1eF18C37f4242D1A24",
|
39
|
+
balanceStorageSlot: 9n,
|
40
|
+
},
|
41
|
+
};
|
42
|
+
|
20
43
|
/*
|
21
44
|
* @internal
|
22
45
|
*/
|
@@ -1,4 +1,5 @@
|
|
1
|
-
import {
|
1
|
+
import { maxUint96 } from "ox/Solidity";
|
2
|
+
import { concat, keccak256, toHex } from "viem";
|
2
3
|
import type { Chain } from "../../../chains/types.js";
|
3
4
|
import type { ThirdwebClient } from "../../../client/client.js";
|
4
5
|
import {
|
@@ -13,6 +14,7 @@ import { encode } from "../../../transaction/actions/encode.js";
|
|
13
14
|
import { toSerializableTransaction } from "../../../transaction/actions/to-serializable-transaction.js";
|
14
15
|
import type { PreparedTransaction } from "../../../transaction/prepare-transaction.js";
|
15
16
|
import type { TransactionReceipt } from "../../../transaction/types.js";
|
17
|
+
import { encodeAbiParameters } from "../../../utils/abi/encodeAbiParameters.js";
|
16
18
|
import { isContractDeployed } from "../../../utils/bytecode/is-contract-deployed.js";
|
17
19
|
import type { Hex } from "../../../utils/encoding/hex.js";
|
18
20
|
import { hexToBytes } from "../../../utils/encoding/to-bytes.js";
|
@@ -361,17 +363,38 @@ async function populateUserOp_v0_7(args: {
|
|
361
363
|
paymasterResult.paymasterVerificationGasLimit;
|
362
364
|
} else {
|
363
365
|
// otherwise fallback to bundler for gas limits
|
364
|
-
const
|
365
|
-
|
366
|
-
|
367
|
-
|
366
|
+
const stateOverrides = overrides?.tokenPaymaster
|
367
|
+
? {
|
368
|
+
[overrides.tokenPaymaster.tokenAddress]: {
|
369
|
+
stateDiff: {
|
370
|
+
[keccak256(
|
371
|
+
encodeAbiParameters(
|
372
|
+
[{ type: "address" }, { type: "uint256" }],
|
373
|
+
[
|
374
|
+
accountContract.address,
|
375
|
+
overrides.tokenPaymaster.balanceStorageSlot,
|
376
|
+
],
|
377
|
+
),
|
378
|
+
)]: toHex(maxUint96, { size: 32 }),
|
379
|
+
},
|
380
|
+
},
|
381
|
+
}
|
382
|
+
: undefined;
|
383
|
+
const estimates = await estimateUserOpGas(
|
384
|
+
{
|
385
|
+
userOp: partialOp,
|
386
|
+
options: bundlerOptions,
|
387
|
+
},
|
388
|
+
stateOverrides,
|
389
|
+
);
|
368
390
|
partialOp.callGasLimit = estimates.callGasLimit;
|
369
391
|
partialOp.verificationGasLimit = estimates.verificationGasLimit;
|
370
392
|
partialOp.preVerificationGas = estimates.preVerificationGas;
|
371
|
-
partialOp.paymasterPostOpGasLimit =
|
372
|
-
|
393
|
+
partialOp.paymasterPostOpGasLimit = overrides?.tokenPaymaster
|
394
|
+
? 500000n // TODO: estimate this better, needed if there's an extra swap needed in the paymaster
|
395
|
+
: estimates.paymasterPostOpGasLimit || 0n;
|
373
396
|
partialOp.paymasterVerificationGasLimit =
|
374
|
-
|
397
|
+
estimates.paymasterVerificationGasLimit || 0n;
|
375
398
|
// need paymaster to re-sign after estimates
|
376
399
|
const paymasterResult2 = (await getPaymasterAndData({
|
377
400
|
userOp: partialOp,
|