thirdweb 5.49.0 → 5.50.0-nightly-ff3abfa79e4f5f8806676d97c11ff24ffd62266f-20240901000406

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 (91) hide show
  1. package/dist/cjs/adapters/ethers5.js +3 -0
  2. package/dist/cjs/adapters/ethers5.js.map +1 -1
  3. package/dist/cjs/exports/extensions/ens.js +6 -1
  4. package/dist/cjs/exports/extensions/ens.js.map +1 -1
  5. package/dist/cjs/extensions/ens/__generated__/L2Resolver/read/name.js +115 -0
  6. package/dist/cjs/extensions/ens/__generated__/L2Resolver/read/name.js.map +1 -0
  7. package/dist/cjs/extensions/ens/constants.js +3 -1
  8. package/dist/cjs/extensions/ens/constants.js.map +1 -1
  9. package/dist/cjs/extensions/ens/resolve-address.js +13 -1
  10. package/dist/cjs/extensions/ens/resolve-address.js.map +1 -1
  11. package/dist/cjs/extensions/ens/resolve-l2-name.js +80 -0
  12. package/dist/cjs/extensions/ens/resolve-l2-name.js.map +1 -0
  13. package/dist/cjs/extensions/ens/resolve-name.js +1 -1
  14. package/dist/cjs/extensions/ens/resolve-name.js.map +1 -1
  15. package/dist/cjs/extensions/erc1155/drops/write/updateMetadata.js +2 -1
  16. package/dist/cjs/extensions/erc1155/drops/write/updateMetadata.js.map +1 -1
  17. package/dist/cjs/extensions/erc721/drops/write/updateMetadata.js +1 -0
  18. package/dist/cjs/extensions/erc721/drops/write/updateMetadata.js.map +1 -1
  19. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js +1 -1
  20. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js.map +1 -1
  21. package/dist/cjs/react/web/ui/ConnectWallet/screens/WalletSwitcherConnectionScreen.js +1 -1
  22. package/dist/cjs/react/web/ui/ConnectWallet/screens/WalletSwitcherConnectionScreen.js.map +1 -1
  23. package/dist/cjs/react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.js +64 -19
  24. package/dist/cjs/react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.js.map +1 -1
  25. package/dist/cjs/version.js +1 -1
  26. package/dist/cjs/version.js.map +1 -1
  27. package/dist/esm/adapters/ethers5.js +3 -3
  28. package/dist/esm/adapters/ethers5.js.map +1 -1
  29. package/dist/esm/exports/extensions/ens.js +2 -0
  30. package/dist/esm/exports/extensions/ens.js.map +1 -1
  31. package/dist/esm/extensions/ens/__generated__/L2Resolver/read/name.js +107 -0
  32. package/dist/esm/extensions/ens/__generated__/L2Resolver/read/name.js.map +1 -0
  33. package/dist/esm/extensions/ens/constants.js +2 -0
  34. package/dist/esm/extensions/ens/constants.js.map +1 -1
  35. package/dist/esm/extensions/ens/resolve-address.js +13 -1
  36. package/dist/esm/extensions/ens/resolve-address.js.map +1 -1
  37. package/dist/esm/extensions/ens/resolve-l2-name.js +75 -0
  38. package/dist/esm/extensions/ens/resolve-l2-name.js.map +1 -0
  39. package/dist/esm/extensions/ens/resolve-name.js +1 -1
  40. package/dist/esm/extensions/ens/resolve-name.js.map +1 -1
  41. package/dist/esm/extensions/erc1155/drops/write/updateMetadata.js +2 -1
  42. package/dist/esm/extensions/erc1155/drops/write/updateMetadata.js.map +1 -1
  43. package/dist/esm/extensions/erc721/drops/write/updateMetadata.js +1 -0
  44. package/dist/esm/extensions/erc721/drops/write/updateMetadata.js.map +1 -1
  45. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js +1 -1
  46. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js.map +1 -1
  47. package/dist/esm/react/web/ui/ConnectWallet/screens/WalletSwitcherConnectionScreen.js +1 -1
  48. package/dist/esm/react/web/ui/ConnectWallet/screens/WalletSwitcherConnectionScreen.js.map +1 -1
  49. package/dist/esm/react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.js +62 -17
  50. package/dist/esm/react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.js.map +1 -1
  51. package/dist/esm/version.js +1 -1
  52. package/dist/esm/version.js.map +1 -1
  53. package/dist/types/adapters/ethers5.d.ts +24 -0
  54. package/dist/types/adapters/ethers5.d.ts.map +1 -1
  55. package/dist/types/exports/extensions/ens.d.ts +2 -0
  56. package/dist/types/exports/extensions/ens.d.ts.map +1 -1
  57. package/dist/types/extensions/ens/__generated__/L2Resolver/read/name.d.ts +84 -0
  58. package/dist/types/extensions/ens/__generated__/L2Resolver/read/name.d.ts.map +1 -0
  59. package/dist/types/extensions/ens/constants.d.ts +2 -0
  60. package/dist/types/extensions/ens/constants.d.ts.map +1 -1
  61. package/dist/types/extensions/ens/resolve-address.d.ts +12 -0
  62. package/dist/types/extensions/ens/resolve-address.d.ts.map +1 -1
  63. package/dist/types/extensions/ens/resolve-l2-name.d.ts +48 -0
  64. package/dist/types/extensions/ens/resolve-l2-name.d.ts.map +1 -0
  65. package/dist/types/extensions/erc1155/drops/write/updateMetadata.d.ts +2 -1
  66. package/dist/types/extensions/erc1155/drops/write/updateMetadata.d.ts.map +1 -1
  67. package/dist/types/extensions/erc721/drops/write/updateMetadata.d.ts +1 -0
  68. package/dist/types/extensions/erc721/drops/write/updateMetadata.d.ts.map +1 -1
  69. package/dist/types/react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.d.ts.map +1 -1
  70. package/dist/types/version.d.ts +1 -1
  71. package/dist/types/version.d.ts.map +1 -1
  72. package/package.json +1 -1
  73. package/src/adapters/ethers5.test.ts +42 -3
  74. package/src/adapters/ethers5.ts +3 -3
  75. package/src/exports/extensions/ens.ts +10 -0
  76. package/src/extensions/ens/__generated__/L2Resolver/read/name.ts +122 -0
  77. package/src/extensions/ens/constants.ts +4 -0
  78. package/src/extensions/ens/resolve-address.test.ts +13 -0
  79. package/src/extensions/ens/resolve-address.ts +13 -1
  80. package/src/extensions/ens/resolve-l2-name.test.ts +30 -0
  81. package/src/extensions/ens/resolve-l2-name.ts +107 -0
  82. package/src/extensions/ens/resolve-name.ts +1 -1
  83. package/src/extensions/erc1155/drops/write/claimTo.test.ts +128 -16
  84. package/src/extensions/erc1155/drops/write/updateMetadata.test.ts +55 -0
  85. package/src/extensions/erc1155/drops/write/updateMetadata.ts +2 -1
  86. package/src/extensions/erc721/drops/write/updateMetadata.test.ts +56 -0
  87. package/src/extensions/erc721/drops/write/updateMetadata.ts +1 -0
  88. package/src/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.tsx +1 -1
  89. package/src/react/web/ui/ConnectWallet/screens/WalletSwitcherConnectionScreen.tsx +1 -1
  90. package/src/react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.tsx +75 -18
  91. package/src/version.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thirdweb",
