Skip to content

Commit d9cd6f5

Browse files
authored
implement additional extensions (#2735)
1 parent 2a5c7d0 commit d9cd6f5

File tree

29 files changed

+1389
-5
lines changed

29 files changed

+1389
-5
lines changed

.changeset/new-dots-move.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"thirdweb": minor
3+
---
4+
5+
added extension support for: Marketplace, ERC1155, ERC721

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
"editor.formatOnSave": true,
33
"editor.defaultFormatter": "biomejs.biome",
44
"editor.codeActionsOnSave": {
5-
"source.fixAll": "explicit"
5+
"quickfix.biome": "explicit",
6+
"source.organizeImports.biome": "explicit"
67
},
78
"typescript.preferences.importModuleSpecifier": "relative"
89
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
[
22
"event SharedMetadataUpdated(string name, string description, string imageURI, string animationURI)",
3-
"function setSharedMetadata((string name, string description, string imageURI, string animationURI) _metadata)"
3+
"function setSharedMetadata((string name, string description, string imageURI, string animationURI) _metadata)",
4+
"function sharedMetadata() view returns (string name, string description, string imageURI, string animationURI)"
45
]

packages/thirdweb/scripts/generate/abis/marketplace/IDirectListings.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,8 @@
1414
"function getAllValidListings(uint256 _startId, uint256 _endId) view returns ((uint256 listingId, uint256 tokenId, uint256 quantity, uint256 pricePerToken, uint128 startTimestamp, uint128 endTimestamp, address listingCreator, address assetContract, address currency, uint8 tokenType, uint8 status, bool reserved)[] listings)",
1515
"function getListing(uint256 _listingId) view returns ((uint256 listingId, uint256 tokenId, uint256 quantity, uint256 pricePerToken, uint128 startTimestamp, uint128 endTimestamp, address listingCreator, address assetContract, address currency, uint8 tokenType, uint8 status, bool reserved) listing)",
1616
"function totalListings() view returns (uint256)",
17-
"function updateListing(uint256 _listingId, (address assetContract, uint256 tokenId, uint256 quantity, address currency, uint256 pricePerToken, uint128 startTimestamp, uint128 endTimestamp, bool reserved) _params)"
17+
"function updateListing(uint256 _listingId, (address assetContract, uint256 tokenId, uint256 quantity, address currency, uint256 pricePerToken, uint128 startTimestamp, uint128 endTimestamp, bool reserved) _params)",
18+
"function isBuyerApprovedForListing(uint256 _listingId, address _buyer) view returns (bool)",
19+
"function isCurrencyApprovedForListing(uint256 _listingId, address _currency) view returns (bool)",
20+
"function currencyPriceForListing(uint256 _listingId, address _currency) view returns (uint256)"
1821
]

packages/thirdweb/src/exports/extensions/erc1155.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ export {
3333
balanceOf,
3434
type BalanceOfParams,
3535
} from "../../extensions/erc1155/__generated__/IERC1155/read/balanceOf.js";
36+
export {
37+
isApprovedForAll,
38+
type IsApprovedForAllParams,
39+
} from "../../extensions/erc1155/__generated__/IERC1155/read/isApprovedForAll.js";
3640

3741
//WRITE
3842

@@ -44,6 +48,41 @@ export {
4448
burnBatch,
4549
type BurnBatchParams,
4650
} from "../../extensions/erc1155/__generated__/IBurnableERC1155/write/burnBatch.js";
51+
export {
52+
setApprovalForAll,
53+
type SetApprovalForAllParams,
54+
} from "../../extensions/erc1155/__generated__/IERC1155/write/setApprovalForAll.js";
55+
export {
56+
safeTransferFrom,
57+
type SafeTransferFromParams,
58+
} from "../../extensions/erc1155/__generated__/IERC1155/write/safeTransferFrom.js";
59+
export {
60+
safeBatchTransferFrom,
61+
type SafeBatchTransferFromParams,
62+
} from "../../extensions/erc1155/__generated__/IERC1155/write/safeBatchTransferFrom.js";
63+
export {
64+
mintTo,
65+
type MintToParams,
66+
} from "../../extensions/erc1155/write/mintTo.js";
67+
export {
68+
mintAdditionalSupplyTo,
69+
type MintAdditionalSupplyToParams,
70+
} from "../../extensions/erc1155/write/mintAdditionalSupplyTo.js";
71+
72+
// EVENTS
73+
74+
export {
75+
transferSingleEvent,
76+
type TransferSingleEventFilters,
77+
} from "../../extensions/erc1155/__generated__/IERC1155/events/TransferSingle.js";
78+
export {
79+
transferBatchEvent,
80+
type TransferBatchEventFilters,
81+
} from "../../extensions/erc1155/__generated__/IERC1155/events/TransferBatch.js";
82+
export {
83+
approvalForAllEvent,
84+
type ApprovalForAllEventFilters,
85+
} from "../../extensions/erc1155/__generated__/IERC1155/events/ApprovalForAll.js";
4786

