thirdweb 5.101.2 → 5.102.1
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/engine/create-server-wallet.js +46 -0
- package/dist/cjs/engine/create-server-wallet.js.map +1 -0
- package/dist/cjs/engine/get-status.js +0 -54
- package/dist/cjs/engine/get-status.js.map +1 -1
- package/dist/cjs/engine/index.js +9 -2
- package/dist/cjs/engine/index.js.map +1 -1
- package/dist/cjs/engine/list-server-wallets.js +40 -0
- package/dist/cjs/engine/list-server-wallets.js.map +1 -0
- package/dist/cjs/engine/search-transactions.js +115 -0
- package/dist/cjs/engine/search-transactions.js.map +1 -0
- package/dist/cjs/engine/server-wallet.js +97 -17
- package/dist/cjs/engine/server-wallet.js.map +1 -1
- package/dist/cjs/engine/wait-for-tx-hash.js +59 -0
- package/dist/cjs/engine/wait-for-tx-hash.js.map +1 -0
- package/dist/cjs/insight/get-nfts.js +6 -1
- package/dist/cjs/insight/get-nfts.js.map +1 -1
- package/dist/cjs/react/native/hooks/wallets/useUnlinkProfile.js +19 -1
- package/dist/cjs/react/native/hooks/wallets/useUnlinkProfile.js.map +1 -1
- package/dist/cjs/react/web/hooks/wallets/useUnlinkProfile.js +19 -1
- package/dist/cjs/react/web/hooks/wallets/useUnlinkProfile.js.map +1 -1
- package/dist/cjs/utils/fetch.js +1 -0
- package/dist/cjs/utils/fetch.js.map +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/wallets/in-app/core/authentication/linkAccount.js +6 -2
- package/dist/cjs/wallets/in-app/core/authentication/linkAccount.js.map +1 -1
- package/dist/cjs/wallets/in-app/native/auth/index.js +1 -1
- package/dist/cjs/wallets/in-app/native/auth/index.js.map +1 -1
- package/dist/cjs/wallets/in-app/native/native-connector.js +2 -1
- package/dist/cjs/wallets/in-app/native/native-connector.js.map +1 -1
- package/dist/cjs/wallets/in-app/web/lib/auth/index.js +30 -1
- package/dist/cjs/wallets/in-app/web/lib/auth/index.js.map +1 -1
- package/dist/cjs/wallets/in-app/web/lib/web-connector.js +2 -1
- package/dist/cjs/wallets/in-app/web/lib/web-connector.js.map +1 -1
- package/dist/esm/engine/create-server-wallet.js +43 -0
- package/dist/esm/engine/create-server-wallet.js.map +1 -0
- package/dist/esm/engine/get-status.js +0 -53
- package/dist/esm/engine/get-status.js.map +1 -1
- package/dist/esm/engine/index.js +5 -1
- package/dist/esm/engine/index.js.map +1 -1
- package/dist/esm/engine/list-server-wallets.js +37 -0
- package/dist/esm/engine/list-server-wallets.js.map +1 -0
- package/dist/esm/engine/search-transactions.js +112 -0
- package/dist/esm/engine/search-transactions.js.map +1 -0
- package/dist/esm/engine/server-wallet.js +96 -16
- package/dist/esm/engine/server-wallet.js.map +1 -1
- package/dist/esm/engine/wait-for-tx-hash.js +56 -0
- package/dist/esm/engine/wait-for-tx-hash.js.map +1 -0
- package/dist/esm/insight/get-nfts.js +6 -1
- package/dist/esm/insight/get-nfts.js.map +1 -1
- package/dist/esm/react/native/hooks/wallets/useUnlinkProfile.js +19 -1
- package/dist/esm/react/native/hooks/wallets/useUnlinkProfile.js.map +1 -1
- package/dist/esm/react/web/hooks/wallets/useUnlinkProfile.js +19 -1
- package/dist/esm/react/web/hooks/wallets/useUnlinkProfile.js.map +1 -1
- package/dist/esm/utils/fetch.js +1 -0
- package/dist/esm/utils/fetch.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/wallets/in-app/core/authentication/linkAccount.js +6 -2
- package/dist/esm/wallets/in-app/core/authentication/linkAccount.js.map +1 -1
- package/dist/esm/wallets/in-app/native/auth/index.js +1 -1
- package/dist/esm/wallets/in-app/native/auth/index.js.map +1 -1
- package/dist/esm/wallets/in-app/native/native-connector.js +2 -1
- package/dist/esm/wallets/in-app/native/native-connector.js.map +1 -1
- package/dist/esm/wallets/in-app/web/lib/auth/index.js +30 -1
- package/dist/esm/wallets/in-app/web/lib/auth/index.js.map +1 -1
- package/dist/esm/wallets/in-app/web/lib/web-connector.js +2 -1
- package/dist/esm/wallets/in-app/web/lib/web-connector.js.map +1 -1
- package/dist/types/engine/create-server-wallet.d.ts +29 -0
- package/dist/types/engine/create-server-wallet.d.ts.map +1 -0
- package/dist/types/engine/get-status.d.ts +0 -23
- package/dist/types/engine/get-status.d.ts.map +1 -1
- package/dist/types/engine/index.d.ts +5 -1
- package/dist/types/engine/index.d.ts.map +1 -1
- package/dist/types/engine/list-server-wallets.d.ts +25 -0
- package/dist/types/engine/list-server-wallets.d.ts.map +1 -0
- package/dist/types/engine/search-transactions.d.ts +127 -0
- package/dist/types/engine/search-transactions.d.ts.map +1 -0
- package/dist/types/engine/server-wallet.d.ts +36 -0
- package/dist/types/engine/server-wallet.d.ts.map +1 -1
- package/dist/types/engine/wait-for-tx-hash.d.ts +25 -0
- package/dist/types/engine/wait-for-tx-hash.d.ts.map +1 -0
- package/dist/types/react/native/hooks/wallets/useUnlinkProfile.d.ts +18 -0
- package/dist/types/react/native/hooks/wallets/useUnlinkProfile.d.ts.map +1 -1
- package/dist/types/react/web/hooks/wallets/useUnlinkProfile.d.ts +18 -0
- package/dist/types/react/web/hooks/wallets/useUnlinkProfile.d.ts.map +1 -1
- package/dist/types/utils/fetch.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/types/wallets/in-app/core/authentication/linkAccount.d.ts +2 -1
- package/dist/types/wallets/in-app/core/authentication/linkAccount.d.ts.map +1 -1
- package/dist/types/wallets/in-app/core/authentication/types.d.ts +1 -0
- package/dist/types/wallets/in-app/core/authentication/types.d.ts.map +1 -1
- package/dist/types/wallets/in-app/core/interfaces/connector.d.ts +1 -1
- package/dist/types/wallets/in-app/core/interfaces/connector.d.ts.map +1 -1
- package/dist/types/wallets/in-app/native/auth/index.d.ts.map +1 -1
- package/dist/types/wallets/in-app/native/native-connector.d.ts +1 -1
- package/dist/types/wallets/in-app/native/native-connector.d.ts.map +1 -1
- package/dist/types/wallets/in-app/web/lib/auth/index.d.ts +29 -0
- package/dist/types/wallets/in-app/web/lib/auth/index.d.ts.map +1 -1
- package/dist/types/wallets/in-app/web/lib/web-connector.d.ts +1 -1
- package/dist/types/wallets/in-app/web/lib/web-connector.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/bridge/Chains.test.ts +1 -1
- package/src/engine/create-server-wallet.ts +57 -0
- package/src/engine/get-status.ts +0 -69
- package/src/engine/index.ts +13 -1
- package/src/engine/list-server-wallets.ts +46 -0
- package/src/engine/search-transactions.ts +132 -0
- package/src/engine/server-wallet.test.ts +54 -0
- package/src/engine/server-wallet.ts +104 -17
- package/src/engine/wait-for-tx-hash.ts +75 -0
- package/src/extensions/erc1155/read/getOwnedNFTs.test.ts +25 -0
- package/src/extensions/erc20/drop20.test.ts +91 -1
- package/src/insight/get-nfts.ts +6 -1
- package/src/react/native/hooks/wallets/useUnlinkProfile.test.tsx +27 -0
- package/src/react/native/hooks/wallets/useUnlinkProfile.ts +24 -1
- package/src/react/web/hooks/wallets/useUnlinkProfile.test.tsx +2 -0
- package/src/react/web/hooks/wallets/useUnlinkProfile.ts +24 -1
- package/src/utils/fetch.ts +1 -0
- package/src/version.ts +1 -1
- package/src/wallets/in-app/core/authentication/linkAccount.test.ts +31 -1
- package/src/wallets/in-app/core/authentication/linkAccount.ts +7 -1
- package/src/wallets/in-app/core/authentication/types.ts +1 -0
- package/src/wallets/in-app/core/interfaces/connector.ts +4 -1
- package/src/wallets/in-app/native/auth/index.ts +4 -1
- package/src/wallets/in-app/native/native-connector.ts +2 -1
- package/src/wallets/in-app/web/lib/auth/index.ts +33 -1
- package/src/wallets/in-app/web/lib/web-connector.ts +2 -1
@@ -19,7 +19,7 @@ import type {
|
|
19
19
|
Account,
|
20
20
|
SendTransactionOption,
|
21
21
|
} from "../wallets/interfaces/wallet.js";
|
22
|
-
import { waitForTransactionHash } from "./
|
22
|
+
import { waitForTransactionHash } from "./wait-for-tx-hash.js";
|
23
23
|
|
24
24
|
/**
|
25
25
|
* Options for creating an server wallet.
|
@@ -54,6 +54,9 @@ export type ServerWallet = Account & {
|
|
54
54
|
transaction: PreparedTransaction;
|
55
55
|
simulate?: boolean;
|
56
56
|
}) => Promise<{ transactionId: string }>;
|
57
|
+
enqueueBatchTransaction: (args: {
|
58
|
+
transactions: PreparedTransaction[];
|
59
|
+
}) => Promise<{ transactionId: string }>;
|
57
60
|
};
|
58
61
|
|
59
62
|
/**
|
@@ -102,6 +105,37 @@ export type ServerWallet = Account & {
|
|
102
105
|
* console.log("Transaction sent:", transactionHash);
|
103
106
|
* ```
|
104
107
|
*
|
108
|
+
* ### Sending a batch of transactions
|
109
|
+
* ```ts
|
110
|
+
* // prepare the transactions
|
111
|
+
* const transaction1 = claimTo({
|
112
|
+
* contract,
|
113
|
+
* to: firstRecipient,
|
114
|
+
* quantity: 1n,
|
115
|
+
* });
|
116
|
+
* const transaction2 = claimTo({
|
117
|
+
* contract,
|
118
|
+
* to: secondRecipient,
|
119
|
+
* quantity: 1n,
|
120
|
+
* });
|
121
|
+
*
|
122
|
+
*
|
123
|
+
* // enqueue the transactions in a batch
|
124
|
+
* const { transactionId } = await myServerWallet.enqueueBatchTransaction({
|
125
|
+
* transactions: [transaction1, transaction2],
|
126
|
+
* });
|
127
|
+
* ```
|
128
|
+
*
|
129
|
+
* ### Polling for the batch of transactions to be submitted onchain
|
130
|
+
* ```ts
|
131
|
+
* // optionally poll for the transaction to be submitted onchain
|
132
|
+
* const { transactionHash } = await Engine.waitForTransactionHash({
|
133
|
+
* client,
|
134
|
+
* transactionId,
|
135
|
+
* });
|
136
|
+
* console.log("Transaction sent:", transactionHash);
|
137
|
+
* ```
|
138
|
+
*
|
105
139
|
* ### Getting the execution status of a transaction
|
106
140
|
* ```ts
|
107
141
|
* const executionResult = await Engine.getTransactionStatus({
|
@@ -130,16 +164,30 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet {
|
|
130
164
|
};
|
131
165
|
};
|
132
166
|
|
133
|
-
const enqueueTx = async (transaction: SendTransactionOption) => {
|
167
|
+
const enqueueTx = async (transaction: SendTransactionOption[]) => {
|
168
|
+
if (transaction.length === 0) {
|
169
|
+
throw new Error("No transactions to enqueue");
|
170
|
+
}
|
171
|
+
const firstTransaction = transaction[0];
|
172
|
+
if (!firstTransaction) {
|
173
|
+
throw new Error("No transactions to enqueue");
|
174
|
+
}
|
175
|
+
const chainId = firstTransaction.chainId;
|
176
|
+
// Validate all transactions are on the same chain
|
177
|
+
for (let i = 1; i < transaction.length; i++) {
|
178
|
+
if (transaction[i]?.chainId !== chainId) {
|
179
|
+
throw new Error(
|
180
|
+
`All transactions in batch must be on the same chain. Expected ${chainId}, got ${transaction[i]?.chainId} at index ${i}`,
|
181
|
+
);
|
182
|
+
}
|
183
|
+
}
|
134
184
|
const body = {
|
135
|
-
executionOptions: getExecutionOptions(
|
136
|
-
params:
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
},
|
142
|
-
],
|
185
|
+
executionOptions: getExecutionOptions(chainId),
|
186
|
+
params: transaction.map((t) => ({
|
187
|
+
to: t.to ?? undefined,
|
188
|
+
data: t.data,
|
189
|
+
value: t.value?.toString(),
|
190
|
+
})),
|
143
191
|
};
|
144
192
|
|
145
193
|
const result = await sendTransaction({
|
@@ -158,11 +206,7 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet {
|
|
158
206
|
if (!data) {
|
159
207
|
throw new Error("No data returned from engine");
|
160
208
|
}
|
161
|
-
|
162
|
-
if (!transactionId) {
|
163
|
-
throw new Error("No transactionId returned from engine");
|
164
|
-
}
|
165
|
-
return transactionId;
|
209
|
+
return data.transactions.map((t) => t.id);
|
166
210
|
};
|
167
211
|
|
168
212
|
return {
|
@@ -193,11 +237,54 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet {
|
|
193
237
|
value: value ?? undefined,
|
194
238
|
};
|
195
239
|
}
|
196
|
-
const
|
240
|
+
const transactionIds = await enqueueTx([serializedTransaction]);
|
241
|
+
const transactionId = transactionIds[0];
|
242
|
+
if (!transactionId) {
|
243
|
+
throw new Error("No transactionId returned from engine");
|
244
|
+
}
|
245
|
+
return { transactionId };
|
246
|
+
},
|
247
|
+
enqueueBatchTransaction: async (args: {
|
248
|
+
transactions: PreparedTransaction[];
|
249
|
+
}) => {
|
250
|
+
const serializedTransactions: SendTransactionOption[] = [];
|
251
|
+
for (const transaction of args.transactions) {
|
252
|
+
const [to, data, value] = await Promise.all([
|
253
|
+
transaction.to ? resolvePromisedValue(transaction.to) : null,
|
254
|
+
encode(transaction),
|
255
|
+
transaction.value ? resolvePromisedValue(transaction.value) : null,
|
256
|
+
]);
|
257
|
+
serializedTransactions.push({
|
258
|
+
chainId: transaction.chain.id,
|
259
|
+
data,
|
260
|
+
to: to ?? undefined,
|
261
|
+
value: value ?? undefined,
|
262
|
+
});
|
263
|
+
}
|
264
|
+
const transactionIds = await enqueueTx(serializedTransactions);
|
265
|
+
const transactionId = transactionIds[0];
|
266
|
+
if (!transactionId) {
|
267
|
+
throw new Error("No transactionId returned from engine");
|
268
|
+
}
|
197
269
|
return { transactionId };
|
198
270
|
},
|
199
271
|
sendTransaction: async (transaction: SendTransactionOption) => {
|
200
|
-
const
|
272
|
+
const transactionIds = await enqueueTx([transaction]);
|
273
|
+
const transactionId = transactionIds[0];
|
274
|
+
if (!transactionId) {
|
275
|
+
throw new Error("No transactionId returned from engine");
|
276
|
+
}
|
277
|
+
return waitForTransactionHash({
|
278
|
+
client,
|
279
|
+
transactionId,
|
280
|
+
});
|
281
|
+
},
|
282
|
+
sendBatchTransaction: async (transactions: SendTransactionOption[]) => {
|
283
|
+
const transactionIds = await enqueueTx(transactions);
|
284
|
+
const transactionId = transactionIds[0];
|
285
|
+
if (!transactionId) {
|
286
|
+
throw new Error("No transactionId returned from engine");
|
287
|
+
}
|
201
288
|
return waitForTransactionHash({
|
202
289
|
client,
|
203
290
|
transactionId,
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import { stringify } from "viem";
|
2
|
+
|
3
|
+
import type { Hex } from "../utils/encoding/hex.js";
|
4
|
+
|
5
|
+
import type { ThirdwebClient } from "../client/client.js";
|
6
|
+
import type { WaitForReceiptOptions } from "../transaction/actions/wait-for-tx-receipt.js";
|
7
|
+
import { getTransactionStatus } from "./get-status.js";
|
8
|
+
|
9
|
+
/**
|
10
|
+
* Wait for a transaction to be submitted onchain and return the transaction hash.
|
11
|
+
* @param args - The arguments for the transaction.
|
12
|
+
* @param args.client - The thirdweb client to use.
|
13
|
+
* @param args.transactionId - The id of the transaction to wait for.
|
14
|
+
* @param args.timeoutInSeconds - The timeout in seconds.
|
15
|
+
* @engine
|
16
|
+
* @example
|
17
|
+
* ```ts
|
18
|
+
* import { Engine } from "thirdweb";
|
19
|
+
*
|
20
|
+
* const { transactionHash } = await Engine.waitForTransactionHash({
|
21
|
+
* client,
|
22
|
+
* transactionId, // the transaction id returned from enqueueTransaction
|
23
|
+
* });
|
24
|
+
* ```
|
25
|
+
*/
|
26
|
+
export async function waitForTransactionHash(args: {
|
27
|
+
client: ThirdwebClient;
|
28
|
+
transactionId: string;
|
29
|
+
timeoutInSeconds?: number;
|
30
|
+
}): Promise<WaitForReceiptOptions> {
|
31
|
+
const startTime = Date.now();
|
32
|
+
const TIMEOUT_IN_MS = args.timeoutInSeconds
|
33
|
+
? args.timeoutInSeconds * 1000
|
34
|
+
: 5 * 60 * 1000; // 5 minutes in milliseconds
|
35
|
+
|
36
|
+
while (Date.now() - startTime < TIMEOUT_IN_MS) {
|
37
|
+
const executionResult = await getTransactionStatus(args);
|
38
|
+
const status = executionResult.status;
|
39
|
+
|
40
|
+
switch (status) {
|
41
|
+
case "FAILED": {
|
42
|
+
throw new Error(
|
43
|
+
`Transaction failed: ${executionResult.error || "Unknown error"}`,
|
44
|
+
);
|
45
|
+
}
|
46
|
+
case "CONFIRMED": {
|
47
|
+
const onchainStatus =
|
48
|
+
executionResult && "onchainStatus" in executionResult
|
49
|
+
? executionResult.onchainStatus
|
50
|
+
: null;
|
51
|
+
if (onchainStatus === "REVERTED") {
|
52
|
+
const revertData =
|
53
|
+
"revertData" in executionResult
|
54
|
+
? executionResult.revertData
|
55
|
+
: undefined;
|
56
|
+
throw new Error(
|
57
|
+
`Transaction reverted: ${revertData?.errorName || "unknown error"} ${revertData?.errorArgs ? stringify(revertData.errorArgs) : ""} - ${executionResult.transactionHash ? executionResult.transactionHash : ""}`,
|
58
|
+
);
|
59
|
+
}
|
60
|
+
return {
|
61
|
+
transactionHash: executionResult.transactionHash as Hex,
|
62
|
+
client: args.client,
|
63
|
+
chain: executionResult.chain,
|
64
|
+
};
|
65
|
+
}
|
66
|
+
default: {
|
67
|
+
// wait for the transaction to be confirmed
|
68
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
69
|
+
}
|
70
|
+
}
|
71
|
+
}
|
72
|
+
throw new Error(
|
73
|
+
`Transaction timed out after ${TIMEOUT_IN_MS / 1000} seconds`,
|
74
|
+
);
|
75
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
2
|
+
|
3
|
+
import { DROP1155_CONTRACT } from "~test/test-contracts.js";
|
4
|
+
import { getOwnedNFTs } from "./getOwnedNFTs.js";
|
5
|
+
|
6
|
+
describe.runIf(process.env.TW_SECRET_KEY)("erc1155.getOwnedNFTs", () => {
|
7
|
+
it("with indexer", async () => {
|
8
|
+
const nfts = await getOwnedNFTs({
|
9
|
+
contract: DROP1155_CONTRACT,
|
10
|
+
address: "0x00d4da27dedce60f859471d8f595fdb4ae861557",
|
11
|
+
});
|
12
|
+
expect(nfts.length).toBe(3);
|
13
|
+
expect(nfts.find((nft) => nft.id === 4n)?.quantityOwned).toBe(411n);
|
14
|
+
});
|
15
|
+
|
16
|
+
it("without indexer", async () => {
|
17
|
+
const nfts = await getOwnedNFTs({
|
18
|
+
contract: DROP1155_CONTRACT,
|
19
|
+
address: "0x00d4da27dedce60f859471d8f595fdb4ae861557",
|
20
|
+
useIndexer: false,
|
21
|
+
});
|
22
|
+
expect(nfts.length).toBe(3);
|
23
|
+
expect(nfts.find((nft) => nft.id === 4n)?.quantityOwned).toBe(411n);
|
24
|
+
});
|
25
|
+
});
|
@@ -11,7 +11,7 @@ import {
|
|
11
11
|
import { type ThirdwebContract, getContract } from "../../contract/contract.js";
|
12
12
|
import { sendAndConfirmTransaction } from "../../transaction/actions/send-and-confirm-transaction.js";
|
13
13
|
import { resolvePromisedValue } from "../../utils/promise/resolve-promised-value.js";
|
14
|
-
import { toEther } from "../../utils/units.js";
|
14
|
+
import { toEther, toWei } from "../../utils/units.js";
|
15
15
|
import { name } from "../common/read/name.js";
|
16
16
|
import { deployERC20Contract } from "../prebuilts/deploy-erc20.js";
|
17
17
|
import { canClaim } from "./drops/read/canClaim.js";
|
@@ -20,6 +20,8 @@ import { claimTo } from "./drops/write/claimTo.js";
|
|
20
20
|
import { resetClaimEligibility } from "./drops/write/resetClaimEligibility.js";
|
21
21
|
import { setClaimConditions } from "./drops/write/setClaimConditions.js";
|
22
22
|
import { getBalance } from "./read/getBalance.js";
|
23
|
+
import { getApprovalForTransaction } from "./write/getApprovalForTransaction.js";
|
24
|
+
import { mintTo } from "./write/mintTo.js";
|
23
25
|
|
24
26
|
describe.runIf(process.env.TW_SECRET_KEY)(
|
25
27
|
"DropERC20",
|
@@ -135,6 +137,94 @@ describe.runIf(process.env.TW_SECRET_KEY)(
|
|
135
137
|
).toBe("2");
|
136
138
|
});
|
137
139
|
|
140
|
+
it("should allow to claim tokens with erc20 price", async () => {
|
141
|
+
expect(
|
142
|
+
(await getBalance({ contract, address: TEST_ACCOUNT_C.address }))
|
143
|
+
.displayValue,
|
144
|
+
).toBe("2");
|
145
|
+
const erc20ContractAddres = await deployERC20Contract({
|
146
|
+
account: TEST_ACCOUNT_A,
|
147
|
+
chain: ANVIL_CHAIN,
|
148
|
+
client: TEST_CLIENT,
|
149
|
+
type: "TokenERC20",
|
150
|
+
params: {
|
151
|
+
name: "Test DropERC20",
|
152
|
+
},
|
153
|
+
});
|
154
|
+
const erc20Contract = getContract({
|
155
|
+
address: erc20ContractAddres,
|
156
|
+
chain: ANVIL_CHAIN,
|
157
|
+
client: TEST_CLIENT,
|
158
|
+
});
|
159
|
+
const mintToTx = mintTo({
|
160
|
+
contract: erc20Contract,
|
161
|
+
to: TEST_ACCOUNT_C.address,
|
162
|
+
amount: "0.02",
|
163
|
+
});
|
164
|
+
await sendAndConfirmTransaction({
|
165
|
+
transaction: mintToTx,
|
166
|
+
account: TEST_ACCOUNT_A,
|
167
|
+
});
|
168
|
+
expect(
|
169
|
+
(
|
170
|
+
await getBalance({
|
171
|
+
contract: erc20Contract,
|
172
|
+
address: TEST_ACCOUNT_C.address,
|
173
|
+
})
|
174
|
+
).displayValue,
|
175
|
+
).toBe("0.02");
|
176
|
+
// set cc with price
|
177
|
+
await sendAndConfirmTransaction({
|
178
|
+
transaction: setClaimConditions({
|
179
|
+
contract,
|
180
|
+
phases: [
|
181
|
+
{
|
182
|
+
price: "0.01",
|
183
|
+
currencyAddress: erc20ContractAddres,
|
184
|
+
},
|
185
|
+
],
|
186
|
+
}),
|
187
|
+
account: TEST_ACCOUNT_A,
|
188
|
+
});
|
189
|
+
const claimTx = claimTo({
|
190
|
+
contract,
|
191
|
+
to: TEST_ACCOUNT_C.address,
|
192
|
+
quantity: "2",
|
193
|
+
});
|
194
|
+
// assert value is set correctly
|
195
|
+
const value = await resolvePromisedValue(claimTx.erc20Value);
|
196
|
+
expect(value).toBeDefined();
|
197
|
+
if (!value) throw new Error("value is undefined");
|
198
|
+
expect(value.amountWei).toBe(toWei("0.02"));
|
199
|
+
const approve = await getApprovalForTransaction({
|
200
|
+
transaction: claimTx,
|
201
|
+
account: TEST_ACCOUNT_C,
|
202
|
+
});
|
203
|
+
if (approve) {
|
204
|
+
await sendAndConfirmTransaction({
|
205
|
+
transaction: approve,
|
206
|
+
account: TEST_ACCOUNT_C,
|
207
|
+
});
|
208
|
+
}
|
209
|
+
// claim
|
210
|
+
await sendAndConfirmTransaction({
|
211
|
+
transaction: claimTx,
|
212
|
+
account: TEST_ACCOUNT_C,
|
213
|
+
});
|
214
|
+
expect(
|
215
|
+
(await getBalance({ contract, address: TEST_ACCOUNT_C.address }))
|
216
|
+
.displayValue,
|
217
|
+
).toBe("4");
|
218
|
+
expect(
|
219
|
+
(
|
220
|
+
await getBalance({
|
221
|
+
contract: erc20Contract,
|
222
|
+
address: TEST_ACCOUNT_C.address,
|
223
|
+
})
|
224
|
+
).displayValue,
|
225
|
+
).toBe("0");
|
226
|
+
});
|
227
|
+
|
138
228
|
describe("Allowlists", () => {
|
139
229
|
it("should allow to claim tokens with an allowlist", async () => {
|
140
230
|
await sendAndConfirmTransaction({
|
package/src/insight/get-nfts.ts
CHANGED
@@ -319,7 +319,12 @@ async function transformNFTModel(
|
|
319
319
|
});
|
320
320
|
}
|
321
321
|
|
322
|
-
return
|
322
|
+
return {
|
323
|
+
...parsedNft,
|
324
|
+
...(contract?.type === "erc1155"
|
325
|
+
? { quantityOwned: balance ? BigInt(balance) : undefined }
|
326
|
+
: {}),
|
327
|
+
};
|
323
328
|
}),
|
324
329
|
);
|
325
330
|
}
|
@@ -40,6 +40,32 @@ describe("useUnlinkProfile", () => {
|
|
40
40
|
client: TEST_CLIENT,
|
41
41
|
ecosystem: undefined,
|
42
42
|
profileToUnlink: mockProfile,
|
43
|
+
allowAccountDeletion: false,
|
44
|
+
});
|
45
|
+
expect(queryClient.invalidateQueries).toHaveBeenCalledWith({
|
46
|
+
queryKey: ["profiles"],
|
47
|
+
});
|
48
|
+
});
|
49
|
+
|
50
|
+
it("should call unlinkProfile with allowAccountDeletion if true", async () => {
|
51
|
+
const { result } = renderHook(() => useUnlinkProfile(), {
|
52
|
+
wrapper,
|
53
|
+
});
|
54
|
+
const mutationFn = result.current.mutateAsync;
|
55
|
+
|
56
|
+
await act(async () => {
|
57
|
+
await mutationFn({
|
58
|
+
client: TEST_CLIENT,
|
59
|
+
profileToUnlink: mockProfile,
|
60
|
+
allowAccountDeletion: true,
|
61
|
+
});
|
62
|
+
});
|
63
|
+
|
64
|
+
expect(unlinkProfile).toHaveBeenCalledWith({
|
65
|
+
client: TEST_CLIENT,
|
66
|
+
ecosystem: undefined,
|
67
|
+
profileToUnlink: mockProfile,
|
68
|
+
allowAccountDeletion: true,
|
43
69
|
});
|
44
70
|
expect(queryClient.invalidateQueries).toHaveBeenCalledWith({
|
45
71
|
queryKey: ["profiles"],
|
@@ -70,6 +96,7 @@ describe("useUnlinkProfile", () => {
|
|
70
96
|
?.partnerId,
|
71
97
|
},
|
72
98
|
profileToUnlink: mockProfile,
|
99
|
+
allowAccountDeletion: false,
|
73
100
|
});
|
74
101
|
});
|
75
102
|
});
|
@@ -31,6 +31,23 @@ import { useConnectedWallets } from "../../../core/hooks/wallets/useConnectedWal
|
|
31
31
|
* };
|
32
32
|
* ```
|
33
33
|
*
|
34
|
+
* ### Unlinking an email account with account deletion
|
35
|
+
*
|
36
|
+
* ```jsx
|
37
|
+
* import { useUnlinkProfile } from "thirdweb/react";
|
38
|
+
*
|
39
|
+
* const { mutate: unlinkProfile } = useUnlinkProfile();
|
40
|
+
*
|
41
|
+
* const onClick = () => {
|
42
|
+
* unlinkProfile({
|
43
|
+
* client,
|
44
|
+
* // Select the profile you want to unlink
|
45
|
+
* profileToUnlink: connectedProfiles[0],
|
46
|
+
* allowAccountDeletion: true, // This will delete the account if it's the last profile linked to the account
|
47
|
+
* });
|
48
|
+
* };
|
49
|
+
* ```
|
50
|
+
*
|
34
51
|
* @wallet
|
35
52
|
*/
|
36
53
|
export function useUnlinkProfile() {
|
@@ -40,7 +57,12 @@ export function useUnlinkProfile() {
|
|
40
57
|
mutationFn: async ({
|
41
58
|
client,
|
42
59
|
profileToUnlink,
|
43
|
-
|
60
|
+
allowAccountDeletion = false,
|
61
|
+
}: {
|
62
|
+
client: ThirdwebClient;
|
63
|
+
profileToUnlink: Profile;
|
64
|
+
allowAccountDeletion?: boolean;
|
65
|
+
}) => {
|
44
66
|
const ecosystemWallet = wallets.find((w) => isEcosystemWallet(w));
|
45
67
|
const ecosystem: Ecosystem | undefined = ecosystemWallet
|
46
68
|
? {
|
@@ -53,6 +75,7 @@ export function useUnlinkProfile() {
|
|
53
75
|
client,
|
54
76
|
ecosystem,
|
55
77
|
profileToUnlink,
|
78
|
+
allowAccountDeletion,
|
56
79
|
});
|
57
80
|
},
|
58
81
|
onSuccess: () => {
|
@@ -40,6 +40,7 @@ describe("useUnlinkProfile", () => {
|
|
40
40
|
client: TEST_CLIENT,
|
41
41
|
ecosystem: undefined,
|
42
42
|
profileToUnlink: mockProfile,
|
43
|
+
allowAccountDeletion: false,
|
43
44
|
});
|
44
45
|
expect(queryClient.invalidateQueries).toHaveBeenCalledWith({
|
45
46
|
queryKey: ["profiles"],
|
@@ -70,6 +71,7 @@ describe("useUnlinkProfile", () => {
|
|
70
71
|
?.partnerId,
|
71
72
|
},
|
72
73
|
profileToUnlink: mockProfile,
|
74
|
+
allowAccountDeletion: false,
|
73
75
|
});
|
74
76
|
});
|
75
77
|
});
|
@@ -31,6 +31,23 @@ import { useConnectedWallets } from "../../../core/hooks/wallets/useConnectedWal
|
|
31
31
|
* };
|
32
32
|
* ```
|
33
33
|
*
|
34
|
+
* ### Unlinking an email account with account deletion
|
35
|
+
*
|
36
|
+
* ```jsx
|
37
|
+
* import { useUnlinkProfile } from "thirdweb/react";
|
38
|
+
*
|
39
|
+
* const { mutate: unlinkProfile } = useUnlinkProfile();
|
40
|
+
*
|
41
|
+
* const onClick = () => {
|
42
|
+
* unlinkProfile({
|
43
|
+
* client,
|
44
|
+
* // Select the profile you want to unlink
|
45
|
+
* profileToUnlink: connectedProfiles[0],
|
46
|
+
* allowAccountDeletion: true, // This will delete the account if it's the last profile linked to the account
|
47
|
+
* });
|
48
|
+
* };
|
49
|
+
* ```
|
50
|
+
*
|
34
51
|
* @wallet
|
35
52
|
*/
|
36
53
|
export function useUnlinkProfile() {
|
@@ -40,7 +57,12 @@ export function useUnlinkProfile() {
|
|
40
57
|
mutationFn: async ({
|
41
58
|
client,
|
42
59
|
profileToUnlink,
|
43
|
-
|
60
|
+
allowAccountDeletion = false,
|
61
|
+
}: {
|
62
|
+
client: ThirdwebClient;
|
63
|
+
profileToUnlink: Profile;
|
64
|
+
allowAccountDeletion?: boolean;
|
65
|
+
}) => {
|
44
66
|
const ecosystemWallet = wallets.find((w) => isEcosystemWallet(w));
|
45
67
|
const ecosystem: Ecosystem | undefined = ecosystemWallet
|
46
68
|
? {
|
@@ -53,6 +75,7 @@ export function useUnlinkProfile() {
|
|
53
75
|
client,
|
54
76
|
ecosystem,
|
55
77
|
profileToUnlink,
|
78
|
+
allowAccountDeletion,
|
56
79
|
});
|
57
80
|
},
|
58
81
|
onSuccess: () => {
|
package/src/utils/fetch.ts
CHANGED
package/src/version.ts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export const version = "5.
|
1
|
+
export const version = "5.102.1";
|
@@ -90,7 +90,37 @@ describe("Account linking functions", () => {
|
|
90
90
|
Authorization: "Bearer iaw-auth-token:mock-token",
|
91
91
|
"Content-Type": "application/json",
|
92
92
|
},
|
93
|
-
body: JSON.stringify(
|
93
|
+
body: JSON.stringify({
|
94
|
+
type: profileToUnlink.type,
|
95
|
+
details: profileToUnlink.details,
|
96
|
+
allowAccountDeletion: false,
|
97
|
+
}),
|
98
|
+
},
|
99
|
+
);
|
100
|
+
expect(result).toEqual(mockLinkedAccounts);
|
101
|
+
});
|
102
|
+
|
103
|
+
it("should successfully unlink an account with allowAccountDeletion", async () => {
|
104
|
+
const result = await unlinkAccount({
|
105
|
+
client: mockClient,
|
106
|
+
profileToUnlink,
|
107
|
+
storage: mockStorage,
|
108
|
+
allowAccountDeletion: true,
|
109
|
+
});
|
110
|
+
|
111
|
+
expect(mockFetch).toHaveBeenCalledWith(
|
112
|
+
"https://embedded-wallet.thirdweb.com/api/2024-05-05/account/disconnect",
|
113
|
+
{
|
114
|
+
method: "POST",
|
115
|
+
headers: {
|
116
|
+
Authorization: "Bearer iaw-auth-token:mock-token",
|
117
|
+
"Content-Type": "application/json",
|
118
|
+
},
|
119
|
+
body: JSON.stringify({
|
120
|
+
type: profileToUnlink.type,
|
121
|
+
details: profileToUnlink.details,
|
122
|
+
allowAccountDeletion: true,
|
123
|
+
}),
|
94
124
|
},
|
95
125
|
);
|
96
126
|
expect(result).toEqual(mockLinkedAccounts);
|
@@ -66,11 +66,13 @@ export async function unlinkAccount({
|
|
66
66
|
client,
|
67
67
|
ecosystem,
|
68
68
|
profileToUnlink,
|
69
|
+
allowAccountDeletion = false,
|
69
70
|
storage,
|
70
71
|
}: {
|
71
72
|
client: ThirdwebClient;
|
72
73
|
ecosystem?: Ecosystem;
|
73
74
|
profileToUnlink: Profile;
|
75
|
+
allowAccountDeletion?: boolean;
|
74
76
|
storage: ClientScopedStorage;
|
75
77
|
}): Promise<Profile[]> {
|
76
78
|
const clientFetch = getClientFetch(client, ecosystem);
|
@@ -90,7 +92,11 @@ export async function unlinkAccount({
|
|
90
92
|
{
|
91
93
|
method: "POST",
|
92
94
|
headers,
|
93
|
-
body: stringify(
|
95
|
+
body: stringify({
|
96
|
+
type: profileToUnlink.type,
|
97
|
+
details: profileToUnlink.details,
|
98
|
+
allowAccountDeletion,
|
99
|
+
}),
|
94
100
|
},
|
95
101
|
);
|
96
102
|
|
@@ -37,7 +37,10 @@ export interface InAppConnector {
|
|
37
37
|
): Promise<AuthLoginReturnType>;
|
38
38
|
logout(): Promise<LogoutReturnType>;
|
39
39
|
linkProfile(args: AuthArgsType): Promise<Profile[]>;
|
40
|
-
unlinkProfile(
|
40
|
+
unlinkProfile(
|
41
|
+
args: Profile,
|
42
|
+
allowAccountDeletion?: boolean,
|
43
|
+
): Promise<Profile[]>;
|
41
44
|
getProfiles(): Promise<Profile[]>;
|
42
45
|
storage: ClientScopedStorage;
|
43
46
|
}
|
@@ -203,7 +203,10 @@ export async function linkProfile(args: AuthArgsType) {
|
|
203
203
|
*/
|
204
204
|
export async function unlinkProfile(args: UnlinkParams) {
|
205
205
|
const connector = await getInAppWalletConnector(args.client, args.ecosystem);
|
206
|
-
return await connector.unlinkProfile(
|
206
|
+
return await connector.unlinkProfile(
|
207
|
+
args.profileToUnlink,
|
208
|
+
args.allowAccountDeletion,
|
209
|
+
);
|
207
210
|
}
|
208
211
|
|
209
212
|
/**
|
@@ -367,7 +367,7 @@ export class InAppNativeConnector implements InAppConnector {
|
|
367
367
|
});
|
368
368
|
}
|
369
369
|
|
370
|
-
async unlinkProfile(profile: Profile) {
|
370
|
+
async unlinkProfile(profile: Profile, allowAccountDeletion?: boolean) {
|
371
371
|
const { unlinkAccount } = await import(
|
372
372
|
"../core/authentication/linkAccount.js"
|
373
373
|
);
|
@@ -376,6 +376,7 @@ export class InAppNativeConnector implements InAppConnector {
|
|
376
376
|
ecosystem: this.ecosystem,
|
377
377
|
storage: this.storage,
|
378
378
|
profileToUnlink: profile,
|
379
|
+
allowAccountDeletion,
|
379
380
|
});
|
380
381
|
}
|
381
382
|
|