3
- "version": "5.49.0",
3
+ "version": "5.50.0-nightly-ff3abfa79e4f5f8806676d97c11ff24ffd62266f-20240901000406",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/thirdweb-dev/js.git#main"
@@ -1,11 +1,19 @@
1
1
  import * as ethers5 from "ethers5";
2
- import { describe, expect, test } from "vitest";
3
- import { ANVIL_CHAIN } from "../../test/src/chains.js";
2
+ import { describe, expect, it, test } from "vitest";
3
+ import { USDT_CONTRACT } from "~test/test-contracts.js";
4
+ import { ANVIL_CHAIN, FORKED_ETHEREUM_CHAIN } from "../../test/src/chains.js";
4
5
  import { TEST_CLIENT } from "../../test/src/test-clients.js";
5
6
  import { ANVIL_PKEY_A, TEST_ACCOUNT_B } from "../../test/src/test-wallets.js";
7
+ import { resolveContractAbi } from "../contract/actions/resolve-abi.js";
8
+ import { decimals } from "../extensions/erc20/__generated__/IERC20/read/decimals.js";
6
9
  import { randomBytesBuffer } from "../utils/random.js";
7
10
  import { privateKeyToAccount } from "../wallets/private-key.js";
8
- import { toEthersSigner } from "./ethers5.js";
11
+ import {
12
+ fromEthersContract,
13
+ toEthersContract,
14
+ toEthersProvider,
15
+ toEthersSigner,
16
+ } from "./ethers5.js";
9
17
 
