thirdweb 5.84.0-nightly-0fdfb8aa778a344aa847503f668e48feb5f72548-20250115000312 → 5.85.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/ai/chat.js +55 -0
- package/dist/cjs/ai/chat.js.map +1 -0
- package/dist/cjs/ai/common.js +76 -0
- package/dist/cjs/ai/common.js.map +1 -0
- package/dist/cjs/ai/execute.js +67 -0
- package/dist/cjs/ai/execute.js.map +1 -0
- package/dist/cjs/ai/index.js +8 -0
- package/dist/cjs/ai/index.js.map +1 -0
- package/dist/cjs/analytics/track/pay.js +1 -0
- package/dist/cjs/analytics/track/pay.js.map +1 -1
- package/dist/cjs/chains/chain-definitions/mode.js +19 -0
- package/dist/cjs/chains/chain-definitions/mode.js.map +1 -0
- package/dist/cjs/contract/deployment/zksync/implementations.js +4 -0
- package/dist/cjs/contract/deployment/zksync/implementations.js.map +1 -1
- package/dist/cjs/exports/ai.js +5 -0
- package/dist/cjs/exports/ai.js.map +1 -0
- package/dist/cjs/exports/chains.js +3 -1
- package/dist/cjs/exports/chains.js.map +1 -1
- package/dist/cjs/exports/wallets/engine.js +6 -0
- package/dist/cjs/exports/wallets/engine.js.map +1 -0
- package/dist/cjs/extensions/prebuilts/deploy-published.js +2 -2
- package/dist/cjs/gas/fee-data.js +1 -0
- package/dist/cjs/gas/fee-data.js.map +1 -1
- package/dist/cjs/react/core/hooks/transaction/useSendTransaction.js +34 -1
- package/dist/cjs/react/core/hooks/transaction/useSendTransaction.js.map +1 -1
- package/dist/cjs/react/web/ui/prebuilt/NFT/description.js +1 -0
- package/dist/cjs/react/web/ui/prebuilt/NFT/description.js.map +1 -1
- package/dist/cjs/react/web/ui/prebuilt/NFT/media.js +3 -1
- package/dist/cjs/react/web/ui/prebuilt/NFT/media.js.map +1 -1
- package/dist/cjs/react/web/ui/prebuilt/NFT/name.js +3 -1
- package/dist/cjs/react/web/ui/prebuilt/NFT/name.js.map +1 -1
- package/dist/cjs/utils/extensions/drops/get-claim-params.js +1 -2
- package/dist/cjs/utils/extensions/drops/get-claim-params.js.map +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/version.js.map +1 -1
- package/dist/cjs/wallets/connection/autoConnect.js +1 -0
- package/dist/cjs/wallets/connection/autoConnect.js.map +1 -1
- package/dist/cjs/wallets/engine/index.js +143 -0
- package/dist/cjs/wallets/engine/index.js.map +1 -0
- package/dist/cjs/wallets/smart/lib/signing.js +1 -1
- package/dist/esm/ai/chat.js +52 -0
- package/dist/esm/ai/chat.js.map +1 -0
- package/dist/esm/ai/common.js +73 -0
- package/dist/esm/ai/common.js.map +1 -0
- package/dist/esm/ai/execute.js +64 -0
- package/dist/esm/ai/execute.js.map +1 -0
- package/dist/esm/ai/index.js +3 -0
- package/dist/esm/ai/index.js.map +1 -0
- package/dist/esm/analytics/track/pay.js +1 -0
- package/dist/esm/analytics/track/pay.js.map +1 -1
- package/dist/esm/chains/chain-definitions/mode.js +16 -0
- package/dist/esm/chains/chain-definitions/mode.js.map +1 -0
- package/dist/esm/contract/deployment/zksync/implementations.js +4 -0
- package/dist/esm/contract/deployment/zksync/implementations.js.map +1 -1
- package/dist/esm/exports/ai.js +2 -0
- package/dist/esm/exports/ai.js.map +1 -0
- package/dist/esm/exports/chains.js +1 -0
- package/dist/esm/exports/chains.js.map +1 -1
- package/dist/esm/exports/wallets/engine.js +2 -0
- package/dist/esm/exports/wallets/engine.js.map +1 -0
- package/dist/esm/extensions/prebuilts/deploy-published.js +2 -2
- package/dist/esm/gas/fee-data.js +1 -0
- package/dist/esm/gas/fee-data.js.map +1 -1
- package/dist/esm/react/core/hooks/transaction/useSendTransaction.js +34 -1
- package/dist/esm/react/core/hooks/transaction/useSendTransaction.js.map +1 -1
- package/dist/esm/react/web/ui/prebuilt/NFT/description.js +1 -0
- package/dist/esm/react/web/ui/prebuilt/NFT/description.js.map +1 -1
- package/dist/esm/react/web/ui/prebuilt/NFT/media.js +3 -1
- package/dist/esm/react/web/ui/prebuilt/NFT/media.js.map +1 -1
- package/dist/esm/react/web/ui/prebuilt/NFT/name.js +3 -1
- package/dist/esm/react/web/ui/prebuilt/NFT/name.js.map +1 -1
- package/dist/esm/utils/extensions/drops/get-claim-params.js +1 -2
- package/dist/esm/utils/extensions/drops/get-claim-params.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/version.js.map +1 -1
- package/dist/esm/wallets/connection/autoConnect.js +1 -0
- package/dist/esm/wallets/connection/autoConnect.js.map +1 -1
- package/dist/esm/wallets/engine/index.js +140 -0
- package/dist/esm/wallets/engine/index.js.map +1 -0
- package/dist/esm/wallets/smart/lib/signing.js +1 -1
- package/dist/types/ai/chat.d.ts +50 -0
- package/dist/types/ai/chat.d.ts.map +1 -0
- package/dist/types/ai/common.d.ts +28 -0
- package/dist/types/ai/common.d.ts.map +1 -0
- package/dist/types/ai/execute.d.ts +53 -0
- package/dist/types/ai/execute.d.ts.map +1 -0
- package/dist/types/ai/index.d.ts +4 -0
- package/dist/types/ai/index.d.ts.map +1 -0
- package/dist/types/analytics/track/pay.d.ts +1 -0
- package/dist/types/analytics/track/pay.d.ts.map +1 -1
- package/dist/types/chains/chain-definitions/mode.d.ts +7 -0
- package/dist/types/chains/chain-definitions/mode.d.ts.map +1 -0
- package/dist/types/contract/deployment/zksync/implementations.d.ts.map +1 -1
- package/dist/types/exports/ai.d.ts +2 -0
- package/dist/types/exports/ai.d.ts.map +1 -0
- package/dist/types/exports/chains.d.ts +1 -0
- package/dist/types/exports/chains.d.ts.map +1 -1
- package/dist/types/exports/wallets/engine.d.ts +2 -0
- package/dist/types/exports/wallets/engine.d.ts.map +1 -0
- package/dist/types/extensions/prebuilts/deploy-published.d.ts +2 -2
- package/dist/types/gas/fee-data.d.ts.map +1 -1
- package/dist/types/react/core/hooks/transaction/useSendTransaction.d.ts.map +1 -1
- package/dist/types/react/web/ui/prebuilt/NFT/description.d.ts.map +1 -1
- package/dist/types/react/web/ui/prebuilt/NFT/media.d.ts +2 -1
- package/dist/types/react/web/ui/prebuilt/NFT/media.d.ts.map +1 -1
- package/dist/types/react/web/ui/prebuilt/NFT/name.d.ts +2 -1
- package/dist/types/react/web/ui/prebuilt/NFT/name.d.ts.map +1 -1
- package/dist/types/utils/extensions/drops/get-claim-params.d.ts +1 -2
- package/dist/types/utils/extensions/drops/get-claim-params.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/connection/autoConnect.d.ts +1 -0
- package/dist/types/wallets/connection/autoConnect.d.ts.map +1 -1
- package/dist/types/wallets/engine/index.d.ts +54 -0
- package/dist/types/wallets/engine/index.d.ts.map +1 -0
- package/dist/types/wallets/smart/lib/signing.d.ts +1 -1
- package/package.json +10 -2
- package/src/ai/chat.test.ts +42 -0
- package/src/ai/chat.ts +52 -0
- package/src/ai/common.ts +131 -0
- package/src/ai/execute.test.ts +48 -0
- package/src/ai/execute.ts +68 -0
- package/src/ai/index.ts +3 -0
- package/src/analytics/track/pay.ts +2 -0
- package/src/auth/verify-signature.test.ts +11 -6
- package/src/chains/chain-definitions/mode.ts +16 -0
- package/src/contract/deployment/zksync/implementations.ts +4 -0
- package/src/exports/ai.ts +1 -0
- package/src/exports/chains.ts +1 -0
- package/src/exports/wallets/engine.ts +4 -0
- package/src/extensions/prebuilts/deploy-published.ts +2 -2
- package/src/gas/fee-data.ts +1 -0
- package/src/react/core/hooks/transaction/useSendTransaction.ts +34 -1
- package/src/react/web/ui/prebuilt/NFT/description.tsx +1 -0
- package/src/react/web/ui/prebuilt/NFT/media.test.tsx +14 -1
- package/src/react/web/ui/prebuilt/NFT/media.tsx +4 -1
- package/src/react/web/ui/prebuilt/NFT/name.test.tsx +44 -6
- package/src/react/web/ui/prebuilt/NFT/name.tsx +4 -1
- package/src/utils/extensions/drops/get-claim-params.ts +1 -2
- package/src/version.ts +1 -1
- package/src/wallets/connection/autoConnect.ts +1 -0
- package/src/wallets/engine/engine-account.test.ts +69 -0
- package/src/wallets/engine/index.ts +198 -0
- package/src/wallets/smart/lib/signing.ts +1 -1
@@ -50,7 +50,7 @@ export type DeployPublishedContractOptions = {
|
|
50
50
|
* ```ts
|
51
51
|
* import { deployPublishedContract } from "thirdweb/deploys";
|
52
52
|
*
|
53
|
-
* const address = await
|
53
|
+
* const address = await deployPublishedContract({
|
54
54
|
* client,
|
55
55
|
* chain,
|
56
56
|
* account,
|
@@ -68,7 +68,7 @@ export type DeployPublishedContractOptions = {
|
|
68
68
|
* ```ts
|
69
69
|
* import { deployPublishedContract } from "thirdweb/deploys";
|
70
70
|
*
|
71
|
-
* const address = await
|
71
|
+
* const address = await deployPublishedContract({
|
72
72
|
* client,
|
73
73
|
* chain,
|
74
74
|
* account,
|
package/src/gas/fee-data.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import { type UseMutationResult, useMutation } from "@tanstack/react-query";
|
2
|
+
import { trackPayEvent } from "../../../../analytics/track/pay.js";
|
2
3
|
import type { Chain } from "../../../../chains/types.js";
|
3
4
|
import type { BuyWithCryptoStatus } from "../../../../pay/buyWithCrypto/getStatus.js";
|
4
5
|
import type { BuyWithFiatStatus } from "../../../../pay/buyWithFiat/getStatus.js";
|
@@ -146,6 +147,13 @@ export function useSendTransactionCore(args: {
|
|
146
147
|
}
|
147
148
|
|
148
149
|
if (!showPayModal) {
|
150
|
+
trackPayEvent({
|
151
|
+
client: tx.client,
|
152
|
+
walletAddress: account.address,
|
153
|
+
walletType: wallet?.id,
|
154
|
+
dstChainId: tx.chain.id,
|
155
|
+
event: "pay_transaction_modal_disabled",
|
156
|
+
});
|
149
157
|
return sendTransaction({
|
150
158
|
transaction: tx,
|
151
159
|
account,
|
@@ -174,7 +182,17 @@ export function useSendTransactionCore(args: {
|
|
174
182
|
await Promise.all([
|
175
183
|
resolvePromisedValue(tx.value),
|
176
184
|
resolvePromisedValue(tx.erc20Value),
|
177
|
-
fetchBuySupportedDestinations(tx.client).catch(() =>
|
185
|
+
fetchBuySupportedDestinations(tx.client).catch((err) => {
|
186
|
+
trackPayEvent({
|
187
|
+
client: tx.client,
|
188
|
+
walletAddress: account.address,
|
189
|
+
walletType: wallet?.id,
|
190
|
+
dstChainId: tx.chain.id,
|
191
|
+
event: "pay_transaction_modal_pay_api_error",
|
192
|
+
error: err?.message,
|
193
|
+
});
|
194
|
+
return null;
|
195
|
+
}),
|
178
196
|
]);
|
179
197
|
|
180
198
|
if (!supportedDestinations) {
|
@@ -198,6 +216,14 @@ export function useSendTransactionCore(args: {
|
|
198
216
|
),
|
199
217
|
))
|
200
218
|
) {
|
219
|
+
trackPayEvent({
|
220
|
+
client: tx.client,
|
221
|
+
walletAddress: account.address,
|
222
|
+
walletType: wallet?.id,
|
223
|
+
dstChainId: tx.chain.id,
|
224
|
+
event: "pay_transaction_modal_chain_token_not_supported",
|
225
|
+
error: `chain ${tx.chain.id} ${_erc20Value ? `/ token ${_erc20Value?.tokenAddress}` : ""} not supported`,
|
226
|
+
});
|
201
227
|
// chain/token not supported, just send the tx
|
202
228
|
sendTx();
|
203
229
|
return;
|
@@ -241,6 +267,13 @@ export function useSendTransactionCore(args: {
|
|
241
267
|
resolveTx: resolve,
|
242
268
|
});
|
243
269
|
} else {
|
270
|
+
trackPayEvent({
|
271
|
+
client: tx.client,
|
272
|
+
walletAddress: account.address,
|
273
|
+
walletType: wallet?.id,
|
274
|
+
dstChainId: tx.chain.id,
|
275
|
+
event: "pay_transaction_modal_has_enough_funds",
|
276
|
+
});
|
244
277
|
sendTx();
|
245
278
|
}
|
246
279
|
} catch (e) {
|
@@ -7,6 +7,8 @@ import {
|
|
7
7
|
import { getFunctionId } from "../../../../../utils/function-id.js";
|
8
8
|
import { fetchNftMedia, getQueryKey } from "./media.js";
|
9
9
|
|
10
|
+
const testContractAddress = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
|
11
|
+
|
10
12
|
describe.runIf(process.env.TW_SECRET_KEY)("NFTMedia", () => {
|
11
13
|
it("fetchNftMedia should work with ERC721", async () => {
|
12
14
|
const desc = await fetchNftMedia({
|
@@ -77,9 +79,16 @@ describe.runIf(process.env.TW_SECRET_KEY)("NFTMedia", () => {
|
|
77
79
|
});
|
78
80
|
|
79
81
|
it("getQueryKey should work without mediaResolver", () => {
|
80
|
-
expect(
|
82
|
+
expect(
|
83
|
+
getQueryKey({
|
84
|
+
chainId: 1,
|
85
|
+
tokenId: 1n,
|
86
|
+
contractAddress: testContractAddress,
|
87
|
+
}),
|
88
|
+
).toStrictEqual([
|
81
89
|
"_internal_nft_media_",
|
82
90
|
1,
|
91
|
+
testContractAddress,
|
83
92
|
"1",
|
84
93
|
{
|
85
94
|
resolver: undefined,
|
@@ -90,6 +99,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("NFTMedia", () => {
|
|
90
99
|
it("getQueryKey should work with mediaResolver being an object", () => {
|
91
100
|
expect(
|
92
101
|
getQueryKey({
|
102
|
+
contractAddress: testContractAddress,
|
93
103
|
chainId: 1,
|
94
104
|
tokenId: 1n,
|
95
105
|
mediaResolver: {
|
@@ -100,6 +110,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("NFTMedia", () => {
|
|
100
110
|
).toStrictEqual([
|
101
111
|
"_internal_nft_media_",
|
102
112
|
1,
|
113
|
+
testContractAddress,
|
103
114
|
"1",
|
104
115
|
{
|
105
116
|
resolver: {
|
@@ -119,12 +130,14 @@ describe.runIf(process.env.TW_SECRET_KEY)("NFTMedia", () => {
|
|
119
130
|
expect(
|
120
131
|
getQueryKey({
|
121
132
|
chainId: 1,
|
133
|
+
contractAddress: testContractAddress,
|
122
134
|
tokenId: 1n,
|
123
135
|
mediaResolver: fn,
|
124
136
|
}),
|
125
137
|
).toStrictEqual([
|
126
138
|
"_internal_nft_media_",
|
127
139
|
1,
|
140
|
+
testContractAddress,
|
128
141
|
"1",
|
129
142
|
{
|
130
143
|
resolver: fnId,
|
@@ -133,6 +133,7 @@ export function NFTMedia({
|
|
133
133
|
const { contract, tokenId } = useNFTContext();
|
134
134
|
const mediaQuery = useQuery({
|
135
135
|
queryKey: getQueryKey({
|
136
|
+
contractAddress: contract.address,
|
136
137
|
chainId: contract.chain.id,
|
137
138
|
tokenId,
|
138
139
|
mediaResolver,
|
@@ -164,6 +165,7 @@ export function NFTMedia({
|
|
164
165
|
* @internal
|
165
166
|
*/
|
166
167
|
export function getQueryKey(props: {
|
168
|
+
contractAddress: string;
|
167
169
|
chainId: number;
|
168
170
|
tokenId: bigint;
|
169
171
|
mediaResolver?:
|
@@ -171,10 +173,11 @@ export function getQueryKey(props: {
|
|
171
173
|
| (() => NFTMediaInfo)
|
172
174
|
| (() => Promise<NFTMediaInfo>);
|
173
175
|
}) {
|
174
|
-
const { chainId, tokenId, mediaResolver } = props;
|
176
|
+
const { chainId, tokenId, mediaResolver, contractAddress } = props;
|
175
177
|
return [
|
176
178
|
"_internal_nft_media_",
|
177
179
|
chainId,
|
180
|
+
contractAddress,
|
178
181
|
tokenId.toString(),
|
179
182
|
{
|
180
183
|
resolver:
|
@@ -7,6 +7,8 @@ import {
|
|
7
7
|
import { getFunctionId } from "../../../../../utils/function-id.js";
|
8
8
|
import { fetchNftName, getQueryKey } from "./name.js";
|
9
9
|
|
10
|
+
const testContractAddress = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
|
11
|
+
|
10
12
|
describe.runIf(process.env.TW_SECRET_KEY)("NFTName", () => {
|
11
13
|
it("fetchNftName should work with ERC721", async () => {
|
12
14
|
const desc = await fetchNftName({
|
@@ -61,9 +63,16 @@ describe.runIf(process.env.TW_SECRET_KEY)("NFTName", () => {
|
|
61
63
|
});
|
62
64
|
|
63
65
|
it("getQueryKey should work without nameResolver", () => {
|
64
|
-
expect(
|
66
|
+
expect(
|
67
|
+
getQueryKey({
|
68
|
+
chainId: 1,
|
69
|
+
tokenId: 1n,
|
70
|
+
contractAddress: testContractAddress,
|
71
|
+
}),
|
72
|
+
).toStrictEqual([
|
65
73
|
"_internal_nft_name_",
|
66
74
|
1,
|
75
|
+
testContractAddress,
|
67
76
|
"1",
|
68
77
|
{ resolver: undefined },
|
69
78
|
]);
|
@@ -71,16 +80,38 @@ describe.runIf(process.env.TW_SECRET_KEY)("NFTName", () => {
|
|
71
80
|
|
72
81
|
it("getQueryKey should work with nameResolver being a string", () => {
|
73
82
|
expect(
|
74
|
-
getQueryKey({
|
75
|
-
|
83
|
+
getQueryKey({
|
84
|
+
chainId: 1,
|
85
|
+
tokenId: 1n,
|
86
|
+
nameResolver: "test",
|
87
|
+
contractAddress: testContractAddress,
|
88
|
+
}),
|
89
|
+
).toStrictEqual([
|
90
|
+
"_internal_nft_name_",
|
91
|
+
1,
|
92
|
+
testContractAddress,
|
93
|
+
"1",
|
94
|
+
{ resolver: "test" },
|
95
|
+
]);
|
76
96
|
});
|
77
97
|
|
78
98
|
it("getQueryKey should work with nameResolver being a () => string", () => {
|
79
99
|
const fn = () => "test";
|
80
100
|
const fnId = getFunctionId(fn);
|
81
101
|
expect(
|
82
|
-
getQueryKey({
|
83
|
-
|
102
|
+
getQueryKey({
|
103
|
+
chainId: 1,
|
104
|
+
tokenId: 1n,
|
105
|
+
nameResolver: fn,
|
106
|
+
contractAddress: testContractAddress,
|
107
|
+
}),
|
108
|
+
).toStrictEqual([
|
109
|
+
"_internal_nft_name_",
|
110
|
+
1,
|
111
|
+
testContractAddress,
|
112
|
+
"1",
|
113
|
+
{ resolver: fnId },
|
114
|
+
]);
|
84
115
|
});
|
85
116
|
|
86
117
|
it("getQueryKey should work with nameResolver being a async () => string", () => {
|
@@ -91,7 +122,14 @@ describe.runIf(process.env.TW_SECRET_KEY)("NFTName", () => {
|
|
91
122
|
chainId: 1,
|
92
123
|
tokenId: 1n,
|
93
124
|
nameResolver: fn,
|
125
|
+
contractAddress: testContractAddress,
|
94
126
|
}),
|
95
|
-
).toStrictEqual([
|
127
|
+
).toStrictEqual([
|
128
|
+
"_internal_nft_name_",
|
129
|
+
1,
|
130
|
+
testContractAddress,
|
131
|
+
"1",
|
132
|
+
{ resolver: fnId },
|
133
|
+
]);
|
96
134
|
});
|
97
135
|
});
|
@@ -95,6 +95,7 @@ export function NFTName({
|
|
95
95
|
|
96
96
|
const nameQuery = useQuery({
|
97
97
|
queryKey: getQueryKey({
|
98
|
+
contractAddress: contract.address,
|
98
99
|
chainId: contract.chain.id,
|
99
100
|
tokenId,
|
100
101
|
nameResolver,
|
@@ -118,14 +119,16 @@ export function NFTName({
|
|
118
119
|
* @internal
|
119
120
|
*/
|
120
121
|
export function getQueryKey(props: {
|
122
|
+
contractAddress: string;
|
121
123
|
chainId: number;
|
122
124
|
tokenId: bigint;
|
123
125
|
nameResolver?: string | (() => string) | (() => Promise<string>);
|
124
126
|
}) {
|
125
|
-
const { chainId, tokenId, nameResolver } = props;
|
127
|
+
const { chainId, tokenId, nameResolver, contractAddress } = props;
|
126
128
|
return [
|
127
129
|
"_internal_nft_name_",
|
128
130
|
chainId,
|
131
|
+
contractAddress,
|
129
132
|
tokenId.toString(),
|
130
133
|
{
|
131
134
|
resolver:
|
@@ -32,7 +32,6 @@ export type GetClaimParamsOptions = {
|
|
32
32
|
* Get the claim parameters for a given drop
|
33
33
|
* @param options - The options for getting the claim parameters
|
34
34
|
* @returns The claim parameters
|
35
|
-
* @extension ERC1155
|
36
35
|
* @example
|
37
36
|
* ```ts
|
38
37
|
* import { getClaimParams } from "thirdweb/utils";
|
@@ -45,7 +44,7 @@ export type GetClaimParamsOptions = {
|
|
45
44
|
* tokenId: 0n,
|
46
45
|
* });
|
47
46
|
* ```
|
48
|
-
* @
|
47
|
+
* @utils
|
49
48
|
*/
|
50
49
|
export async function getClaimParams(options: GetClaimParamsOptions) {
|
51
50
|
const cc: ClaimCondition = await (async () => {
|
package/src/version.ts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export const version = "5.
|
1
|
+
export const version = "5.85.0";
|
@@ -27,6 +27,7 @@ import type { AutoConnectProps } from "./types.js";
|
|
27
27
|
* @param props - The auto-connect configuration properties
|
28
28
|
* @param props.wallets - Array of wallet instances to consider for auto-connection
|
29
29
|
* @returns {boolean} a promise resolving to true or false depending on whether the auto connect function connected to a wallet or not
|
30
|
+
* @walletConnection
|
30
31
|
*/
|
31
32
|
export const autoConnect = async (
|
32
33
|
props: AutoConnectProps & {
|
@@ -0,0 +1,69 @@
|
|
1
|
+
import { 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 { sepolia } from "../../chains/chain-definitions/sepolia.js";
|
6
|
+
import { getContract } from "../../contract/contract.js";
|
7
|
+
import { claimTo } from "../../extensions/erc1155/drops/write/claimTo.js";
|
8
|
+
import { sendTransaction } from "../../transaction/actions/send-transaction.js";
|
9
|
+
import { engineAccount } from "./index.js";
|
10
|
+
|
11
|
+
describe.runIf(
|
12
|
+
process.env.TW_SECRET_KEY &&
|
13
|
+
process.env.ENGINE_URL &&
|
14
|
+
process.env.ENGINE_AUTH_TOKEN &&
|
15
|
+
process.env.ENGINE_WALLET_ADDRESS,
|
16
|
+
)("Engine", () => {
|
17
|
+
const engineAcc = engineAccount({
|
18
|
+
engineUrl: process.env.ENGINE_URL as string,
|
19
|
+
authToken: process.env.ENGINE_AUTH_TOKEN as string,
|
20
|
+
walletAddress: process.env.ENGINE_WALLET_ADDRESS as string,
|
21
|
+
chain: sepolia,
|
22
|
+
});
|
23
|
+
|
24
|
+
it("should sign a message", async () => {
|
25
|
+
const signature = await engineAcc.signMessage({
|
26
|
+
message: "hello",
|
27
|
+
});
|
28
|
+
expect(signature).toBeDefined();
|
29
|
+
});
|
30
|
+
|
31
|
+
it("should sign typed data", async () => {
|
32
|
+
const signature = await engineAcc.signTypedData({
|
33
|
+
...typedData.basic,
|
34
|
+
});
|
35
|
+
expect(signature).toBeDefined();
|
36
|
+
});
|
37
|
+
|
38
|
+
it("should send a tx", async () => {
|
39
|
+
const tx = await sendTransaction({
|
40
|
+
account: engineAcc,
|
41
|
+
transaction: {
|
42
|
+
client: TEST_CLIENT,
|
43
|
+
chain: sepolia,
|
44
|
+
to: TEST_ACCOUNT_B.address,
|
45
|
+
value: 0n,
|
46
|
+
},
|
47
|
+
});
|
48
|
+
expect(tx).toBeDefined();
|
49
|
+
});
|
50
|
+
|
51
|
+
it("should send a extension tx", async () => {
|
52
|
+
const nftContract = getContract({
|
53
|
+
client: TEST_CLIENT,
|
54
|
+
chain: sepolia,
|
55
|
+
address: "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8",
|
56
|
+
});
|
57
|
+
const claimTx = claimTo({
|
58
|
+
contract: nftContract,
|
59
|
+
to: TEST_ACCOUNT_B.address,
|
60
|
+
tokenId: 0n,
|
61
|
+
quantity: 1n,
|
62
|
+
});
|
63
|
+
const tx = await sendTransaction({
|
64
|
+
account: engineAcc,
|
65
|
+
transaction: claimTx,
|
66
|
+
});
|
67
|
+
expect(tx).toBeDefined();
|
68
|
+
});
|
69
|
+
});
|
@@ -0,0 +1,198 @@
|
|
1
|
+
import type { Chain } from "../../chains/types.js";
|
2
|
+
import type { Hex } from "../../utils/encoding/hex.js";
|
3
|
+
import { toHex } from "../../utils/encoding/hex.js";
|
4
|
+
import type { Account, SendTransactionOption } from "../interfaces/wallet.js";
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Options for creating an engine account.
|
8
|
+
*/
|
9
|
+
export type EngineAccountOptions = {
|
10
|
+
/**
|
11
|
+
* The URL of your engine instance.
|
12
|
+
*/
|
13
|
+
engineUrl: string;
|
14
|
+
/**
|
15
|
+
* The auth token to use with the engine instance.
|
16
|
+
*/
|
17
|
+
authToken: string;
|
18
|
+
/**
|
19
|
+
* The backend wallet to use for sending transactions inside engine.
|
20
|
+
*/
|
21
|
+
walletAddress: string;
|
22
|
+
/**
|
23
|
+
* The chain to use for signing messages and typed data (smart backend wallet only).
|
24
|
+
*/
|
25
|
+
chain?: Chain;
|
26
|
+
};
|
27
|
+
|
28
|
+
/**
|
29
|
+
* Creates an account that uses your engine backend wallet for sending transactions and signing messages.
|
30
|
+
*
|
31
|
+
* @param options - The options for the engine account.
|
32
|
+
* @returns An account that uses your engine backend wallet.
|
33
|
+
*
|
34
|
+
* @beta
|
35
|
+
* @wallet
|
36
|
+
*
|
37
|
+
* @example
|
38
|
+
* ```ts
|
39
|
+
* import { engineAccount } from "thirdweb/wallets/engine";
|
40
|
+
*
|
41
|
+
* const engineAcc = engineAccount({
|
42
|
+
* engineUrl: "https://engine.thirdweb.com",
|
43
|
+
* authToken: "your-auth-token",
|
44
|
+
* walletAddress: "0x...",
|
45
|
+
* });
|
46
|
+
*
|
47
|
+
* // then use the account as you would any other account
|
48
|
+
* const transaction = claimTo({
|
49
|
+
* contract,
|
50
|
+
* to: "0x...",
|
51
|
+
* quantity: 1n,
|
52
|
+
* });
|
53
|
+
* const result = await sendTransaction({ transaction, account: engineAcc });
|
54
|
+
* console.log("Transaction sent:", result.transactionHash);
|
55
|
+
* ```
|
56
|
+
*/
|
57
|
+
export function engineAccount(options: EngineAccountOptions): Account {
|
58
|
+
const { engineUrl, authToken, walletAddress, chain } = options;
|
59
|
+
|
60
|
+
// these are shared across all methods
|
61
|
+
const headers: HeadersInit = {
|
62
|
+
"x-backend-wallet-address": walletAddress,
|
63
|
+
Authorization: `Bearer ${authToken}`,
|
64
|
+
"Content-Type": "application/json",
|
65
|
+
};
|
66
|
+
|
67
|
+
return {
|
68
|
+
address: walletAddress,
|
69
|
+
sendTransaction: async (transaction: SendTransactionOption) => {
|
70
|
+
const ENGINE_URL = new URL(engineUrl);
|
71
|
+
ENGINE_URL.pathname = `/backend-wallet/${transaction.chainId}/send-transaction`;
|
72
|
+
|
73
|
+
const engineData: Record<string, string | undefined> = {
|
74
|
+
// add to address if we have it (is optional to pass to engine)
|
75
|
+
toAddress: transaction.to || undefined,
|
76
|
+
// engine wants a hex string here so we serialize it
|
77
|
+
data: transaction.data || "0x",
|
78
|
+
// value is always required
|
79
|
+
value: toHex(transaction.value ?? 0n),
|
80
|
+
};
|
81
|
+
|
82
|
+
// TODO: gas overrides etc?
|
83
|
+
|
84
|
+
const engineRes = await fetch(ENGINE_URL, {
|
85
|
+
method: "POST",
|
86
|
+
headers,
|
87
|
+
body: JSON.stringify(engineData),
|
88
|
+
});
|
89
|
+
if (!engineRes.ok) {
|
90
|
+
const body = await engineRes.text();
|
91
|
+
throw new Error(
|
92
|
+
`Engine request failed with status ${engineRes.status} - ${body}`,
|
93
|
+
);
|
94
|
+
}
|
95
|
+
const engineJson = (await engineRes.json()) as {
|
96
|
+
result: {
|
97
|
+
queueId: string;
|
98
|
+
};
|
99
|
+
};
|
100
|
+
|
101
|
+
// wait for the queueId to be processed
|
102
|
+
ENGINE_URL.pathname = `/transaction/status/${engineJson.result.queueId}`;
|
103
|
+
const startTime = Date.now();
|
104
|
+
const TIMEOUT_IN_MS = 5 * 60 * 1000; // 5 minutes in milliseconds
|
105
|
+
|
106
|
+
while (Date.now() - startTime < TIMEOUT_IN_MS) {
|
107
|
+
const queueRes = await fetch(ENGINE_URL, {
|
108
|
+
method: "GET",
|
109
|
+
headers,
|
110
|
+
});
|
111
|
+
if (!queueRes.ok) {
|
112
|
+
const body = await queueRes.text();
|
113
|
+
throw new Error(
|
114
|
+
`Engine request failed with status ${queueRes.status} - ${body}`,
|
115
|
+
);
|
116
|
+
}
|
117
|
+
const queueJSON = (await queueRes.json()) as {
|
118
|
+
result: {
|
119
|
+
status: "queued" | "mined" | "cancelled" | "errored";
|
120
|
+
transactionHash: Hex | null;
|
121
|
+
userOpHash: Hex | null;
|
122
|
+
errorMessage: string | null;
|
123
|
+
};
|
124
|
+
};
|
125
|
+
|
126
|
+
if (
|
127
|
+
queueJSON.result.status === "errored" &&
|
128
|
+
queueJSON.result.errorMessage
|
129
|
+
) {
|
130
|
+
throw new Error(queueJSON.result.errorMessage);
|
131
|
+
}
|
132
|
+
if (queueJSON.result.transactionHash) {
|
133
|
+
return {
|
134
|
+
transactionHash: queueJSON.result.transactionHash,
|
135
|
+
};
|
136
|
+
}
|
137
|
+
// wait 1s before checking again
|
138
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
139
|
+
}
|
140
|
+
throw new Error("Transaction timed out after 5 minutes");
|
141
|
+
},
|
142
|
+
signMessage: async ({ message }) => {
|
143
|
+
let engineMessage: string | Hex;
|
144
|
+
let isBytes = false;
|
145
|
+
if (typeof message === "string") {
|
146
|
+
engineMessage = message;
|
147
|
+
} else {
|
148
|
+
engineMessage = toHex(message.raw);
|
149
|
+
isBytes = true;
|
150
|
+
}
|
151
|
+
|
152
|
+
const ENGINE_URL = new URL(engineUrl);
|
153
|
+
ENGINE_URL.pathname = "/backend-wallet/sign-message";
|
154
|
+
const engineRes = await fetch(ENGINE_URL, {
|
155
|
+
method: "POST",
|
156
|
+
headers,
|
157
|
+
body: JSON.stringify({
|
158
|
+
message: engineMessage,
|
159
|
+
isBytes,
|
160
|
+
chainId: chain?.id,
|
161
|
+
}),
|
162
|
+
});
|
163
|
+
if (!engineRes.ok) {
|
164
|
+
const body = await engineRes.text();
|
165
|
+
throw new Error(
|
166
|
+
`Engine request failed with status ${engineRes.status} - ${body}`,
|
167
|
+
);
|
168
|
+
}
|
169
|
+
const engineJson = (await engineRes.json()) as {
|
170
|
+
result: Hex;
|
171
|
+
};
|
172
|
+
return engineJson.result;
|
173
|
+
},
|
174
|
+
signTypedData: async (_typedData) => {
|
175
|
+
const ENGINE_URL = new URL(engineUrl);
|
176
|
+
ENGINE_URL.pathname = "/backend-wallet/sign-typed-data";
|
177
|
+
const engineRes = await fetch(ENGINE_URL, {
|
178
|
+
method: "POST",
|
179
|
+
headers,
|
180
|
+
body: JSON.stringify({
|
181
|
+
domain: _typedData.domain,
|
182
|
+
types: _typedData.types,
|
183
|
+
value: _typedData.message,
|
184
|
+
}),
|
185
|
+
});
|
186
|
+
if (!engineRes.ok) {
|
187
|
+
engineRes.body?.cancel();
|
188
|
+
throw new Error(
|
189
|
+
`Engine request failed with status ${engineRes.status}`,
|
190
|
+
);
|
191
|
+
}
|
192
|
+
const engineJson = (await engineRes.json()) as {
|
193
|
+
result: Hex;
|
194
|
+
};
|
195
|
+
return engineJson.result;
|
196
|
+
},
|
197
|
+
};
|
198
|
+
}
|