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/silent-eels-explain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"thirdweb": minor
---

Add new ERC1155 extension: mintAdditionalSupplyToBatch
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 @@ -203,3 +203,8 @@ export {
mintToBatch,
type MintToBatchParams,
} from "../../extensions/erc1155/write/mintToBatch.js";

export {
mintAdditionalSupplyToBatch,
type MintAdditionalSupplyToBatchParams,
} from "../../extensions/erc1155/write/mintAdditionalSupplyToBatch.js";
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
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 { mintAdditionalSupplyToBatch } from "./mintAdditionalSupplyToBatch.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 },
],
}),
});

await sendAndConfirmTransaction({
account,
transaction: mintAdditionalSupplyToBatch({
contract,
nfts: [
{ tokenId: 0n, supply: 99n, to: account.address },
{ tokenId: 1n, supply: 98n, to: account.address },
{ tokenId: 2n, supply: 97n, to: account.address },
],
}),
});

const nfts = await getNFTs({ contract });
expect(nfts).toStrictEqual([
{
metadata: { name: "token 0" },
owner: null,
id: 0n,
tokenURI: "ipfs://QmPZ6LpGqMuFbHKTXrNW1NRNLHf1nrxS4dtoFqdZZTKvPX/0",
type: "ERC1155",
supply: 100n,
},
{
metadata: { name: "token 1" },
owner: null,
id: 1n,
tokenURI: "ipfs://QmRFPyc3yEYxR4pQxwyTQWTine51TxWCoD6nzJWR3eX45b/0",
type: "ERC1155",
supply: 100n,
},
{
metadata: { name: "token 2" },
owner: null,
id: 2n,
tokenURI: "ipfs://QmesQiRLHCgqWZM2GFCs7Nb7rr2S72hU1BVQc7xiTyKZtT/0",
type: "ERC1155",
supply: 100n,
},
]);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { multicall } from "../../../extensions/common/__generated__/IMulticall/write/multicall.js";
import type { BaseTransactionOptions } from "../../../transaction/types.js";
import { uri } from "../__generated__/IERC1155/read/uri.js";
import { encodeMintTo } from "../__generated__/IMintableERC1155/write/mintTo.js";
import type { MintAdditionalSupplyToParams } from "./mintAdditionalSupplyTo.js";

/**
* @extension ERC1155
*/
export type MintAdditionalSupplyToBatchParams = {
nfts: MintAdditionalSupplyToParams[];
};

/**
* This extension batches multiple `mintAdditionalSupplyToBatch` 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.
* @extension ERC1155
* @example
* ```ts
* import { mintAdditionalSupplyToBatch } from "thirdweb/extensions/erc1155";
*
* const transaction = mintAdditionalSupplyToBatch({
* contract,
* nfts: [
* { tokenId: 0n, supply: 99n, to: account.address },
* { tokenId: 1n, supply: 98n, to: account.address },
* { tokenId: 2n, supply: 97n, to: account.address },
* ],
* });
* ```
*/
export function mintAdditionalSupplyToBatch(
options: BaseTransactionOptions<MintAdditionalSupplyToBatchParams>,
) {
return multicall({
contract: options.contract,
asyncParams: async () => {
const data = await Promise.all(
options.nfts.map(async (nft) => {
const tokenUri = await uri({
contract: options.contract,
tokenId: nft.tokenId,
});
return encodeMintTo({
to: nft.to,
tokenId: nft.tokenId,
amount: nft.supply,
uri: tokenUri,
});
}),
);
return { data };
},
});
}
39 changes: 15 additions & 24 deletions packages/thirdweb/src/extensions/erc1155/write/mintToBatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,33 +83,24 @@
return multicall({
contract: options.contract,
asyncParams: async () => {
const uris = await Promise.all(
options.nfts.map((item) => {
if (typeof item.metadata === "string") {
return item.metadata;
}
return upload({
client: options.contract.client,
files: [item.metadata],
const data = await Promise.all(
options.nfts.map(async (nft) => {
const uri =
typeof nft.metadata === "string"
? nft.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#L90

Added line #L90 was not covered by tests
: await upload({
client: options.contract.client,
files: [nft.metadata],
});
return encodeMintTo({
to: options.to,
// maxUint256 is used to indicate that this is a NEW token!
tokenId: maxUint256,
uri,
amount: nft.supply,
});
}),
);

const data = uris.map((uri, index) => {
const item = options.nfts[index];
if (!item) {
// Should not happen
throw new Error("Index mismatch");
}
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,
Expand Down
Loading