10
18
  const account = privateKeyToAccount({
11
19
  privateKey: ANVIL_PKEY_A,
@@ -110,4 +118,35 @@ describe("ethers5 adapter", () => {
110
118
  });
111
119
  expect(txResponse.hash.length).toBe(66);
112
120
  });
121
+
122
+ it("toEthersContract should work", async () => {
123
+ const ethersContract = await toEthersContract(ethers5, USDT_CONTRACT);
124
+ expect(ethersContract.address.toLowerCase()).toBe(
125
+ USDT_CONTRACT.address.toLowerCase(),
126
+ );
127
+ const decimals = await ethersContract.decimals();
128
+ expect(decimals.toString()).toBe("6");
129
+ });
130
+
131
+ it("fromEthersContract should work", async () => {
132
+ const provider = toEthersProvider(
133
+ ethers5,
134
+ TEST_CLIENT,
135
+ FORKED_ETHEREUM_CHAIN,
136
+ );
137
+ const ethersContract = new ethers5.Contract(
138
+ USDT_CONTRACT.address,
139
+ await resolveContractAbi(USDT_CONTRACT),
140
+ provider,
141
+ );
142
+
143
+ const thirdwebContract = await fromEthersContract({
144
+ client: TEST_CLIENT,
145
+ ethersContract,
146
+ chain: FORKED_ETHEREUM_CHAIN,
147
+ });
148
+
149
+ const _decimals = await decimals({ contract: thirdwebContract });
150
+ expect(_decimals).toBe(6);
151
+ });
113
152
  });
