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.
- package/dist/cjs/adapters/ethers5.js +3 -0
- package/dist/cjs/adapters/ethers5.js.map +1 -1
- package/dist/cjs/exports/extensions/ens.js +6 -1
- package/dist/cjs/exports/extensions/ens.js.map +1 -1
- package/dist/cjs/extensions/ens/__generated__/L2Resolver/read/name.js +115 -0
- package/dist/cjs/extensions/ens/__generated__/L2Resolver/read/name.js.map +1 -0
- package/dist/cjs/extensions/ens/constants.js +3 -1
- package/dist/cjs/extensions/ens/constants.js.map +1 -1
- package/dist/cjs/extensions/ens/resolve-address.js +13 -1
- package/dist/cjs/extensions/ens/resolve-address.js.map +1 -1
- package/dist/cjs/extensions/ens/resolve-l2-name.js +80 -0
- package/dist/cjs/extensions/ens/resolve-l2-name.js.map +1 -0
- package/dist/cjs/extensions/ens/resolve-name.js +1 -1
- package/dist/cjs/extensions/ens/resolve-name.js.map +1 -1
- package/dist/cjs/extensions/erc1155/drops/write/updateMetadata.js +2 -1
- package/dist/cjs/extensions/erc1155/drops/write/updateMetadata.js.map +1 -1
- package/dist/cjs/extensions/erc721/drops/write/updateMetadata.js +1 -0
- package/dist/cjs/extensions/erc721/drops/write/updateMetadata.js.map +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js.map +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/screens/WalletSwitcherConnectionScreen.js +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/screens/WalletSwitcherConnectionScreen.js.map +1 -1
- package/dist/cjs/react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.js +64 -19
- package/dist/cjs/react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.js.map +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/version.js.map +1 -1
- package/dist/esm/adapters/ethers5.js +3 -3
- package/dist/esm/adapters/ethers5.js.map +1 -1
- package/dist/esm/exports/extensions/ens.js +2 -0
- package/dist/esm/exports/extensions/ens.js.map +1 -1
- package/dist/esm/extensions/ens/__generated__/L2Resolver/read/name.js +107 -0
- package/dist/esm/extensions/ens/__generated__/L2Resolver/read/name.js.map +1 -0
- package/dist/esm/extensions/ens/constants.js +2 -0
- package/dist/esm/extensions/ens/constants.js.map +1 -1
- package/dist/esm/extensions/ens/resolve-address.js +13 -1
- package/dist/esm/extensions/ens/resolve-address.js.map +1 -1
- package/dist/esm/extensions/ens/resolve-l2-name.js +75 -0
- package/dist/esm/extensions/ens/resolve-l2-name.js.map +1 -0
- package/dist/esm/extensions/ens/resolve-name.js +1 -1
- package/dist/esm/extensions/ens/resolve-name.js.map +1 -1
- package/dist/esm/extensions/erc1155/drops/write/updateMetadata.js +2 -1
- package/dist/esm/extensions/erc1155/drops/write/updateMetadata.js.map +1 -1
- package/dist/esm/extensions/erc721/drops/write/updateMetadata.js +1 -0
- package/dist/esm/extensions/erc721/drops/write/updateMetadata.js.map +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js.map +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/screens/WalletSwitcherConnectionScreen.js +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/screens/WalletSwitcherConnectionScreen.js.map +1 -1
- package/dist/esm/react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.js +62 -17
- package/dist/esm/react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/version.js.map +1 -1
- package/dist/types/adapters/ethers5.d.ts +24 -0
- package/dist/types/adapters/ethers5.d.ts.map +1 -1
- package/dist/types/exports/extensions/ens.d.ts +2 -0
- package/dist/types/exports/extensions/ens.d.ts.map +1 -1
- package/dist/types/extensions/ens/__generated__/L2Resolver/read/name.d.ts +84 -0
- package/dist/types/extensions/ens/__generated__/L2Resolver/read/name.d.ts.map +1 -0
- package/dist/types/extensions/ens/constants.d.ts +2 -0
- package/dist/types/extensions/ens/constants.d.ts.map +1 -1
- package/dist/types/extensions/ens/resolve-address.d.ts +12 -0
- package/dist/types/extensions/ens/resolve-address.d.ts.map +1 -1
- package/dist/types/extensions/ens/resolve-l2-name.d.ts +48 -0
- package/dist/types/extensions/ens/resolve-l2-name.d.ts.map +1 -0
- package/dist/types/extensions/erc1155/drops/write/updateMetadata.d.ts +2 -1
- package/dist/types/extensions/erc1155/drops/write/updateMetadata.d.ts.map +1 -1
- package/dist/types/extensions/erc721/drops/write/updateMetadata.d.ts +1 -0
- package/dist/types/extensions/erc721/drops/write/updateMetadata.d.ts.map +1 -1
- package/dist/types/react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/types/version.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/adapters/ethers5.test.ts +42 -3
- package/src/adapters/ethers5.ts +3 -3
- package/src/exports/extensions/ens.ts +10 -0
- package/src/extensions/ens/__generated__/L2Resolver/read/name.ts +122 -0
- package/src/extensions/ens/constants.ts +4 -0
- package/src/extensions/ens/resolve-address.test.ts +13 -0
- package/src/extensions/ens/resolve-address.ts +13 -1
- package/src/extensions/ens/resolve-l2-name.test.ts +30 -0
- package/src/extensions/ens/resolve-l2-name.ts +107 -0
- package/src/extensions/ens/resolve-name.ts +1 -1
- package/src/extensions/erc1155/drops/write/claimTo.test.ts +128 -16
- package/src/extensions/erc1155/drops/write/updateMetadata.test.ts +55 -0
- package/src/extensions/erc1155/drops/write/updateMetadata.ts +2 -1
- package/src/extensions/erc721/drops/write/updateMetadata.test.ts +56 -0
- package/src/extensions/erc721/drops/write/updateMetadata.ts +1 -0
- package/src/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.tsx +1 -1
- package/src/react/web/ui/ConnectWallet/screens/WalletSwitcherConnectionScreen.tsx +1 -1
- package/src/react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.tsx +75 -18
- package/src/version.ts +1 -1
package/package.json
CHANGED
@@ -1,11 +1,19 @@
|
|
1
1
|
import * as ethers5 from "ethers5";
|
2
|
-
import { describe, expect, test } from "vitest";
|
3
|
-
import {
|
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 {
|
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
|
});
|
package/src/adapters/ethers5.ts
CHANGED
@@ -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
|
+
}
|
@@ -1,13 +1,12 @@
|
|
1
|
-
import {
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
+
});
|