Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/six-drinks-joke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"thirdweb": minor
---

Add ERC1155 extension: mintToBatch
5 changes: 5 additions & 0 deletions packages/thirdweb/src/exports/extensions/erc1155.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,8 @@ export {

// Zora 1155 contract
export { nextTokenId } from "../../extensions/erc1155/__generated__/Zora1155/read/nextTokenId.js";

export {
mintToBatch,
type MintToBatchParams,
} from "../../extensions/erc1155/write/mintToBatch.js";
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { describe, expect, it } from "vitest";
import { ANVIL_CHAIN } from "~test/chains.js";
import { TEST_CONTRACT_URI } from "~test/ipfs-uris.js";
import { TEST_CLIENT } from "~test/test-clients.js";
import { TEST_ACCOUNT_C } from "~test/test-wallets.js";
import { getContract } from "../../../contract/contract.js";
import { deployERC1155Contract } from "../../../extensions/prebuilts/deploy-erc1155.js";
import { sendAndConfirmTransaction } from "../../../transaction/actions/send-and-confirm-transaction.js";
import { getNFTs } from "../read/getNFTs.js";
import { mintToBatch } from "./mintToBatch.js";

const chain = ANVIL_CHAIN;
const client = TEST_CLIENT;
const account = TEST_ACCOUNT_C;

describe("ERC1155 Edition: mintToBatch", () => {
it("should mint multiple tokens in one tx", async () => {
const contract = getContract({
chain,
client,
address: await deployERC1155Contract({
chain,
client,
account,
type: "TokenERC1155",
params: {
name: "edition",
contractURI: TEST_CONTRACT_URI,
},
}),
});

await sendAndConfirmTransaction({
account,
transaction: mintToBatch({
contract,
to: account.address,
nfts: [
{ metadata: { name: "token 0" }, supply: 1n },
{ metadata: { name: "token 1" }, supply: 2n },
{ metadata: { name: "token 2" }, supply: 3n },
],
}),
});

const nfts = await getNFTs({ contract });
expect(nfts).toStrictEqual([
{
metadata: { name: "token 0" },
owner: null,
id: 0n,
tokenURI: "ipfs://QmPZ6LpGqMuFbHKTXrNW1NRNLHf1nrxS4dtoFqdZZTKvPX/0",
type: "ERC1155",
supply: 1n,
},
{
metadata: { name: "token 1" },
owner: null,
id: 1n,
tokenURI: "ipfs://QmRFPyc3yEYxR4pQxwyTQWTine51TxWCoD6nzJWR3eX45b/0",
type: "ERC1155",
supply: 2n,
},
{
metadata: { name: "token 2" },
owner: null,
id: 2n,
tokenURI: "ipfs://QmesQiRLHCgqWZM2GFCs7Nb7rr2S72hU1BVQc7xiTyKZtT/0",
type: "ERC1155",
supply: 3n,
},
]);
});
});
117 changes: 117 additions & 0 deletions packages/thirdweb/src/extensions/erc1155/write/mintToBatch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { maxUint256 } from "viem";
import { multicall } from "../../../extensions/common/__generated__/IMulticall/write/multicall.js";
import { upload } from "../../../storage/upload.js";
import type {
BaseTransactionOptions,
WithOverrides,
} from "../../../transaction/types.js";
import type { NFTInput } from "../../../utils/nft/parseNft.js";
import { encodeMintTo } from "../__generated__/IMintableERC1155/write/mintTo.js";

/**
* @extension ERC1155
*/
export type MintToBatchParams = WithOverrides<{
/**
* The wallet that the NFTs will be minted to
*/
to: string;
/**
* An array of NFT metadata & supply to mint
* @example
* ```ts
* const nfts = [
* {
* metadata: { name: "token 0" },
* supply: 1n,
* },
* {
* metadata: { name: "token 1" },
* supply: 10n,
* },
* ]
* ```
*/
nfts: Array<{
supply: bigint;
metadata: NFTInput | string;
}>;
}>;

/**
* This extension batches multiple `mintTo` extensions into one single multicall.
* Keep in mind that there is a limit of how many NFTs you can mint per transaction.
* This limit varies depends on the network that you are transacting on.
*
* You are recommended to experiment with the number to figure out the best number for your chain of choice.
* @param options - the transaction options
* @returns A promise that resolves to the transaction result.
* @extension ERC1155
* @example
* ```ts
* import { mintBatchTo } from "thirdweb/extension/erc1155";
*
* const transaction = mintToBatch({
* contract: editionContract,
* to: "0x...",
* nfts: [
* {
* metadata: {
* name: "Token #0",
* image: "...",
* attributes: [],
* },
* supply: 100n,
* },
* {
* metadata: {
* name: "Token #1",
* image: "...",
* attributes: [],
* },
* supply: 111n,
* },
* ],
* });
*
* await sendTransaction({ transaction, account });
* ```
*/
export function mintToBatch(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add TS doc

also make sure you add a comment about the size of the batch - should not be too big otherwise it will not fit / not be included in a block

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ty ser. was waiting for a review on the code before I add the docs, seems all good!

options: BaseTransactionOptions<MintToBatchParams>,
) {
return multicall({
contract: options.contract,
asyncParams: async () => {
const uris = await Promise.all(
options.nfts.map((item) => {
if (typeof item.metadata === "string") {
return item.metadata;
}

Check warning on line 90 in packages/thirdweb/src/extensions/erc1155/write/mintToBatch.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/extensions/erc1155/write/mintToBatch.ts#L89-L90

Added lines #L89 - L90 were not covered by tests
return upload({
client: options.contract.client,
files: [item.metadata],
});
}),
);

const data = uris.map((uri, index) => {
const item = options.nfts[index];
if (!item) {
// Should not happen
throw new Error("Index mismatch");
}

Check warning on line 103 in packages/thirdweb/src/extensions/erc1155/write/mintToBatch.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/extensions/erc1155/write/mintToBatch.ts#L102-L103

Added lines #L102 - L103 were not covered by tests
return encodeMintTo({
to: options.to,
// maxUint256 is used to indicate that this is a NEW token!
tokenId: maxUint256,
uri,
amount: item.supply,
});
});

return { data };
},
overrides: options.overrides,
});
}
Loading