@@ -274,7 +274,7 @@ export const ethers5Adapter = /* @__PURE__ */ (() => {
274
274
  * @returns The ethers.js provider.
275
275
  * @internal
276
276
  */
277
- function toEthersProvider(
277
+ export function toEthersProvider(
278
278
  ethers: Ethers5,
279
279
  client: ThirdwebClient,
280
280
  chain: Chain,
@@ -299,7 +299,7 @@ function toEthersProvider(
299
299
  * @returns A Promise that resolves to an ethers.js Contract.
300
300
  * @internal
301
301
  */
302
- async function toEthersContract<abi extends Abi = []>(
302
+ export async function toEthersContract<abi extends Abi = []>(
303
303
  ethers: Ethers5,
304
304
  twContract: ThirdwebContract<abi>,
305
305
  ): Promise<ethers5.Contract> {
@@ -336,7 +336,7 @@ type FromEthersContractOptions = {
336
336
  * @returns A promise that resolves to a ThirdwebContract instance.
337
337
  * @internal
338
338
  */
339
- async function fromEthersContract<abi extends Abi>(
339
+ export async function fromEthersContract<abi extends Abi>(
340
340
  options: FromEthersContractOptions,
341
341
  ): Promise<ThirdwebContract<abi>> {
342
342
  return getContract({
@@ -17,3 +17,13 @@ export {
17
17
  type ResolveNameOptions,
18
18
  resolveName,
19
19
  } from "../../extensions/ens/resolve-name.js";
20
+
21
+ export {
22
+ type ResolveL2NameOptions,
23
+ resolveL2Name,
24
+ } from "../../extensions/ens/resolve-l2-name.js";
25
+
26
+ export {
27
+ BASENAME_RESOLVER_ADDRESS,
28
+ BASE_SEPOLIA_BASENAME_RESOLVER_ADDRESS,
29
+ } from "../../extensions/ens/constants.js";
@@ -0,0 +1,122 @@
1
+ import type { AbiParameterToPrimitiveType } from "abitype";
2
+ import { readContract } from "../../../../../transaction/read-contract.js";
3
+ import type { BaseTransactionOptions } from "../../../../../transaction/types.js";
4
+ import { encodeAbiParameters } from "../../../../../utils/abi/encodeAbiParameters.js";
5
+ import { decodeAbiParameters } from "viem";
6
+ import type { Hex } from "../../../../../utils/encoding/hex.js";
7
+ import { detectMethod } from "../../../../../utils/bytecode/detectExtension.js";
8
+
9
+ /**
10
+ * Represents the parameters for the "name" function.
11
+ */
12
+ export type NameParams = {
13
+ node: AbiParameterToPrimitiveType<{ type: "bytes32"; name: "node" }>;
14
+ };
15
+
16
+ export const FN_SELECTOR = "0x691f3431" as const;
17
+ const FN_INPUTS = [
18
+ {
19
+ type: "bytes32",
20
+ name: "node",
21
+ },
22
+ ] as const;
23
+ const FN_OUTPUTS = [
24
+ {
25
+ type: "string",
26
+ },
27
+ ] as const;
28
+
29
+ /**
30
+ * Checks if the `name` method is supported by the given contract.
31
+ * @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.
32
+ * @returns A boolean indicating if the `name` method is supported.
33
+ * @extension ENS
34
+ * @example
35
+ * ```ts
36
+ * import { isNameSupported } from "thirdweb/extensions/ens";
37
+ *
38
+ * const supported = isNameSupported(["0x..."]);
39
+ * ```
40
+ */
41
+ export function isNameSupported(availableSelectors: string[]) {
42
+ return detectMethod({
43
+ availableSelectors,
44
+ method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const,
45
+ });
46
+ }
47
+
48
+ /**
49
+ * Encodes the parameters for the "name" function.
50
+ * @param options - The options for the name function.
51
+ * @returns The encoded ABI parameters.
52
+ * @extension ENS
53
+ * @example
54
+ * ```ts
55
+ * import { encodeNameParams } "thirdweb/extensions/ens";
56
+ * const result = encodeNameParams({
57
+ * node: ...,
58
+ * });
59
+ * ```
60
+ */
61
+ export function encodeNameParams(options: NameParams) {
62
+ return encodeAbiParameters(FN_INPUTS, [options.node]);
63
+ }
64
+
65
+ /**
66
+ * Encodes the "name" function into a Hex string with its parameters.
67
+ * @param options - The options for the name function.
68
+ * @returns The encoded hexadecimal string.
69
+ * @extension ENS
70
+ * @example
71
+ * ```ts
72
+ * import { encodeName } "thirdweb/extensions/ens";
73
+ * const result = encodeName({
74
+ * node: ...,
75
+ * });
76
+ * ```
77
+ */
78
+ export function encodeName(options: NameParams) {
79
+ // we do a "manual" concat here to avoid the overhead of the "concatHex" function
80
+ // we can do this because we know the specific formats of the values
81
+ return (FN_SELECTOR +
82
+ encodeNameParams(options).slice(2)) as `${typeof FN_SELECTOR}${string}`;
83
+ }
84
+
85
+ /**
86
+ * Decodes the result of the name function call.
87
+ * @param result - The hexadecimal result to decode.
88
+ * @returns The decoded result as per the FN_OUTPUTS definition.
89
+ * @extension ENS
90
+ * @example
91
+ * ```ts
92
+ * import { decodeNameResult } from "thirdweb/extensions/ens";
93
+ * const result = decodeNameResult("...");
94
+ * ```
95
+ */
96
+ export function decodeNameResult(result: Hex) {
97
+ return decodeAbiParameters(FN_OUTPUTS, result)[0];
98
+ }
99
+
100
+ /**
101
+ * Calls the "name" function on the contract.
102
+ * @param options - The options for the name function.
103
+ * @returns The parsed result of the function call.
104
+ * @extension ENS
105
+ * @example
106
+ * ```ts
107
+ * import { name } from "thirdweb/extensions/ens";
108
+ *
109
+ * const result = await name({
110
+ * contract,
111
+ * node: ...,
112
+ * });
113
+ *
114
+ * ```
115
+ */
116
+ export async function name(options: BaseTransactionOptions<NameParams>) {
117
+ return readContract({
118
+ contract: options.contract,
119
+ method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const,
120
+ params: [options.node],
121
+ });
122
+ }
@@ -1,2 +1,6 @@
1
1
  export const UNIVERSAL_RESOLVER_ADDRESS =
2
2
  "0xce01f8eee7E479C928F8919abD53E553a36CeF67";
3
+ export const BASENAME_RESOLVER_ADDRESS =
4
+ "0xC6d566A56A1aFf6508b41f6c90ff131615583BCD";
5
+ export const BASE_SEPOLIA_BASENAME_RESOLVER_ADDRESS =
6
+ "0x6533C94869D28fAA8dF77cc63f9e2b2D6Cf77eBA";
@@ -1,5 +1,7 @@
1
1
  import { describe, expect, it } from "vitest";
2
2
  import { TEST_CLIENT } from "../../../test/src/test-clients.js";
3
+ import { base } from "../../chains/chain-definitions/base.js";
4
+ import { BASENAME_RESOLVER_ADDRESS } from "./constants.js";
3
5
  import { resolveAddress } from "./resolve-address.js";
4
6
 
5
7
  // skip this test suite if there is no secret key available to test with
@@ -22,4 +24,15 @@ describe.runIf(process.env.TW_SECRET_KEY)("ENS:resolve-address", () => {
22
24
  });
23
25
  expect(address).toBe("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045");
24
26
  });
27
+
28
+ it("should resolve Basename", async () => {
29
+ const name = "myk.base.eth";
30
+ const address = await resolveAddress({
31
+ client: TEST_CLIENT,
32
+ name,
33
+ resolverChain: base,
34
+ resolverAddress: BASENAME_RESOLVER_ADDRESS,
35
+ });
36
+ expect(address).toBe("0x653Ff253b0c7C1cc52f484e891b71f9f1F010Bfb");
37
+ });
25
38
  });
@@ -32,6 +32,18 @@ export type ResolveAddressOptions = {
32
32
  * name: "vitalik.eth",
33
33
  * });
34
34
  * ```
35
+ *
36
+ * Resolve an address to a Basename.
37
+ * ```ts
38
+ * import { resolveAddress, BASENAME_RESOLVER_ADDRESS } from "thirdweb/extensions/ens";
39
+ * import { base } from "thirdweb/chains";
40
+ * const address = await resolveAddress({
41
+ * client,
42
+ * name: "myk.base.eth",
43
+ * resolverAddress: BASENAME_RESOLVER_ADDRESS,
44
+ * resolverChain: base,
45
+ * });
46
+ * ```
35
47
  * @extension ENS
36
48
  * @returns A promise that resolves to the Ethereum address.
37
49
  */
@@ -58,7 +70,7 @@ export async function resolveAddress(options: ResolveAddressOptions) {
58
70
  return resolvedAddress;
59
71
  },
60
72
  {
61
- cacheKey: `ens:addr:${name}`,
73
+ cacheKey: `ens:addr:${resolverChain?.id || 1}:${name}`,
62
74
  // 1min cache
63
75
  cacheTime: 60 * 1000,
64
76
  },
@@ -0,0 +1,30 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { TEST_CLIENT } from "../../../test/src/test-clients.js";
3
+ import { base } from "../../chains/chain-definitions/base.js";
4
+ import { BASENAME_RESOLVER_ADDRESS } from "./constants.js";
5
+ import { resolveL2Name } from "./resolve-l2-name.js";
6
+
7
+ // skip this test suite if there is no secret key available to test with
8
+ // TODO: remove reliance on secret key during unit tests entirely
9
+ describe.runIf(process.env.TW_SECRET_KEY)("ENS:resolve-l2-name", () => {
10
+ it("should resolve Basename", async () => {
11
+ const ens = await resolveL2Name({
12
+ client: TEST_CLIENT,
13
+ // myk.base.eth
14
+ address: "0x653Ff253b0c7C1cc52f484e891b71f9f1F010Bfb",
15
+ resolverChain: base,
16
+ resolverAddress: BASENAME_RESOLVER_ADDRESS,
17
+ });
18
+ expect(ens).toBe("myk.base.eth");
19
+ });
20
+
21
+ it("should return null if no Basename exists for the address", async () => {
22
+ const ens = await resolveL2Name({
23
+ client: TEST_CLIENT,
24
+ address: "0xc6248746A9CA5935ae722E2061347A5897548c03",
25
+ resolverChain: base,
26
+ resolverAddress: BASENAME_RESOLVER_ADDRESS,
27
+ });
28
+ expect(ens).toBeNull();
29
+ });
30
+ });
@@ -0,0 +1,107 @@
1
+ import type { Address } from "abitype";
2
+ import { type Hex, encodePacked, keccak256, namehash } from "viem";
3
+ import type { Chain } from "../../chains/types.js";
4
+ import type { ThirdwebClient } from "../../client/client.js";
5
+ import { getContract } from "../../contract/contract.js";
6
+ import { withCache } from "../../utils/promise/withCache.js";
7
+ import { name } from "./__generated__/L2Resolver/read/name.js";
8
+
9
+ /**
10
+ * @extension ENS
11
+ */
12
+ export type ResolveL2NameOptions = {
13
+ client: ThirdwebClient;
14
+ address: Address;
15
+ resolverAddress: string;
16
+ resolverChain: Chain;
17
+ };
18
+
19
+ /**
20
+ * Convert an address to a reverse node for ENS resolution
21
+ *
22
+ * @internal
23
+ */
24
+ export const convertReverseNodeToBytes = (
25
+ address: Address,
26
+ chainId: number,
27
+ ) => {
28
+ const addressFormatted = address.toLocaleLowerCase() as Address;
29
+ const addressNode = keccak256(addressFormatted.substring(2) as Hex);
30
+ const cointype = (0x80000000 | chainId) >>> 0;
31
+
32
+ const chainCoinType = cointype.toString(16).toLocaleUpperCase();
33
+ const reverseNode = namehash(`${chainCoinType.toLocaleUpperCase()}.reverse`);
34
+
35
+ const addressReverseNode = keccak256(
36
+ encodePacked(["bytes32", "bytes32"], [reverseNode, addressNode]),
37
+ );
38
+ return addressReverseNode;
39
+ };
40
+
41
+ /**
42
+ * Resolves the L2 name for a specified address.
43
+ * @param options - The options for resolving an L2 ENS address.
44
+ * @example
45
+ * ```ts
46
+ * import { resolveL2Name } from "thirdweb/extensions/ens";
47
+ * const name = await resolveL2Name({
48
+ * client,
49
+ * address: "0x1234...",
50
+ * resolverAddress: "0x...",
51
+ * resolverChain: base,
52
+ * });
53
+ * ```
54
+ *
55
+ * Resolve a Basename.
56
+ * ```ts
57
+ * import { resolveL2Name, BASENAME_RESOLVER_ADDRESS } from "thirdweb/extensions/ens";
58
+ * import { base } from "thirdweb/chains";
59
+ * const name = await resolveL2Name({
60
+ * client,
61
+ * address: "0x1234...",
62
+ * resolverAddress: BASENAME_RESOLVER_ADDRESS,
63
+ * resolverChain: base,
64
+ * });
65
+ * ```
66
+ * @extension ENS
67
+ * @returns A promise that resolves to the Ethereum address.
68
+ */
69
+ export async function resolveL2Name(options: ResolveL2NameOptions) {
70
+ const { client, address, resolverAddress, resolverChain } = options;
71
+
72
+ return withCache(
73
+ async () => {
74
+ const contract = getContract({
75
+ client,
76
+ chain: resolverChain,
77
+ address: resolverAddress,
78
+ });
79
+
80
+ const reverseName = convertReverseNodeToBytes(
81
+ address,
82
+ resolverChain.id || 1,
83
+ );
84
+
85
+ const resolvedName = await name({
86
+ contract,
87
+ node: reverseName,
88
+ }).catch((e) => {
89
+ if ("data" in e && e.data === "0x7199966d") {
90
+ return null;
91
+ }
92
+ throw e;
93
+ });
94
+
95
+ if (resolvedName === "") {
96
+ return null;
97
+ }
98
+
99
+ return resolvedName;
100
+ },
101
+ {
102
+ cacheKey: `ens:name:${resolverChain}:${address}`,
103
+ // 1min cache
104
+ cacheTime: 60 * 1000,
105
+ },
106
+ );
107
+ }
@@ -65,7 +65,7 @@ export async function resolveName(options: ResolveNameOptions) {
65
65
  return name;
66
66
  },
67
67
  {
68
- cacheKey: `ens:name:${address}`,
68
+ cacheKey: `ens:name:${resolverChain?.id || 1}:${address}`,
69
69
  // 1min cache
70
70
  cacheTime: 60 * 1000,
71
71
  },
@@ -1,13 +1,12 @@
1
- import { beforeEach, describe, expect, it } from "vitest";
1
+ import { describe, expect, it } from "vitest";
2
2
  import { ANVIL_CHAIN } from "~test/chains.js";
3
3
  import { TEST_CLIENT } from "~test/test-clients.js";
4
- import { TEST_ACCOUNT_A } from "~test/test-wallets.js";
4
+ import { TEST_ACCOUNT_A, TEST_ACCOUNT_B } from "~test/test-wallets.js";
5
5
 
6
+ import { TEST_CONTRACT_URI } from "~test/ipfs-uris.js";
6
7
  import { NATIVE_TOKEN_ADDRESS } from "../../../../constants/addresses.js";
7
- import {
8
- type ThirdwebContract,
9
- getContract,
10
- } from "../../../../contract/contract.js";
8
+ import { getContract } from "../../../../contract/contract.js";
9
+ import { deployERC20Contract } from "../../../../extensions/prebuilts/deploy-erc20.js";
11
10
  import { deployERC1155Contract } from "../../../../extensions/prebuilts/deploy-erc1155.js";
12
11
  import { sendAndConfirmTransaction } from "../../../../transaction/actions/send-and-confirm-transaction.js";
13
12
  import { totalSupply } from "../../__generated__/IERC1155/read/totalSupply.js";
@@ -15,13 +14,12 @@ import { lazyMint } from "../../write/lazyMint.js";
15
14
  import { claimTo } from "./claimTo.js";
16
15
  import { setClaimConditions } from "./setClaimConditions.js";
17
16
 
18
- let contract: ThirdwebContract;
19
17
  const account = TEST_ACCOUNT_A;
20
18
  const client = TEST_CLIENT;
21
19
  const chain = ANVIL_CHAIN;
22
20
 
23
21
  describe.runIf(process.env.TW_SECRET_KEY)("erc1155 claimTo extension", () => {
24
- beforeEach(async () => {
22
+ it("should claim the nft", async () => {
25
23
  const address = await deployERC1155Contract({
26
24
  client,
27
25
  chain,
@@ -29,17 +27,16 @@ describe.runIf(process.env.TW_SECRET_KEY)("erc1155 claimTo extension", () => {
29
27
  type: "DropERC1155",
30
28
  params: {
31
29
  name: "Edition Drop",
30
+ contractURI: TEST_CONTRACT_URI,
32
31
  },
33
32
  });
34
- contract = getContract({
33
+ const contract = getContract({
35
34
  address,
36
35
  client,
37
36
  chain,
38
37
  });
39
-
40
- const transaction = lazyMint({ contract, nfts: [{ name: "token 0" }] });
41
- await sendAndConfirmTransaction({ transaction, account });
42
-
38
+ const lazyMintTx = lazyMint({ contract, nfts: [{ name: "token 0" }] });
39
+ await sendAndConfirmTransaction({ transaction: lazyMintTx, account });
43
40
  const setClaimTx = setClaimConditions({
44
41
  contract,
45
42
  tokenId: 0n,
@@ -53,20 +50,135 @@ describe.runIf(process.env.TW_SECRET_KEY)("erc1155 claimTo extension", () => {
53
50
  },
54
51
  ],
55
52
  });
53
+ await sendAndConfirmTransaction({ transaction: setClaimTx, account });
56
54
 
55
+ const transaction = claimTo({
56
+ contract,
57
+ tokenId: 0n,
58
+ quantity: 1n,
59
+ to: account.address,
60
+ });
61
+ await sendAndConfirmTransaction({ transaction, account });
62
+ const supplyCount = await totalSupply({ contract, id: 0n });
63
+ expect(supplyCount).toBe(1n);
64
+ });
65
+
66
+ it("should claim with allowlist", async () => {
67
+ const address = await deployERC1155Contract({
68
+ client,
69
+ chain,
70
+ account,
71
+ type: "DropERC1155",
72
+ params: {
73
+ name: "Edition Drop",
74
+ contractURI: TEST_CONTRACT_URI,
75
+ },
76
+ });
77
+ const contract = getContract({
78
+ address,
79
+ client,
80
+ chain,
81
+ });
82
+ const lazyMintTx = lazyMint({ contract, nfts: [{ name: "token 0" }] });
83
+ await sendAndConfirmTransaction({ transaction: lazyMintTx, account });
84
+ const setClaimTx = setClaimConditions({
85
+ contract,
86
+ tokenId: 0n,
87
+ phases: [
88
+ {
89
+ maxClaimableSupply: 100n,
90
+ maxClaimablePerWallet: 5n,
91
+ currencyAddress: NATIVE_TOKEN_ADDRESS,
92
+ price: 0.06,
93
+ startTime: new Date(),
94
+ overrideList: [
95
+ {
96
+ address: TEST_ACCOUNT_B.address,
97
+ maxClaimable: "50",
98
+ price: "0.3",
99
+ currencyAddress: NATIVE_TOKEN_ADDRESS,
100
+ },
101
+ ],
102
+ },
103
+ ],
104
+ });
57
105
  await sendAndConfirmTransaction({ transaction: setClaimTx, account });
106
+
107
+ const transaction = claimTo({
108
+ contract,
109
+ tokenId: 0n,
110
+ quantity: 50n,
111
+ to: TEST_ACCOUNT_B.address,
112
+ });
113
+ await sendAndConfirmTransaction({ transaction, account: TEST_ACCOUNT_B });
114
+ const supplyCount = await totalSupply({ contract, id: 0n });
115
+ expect(supplyCount).toBe(50n);
58
116
  });
59
117
 
60
- it("should claim the nft", async () => {
118
+ /**
119
+ * This is to document the behavior where one can claim without paying if the claiming address
120
+ * is the same as the PrimaryRecipientAddress, because of this Solidity code:
121
+ * ```solidity
122
+ * // CurrencyTransferLib.sol
123
+ * function safeTransferERC20(address _currency, address _from, address _to, uint256 _amount) internal {
124
+ * if (_from == _to) {
125
+ * return;
126
+ * }
127
+ * ...
128
+ * }
129
+ * ```
130
+ */
131
+ it("address that is the same with PrimaryFeeRecipient can claim without paying ERC20", async () => {
132
+ const tokenAddress = await deployERC20Contract({
133
+ client,
134
+ chain,
135
+ account,
136
+ type: "TokenERC20",
137
+ params: {
138
+ name: "token20",
139
+ contractURI: TEST_CONTRACT_URI,
140
+ },
141
+ });
142
+ const address = await deployERC1155Contract({
143
+ client,
144
+ chain,
145
+ account,
146
+ type: "DropERC1155",
147
+ params: {
148
+ name: "Edition Drop",
149
+ contractURI: TEST_CONTRACT_URI,
150
+ saleRecipient: account.address,
151
+ },
152
+ });
153
+ const contract = getContract({
154
+ address,
155
+ client,
156
+ chain,
157
+ });
158
+ const lazyMintTx = lazyMint({ contract, nfts: [{ name: "token 0" }] });
159
+ await sendAndConfirmTransaction({ transaction: lazyMintTx, account });
160
+ const setClaimTx = setClaimConditions({
161
+ contract,
162
+ tokenId: 0n,
163
+ phases: [
164
+ {
165
+ maxClaimableSupply: 100n,
166
+ maxClaimablePerWallet: 100n,
167
+ currencyAddress: tokenAddress,
168
+ price: 1000,
169
+ startTime: new Date(),
170
+ },
171
+ ],
172
+ });
173
+ await sendAndConfirmTransaction({ transaction: setClaimTx, account });
174
+
61
175
  const transaction = claimTo({
62
176
  contract,
63
177
  tokenId: 0n,
64
178
  quantity: 1n,
65
179
  to: account.address,
66
180
  });
67
-
68
181
  await sendAndConfirmTransaction({ transaction, account });
69
-
70
182
  const supplyCount = await totalSupply({ contract, id: 0n });
71
183
  expect(supplyCount).toBe(1n);
72
184
  });
@@ -0,0 +1,55 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { ANVIL_CHAIN } from "~test/chains.js";
3
+ import { TEST_CLIENT } from "~test/test-clients.js";
4
+ import { TEST_ACCOUNT_A } from "~test/test-wallets.js";
5
+
6
+ import { TEST_CONTRACT_URI } from "~test/ipfs-uris.js";
7
+ import { getContract } from "../../../../contract/contract.js";
8
+ import { deployERC1155Contract } from "../../../../extensions/prebuilts/deploy-erc1155.js";
9
+ import { sendAndConfirmTransaction } from "../../../../transaction/actions/send-and-confirm-transaction.js";
10
+ import { getNFTs } from "../../read/getNFTs.js";
11
+ import { lazyMint } from "../../write/lazyMint.js";
12
+ import { updateMetadata } from "./updateMetadata.js";
13
+
14
+ const account = TEST_ACCOUNT_A;
15
+ const client = TEST_CLIENT;
16
+ const chain = ANVIL_CHAIN;
17
+ describe.runIf(process.env.TW_SECRET_KEY)("updateMetadata ERC1155", () => {
18
+ it("should update metadata", async () => {
19
+ const address = await deployERC1155Contract({
20
+ client,
21
+ chain,
22
+ account,
23
+ type: "DropERC1155",
24
+ params: {
25
+ name: "Edition Drop",
26
+ contractURI: TEST_CONTRACT_URI,
27
+ },
28
+ });
29
+ const contract = getContract({
30
+ address,
31
+ client,
32
+ chain,
33
+ });
34
+ const lazyMintTx = lazyMint({
35
+ contract,
36
+ nfts: [{ name: "token 0" }, { name: "token 1" }, { name: "token 2" }],
37
+ });
38
+ await sendAndConfirmTransaction({ transaction: lazyMintTx, account });
39
+
40
+ const updateTx = updateMetadata({
41
+ contract,
42
+ targetTokenId: 1n,
43
+ newMetadata: { name: "token 1 - updated" },
44
+ client,
45
+ });
46
+ await sendAndConfirmTransaction({ transaction: updateTx, account });
47
+
48
+ const nfts = await getNFTs({ contract });
49
+
50
+ expect(nfts.length).toBe(3);
51
+ expect(nfts[0]?.metadata.name).toBe("token 0");
52
+ expect(nfts[1]?.metadata.name).toBe("token 1 - updated");
53
+ expect(nfts[2]?.metadata.name).toBe("token 2");
54
+ });
55
+ });