diff --git a/.changeset/heavy-ties-lick.md b/.changeset/heavy-ties-lick.md new file mode 100644 index 00000000000..5d6aee72561 --- /dev/null +++ b/.changeset/heavy-ties-lick.md @@ -0,0 +1,5 @@ +--- +"@thirdweb-dev/solana": patch +--- + +Fixes for dashboard integration diff --git a/packages/solana/src/classes/deployer.ts b/packages/solana/src/classes/deployer.ts index 9f175bc7d8a..81f988c56af 100644 --- a/packages/solana/src/classes/deployer.ts +++ b/packages/solana/src/classes/deployer.ts @@ -6,6 +6,7 @@ import { } from "../types/contracts"; import { NFTDropConditionsOutputSchema, + NFTDropContractInput, NFTDropMetadataInput, } from "../types/contracts/nft-drop"; import { enforceCreator } from "./helpers/creators-helper"; @@ -100,7 +101,7 @@ export class Deployer { return collectionNft.mint.address.toBase58(); } - async createNftDrop(metadata: NFTDropMetadataInput): Promise { + async createNftDrop(metadata: NFTDropContractInput): Promise { const collectionInfo = NFTCollectionMetadataInputSchema.parse(metadata); const candyMachineInfo = NFTDropConditionsOutputSchema.parse(metadata); const uri = await this.storage.uploadMetadata(collectionInfo); diff --git a/packages/solana/src/classes/helpers/nft-helper.ts b/packages/solana/src/classes/helpers/nft-helper.ts index 36d98b6a454..eae41453dd6 100644 --- a/packages/solana/src/classes/helpers/nft-helper.ts +++ b/packages/solana/src/classes/helpers/nft-helper.ts @@ -52,7 +52,7 @@ export class NFTHelper { }; } - async balanceOf(walletAddress: string, mintAddress: string): Promise { + async balanceOf(walletAddress: string, mintAddress: string): Promise { const address = await getAssociatedTokenAddress( new PublicKey(mintAddress), new PublicKey(walletAddress), @@ -60,9 +60,9 @@ export class NFTHelper { try { const account = await getAccount(this.connection, address); - return account.amount; + return Number(account.amount); } catch (e) { - return BigInt(0); + return 0; } } diff --git a/packages/solana/src/contracts/nft-collection.ts b/packages/solana/src/contracts/nft-collection.ts index b91e1cd3ec6..51ee43a53f7 100644 --- a/packages/solana/src/contracts/nft-collection.ts +++ b/packages/solana/src/contracts/nft-collection.ts @@ -49,7 +49,12 @@ export class NFTCollection { return this.nft.get(mintAddress); } - async getAll(): Promise { + async getAll(): Promise { + const addresses = await this.getAllNFTAddresses(); + return await Promise.all(addresses.map((a) => this.get(a))); + } + + async getAllNFTAddresses(): Promise { const allSignatures: ConfirmedSignatureInfo[] = []; // This returns the first 1000, so we need to loop through until we run out of signatures to get. let signatures = await this.metaplex.connection.getSignaturesForAddress( @@ -132,12 +137,12 @@ export class NFTCollection { return Array.from(mintAddresses); } - async balance(mintAddress: string): Promise { + async balance(mintAddress: string): Promise { const address = this.metaplex.identity().publicKey.toBase58(); return this.balanceOf(address, mintAddress); } - async balanceOf(walletAddress: string, mintAddress: string): Promise { + async balanceOf(walletAddress: string, mintAddress: string): Promise { return this.nft.balanceOf(walletAddress, mintAddress); } @@ -210,8 +215,7 @@ export class NFTCollection { const { nft } = await this.metaplex .nfts() .create({ - // useExistingMint: newMint, - name: metadata.name || "", + name: metadata.name?.toString() || "", uri, sellerFeeBasisPoints: 0, collection: this.publicKey, diff --git a/packages/solana/src/contracts/nft-drop.ts b/packages/solana/src/contracts/nft-drop.ts index a9a1114e5d4..e11b80c5bed 100644 --- a/packages/solana/src/contracts/nft-drop.ts +++ b/packages/solana/src/contracts/nft-drop.ts @@ -45,14 +45,13 @@ export class NFTDrop { // TODO: Add pagination to get NFT functions async getAll(): Promise { const info = await this.getCandyMachine(); - const nfts = await Promise.all( + // TODO merge with getAllClaimed() + return await Promise.all( info.items.map(async (item) => { const metadata = await this.storage.get(item.uri); return { uri: item.uri, ...metadata }; }), ); - - return nfts; } async getAllClaimed(): Promise { @@ -61,29 +60,29 @@ export class NFTDrop { .findMintedNfts({ candyMachine: this.publicKey }) .run(); - const metadatas = nfts.map((nft) => this.nft.toNFTMetadata(nft)); - return metadatas; + return nfts.map((nft) => this.nft.toNFTMetadata(nft)); } - async balance(mintAddress: string): Promise { + async balance(mintAddress: string): Promise { const address = this.metaplex.identity().publicKey.toBase58(); return this.balanceOf(address, mintAddress); } - async balanceOf(walletAddress: string, mintAddress: string): Promise { + async balanceOf(walletAddress: string, mintAddress: string): Promise { return this.nft.balanceOf(walletAddress, mintAddress); } - async totalUnclaimedSupply(): Promise { + async totalUnclaimedSupply(): Promise { const info = await this.getCandyMachine(); - return BigInt( - Math.min(info.itemsLoaded.toNumber(), info.itemsRemaining.toNumber()), + return Math.min( + info.itemsLoaded.toNumber(), + info.itemsRemaining.toNumber(), ); } - async totalClaimedSupply(): Promise { + async totalClaimedSupply(): Promise { const info = await this.getCandyMachine(); - return BigInt(info.itemsMinted.toNumber()); + return info.itemsMinted.toNumber(); } async transfer( @@ -99,7 +98,7 @@ export class NFTDrop { ); const upload = await this.storage.uploadMetadataBatch(parsedMetadatas); const items = upload.uris.map((uri, i) => ({ - name: parsedMetadatas[i].name || "", + name: parsedMetadatas[i].name?.toString() || "", uri, })); diff --git a/packages/solana/src/sdk.ts b/packages/solana/src/sdk.ts index ec4154cc998..e03d771a90d 100644 --- a/packages/solana/src/sdk.ts +++ b/packages/solana/src/sdk.ts @@ -20,7 +20,13 @@ import { IpfsStorage, IStorage, PinataUploader } from "@thirdweb-dev/storage"; export class ThirdwebSDK { static fromNetwork(network: Network, storage?: IStorage): ThirdwebSDK { - return new ThirdwebSDK(new Connection(getUrlForNetwork(network)), storage); + return new ThirdwebSDK( + new Connection(getUrlForNetwork(network), { + disableRetryOnRateLimit: true, + commitment: "confirmed", + }), + storage, + ); } private connection: Connection; diff --git a/packages/solana/src/types/contracts/nft-drop.ts b/packages/solana/src/types/contracts/nft-drop.ts index 70111fbbea9..cb7bf7a9bc6 100644 --- a/packages/solana/src/types/contracts/nft-drop.ts +++ b/packages/solana/src/types/contracts/nft-drop.ts @@ -1,4 +1,5 @@ import { NFTCollectionMetadataInputSchema } from "."; +import { AmountSchema } from "../common"; import { sol, toBigNumber, toDateTime } from "@metaplex-foundation/js"; import { PublicKey } from "@solana/web3.js"; import { z } from "zod"; @@ -8,9 +9,9 @@ import { z } from "zod"; */ // TODO: Handle allow lists and end times export const NFTDropConditionsInputSchema = z.object({ + itemsAvailable: AmountSchema, price: z.number().default(0), sellerFeeBasisPoints: z.number().default(0), - itemsAvailable: z.number().default(0), goLiveDate: z.date().optional(), splToken: z.string().optional(), solTreasuryAccount: z.string().optional(), @@ -23,10 +24,7 @@ export const NFTDropConditionsOutputSchema = z.object({ .transform((p) => sol(p)) .optional(), sellerFeeBasisPoints: z.number().optional(), - itemsAvailable: z - .number() - .transform((bn) => toBigNumber(bn)) - .optional(), + itemsAvailable: AmountSchema.transform((bn) => toBigNumber(bn)).optional(), goLiveDate: z .date() .transform((d) => toDateTime(d)) @@ -48,4 +46,6 @@ export const NFTDropConditionsOutputSchema = z.object({ export const NFTDropContractInputSchema = NFTCollectionMetadataInputSchema.merge(NFTDropConditionsInputSchema); +export type NFTDropContractInput = z.input; + export type NFTDropMetadataInput = z.input; diff --git a/packages/solana/src/types/nft.ts b/packages/solana/src/types/nft.ts index d453b8c934c..e32d6d643ca 100644 --- a/packages/solana/src/types/nft.ts +++ b/packages/solana/src/types/nft.ts @@ -7,7 +7,7 @@ import { z } from "zod"; */ export const CommonTokenInput = z .object({ - name: z.string().optional(), + name: z.union([z.string(), z.number()]).optional(), symbol: z.string().optional(), description: z.string().nullable().optional(), image: FileBufferOrStringSchema.nullable().optional(), @@ -32,6 +32,7 @@ export const CommonNFTInput = CommonTokenInput.extend({ animation_url: FileBufferOrStringSchema.optional(), background_color: HexColor.optional(), properties: OptionalPropertiesInput, + attributes: OptionalPropertiesInput, }); /** diff --git a/packages/solana/test/nft-collection.test.ts b/packages/solana/test/nft-collection.test.ts index 92a49848b18..76c645f662c 100644 --- a/packages/solana/test/nft-collection.test.ts +++ b/packages/solana/test/nft-collection.test.ts @@ -27,33 +27,32 @@ describe("NFTCollection", async () => { it("should fetch NFTs", async () => { const all = await collection.getAll(); expect(all.length).to.eq(1); - const single = await collection.get(all[0]); - expect(single.name).to.eq("Test NFT"); + expect(all[0].name).to.eq("Test NFT"); }); it("should fetch balance of NFTs", async () => { const all = await collection.getAll(); const balance = await collection.balanceOf( sdk.wallet.getAddress() || "", - all[0], + all[0].id, ); - expect(balance).to.eq(1n); + expect(balance).to.eq(1); }); it("should transfer NFTs", async () => { const all = await collection.getAll(); const wallet = Keypair.generate(); - await collection.transfer(wallet.publicKey.toBase58() || "", all[0]); + await collection.transfer(wallet.publicKey.toBase58() || "", all[0].id); const balance = await collection.balanceOf( wallet.publicKey.toBase58() || "", - all[0], + all[0].id, ); - expect(balance).to.eq(1n); + expect(balance).to.eq(1); const balance2 = await collection.balanceOf( sdk.wallet.getAddress() || "", - all[0], + all[0].id, ); - expect(balance2).to.eq(0n); + expect(balance2).to.eq(0); }); it("should mint additional supply", async () => { @@ -63,9 +62,9 @@ describe("NFTCollection", async () => { }); const printed = await collection.mintAdditionalSupply(mint); let balance = await collection.balance(mint); - expect(balance).to.equal(1n); + expect(balance).to.equal(1); balance = await collection.balance(printed); - expect(balance).to.equal(1n); + expect(balance).to.equal(1); }); it("test supply of", async () => { diff --git a/packages/solana/test/nft-drop.test.ts b/packages/solana/test/nft-drop.test.ts index 96642a411a8..8848ba6dac8 100644 --- a/packages/solana/test/nft-drop.test.ts +++ b/packages/solana/test/nft-drop.test.ts @@ -18,7 +18,7 @@ describe("NFTDrop", async () => { it("should lazy mint NFTs", async () => { let supply = await drop.totalUnclaimedSupply(); - expect(supply).to.equal(0n); + expect(supply).to.equal(0); await drop.lazyMint([ { name: "NFT #1", description: "This is the #1 NFT" }, @@ -29,24 +29,24 @@ describe("NFTDrop", async () => { ]); supply = await drop.totalUnclaimedSupply(); - expect(supply).to.equal(5n); + expect(supply).to.equal(5); }); it("should claim free drop", async () => { let unclaimed = await drop.totalUnclaimedSupply(); let claimed = await drop.totalClaimedSupply(); - expect(unclaimed).to.equal(5n); - expect(claimed).to.equal(0n); + expect(unclaimed).to.equal(5); + expect(claimed).to.equal(0); const address = await drop.claim(); unclaimed = await drop.totalUnclaimedSupply(); claimed = await drop.totalClaimedSupply(); - expect(unclaimed).to.equal(4n); - expect(claimed).to.equal(1n); + expect(unclaimed).to.equal(4); + expect(claimed).to.equal(1); const balance = await drop.balance(address); - expect(balance).to.equal(1n); + expect(balance).to.equal(1); }); it("should get all nfts", async () => {