Skip to content
This repository was archived by the owner on Aug 30, 2022. It is now read-only.

Commit 798b586

Browse files
Allow creating batches from existing URIs for NFT/Edition Drop (#479)
* Allow creating batches from existing URIs for NFT/Edition Drop * add test
1 parent 9e4f8c8 commit 798b586

File tree

8 files changed

+85
-26
lines changed

8 files changed

+85
-26
lines changed

docs/sdk.editiondrop.createbatch.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@ Create a batch of NFTs to be claimed in the future
99
<b>Signature:</b>
1010

1111
```typescript
12-
createBatch(metadatas: NFTMetadataInput[]): Promise<TransactionResultWithId<NFTMetadata>[]>;
12+
createBatch(metadatas: NFTMetadataOrUri[], options?: {
13+
onProgress: (event: UploadProgressEvent) => void;
14+
}): Promise<TransactionResultWithId<NFTMetadata>[]>;
1315
```
1416

1517
## Parameters
1618

1719
| Parameter | Type | Description |
1820
| --- | --- | --- |
19-
| metadatas | [NFTMetadataInput](./sdk.nftmetadatainput.md)<!-- -->\[\] | |
21+
| metadatas | NFTMetadataOrUri\[\] | The metadata to include in the batch. |
22+
| options | { onProgress: (event: [UploadProgressEvent](./sdk.uploadprogressevent.md)<!-- -->) =&gt; void; } | <i>(Optional)</i> optional upload progress callback |
2023

2124
<b>Returns:</b>
2225

docs/sdk.editiondrop.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const contract = sdk.getEditionDrop("{{contract_address}}");
5454
| [burn(tokenId, amount)](./sdk.editiondrop.burn.md) | | Burn a specified amount of a NFT |
5555
| [claim(tokenId, quantity, proofs)](./sdk.editiondrop.claim.md) | | Claim a token to the connected wallet |
5656
| [claimTo(destinationAddress, tokenId, quantity, proofs)](./sdk.editiondrop.claimto.md) | | Claim NFTs to a specific Wallet |
57-
| [createBatch(metadatas)](./sdk.editiondrop.createbatch.md) | | Create a batch of NFTs to be claimed in the future |
57+
| [createBatch(metadatas, options)](./sdk.editiondrop.createbatch.md) | | Create a batch of NFTs to be claimed in the future |
5858
| [getAll(queryParams)](./sdk.editiondrop.getall.md) | | Get All Minted NFTs |
5959
| [getOwned(walletAddress)](./sdk.editiondrop.getowned.md) | | Get Owned NFTs |
6060
| [getTotalCount()](./sdk.editiondrop.gettotalcount.md) | | Get the number of NFTs minted |

docs/sdk.nftdrop.createbatch.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Create a batch of unique NFTs to be claimed in the future
99
<b>Signature:</b>
1010

1111
```typescript
12-
createBatch(metadatas: NFTMetadataInput[], options?: {
12+
createBatch(metadatas: NFTMetadataOrUri[], options?: {
1313
onProgress: (event: UploadProgressEvent) => void;
1414
}): Promise<TransactionResultWithId<NFTMetadata>[]>;
1515
```
@@ -18,7 +18,7 @@ createBatch(metadatas: NFTMetadataInput[], options?: {
1818

1919
| Parameter | Type | Description |
2020
| --- | --- | --- |
21-
| metadatas | [NFTMetadataInput](./sdk.nftmetadatainput.md)<!-- -->\[\] | The metadata to include in the batch. |
21+
| metadatas | NFTMetadataOrUri\[\] | The metadata to include in the batch. |
2222
| options | { onProgress: (event: [UploadProgressEvent](./sdk.uploadprogressevent.md)<!-- -->) =&gt; void; } | <i>(Optional)</i> optional upload progress callback |
2323

2424
<b>Returns:</b>

etc/sdk.api.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,7 +1101,10 @@ export class EditionDrop extends Erc1155<DropERC1155> {
11011101
static contractRoles: readonly ["admin", "minter", "transfer"];
11021102
// (undocumented)
11031103
static contractType: "edition-drop";
1104-
createBatch(metadatas: NFTMetadataInput[]): Promise<TransactionResultWithId<NFTMetadata>[]>;
1104+
// Warning: (ae-forgotten-export) The symbol "NFTMetadataOrUri" needs to be exported by the entry point index.d.ts
1105+
createBatch(metadatas: NFTMetadataOrUri[], options?: {
1106+
onProgress: (event: UploadProgressEvent) => void;
1107+
}): Promise<TransactionResultWithId<NFTMetadata>[]>;
11051108
// (undocumented)
11061109
encoder: ContractEncoder<DropERC1155>;
11071110
// (undocumented)
@@ -1723,7 +1726,6 @@ export class Erc721BatchMintable implements DetectableFeature {
17231726
constructor(erc721: Erc721, contractWrapper: ContractWrapper<IMintableERC721 & IMulticall>, storage: IStorage);
17241727
// (undocumented)
17251728
featureName: "ERC721BatchMintable";
1726-
// Warning: (ae-forgotten-export) The symbol "NFTMetadataOrUri" needs to be exported by the entry point index.d.ts
17271729
to(to: string, metadatas: NFTMetadataOrUri[]): Promise<TransactionResultWithId<NFTMetadataOwner>[]>;
17281730
}
17291731

@@ -2704,7 +2706,7 @@ export class NFTDrop extends Erc721<DropERC721> {
27042706
static contractRoles: readonly ["admin", "minter", "transfer"];
27052707
// (undocumented)
27062708
static contractType: "nft-drop";
2707-
createBatch(metadatas: NFTMetadataInput[], options?: {
2709+
createBatch(metadatas: NFTMetadataOrUri[], options?: {
27082710
onProgress: (event: UploadProgressEvent) => void;
27092711
}): Promise<TransactionResultWithId<NFTMetadata>[]>;
27102712
// (undocumented)

src/common/nft.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
import ERC721MetadataAbi from "../../abis/IERC721Metadata.json";
1717
import ERC1155MetadataAbi from "../../abis/IERC1155Metadata.json";
1818
import ERC165MetadataAbi from "../../abis/IERC165.json";
19+
import { UploadProgressEvent } from "../types/index";
1920

2021
const FALLBACK_METADATA = {
2122
name: "Failed to load NFT metadata",
@@ -124,16 +125,30 @@ export async function uploadOrExtractURI(
124125
* @internal
125126
* @param metadatas
126127
* @param storage
128+
* @param startNumber
129+
* @param contractAddress
130+
* @param signerAddress
131+
* @param options
127132
*/
128133
export async function uploadOrExtractURIs(
129134
metadatas: NFTMetadataOrUri[],
130135
storage: IStorage,
136+
startNumber?: number,
137+
contractAddress?: string,
138+
signerAddress?: string,
139+
options?: {
140+
onProgress: (event: UploadProgressEvent) => void;
141+
},
131142
): Promise<string[]> {
132143
if (isUriList(metadatas)) {
133144
return metadatas;
134145
} else if (isMetadataList(metadatas)) {
135146
const { uris } = await storage.uploadMetadataBatch(
136147
metadatas.map((m) => CommonNFTInput.parse(m)),
148+
startNumber,
149+
contractAddress,
150+
signerAddress,
151+
options,
137152
);
138153
return uris;
139154
} else {

src/contracts/edition-drop.ts

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,18 @@ import {
1313
} from "../core/types";
1414
import { SDKOptions } from "../schema/sdk-options";
1515
import { ContractWrapper } from "../core/classes/contract-wrapper";
16-
import {
17-
CommonNFTInput,
18-
NFTMetadata,
19-
NFTMetadataInput,
20-
} from "../schema/tokens/common";
16+
import { NFTMetadata, NFTMetadataOrUri } from "../schema/tokens/common";
2117
import { BigNumber, BigNumberish, BytesLike, constants, utils } from "ethers";
2218
import { prepareClaim } from "../common/claim-conditions";
2319
import { DropErc1155ClaimConditions } from "../core/classes/drop-erc1155-claim-conditions";
2420
import { DropErc1155ContractSchema } from "../schema/contracts/drop-erc1155";
2521
import { ContractEncoder } from "../core/classes/contract-encoder";
2622
import { GasCostEstimator } from "../core/classes/gas-cost-estimator";
27-
import { ClaimVerification, QueryAllParams } from "../types";
23+
import {
24+
ClaimVerification,
25+
QueryAllParams,
26+
UploadProgressEvent,
27+
} from "../types";
2828
import { DropErc1155History } from "../core/classes/drop-erc1155-history";
2929
import { ContractEvents } from "../core/classes/contract-events";
3030
import { ContractPlatformFee } from "../core/classes/contract-platform-fee";
@@ -34,6 +34,7 @@ import { getRoleHash } from "../common";
3434

3535
import { EditionMetadata, EditionMetadataOwner } from "../schema";
3636
import { ContractAnalytics } from "../core/classes/contract-analytics";
37+
import { uploadOrExtractURIs } from "../common/nft";
3738

3839
/**
3940
* Setup a collection of NFTs with a customizable number of each NFT that are minted as users claim them.
@@ -253,21 +254,39 @@ export class EditionDrop extends Erc1155<DropERC1155> {
253254
* const firstTokenId = results[0].id; // token id of the first created NFT
254255
* const firstNFT = await results[0].data(); // (optional) fetch details of the first created NFT
255256
* ```
257+
*
258+
* @param metadatas - The metadata to include in the batch.
259+
* @param options - optional upload progress callback
256260
*/
257261
public async createBatch(
258-
metadatas: NFTMetadataInput[],
262+
metadatas: NFTMetadataOrUri[],
263+
options?: {
264+
onProgress: (event: UploadProgressEvent) => void;
265+
},
259266
): Promise<TransactionResultWithId<NFTMetadata>[]> {
260267
const startFileNumber =
261268
await this.contractWrapper.readContract.nextTokenIdToMint();
262-
const batch = await this.storage.uploadMetadataBatch(
263-
metadatas.map((m) => CommonNFTInput.parse(m)),
269+
const batch = await uploadOrExtractURIs(
270+
metadatas,
271+
this.storage,
264272
startFileNumber.toNumber(),
265273
this.contractWrapper.readContract.address,
266274
await this.contractWrapper.getSigner()?.getAddress(),
275+
options,
267276
);
277+
// ensure baseUri is the same for the entire batch
278+
const baseUri = batch[0].substring(0, batch[0].lastIndexOf("/"));
279+
for (let i = 0; i < batch.length; i++) {
280+
const uri = batch[i].substring(0, batch[i].lastIndexOf("/"));
281+
if (baseUri !== uri) {
282+
throw new Error(
283+
`Can only create batches with the same base URI for every entry in the batch. Expected '${baseUri}' but got '${uri}'`,
284+
);
285+
}
286+
}
268287
const receipt = await this.contractWrapper.sendTransaction("lazyMint", [
269-
batch.uris.length,
270-
`${batch.baseUri.endsWith("/") ? batch.baseUri : `${batch.baseUri}/`}`,
288+
batch.length,
289+
`${baseUri.endsWith("/") ? baseUri : `${baseUri}/`}`,
271290
]);
272291
const event = this.contractWrapper.parseLogs<TokensLazyMintedEvent>(
273292
"TokensLazyMinted",

src/contracts/nft-drop.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,8 @@ import {
1919
import { DropErc721ContractSchema } from "../schema/contracts/drop-erc721";
2020
import { SDKOptions } from "../schema/sdk-options";
2121
import {
22-
CommonNFTInput,
2322
NFTMetadata,
24-
NFTMetadataInput,
23+
NFTMetadataOrUri,
2524
NFTMetadataOwner,
2625
} from "../schema/tokens/common";
2726
import { DEFAULT_QUERY_ALL_COUNT, QueryAllParams } from "../types/QueryParams";
@@ -46,6 +45,7 @@ import {
4645
} from "contracts/DropERC721";
4746
import { ContractAnalytics } from "../core/classes/contract-analytics";
4847
import { UploadProgressEvent } from "../types/events";
48+
import { uploadOrExtractURIs } from "../common/nft";
4949

5050
/**
5151
* Setup a collection of one-of-one NFTs that are minted as users claim them.
@@ -413,23 +413,33 @@ export class NFTDrop extends Erc721<DropERC721> {
413413
* @param options - optional upload progress callback
414414
*/
415415
public async createBatch(
416-
metadatas: NFTMetadataInput[],
416+
metadatas: NFTMetadataOrUri[],
417417
options?: {
418418
onProgress: (event: UploadProgressEvent) => void;
419419
},
420420
): Promise<TransactionResultWithId<NFTMetadata>[]> {
421421
const startFileNumber =
422422
await this.contractWrapper.readContract.nextTokenIdToMint();
423-
const batch = await this.storage.uploadMetadataBatch(
424-
metadatas.map((m) => CommonNFTInput.parse(m)),
423+
const batch = await uploadOrExtractURIs(
424+
metadatas,
425+
this.storage,
425426
startFileNumber.toNumber(),
426427
this.contractWrapper.readContract.address,
427428
await this.contractWrapper.getSigner()?.getAddress(),
428429
options,
429430
);
430-
const baseUri = batch.baseUri;
431+
// ensure baseUri is the same for the entire batch
432+
const baseUri = batch[0].substring(0, batch[0].lastIndexOf("/"));
433+
for (let i = 0; i < batch.length; i++) {
434+
const uri = batch[i].substring(0, batch[i].lastIndexOf("/"));
435+
if (baseUri !== uri) {
436+
throw new Error(
437+
`Can only create batches with the same base URI for every entry in the batch. Expected '${baseUri}' but got '${uri}'`,
438+
);
439+
}
440+
}
431441
const receipt = await this.contractWrapper.sendTransaction("lazyMint", [
432-
batch.uris.length,
442+
batch.length,
433443
baseUri.endsWith("/") ? baseUri : `${baseUri}/`,
434444
ethers.utils.toUtf8Bytes(""),
435445
]);

test/nft-drop.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ describe("NFT Drop Contract", async () => {
4040
dropContract = sdk.getNFTDrop(address);
4141
});
4242

43+
it("should lazy mint with URI", async () => {
44+
const uri = await storage.uploadMetadata({
45+
name: "Test1",
46+
});
47+
await dropContract.createBatch([uri]);
48+
const nft = await dropContract.get("0");
49+
assert.isNotNull(nft);
50+
assert.equal(nft.metadata.name, "Test1");
51+
});
52+
4353
it("should allow a snapshot to be set", async () => {
4454
await dropContract.claimConditions.set([
4555
{

0 commit comments

Comments
 (0)