4887
/**
4988
* DROPS extension for ERC1155

packages/thirdweb/src/exports/extensions/erc721.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ export {
9797
/**
9898
* DROPS extension for ERC721
9999
*/
100+
export { getClaimConditionById } from "../../extensions/erc721/__generated__/IDrop/read/getClaimConditionById.js";
100101
export { getActiveClaimCondition } from "../../extensions/erc721/drops/read/getActiveClaimCondition.js";
101102
export {
102103
claimTo,
@@ -111,3 +112,12 @@ export {
111112
type GenerateMintSignatureOptions,
112113
generateMintSignature,
113114
} from "../../extensions/erc721/write/sigMint.js";
115+
116+
/**
117+
* SHARED METADATA extension for ERC721
118+
*/
119+
export { sharedMetadata } from "../../extensions/erc721/__generated__/ISharedMetadata/read/sharedMetadata.js";
120+
export {
121+
setSharedMetadata,
122+
type SetSharedMetadataParams,
123+
} from "../../extensions/erc721/write/setSharedMetadata.js";

packages/thirdweb/src/exports/extensions/marketplace.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,44 @@ export {
2525
getAllValidListings,
2626
type GetAllValidListingParams,
2727
} from "../../extensions/marketplace/read/direct/getAllValidListings.js";
28+
export {
29+
isBuyerApprovedForListing,
30+
type IsBuyerApprovedForListingParams,
31+
} from "../../extensions/marketplace/read/direct/isBuyerApprovedForListing.js";
32+
export {
33+
isCurrencyApprovedForListing,
34+
type IsCurrencyApprovedForListingParams,
35+
} from "../../extensions/marketplace/__generated__/IDirectListings/read/isCurrencyApprovedForListing.js";
36+
export {
37+
currencyPriceForListing,
38+
type CurrencyPriceForListingParams,
39+
} from "../../extensions/marketplace/read/direct/currencyPriceForListing.js";
2840

2941
// WRITE
3042
export {
3143
createListing,
3244
type CreateListingParams,
3345
} from "../../extensions/marketplace/write/direct/createListing.js";
46+
export {
47+
updateListing,
48+
type UpdateListingParams,
49+
} from "../../extensions/marketplace/write/direct/updateListing.js";
50+
export {
51+
cancelListing,
52+
type CancelListingParams,
53+
} from "../../extensions/marketplace/__generated__/IDirectListings/write/cancelListing.js";
54+
export {
55+
buyFromListing,
56+
type BuyFromListingParams,
57+
} from "../../extensions/marketplace/write/direct/buyFromListing.js";
58+
export {
59+
approveBuyerForListing,
60+
type ApproveBuyerForListingParams,
61+
} from "../../extensions/marketplace/__generated__/IDirectListings/write/approveBuyerForListing.js";
62+
export {
63+
approveCurrencyForListing,
64+
type ApproveCurrencyForListingParams,
65+
} from "../../extensions/marketplace/__generated__/IDirectListings/write/approveCurrencyForListing.js";
3466

3567
// EVENTS
3668
export {
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import { beforeAll, describe, expect, it } from "vitest";
2+
import { ANVIL_CHAIN } from "../../../test/src/chains.js";
3+
import { TEST_CLIENT } from "../../../test/src/test-clients.js";
4+
import {
5+
TEST_ACCOUNT_A,
6+
TEST_ACCOUNT_B,
7+
} from "../../../test/src/test-wallets.js";
8+
import { type ThirdwebContract, getContract } from "../../contract/contract.js";
9+
import { sendAndConfirmTransaction } from "../../exports/transaction.js";
10+
import { getContractMetadata } from "../common/read/getContractMetadata.js";
11+
import { deployERC1155Contract } from "../prebuilts/deploy-erc1155.js";
12+
import { balanceOf } from "./__generated__/IERC1155/read/balanceOf.js";
13+
import { totalSupply } from "./__generated__/IERC1155/read/totalSupply.js";
14+
import { nextTokenIdToMint } from "./__generated__/IERC1155Enumerable/read/nextTokenIdToMint.js";
15+
import { getNFT } from "./read/getNFT.js";
16+
import { getNFTs } from "./read/getNFTs.js";
17+
import { mintAdditionalSupplyTo } from "./write/mintAdditionalSupplyTo.js";
18+
import { mintTo } from "./write/mintTo.js";
19+
20+
describe.runIf(process.env.TW_SECRET_KEY)("TokenERC1155", () => {
21+
let contract: ThirdwebContract;
22+
23+
beforeAll(async () => {
24+
const contractAddress = await deployERC1155Contract({
25+
account: TEST_ACCOUNT_A,
26+
chain: ANVIL_CHAIN,
27+
client: TEST_CLIENT,
28+
params: {
29+
name: "Test TokenERC1155",
30+
},
31+
type: "TokenERC1155",
32+
});
33+
34+
contract = getContract({
35+
address: contractAddress,
36+
chain: ANVIL_CHAIN,
37+
client: TEST_CLIENT,
38+
});
39+
// this deploys a contract, it may take some time
40+
}, 60_000);
41+
42+
describe("Deployment", () => {
43+
it("should deploy", async () => {
44+
expect(contract).toBeDefined();
45+
});
46+
it("should have the correct name", async () => {
47+
const metadata = await getContractMetadata({ contract });
48+
expect(metadata.name).toBe("Test TokenERC1155");
49+
});
50+
});
51+
52+
it("should allow for minting tokens", async () => {
53+
// initially no tokens minted
54+
await expect(nextTokenIdToMint({ contract })).resolves.toBe(0n);
55+
56+
// mint 1 token
57+
const mintTx = mintTo({
58+
contract,
59+
to: TEST_ACCOUNT_A.address,
60+
supply: 10n,
61+
nft: { name: "Test NFT" },
62+
});
63+
await sendAndConfirmTransaction({
64+
transaction: mintTx,
65+
account: TEST_ACCOUNT_A,
66+
});
67+
68+
// now 1 token minted
69+
await expect(nextTokenIdToMint({ contract })).resolves.toBe(1n);
70+
// tokenId 0 is minted
71+
await expect(
72+
getNFT({ contract, tokenId: 0n }),
73+
).resolves.toMatchInlineSnapshot(`
74+
{
75+
"id": 0n,
76+
"metadata": {
77+
"name": "Test NFT",
78+
},
79+
"owner": null,
80+
"supply": 10n,
81+
"tokenURI": "ipfs://QmUut8sypH8NaPUeksnirut7MgggMeQa9RvJ37sV513sw3/0",
82+
"type": "ERC1155",
83+
}
84+
`);
85+
// account should have a balance of 10
86+
await expect(
87+
balanceOf({ contract, owner: TEST_ACCOUNT_A.address, tokenId: 0n }),
88+
).resolves.toBe(10n);
89+
// totalSupply should be 10
90+
await expect(totalSupply({ contract, id: 0n })).resolves.toBe(10n);
91+
92+
// mint additional supply
93+
const mintTx2 = mintAdditionalSupplyTo({
94+
contract,
95+
to: TEST_ACCOUNT_A.address,
96+
supply: 5n,
97+
tokenId: 0n,
98+
});
99+
100+
await sendAndConfirmTransaction({
101+
transaction: mintTx2,
102+
account: TEST_ACCOUNT_A,
103+
});
104+
105+
// still 1 token minted
106+
await expect(nextTokenIdToMint({ contract })).resolves.toBe(1n);
107+
// tokenId 0 is minted
108+
// supply should be 15
109+
await expect(
110+
getNFT({ contract, tokenId: 0n }),
111+
).resolves.toMatchInlineSnapshot(`
112+
{
113+
"id": 0n,
114+
"metadata": {
115+
"name": "Test NFT",
116+
},
117+
"owner": null,
118+
"supply": 15n,
119+
"tokenURI": "ipfs://QmUut8sypH8NaPUeksnirut7MgggMeQa9RvJ37sV513sw3/0",
120+
"type": "ERC1155",
121+
}
122+
`);
123+
// account should have a balance of 15
124+
await expect(
125+
balanceOf({ contract, owner: TEST_ACCOUNT_A.address, tokenId: 0n }),
126+
).resolves.toBe(15n);
127+
// totalSupply should be 15
128+
await expect(totalSupply({ contract, id: 0n })).resolves.toBe(15n);
129+
130+
// mint a second token
131+
const mintTx3 = mintTo({
132+
contract,
133+
to: TEST_ACCOUNT_B.address,
134+
supply: 5n,
135+
nft: { name: "Test NFT 2" },
136+
});
137+
138+
await sendAndConfirmTransaction({
139+
transaction: mintTx3,
140+
account: TEST_ACCOUNT_A,
141+
});
142+
143+
// now 2 tokens minted
144+
await expect(nextTokenIdToMint({ contract })).resolves.toBe(2n);
145+
await expect(getNFTs({ contract })).resolves.toMatchInlineSnapshot(`
146+
[
147+
{
148+
"id": 0n,
149+
"metadata": {
150+
"name": "Test NFT",
151+
},
152+
"owner": null,
153+
"supply": 15n,
154+
"tokenURI": "ipfs://QmUut8sypH8NaPUeksnirut7MgggMeQa9RvJ37sV513sw3/0",
155+
"type": "ERC1155",
156+
},
157+
{
158+
"id": 1n,
159+
"metadata": {
160+
"name": "Test NFT 2",
161+
},
162+
"owner": null,
163+
"supply": 5n,
164+
"tokenURI": "ipfs://QmV6gsfzdiMRtpnh8ay3CgutStVbes7qoF4DKpYE64h8hT/0",
165+
"type": "ERC1155",
166+
},
167+
]
168+
`);
169+
});
170+
});
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import type { BaseTransactionOptions } from "../../../transaction/types.js";
2+
import { uri } from "../__generated__/IERC1155/read/uri.js";
3+
import { mintTo as generatedMintTo } from "../__generated__/IMintableERC1155/write/mintTo.js";
4+
5+
export type MintAdditionalSupplyToParams = {
6+
to: string;
7+
tokenId: bigint;
8+
supply: bigint;
9+
};
10+
11+
/**
12+
* Mints a "supply" number of additional ERC1155 tokens to the specified "to" address.
13+
* @param options - The transaction options.
14+
* @returns A promise that resolves to the transaction result.
15+
* @extension ERC1155
16+
* @example
17+
* ```ts
18+
* import { mintAdditionalSupplyTo } from "thirdweb/extensions/erc1155";
19+
* const transaction = mintTo({
20+
* contract,
21+
* to: "0x...",
22+
* tokenId: 1n,
23+
* supply: 10n,
24+
* });
25+
*
26+
* const { transactionHash } = await sendTransaction({ transaction, account });
27+
*
28+
* ```
29+
*/
30+
export function mintAdditionalSupplyTo(
31+
options: BaseTransactionOptions<MintAdditionalSupplyToParams>,
32+
) {
33+
return generatedMintTo({
34+
contract: options.contract,
35+
asyncParams: async () => {
36+
// we'll be re-using the exising token URI
37+
const tokenUri = await uri({
38+
contract: options.contract,
39+
tokenId: options.tokenId,
40+
});
41+
42+
return {
43+
to: options.to,
44+
tokenId: options.tokenId,
45+
uri: tokenUri,
46+
amount: options.supply,
47+
};
48+
},
49+
});
50+
}

0 commit comments

Comments
 (0)