Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9124b3180c | ||
|
|
f41a443c57 | ||
|
|
b7cd744cd0 | ||
|
|
bb1b4e6ac3 | ||
|
|
2f8ec89c4c | ||
|
|
6ae52664e5 | ||
|
|
4f867e15ed | ||
|
|
cc8f983615 | ||
|
|
f45ef62128 | ||
|
|
9727502eb3 | ||
|
|
b6eec6146c | ||
|
|
88daa3c5cb | ||
|
|
53c6507669 | ||
|
|
782b58d3f6 | ||
|
|
e17e41f4d1 | ||
|
|
712b11a43e | ||
|
|
306debb029 | ||
|
|
86f0ceff46 | ||
|
|
7f0d1ec947 | ||
|
|
b1218cbd7d | ||
|
|
97ef35ce0f |
@@ -1,5 +1,13 @@
|
||||
# @thirdweb-dev/auth
|
||||
|
||||
## 2.0.18
|
||||
|
||||
## 2.0.17
|
||||
|
||||
## 2.0.16
|
||||
|
||||
## 2.0.15
|
||||
|
||||
## 2.0.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/auth",
|
||||
"version": "2.0.14",
|
||||
"version": "2.0.18",
|
||||
"exports": {
|
||||
"./next": {
|
||||
"module": "./next/dist/thirdweb-dev-auth-next.esm.js",
|
||||
|
||||
@@ -1,5 +1,33 @@
|
||||
# thirdweb
|
||||
|
||||
## 0.8.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`4f867e1`](https://github.com/thirdweb-dev/js/commit/4f867e15edbe5757afbf54cab207458711a8986c), [`b6eec61`](https://github.com/thirdweb-dev/js/commit/b6eec6146c23b66a3681bbb48b173b9019254214), [`9727502`](https://github.com/thirdweb-dev/js/commit/9727502eb30ac139382b7c7c8e8fc0967cbfbcf1), [`782b58d`](https://github.com/thirdweb-dev/js/commit/782b58d3f6a3b49ff9b3d837551db5161f96171a), [`f41a443`](https://github.com/thirdweb-dev/js/commit/f41a443c5785240197607b5bf93ff18a1c8e8307), [`f45ef62`](https://github.com/thirdweb-dev/js/commit/f45ef62128cfefe06275a38440c90d45e9f3cef7), [`2f8ec89`](https://github.com/thirdweb-dev/js/commit/2f8ec89c4c83ae577092c840c198e6fcfb114e69), [`b7cd744`](https://github.com/thirdweb-dev/js/commit/b7cd744cd0482a6c3fe5ae0c858f20cd380d4114), [`53c6507`](https://github.com/thirdweb-dev/js/commit/53c65076696a43bd9a7e58a7493d4e65c172900f)]:
|
||||
- @thirdweb-dev/sdk@3.2.6
|
||||
|
||||
## 0.8.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`712b11a`](https://github.com/thirdweb-dev/js/commit/712b11a43e389ae10b7f09648779a69c05b2c913)]:
|
||||
- @thirdweb-dev/sdk@3.2.5
|
||||
|
||||
## 0.8.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/sdk@3.2.4
|
||||
|
||||
## 0.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/sdk@3.2.3
|
||||
|
||||
## 0.8.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "thirdweb",
|
||||
"main": "dist/cli/index.js",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.4",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -11,7 +11,8 @@ module.exports = {
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-non-null-assertion": "error",
|
||||
"@typescript-eslint/no-parameter-properties": "error",
|
||||
"@typescript-eslint/no-unused-vars": "warn",
|
||||
// making this an error going forward
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
|
||||
// import rules
|
||||
"import/first": "error",
|
||||
|
||||
@@ -1,5 +1,31 @@
|
||||
# @thirdweb-dev/react
|
||||
|
||||
## 3.2.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#316](https://github.com/thirdweb-dev/js/pull/316) [`6ae5266`](https://github.com/thirdweb-dev/js/commit/6ae52664e5865564cd4fc2e00e3120675b9e0ca3) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix SIWE when using an external signer
|
||||
|
||||
- [#310](https://github.com/thirdweb-dev/js/pull/310) [`9727502`](https://github.com/thirdweb-dev/js/commit/9727502eb30ac139382b7c7c8e8fc0967cbfbcf1) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - [SOL] - add useMintNFTSupply hook in react and accomodate inputs for it in SDK
|
||||
|
||||
- [#319](https://github.com/thirdweb-dev/js/pull/319) [`2f8ec89`](https://github.com/thirdweb-dev/js/commit/2f8ec89c4c83ae577092c840c198e6fcfb114e69) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Expose total claimed and unclaimed supply for erc721 drop contracts
|
||||
|
||||
- [#318](https://github.com/thirdweb-dev/js/pull/318) [`bb1b4e6`](https://github.com/thirdweb-dev/js/commit/bb1b4e6ac39d98cc68b8e31e659cd68be3a5b967) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Add useMinimumNextBid hook and change invariant for other marketplace hooks
|
||||
|
||||
## 3.2.5
|
||||
|
||||
## 3.2.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#301](https://github.com/thirdweb-dev/js/pull/301) [`86f0cef`](https://github.com/thirdweb-dev/js/commit/86f0ceff46f72df8ebd81f843e3c66a245f23992) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Remove useAddress hook for now
|
||||
|
||||
## 3.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#299](https://github.com/thirdweb-dev/js/pull/299) [`b1218cb`](https://github.com/thirdweb-dev/js/commit/b1218cbd7d97ca7949d94a7e4ab93fef4ffbacd5) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Recreate SDK on wallet changes for hook propagation
|
||||
|
||||
## 3.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react",
|
||||
"version": "3.2.2",
|
||||
"version": "3.2.6",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RequiredParam } from "../types/shared";
|
||||
import { RequiredParam } from "./required-param";
|
||||
import type { QueryKey } from "@tanstack/react-query";
|
||||
import type { ValidContractInstance } from "@thirdweb-dev/sdk";
|
||||
import type {
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/**
|
||||
* Makes a parameter required to be passed, but still allowes it to be null or undefined.
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
export type RequiredParam<T> = T | null | undefined;
|
||||
|
||||
export function requiredParamInvariant<TValue>(
|
||||
condition: RequiredParam<TValue>,
|
||||
message?: string,
|
||||
): asserts condition {
|
||||
invariant(condition !== null || condition !== undefined, message);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
/**
|
||||
* Makes a parameter required to be passed, but still allowes it to be null or undefined.
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
export type RequiredParam<T> = T | null | undefined;
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
SupportedChainId,
|
||||
defaultSupportedChains,
|
||||
} from "../constants/chain";
|
||||
import { ChainId } from "@thirdweb-dev/sdk";
|
||||
import { DEFAULT_RPC_URLS } from "@thirdweb-dev/sdk";
|
||||
import React, { PropsWithChildren, createContext, useContext } from "react";
|
||||
|
||||
interface ThirdwebConfigContext {
|
||||
@@ -11,17 +11,8 @@ interface ThirdwebConfigContext {
|
||||
supportedChains: Chain[];
|
||||
}
|
||||
|
||||
export const defaultChainRpc: Record<SupportedChainId | number, string> = {
|
||||
[ChainId.Mainnet]: "mainnet",
|
||||
[ChainId.Goerli]: "goerli",
|
||||
[ChainId.Polygon]: "polygon",
|
||||
[ChainId.Mumbai]: "mumbai",
|
||||
[ChainId.Fantom]: "fantom",
|
||||
[ChainId.Avalanche]: "avalanche",
|
||||
};
|
||||
|
||||
const ThirdwebConfigContext = createContext<ThirdwebConfigContext>({
|
||||
rpcUrlMap: defaultChainRpc,
|
||||
rpcUrlMap: DEFAULT_RPC_URLS,
|
||||
supportedChains: defaultSupportedChains,
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import {
|
||||
RequiredParam,
|
||||
requiredParamInvariant,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/base";
|
||||
import { getErcs, DropContract, WalletAddress } from "../../types";
|
||||
import {
|
||||
@@ -70,8 +73,8 @@ export function useActiveClaimCondition(
|
||||
cacheKeys.extensions.claimConditions.getActive(contractAddress, tokenId),
|
||||
() => {
|
||||
if (erc1155) {
|
||||
invariant(
|
||||
tokenId !== undefined,
|
||||
requiredParamInvariant(
|
||||
tokenId,
|
||||
"tokenId is required for ERC1155 claim conditions",
|
||||
);
|
||||
return erc1155.claimConditions.getActive(tokenId);
|
||||
@@ -126,7 +129,10 @@ export function useClaimConditions(
|
||||
cacheKeys.extensions.claimConditions.getAll(contractAddress, tokenId),
|
||||
() => {
|
||||
if (erc1155) {
|
||||
invariant(tokenId, "tokenId is required for ERC1155 claim conditions");
|
||||
requiredParamInvariant(
|
||||
tokenId,
|
||||
"tokenId is required for ERC1155 claim conditions",
|
||||
);
|
||||
return erc1155.claimConditions.getAll(tokenId);
|
||||
}
|
||||
if (erc721) {
|
||||
@@ -184,7 +190,7 @@ export function useClaimIneligibilityReasons(
|
||||
),
|
||||
() => {
|
||||
if (erc1155) {
|
||||
invariant(
|
||||
requiredParamInvariant(
|
||||
tokenId,
|
||||
"tokenId is required for ERC1155 claim ineligibility reasons",
|
||||
);
|
||||
@@ -270,11 +276,14 @@ export function useSetClaimConditions(
|
||||
|
||||
return useMutation(
|
||||
async (data: SetClaimConditionsParams) => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
const { phases, reset = false } = data;
|
||||
invariant(phases, 'No "phases" provided');
|
||||
if (erc1155) {
|
||||
invariant(tokenId, "tokenId is required for ERC1155 claim conditions");
|
||||
requiredParamInvariant(
|
||||
tokenId,
|
||||
"tokenId is required for ERC1155 claim conditions",
|
||||
);
|
||||
return erc1155.claimConditions.set(tokenId, phases, reset);
|
||||
}
|
||||
if (erc721) {
|
||||
@@ -351,7 +360,10 @@ export function useResetClaimConditions(
|
||||
};
|
||||
|
||||
if (erc1155) {
|
||||
invariant(tokenId, "tokenId is required for ERC1155 claim conditions");
|
||||
requiredParamInvariant(
|
||||
tokenId,
|
||||
"tokenId is required for ERC1155 claim conditions",
|
||||
);
|
||||
const claimConditions = await erc1155.claimConditions.getAll(tokenId);
|
||||
return erc1155.claimConditions.set(
|
||||
tokenId,
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import {
|
||||
RequiredParam,
|
||||
requiredParamInvariant,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/base";
|
||||
import { WalletAddress } from "../../types";
|
||||
import {
|
||||
@@ -35,7 +38,7 @@ export function usePrimarySaleRecipient(
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.extensions.sales.getRecipient(contractAddress),
|
||||
() => {
|
||||
invariant(contract, "No contract provided");
|
||||
requiredParamInvariant(contract, "No contract provided");
|
||||
invariant(
|
||||
"sales" in contract && contract.sales,
|
||||
"Contract does not support primarySale",
|
||||
@@ -86,7 +89,7 @@ export function useUpdatePrimarySaleRecipient(
|
||||
const activeChainId = useSDKChainId();
|
||||
return useMutation(
|
||||
(newRecipient: WalletAddress) => {
|
||||
invariant(contract, "No contract provided");
|
||||
requiredParamInvariant(contract, "No contract provided");
|
||||
invariant(
|
||||
"sales" in contract && contract.sales,
|
||||
"Contract does not support primarySale",
|
||||
@@ -128,7 +131,7 @@ export function useRoyaltySettings(
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.extensions.royalties.getDefaultRoyaltyInfo(contractAddress),
|
||||
() => {
|
||||
invariant(contract, "No contract provided");
|
||||
requiredParamInvariant(contract, "No contract provided");
|
||||
invariant(
|
||||
"royalties" in contract && contract.royalties,
|
||||
"Contract does not support royalties",
|
||||
@@ -182,7 +185,7 @@ export function useUpdateRoyaltySettings(
|
||||
seller_fee_basis_points?: number;
|
||||
fee_recipient?: WalletAddress;
|
||||
}) => {
|
||||
invariant(contract, "No contract provided");
|
||||
requiredParamInvariant(contract, "No contract provided");
|
||||
invariant(
|
||||
"royalties" in contract && contract.royalties,
|
||||
"Contract does not support royalties",
|
||||
@@ -224,7 +227,7 @@ export function usePlatformFees(
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.extensions.platformFees.get(contractAddress),
|
||||
() => {
|
||||
invariant(contract, "No contract provided");
|
||||
requiredParamInvariant(contract, "No contract provided");
|
||||
invariant(
|
||||
"platformFees" in contract && contract.platformFees,
|
||||
"Contract does not support platformFees",
|
||||
@@ -277,7 +280,7 @@ export function useUpdatePlatformFees(
|
||||
platform_fee_basis_points?: number;
|
||||
fee_recipient?: WalletAddress;
|
||||
}) => {
|
||||
invariant(contract, "No contract provided");
|
||||
requiredParamInvariant(contract, "No contract provided");
|
||||
invariant(
|
||||
"platformFees" in contract && contract.platformFees,
|
||||
"Contract does not support platformFees",
|
||||
@@ -317,7 +320,7 @@ export function useMetadata(contract: RequiredParam<ValidContractInstance>) {
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.extensions.metadata.get(contractAddress),
|
||||
() => {
|
||||
invariant(contract, "No contract provided");
|
||||
requiredParamInvariant(contract, "No contract provided");
|
||||
invariant(
|
||||
"metadata" in contract && contract.metadata,
|
||||
"Contract does not support metadata",
|
||||
@@ -366,7 +369,7 @@ export function useUpdateMetadata(
|
||||
const activeChainId = useSDKChainId();
|
||||
return useMutation(
|
||||
(updatePayload: CustomContractMetadata) => {
|
||||
invariant(contract, "No contract provided");
|
||||
requiredParamInvariant(contract, "No contract provided");
|
||||
invariant(
|
||||
"metadata" in contract && contract.metadata,
|
||||
"Contract does not support metadata",
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { neverPersist } from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import {
|
||||
RequiredParam,
|
||||
requiredParamInvariant,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDK, useSDKChainId } from "../../providers/base";
|
||||
import { ContractAddress } from "../../types";
|
||||
import {
|
||||
@@ -216,7 +219,7 @@ export function useContract(
|
||||
{ wallet, walletChainId, sdkTimestamp },
|
||||
]),
|
||||
async () => {
|
||||
invariant(contractAddress, "contract address is required");
|
||||
requiredParamInvariant(contractAddress, "contract address is required");
|
||||
invariant(sdk, "SDK not initialized");
|
||||
invariant(activeChainId, "active chain id is required");
|
||||
|
||||
@@ -290,7 +293,7 @@ export function useContractMetadata<TContract extends ValidContractInstance>(
|
||||
>(
|
||||
cacheKeys.contract.metadata(contract?.getAddress()),
|
||||
async () => {
|
||||
invariant(contract, "contract is required");
|
||||
requiredParamInvariant(contract, "contract is required");
|
||||
return await contract.metadata.get();
|
||||
},
|
||||
{
|
||||
@@ -311,7 +314,7 @@ export function useContractMetadataUpdate(
|
||||
|
||||
return useMutation(
|
||||
async (metadata: CommonContractSchemaInput) => {
|
||||
invariant(contract, "contract must be defined");
|
||||
requiredParamInvariant(contract, "contract must be defined");
|
||||
|
||||
return contract.metadata.update(metadata);
|
||||
},
|
||||
@@ -406,7 +409,7 @@ export function useContractEvents(
|
||||
return useQuery(
|
||||
cacheKey,
|
||||
() => {
|
||||
invariant(contract, "contract must be defined");
|
||||
requiredParamInvariant(contract, "contract must be defined");
|
||||
if (eventName) {
|
||||
return contract.events.getEvents(eventName, options.queryFilter);
|
||||
}
|
||||
@@ -447,8 +450,8 @@ export function useContractRead(
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.call(contractAddress, functionName, args),
|
||||
() => {
|
||||
invariant(contract, "contract must be defined");
|
||||
invariant(functionName, "function name must be provided");
|
||||
requiredParamInvariant(contract, "contract must be defined");
|
||||
requiredParamInvariant(functionName, "function name must be provided");
|
||||
return contract.call(functionName, ...args);
|
||||
},
|
||||
{
|
||||
@@ -485,8 +488,8 @@ export function useContractWrite(
|
||||
|
||||
return useMutation(
|
||||
async (callParams?: unknown[] | [...unknown[], CallOverrides]) => {
|
||||
invariant(contract, "contract must be defined");
|
||||
invariant(functionName, "function name must be provided");
|
||||
requiredParamInvariant(contract, "contract must be defined");
|
||||
requiredParamInvariant(functionName, "function name must be provided");
|
||||
if (!callParams?.length) {
|
||||
return contract.call(functionName);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import {
|
||||
RequiredParam,
|
||||
requiredParamInvariant,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/base";
|
||||
import {
|
||||
ClaimNFTParams,
|
||||
@@ -51,7 +54,7 @@ export function useUnclaimedNFTs(
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.nft.drop.getAllUnclaimed(contractAddress, queryParams),
|
||||
() => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
// TODO make this work for custom contracts (needs ABI change)
|
||||
invariant(
|
||||
contract.getAllUnclaimed,
|
||||
@@ -94,18 +97,18 @@ export function useClaimedNFTs(
|
||||
*/
|
||||
export function useUnclaimedNFTSupply(contract: RequiredParam<DropContract>) {
|
||||
const contractAddress = contract?.getAddress();
|
||||
const { erc721 } = getErcs(contract);
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.nft.drop.totalUnclaimedSupply(contractAddress),
|
||||
() => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
// TODO make this work for custom contracts (needs ABI change)
|
||||
invariant(
|
||||
"totalUnclaimedSupply" in contract && contract.totalUnclaimedSupply,
|
||||
"Contract instance does not support fetching unclaimed supply",
|
||||
);
|
||||
return contract.totalUnclaimedSupply();
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
if (erc721) {
|
||||
invariant(erc721, "No ERC721 Contract instance provided");
|
||||
return erc721.totalUnclaimedSupply();
|
||||
}
|
||||
invariant(false, "Contract is not an instance of ERC721")
|
||||
},
|
||||
{ enabled: !!contract },
|
||||
{ enabled: !!erc721 },
|
||||
);
|
||||
}
|
||||
|
||||
@@ -118,18 +121,17 @@ export function useUnclaimedNFTSupply(contract: RequiredParam<DropContract>) {
|
||||
*/
|
||||
export function useClaimedNFTSupply(contract: RequiredParam<DropContract>) {
|
||||
const contractAddress = contract?.getAddress();
|
||||
const { erc721 } = getErcs(contract);
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.nft.drop.totalClaimedSupply(contractAddress),
|
||||
() => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
// TODO make this work for custom contracts (needs ABI change)
|
||||
invariant(
|
||||
"totalClaimedSupply" in contract && contract.totalClaimedSupply,
|
||||
"Contract instance does not support fetching unclaimed supply",
|
||||
);
|
||||
return contract.totalClaimedSupply();
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
if (erc721) {
|
||||
return erc721.totalClaimedSupply();
|
||||
}
|
||||
invariant(false, "Contract is not an instance of ERC721")
|
||||
},
|
||||
{ enabled: !!contract },
|
||||
{ enabled: !!erc721 },
|
||||
);
|
||||
}
|
||||
|
||||
@@ -206,10 +208,10 @@ export function useClaimNFT<TContract extends DropContract>(
|
||||
|
||||
return useMutation(
|
||||
async (data: ClaimNFTParams) => {
|
||||
invariant(contract, "contract is undefined");
|
||||
requiredParamInvariant(contract, "contract is undefined");
|
||||
|
||||
if (erc1155) {
|
||||
invariant(!!data.tokenId, "tokenId not provided");
|
||||
requiredParamInvariant(data.tokenId, "tokenId not provided");
|
||||
if (!data.to) {
|
||||
return (await erc1155.claim(
|
||||
data.tokenId,
|
||||
@@ -270,7 +272,7 @@ export function useLazyMint<TContract extends DropContract>(
|
||||
|
||||
return useMutation(
|
||||
async (data: { metadatas: NFTMetadataInput[] }) => {
|
||||
invariant(contract, "contract is undefined");
|
||||
requiredParamInvariant(contract, "contract is undefined");
|
||||
let options;
|
||||
if (onProgress) {
|
||||
options = {
|
||||
@@ -316,7 +318,7 @@ export function useDelayedRevealLazyMint<TContract extends RevealableContract>(
|
||||
|
||||
return useMutation(
|
||||
async (data: DelayedRevealLazyMintInput) => {
|
||||
invariant(contract, "contract is undefined");
|
||||
requiredParamInvariant(contract, "contract is undefined");
|
||||
let options;
|
||||
if (onProgress) {
|
||||
options = {
|
||||
@@ -370,7 +372,7 @@ export function useRevealLazyMint<TContract extends RevealableContract>(
|
||||
|
||||
return useMutation(
|
||||
async (data: RevealLazyMintInput) => {
|
||||
invariant(contract, "contract is undefined");
|
||||
requiredParamInvariant(contract, "contract is undefined");
|
||||
const { erc721, erc1155 } = getErcs(contract);
|
||||
if (erc721) {
|
||||
return await erc721.revealer.reveal(data.batchId, data.password);
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import {
|
||||
RequiredParam,
|
||||
requiredParamInvariant,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/base";
|
||||
import { BuyNowParams, MakeBidParams } from "../../types";
|
||||
import {
|
||||
@@ -17,7 +20,7 @@ import type {
|
||||
} from "@thirdweb-dev/sdk";
|
||||
import { ListingType } from "@thirdweb-dev/sdk";
|
||||
import { Marketplace } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/prebuilt-implementations/marketplace";
|
||||
import { BigNumber, BigNumberish } from "ethers";
|
||||
import { BigNumberish } from "ethers";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/** **********************/
|
||||
@@ -45,8 +48,9 @@ export function useListing(
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.marketplace.getListing(contractAddress, listingId),
|
||||
() => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
return contract.getListing(BigNumber.from(listingId || 0));
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
requiredParamInvariant(listingId, "No listing id provided");
|
||||
return contract.getListing(listingId);
|
||||
},
|
||||
{
|
||||
enabled: !!contract,
|
||||
@@ -76,7 +80,7 @@ export function useListings(
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.marketplace.getAllListings(contractAddress, filter),
|
||||
() => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
return contract.getAllListings(filter);
|
||||
},
|
||||
{
|
||||
@@ -103,7 +107,7 @@ export function useListingsCount(contract: RequiredParam<Marketplace>) {
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.marketplace.getTotalCount(contractAddress),
|
||||
() => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
return contract.getTotalCount();
|
||||
},
|
||||
{
|
||||
@@ -133,7 +137,7 @@ export function useActiveListings(
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.marketplace.getActiveListings(contractAddress, filter),
|
||||
() => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
|
||||
return contract.getActiveListings(filter);
|
||||
},
|
||||
@@ -168,8 +172,9 @@ export function useWinningBid(
|
||||
listingId,
|
||||
),
|
||||
() => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
return contract.auction.getWinningBid(BigNumber.from(listingId || 0));
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
requiredParamInvariant(listingId, "No listing id provided");
|
||||
return contract.auction.getWinningBid(listingId);
|
||||
},
|
||||
{
|
||||
enabled: !!contract && listingId !== undefined,
|
||||
@@ -201,12 +206,11 @@ export function useAuctionWinner(
|
||||
listingId,
|
||||
),
|
||||
async () => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
requiredParamInvariant(listingId, "No listing id provided");
|
||||
let winner: string | undefined;
|
||||
try {
|
||||
winner = await contract.auction.getWinner(
|
||||
BigNumber.from(listingId || 0),
|
||||
);
|
||||
winner = await contract.auction.getWinner(listingId);
|
||||
} catch (err) {
|
||||
if (!(err as Error)?.message?.includes("Could not find auction")) {
|
||||
throw err;
|
||||
@@ -238,7 +242,7 @@ export function useBidBuffer(contract: RequiredParam<Marketplace>) {
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.marketplace.getBidBufferBps(contractAddress),
|
||||
() => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
return contract.getBidBufferBps();
|
||||
},
|
||||
{
|
||||
@@ -247,6 +251,40 @@ export function useBidBuffer(contract: RequiredParam<Marketplace>) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to get the minimum next bid for the auction listing from your marketplace contract.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { data: minimumNextBid, isLoading, error } = useMinimumNextBid(<YourMarketplaceContractInstance>, <listingId>);
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a marketplace contract
|
||||
* @param listingId - the listing id to check
|
||||
* @returns a response object that includes the minimum next bid for the auction listing
|
||||
* @beta
|
||||
*/
|
||||
export function useMinimumNextBid(
|
||||
contract: RequiredParam<Marketplace>,
|
||||
listingId: RequiredParam<BigNumberish>,
|
||||
) {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.marketplace.auction.getWinner(
|
||||
contractAddress,
|
||||
listingId,
|
||||
),
|
||||
async () => {
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
requiredParamInvariant(listingId, "No listing id provided");
|
||||
return await contract.auction.getMinimumNextBid(listingId);
|
||||
},
|
||||
{
|
||||
enabled: !!contract && listingId !== undefined,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/** **********************/
|
||||
/** WRITE HOOKS **/
|
||||
/** **********************/
|
||||
@@ -290,8 +328,9 @@ export function useCreateDirectListing(contract: RequiredParam<Marketplace>) {
|
||||
return useMutation(
|
||||
async (data: NewDirectListing) => {
|
||||
invariant(walletAddress, "no wallet connected, cannot create listing");
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(
|
||||
contract?.direct?.createListing,
|
||||
contract.direct.createListing,
|
||||
"contract does not support direct.createListing",
|
||||
);
|
||||
return await contract.direct.createListing(data);
|
||||
@@ -346,8 +385,9 @@ export function useCreateAuctionListing(contract: RequiredParam<Marketplace>) {
|
||||
return useMutation(
|
||||
async (data: NewAuctionListing) => {
|
||||
invariant(walletAddress, "no wallet connected, cannot create listing");
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(
|
||||
contract?.direct?.createListing,
|
||||
contract.direct.createListing,
|
||||
"contract does not support auction.createListing",
|
||||
);
|
||||
return await contract.auction.createListing(data);
|
||||
@@ -456,8 +496,9 @@ export function useMakeBid(contract: RequiredParam<Marketplace>) {
|
||||
return useMutation(
|
||||
async (data: MakeBidParams) => {
|
||||
invariant(walletAddress, "no wallet connected, cannot make bid");
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(
|
||||
contract?.auction?.makeBid,
|
||||
contract.auction.makeBid,
|
||||
"contract does not support auction.makeBid",
|
||||
);
|
||||
return await contract.auction.makeBid(data.listingId, data.bid);
|
||||
@@ -512,9 +553,10 @@ export function useBuyNow(contract: RequiredParam<Marketplace>) {
|
||||
return useMutation(
|
||||
async (data: BuyNowParams) => {
|
||||
invariant(walletAddress, "no wallet connected, cannot make bid");
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
if (data.type === ListingType.Direct) {
|
||||
invariant(
|
||||
contract?.direct.buyoutListing,
|
||||
contract.direct.buyoutListing,
|
||||
"contract does not support direct.buyoutListing",
|
||||
);
|
||||
|
||||
@@ -525,7 +567,7 @@ export function useBuyNow(contract: RequiredParam<Marketplace>) {
|
||||
);
|
||||
}
|
||||
invariant(
|
||||
contract?.auction?.buyoutListing,
|
||||
contract.auction.buyoutListing,
|
||||
"contract does not support auction.buyoutListing",
|
||||
);
|
||||
return await contract.auction.buyoutListing(data.id);
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/base";
|
||||
import {
|
||||
AirdropNFTParams,
|
||||
@@ -50,7 +53,7 @@ export function useNFT<TContract extends NFTContract>(
|
||||
return useQueryWithNetwork<NFT>(
|
||||
cacheKeys.contract.nft.get(contractAddress, tokenId),
|
||||
async () => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
|
||||
if (erc1155) {
|
||||
invariant(erc1155.get, "Contract instance does not support get");
|
||||
@@ -93,7 +96,7 @@ export function useNFTs<TContract extends NFTContract>(
|
||||
return useQueryWithNetwork<NFT[]>(
|
||||
cacheKeys.contract.nft.query.all(contractAddress, queryParams),
|
||||
async () => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
|
||||
if (erc721) {
|
||||
invariant(erc721.getAll, "Contract instance does not support getAll");
|
||||
@@ -134,7 +137,7 @@ export function useTotalCount<TContract extends NFTContract>(
|
||||
return useQueryWithNetwork<BigNumber>(
|
||||
cacheKeys.contract.nft.query.totalCount(contractAddress),
|
||||
async () => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
|
||||
if (erc1155) {
|
||||
invariant(
|
||||
@@ -182,14 +185,14 @@ export function useTotalCirculatingSupply(
|
||||
return useQueryWithNetwork<BigNumber>(
|
||||
cacheKeys.contract.nft.query.totalCirculatingSupply(contractAddress),
|
||||
async () => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
|
||||
if (erc1155) {
|
||||
invariant(
|
||||
erc1155.totalCirculatingSupply,
|
||||
"Contract instance does not support totalCirculatingSupply",
|
||||
);
|
||||
invariant(tokenId, "No tokenId provided");
|
||||
requiredParamInvariant(tokenId, "No tokenId provided");
|
||||
return await erc1155.totalCirculatingSupply(tokenId);
|
||||
}
|
||||
if (erc721) {
|
||||
@@ -232,7 +235,7 @@ export function useOwnedNFTs<TContract extends NFTContract>(
|
||||
return useQueryWithNetwork<NFT[]>(
|
||||
cacheKeys.contract.nft.query.owned.all(contractAddress, ownerWalletAddress),
|
||||
async () => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(ownerWalletAddress, "No wallet address provided");
|
||||
if (erc721) {
|
||||
return await erc721.getOwned(ownerWalletAddress);
|
||||
@@ -277,11 +280,11 @@ export function useNFTBalance(
|
||||
tokenId,
|
||||
),
|
||||
() => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
|
||||
invariant(ownerWalletAddress, "No owner wallet address provided");
|
||||
if (erc1155) {
|
||||
invariant(tokenId, "No tokenId provided");
|
||||
requiredParamInvariant(tokenId, "No tokenId provided");
|
||||
invariant(
|
||||
erc1155.balanceOf,
|
||||
"Contract instance does not support balanceOf",
|
||||
@@ -375,7 +378,7 @@ export function useMintNFT<TContract extends NFTContract>(
|
||||
return useMutation(
|
||||
async (data: MintNFTParams) => {
|
||||
invariant(data.to, 'No "to" address provided');
|
||||
invariant(contract, "contract is undefined");
|
||||
requiredParamInvariant(contract, "contract is undefined");
|
||||
if (erc1155) {
|
||||
invariant("supply" in data, "supply not provided");
|
||||
const { to, metadata, supply } = data;
|
||||
@@ -444,9 +447,9 @@ export function useMintNFTSupply(contract: Erc1155) {
|
||||
return useMutation(
|
||||
async (data: MintNFTSupplyParams) => {
|
||||
invariant(data.to, 'No "to" address provided');
|
||||
invariant(contract, "contract is undefined");
|
||||
requiredParamInvariant(contract, "contract is undefined");
|
||||
|
||||
invariant("tokenId" in data, "tokenId not provided");
|
||||
requiredParamInvariant(data.tokenId, "tokenId not provided");
|
||||
invariant("additionalSupply" in data, "additionalSupply not provided");
|
||||
const { to, tokenId, additionalSupply } = data;
|
||||
return await contract.mintAdditionalSupplyTo(
|
||||
@@ -512,7 +515,7 @@ export function useTransferNFT<TContract extends NFTContract>(
|
||||
invariant("to" in data, "to not provided");
|
||||
if (erc1155) {
|
||||
invariant(erc1155.transfer, "contract does not support transfer");
|
||||
invariant("tokenId" in data, "tokenId not provided");
|
||||
requiredParamInvariant(data.tokenId, "tokenId not provided");
|
||||
invariant("amount" in data, "amount not provided");
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
return erc1155.transfer(data.to, data.tokenId, data.amount!);
|
||||
@@ -602,7 +605,8 @@ export function useAirdropNFT(contract: Erc1155) {
|
||||
|
||||
return useMutation(
|
||||
({ tokenId, addresses }: AirdropNFTParams) => {
|
||||
invariant(contract?.airdrop, "contract does not support airdrop");
|
||||
requiredParamInvariant(contract, "contract is undefined");
|
||||
invariant(contract.airdrop, "contract does not support airdrop");
|
||||
|
||||
return contract.airdrop(tokenId, addresses);
|
||||
},
|
||||
@@ -688,8 +692,8 @@ export function useBurnNFT<TContract extends NFTContract>(
|
||||
|
||||
return useMutation(
|
||||
async (data: BurnNFTParams) => {
|
||||
invariant(data.tokenId, "No tokenId provided");
|
||||
invariant(contract, "contract is undefined");
|
||||
requiredParamInvariant(data.tokenId, "No tokenId provided");
|
||||
requiredParamInvariant(contract, "contract is undefined");
|
||||
if (erc1155) {
|
||||
invariant("amount" in data, "amount not provided");
|
||||
const { tokenId, amount } = data;
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/base";
|
||||
import { WalletAddress } from "../../types";
|
||||
import {
|
||||
@@ -61,7 +64,7 @@ export function useAllRoleMembers<TContract extends ContractWithRoles>(
|
||||
return useQueryWithNetwork<Awaited<GetAllReturnType<TContract>>>(
|
||||
cacheKeys.extensions.roles.getAll(contractAddress),
|
||||
() => {
|
||||
invariant(contract, "No contract provided");
|
||||
requiredParamInvariant(contract, "No contract provided");
|
||||
invariant(contract.roles, "Contract does not support roles");
|
||||
// have to cast to any because of role bs, type is defined in the useQueryWithNetwork definition above
|
||||
return contract.roles.getAll() as any;
|
||||
@@ -94,7 +97,7 @@ export function useRoleMembers<TContract extends ContractWithRoles>(
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.extensions.roles.get(contractAddress, role),
|
||||
() => {
|
||||
invariant(contract, "No contract provided");
|
||||
requiredParamInvariant(contract, "No contract provided");
|
||||
invariant(contract.roles, "Contract does not support roles");
|
||||
return contract.roles.get(role);
|
||||
},
|
||||
@@ -192,7 +195,7 @@ export function useSetAllRoleMembers<TContract extends ContractWithRoles>(
|
||||
async (rolesWithAddresses: {
|
||||
[role in RolesForContract<TContract>]: string[];
|
||||
}) => {
|
||||
invariant(contract, "No contract provided");
|
||||
requiredParamInvariant(contract, "No contract provided");
|
||||
invariant(contract.roles, "Contract does not support roles");
|
||||
await contract.roles.setAll(rolesWithAddresses);
|
||||
},
|
||||
@@ -253,7 +256,7 @@ export function useGrantRole<TContract extends ContractWithRoles>(
|
||||
role: RolesForContract<TContract>;
|
||||
address: WalletAddress;
|
||||
}) => {
|
||||
invariant(contract, "No contract provided");
|
||||
requiredParamInvariant(contract, "No contract provided");
|
||||
invariant(contract.roles, "Contract does not support roles");
|
||||
await contract.roles.grant(params.role as any, params.address);
|
||||
},
|
||||
@@ -311,7 +314,7 @@ export function useRevokeRole<TContract extends ContractWithRoles>(
|
||||
role: RolesForContract<TContract>;
|
||||
address: WalletAddress;
|
||||
}) => {
|
||||
invariant(contract, "No contract provided");
|
||||
requiredParamInvariant(contract, "No contract provided");
|
||||
invariant(contract.roles, "Contract does not support roles");
|
||||
await contract.roles.revoke(params.role as any, params.address);
|
||||
},
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/base";
|
||||
import {
|
||||
ClaimTokenParams,
|
||||
@@ -39,7 +42,7 @@ export function useTokenSupply(contract: RequiredParam<TokenContract>) {
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.token.totalSupply(contractAddress),
|
||||
() => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
const erc20 = getErc20(contract);
|
||||
if (erc20) {
|
||||
return erc20.totalSupply();
|
||||
@@ -75,7 +78,7 @@ export function useTokenBalance(
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.token.balanceOf(contractAddress, walletAddress),
|
||||
async () => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(walletAddress, "No address provided");
|
||||
if (erc20) {
|
||||
return await erc20.balanceOf(walletAddress);
|
||||
@@ -109,7 +112,7 @@ export function useTokenDecimals(contract: RequiredParam<TokenContract>) {
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.token.decimals(contractAddress),
|
||||
async () => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
|
||||
if (erc20) {
|
||||
return (await erc20.get()).decimals;
|
||||
@@ -168,7 +171,7 @@ export function useMintToken(contract: RequiredParam<TokenContract>) {
|
||||
return useMutation(
|
||||
(data: TokenParams) => {
|
||||
const { to, amount } = data;
|
||||
invariant(contract, "contract is undefined");
|
||||
requiredParamInvariant(contract, "contract is undefined");
|
||||
if (erc20) {
|
||||
return erc20.mintTo(to, amount);
|
||||
}
|
||||
@@ -350,7 +353,7 @@ export function useTransferBatchToken(contract: RequiredParam<TokenContract>) {
|
||||
(data: TokenParams[]) => {
|
||||
if (erc20) {
|
||||
invariant(
|
||||
erc20?.transferBatch,
|
||||
erc20.transferBatch,
|
||||
"contract does not support transferBatch",
|
||||
);
|
||||
const convertedData = data.map((token) => ({
|
||||
@@ -415,9 +418,9 @@ export function useBurnToken(contract: RequiredParam<TokenContract>) {
|
||||
return useMutation(
|
||||
(data: TokenBurnParams) => {
|
||||
const { amount } = data;
|
||||
invariant(contract, "contract is undefined");
|
||||
requiredParamInvariant(contract, "contract is undefined");
|
||||
if (erc20) {
|
||||
invariant(erc20?.burn, "contract does not support burn");
|
||||
invariant(erc20.burn, "contract does not support burn");
|
||||
return erc20.burn(amount);
|
||||
}
|
||||
invariant(false, "Smart contract is not a valid erc20 contract");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { RequiredParam } from "../../../core/query-utils/required-param";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
|
||||
@@ -8,16 +8,16 @@ import { useContract } from "../async/contracts";
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useEdition } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const edition = useEdition("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useContract("<YOUR-CONTRACT-ADDRESS>", "edition")
|
||||
*
|
||||
* // Now you can use the edition contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will return all the NFTs on this contract
|
||||
* async function getNFTs() {
|
||||
* const nfts = await edition.getAll()
|
||||
* const nfts = await contract.getAll()
|
||||
* return nfts
|
||||
* }
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { RequiredParam } from "../../../core/query-utils/required-param";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
|
||||
@@ -8,16 +8,16 @@ import { useContract } from "../async/contracts";
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useEditionDrop } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const editionDrop = useEditionDrop("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useContract("<YOUR-CONTRACT-ADDRESS>", "edition-drop")
|
||||
*
|
||||
* // Now you can use the edition drop contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will let the connected wallet claim a new NFT
|
||||
* async function claim(tokenId, quantity) {
|
||||
* await editionDrop.claim(tokenId, quantity)
|
||||
* await contract.claim(tokenId, quantity)
|
||||
* }
|
||||
*
|
||||
* ...
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { RequiredParam } from "../../../core/query-utils/required-param";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
|
||||
@@ -8,16 +8,16 @@ import { useContract } from "../async/contracts";
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useMarketplace } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const marketplace = useMarketplace("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useContract("<YOUR-CONTRACT-ADDRESS>", "marketplace")
|
||||
*
|
||||
* // Now you can use the marketplace contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will return all the listings on the marketplace
|
||||
* async function getListings() {
|
||||
* const listings = await marketplace.getAll()
|
||||
* const listings = await contract.getAll()
|
||||
* return listings
|
||||
* }
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { RequiredParam } from "../../../core/query-utils/required-param";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
|
||||
@@ -8,16 +8,16 @@ import { useContract } from "../async/contracts";
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useMultiwrap } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const multiwrap = useMultiwrap("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useContract("<YOUR-CONTRACT-ADDRESS>", "multiwrap")
|
||||
*
|
||||
* // Now you can use the multiwrap contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will let the connected wallet wrap tokens
|
||||
* async function wrap(tokensToWrap, wrappedNFTMetadata) {
|
||||
* await multiwrap.wrap(tokensToWrap, wrappedNFTMetadata)
|
||||
* await contract.wrap(tokensToWrap, wrappedNFTMetadata)
|
||||
* }
|
||||
*
|
||||
* ...
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { RequiredParam } from "../../../core/query-utils/required-param";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
|
||||
@@ -8,16 +8,16 @@ import { useContract } from "../async/contracts";
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useNFTCollection } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const nftCollection = useNFTCollection("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useNFTCollection("<YOUR-CONTRACT-ADDRESS>", "nft-collection")
|
||||
*
|
||||
* // Now you can use the nftCollection contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will return all the NFTs on this contract
|
||||
* async function getNFTs() {
|
||||
* const nfts = await nftCollection.getAll()
|
||||
* const nfts = await contract.getAll()
|
||||
* return nfts
|
||||
* }
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { RequiredParam } from "../../../core/query-utils/required-param";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
|
||||
@@ -8,16 +8,16 @@ import { useContract } from "../async/contracts";
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useNFTDrop } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const nftDrop = useNFTDrop("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useContract("<YOUR-CONTRACT-ADDRESS>", "nft-drop")
|
||||
*
|
||||
* // Now you can use the nft drop contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will let the connected wallet claim a new NFT
|
||||
* async function claim(quantity) {
|
||||
* await nftDrop.claim(quantity)
|
||||
* await contract.claim(quantity)
|
||||
* }
|
||||
*
|
||||
* ...
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { RequiredParam } from "../../../core/query-utils/required-param";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
|
||||
@@ -8,16 +8,16 @@ import { useContract } from "../async/contracts";
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { usePack } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const pack = usePack("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = usePack("<YOUR-CONTRACT-ADDRESS>", "pack")
|
||||
*
|
||||
* // Now you can use the pack contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will get all the packs on this contract
|
||||
* async function getPacks() {
|
||||
* const packs = await pack.getAll()
|
||||
* const packs = await contract.getAll()
|
||||
* return packs
|
||||
* }
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { RequiredParam } from "../../../core/query-utils/required-param";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
|
||||
@@ -8,16 +8,16 @@ import { useContract } from "../async/contracts";
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useSignatureDrop } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const signatureDrop = useSignatureDrop("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useContract("<YOUR-CONTRACT-ADDRESS>", "signature-drop")
|
||||
*
|
||||
* // Now you can use the Signature drop contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will let the connected wallet claim a new NFT
|
||||
* async function claim(quantity) {
|
||||
* await signatureDrop.claim(quantity)
|
||||
* await contract.claim(quantity)
|
||||
* }
|
||||
*
|
||||
* ...
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { RequiredParam } from "../../../core/query-utils/required-param";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
|
||||
@@ -8,16 +8,16 @@ import { useContract } from "../async/contracts";
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useSplit } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const split = useSplit("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useContract("<YOUR-CONTRACT-ADDRESS>", "split")
|
||||
*
|
||||
* // Now you can use the split contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will retrun all the receipients of the split
|
||||
* async function getRecipients() {
|
||||
* const recipients = await split.getAllRecipients()
|
||||
* const recipients = await contract.getAllRecipients()
|
||||
* return recipients
|
||||
* }
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { RequiredParam } from "../../../core/query-utils/required-param";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
|
||||
@@ -8,16 +8,16 @@ import { useContract } from "../async/contracts";
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useToken } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const token = useToken("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useContract("<YOUR-CONTRACT-ADDRESS>", "token")
|
||||
*
|
||||
* // Now you can use the token contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will get the connected wallets token balance
|
||||
* async function balance() {
|
||||
* const balance = await token.balance()
|
||||
* const balance = await contract.balance()
|
||||
* return balance
|
||||
* }
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { RequiredParam } from "../../../core/query-utils/required-param";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
|
||||
@@ -8,16 +8,16 @@ import { useContract } from "../async/contracts";
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useTokenDrop } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const tokenDrop = useTokenDrop("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useContract("<YOUR-CONTRACT-ADDRESS>", "token-drop")
|
||||
*
|
||||
* // Now you can use the token drop contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will get the connected wallets token balance
|
||||
* async function balance() {
|
||||
* const balance = await tokenDrop.balance()
|
||||
* const balance = await contract.balance()
|
||||
* return balance
|
||||
* }
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { RequiredParam } from "../../../core/query-utils/required-param";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
|
||||
@@ -8,16 +8,16 @@ import { useContract } from "../async/contracts";
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useVote } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const vote = useVote("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useContract("<YOUR-CONTRACT-ADDRESS>", "vote")
|
||||
*
|
||||
* // Now you can use the vote contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will get all the proposals on this contract
|
||||
* async function getProposals() {
|
||||
* const proposals = await vote.getAll()
|
||||
* const proposals = await contract.getAll()
|
||||
* return proposals
|
||||
* }
|
||||
*
|
||||
|
||||
@@ -2,8 +2,8 @@ import {
|
||||
QueryClientProviderProps,
|
||||
QueryClientProviderWithDefault,
|
||||
} from "../../core/providers/query-client";
|
||||
import { RequiredParam } from "../../core/query-utils/required-param";
|
||||
import { ComponentWithChildren } from "../../core/types/component";
|
||||
import { RequiredParam } from "../../core/types/shared";
|
||||
import {
|
||||
ThirdwebAuthConfig,
|
||||
ThirdwebAuthConfigProvider,
|
||||
|
||||
@@ -9,10 +9,7 @@ import {
|
||||
defaultSupportedChains,
|
||||
} from "../constants/chain";
|
||||
import { ThirdwebAuthConfig } from "../contexts/thirdweb-auth";
|
||||
import {
|
||||
ThirdwebConfigProvider,
|
||||
defaultChainRpc,
|
||||
} from "../contexts/thirdweb-config";
|
||||
import { ThirdwebConfigProvider } from "../contexts/thirdweb-config";
|
||||
import { ThirdwebSDKProvider, ThirdwebSDKProviderProps } from "./base";
|
||||
import { QueryClient } from "@tanstack/react-query";
|
||||
import {
|
||||
@@ -20,6 +17,7 @@ import {
|
||||
getProviderForNetwork,
|
||||
SDKOptionsOutput,
|
||||
} from "@thirdweb-dev/sdk";
|
||||
import { DEFAULT_RPC_URLS } from "@thirdweb-dev/sdk";
|
||||
import type { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import React, { useMemo } from "react";
|
||||
import {
|
||||
@@ -223,7 +221,7 @@ export const ThirdwebProvider = <
|
||||
TSupportedChain extends SupportedChain = SupportedChain,
|
||||
>({
|
||||
sdkOptions,
|
||||
chainRpc = defaultChainRpc,
|
||||
chainRpc = DEFAULT_RPC_URLS,
|
||||
supportedChains = defaultSupportedChains.map(
|
||||
(c) => c.id,
|
||||
) as TSupportedChain[],
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RequiredParam } from "../core/types/shared";
|
||||
import { RequiredParam } from "../core/query-utils/required-param";
|
||||
import type {
|
||||
AirdropInput,
|
||||
Amount,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RequiredParam } from "../../core/types/shared";
|
||||
import { RequiredParam } from "../../core/query-utils/required-param";
|
||||
import { SupportedChainId } from "../constants/chain";
|
||||
import { ContractAddress, WalletAddress } from "../types";
|
||||
import { QueryClient, QueryKey } from "@tanstack/react-query";
|
||||
|
||||
@@ -3,4 +3,4 @@ export * from "./evm";
|
||||
|
||||
// core exports
|
||||
export { shouldNeverPersistQuery } from "./core/query-utils/query-key";
|
||||
export type { RequiredParam } from "./core/types/shared";
|
||||
export type { RequiredParam } from "./core/query-utils/required-param";
|
||||
|
||||
+8
-10
@@ -1,6 +1,6 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { MintNFTParams } from "../../../evm/types";
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../../core/query-utils/required-param";
|
||||
import { MintNFTParams } from "../../../types";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { NFTCollection } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
@@ -15,15 +15,10 @@ import invariant from "tiny-invariant";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { mutateAsync: mint, isLoading, error } = useMintNFT(program);
|
||||
*
|
||||
* function mintNFT() {
|
||||
* const metadata = { name: "First NFT", description: "This is a cool NFT!" };
|
||||
* mint({ to: "{{wallet_address}}", metadata });
|
||||
* }
|
||||
* const { mutateAsync: mintNFT, isLoading, error } = useMintNFT(program);
|
||||
*
|
||||
* return (
|
||||
* <button onClick={() => mintNFT()}>
|
||||
* <button onClick={() => mintNFT({ metadata: { name: "First NFT" } })}>
|
||||
* Mint
|
||||
* </button>
|
||||
* )
|
||||
@@ -37,6 +32,9 @@ export function useMintNFT(program: RequiredParam<NFTCollection>) {
|
||||
return useMutation(
|
||||
async (data: MintNFTParams) => {
|
||||
invariant(program, "program is required");
|
||||
if (!data.to) {
|
||||
return await program.mint(data.metadata);
|
||||
}
|
||||
return await program.mintTo(data.to, data.metadata);
|
||||
},
|
||||
{
|
||||
@@ -0,0 +1,51 @@
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../../core/query-utils/required-param";
|
||||
import { MintNFTSupplyParams } from "../../../types";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { NFTCollection } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
/**
|
||||
* Mint additional supply for an NFT on your NFT program
|
||||
* @param program - The NFT program to mint additional NFTs to
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useMintNFTSupply } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { mutateAsync: mintSupply, isLoading, error } = useMintNFTSupply(program);
|
||||
*
|
||||
* return (
|
||||
* <button onClick={() => mintSupply({ nftAddress: "111...", amount: 10 })}>
|
||||
* Mint Additional Supply
|
||||
* </button>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useMintNFTSupply(program: RequiredParam<NFTCollection>) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
async (data: MintNFTSupplyParams) => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
if (!data.to) {
|
||||
return await program.mintAdditionalSupply(data.nftAddress, data.amount);
|
||||
}
|
||||
return await program.mintAdditionalSupplyTo(
|
||||
data.to,
|
||||
data.nftAddress,
|
||||
data.amount,
|
||||
);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
queryClient.invalidateQueries(createSOLProgramQueryKey(program)),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../../core/types/shared";
|
||||
import { RequiredParam } from "../../../../core/query-utils/required-param";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../../core/types/shared";
|
||||
import { RequiredParam } from "../../../../core/query-utils/required-param";
|
||||
import { ClaimNFTParams } from "../../../types";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../../core/types/shared";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../../core/query-utils/required-param";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
export function dropTotalClaimedSupplyQuery(program: RequiredParam<NFTDrop>) {
|
||||
return {
|
||||
@@ -11,7 +13,7 @@ export function dropTotalClaimedSupplyQuery(program: RequiredParam<NFTDrop>) {
|
||||
] as const),
|
||||
|
||||
queryFn: async () => {
|
||||
invariant(program, "program is required");
|
||||
requiredParamInvariant(program, "program is required");
|
||||
|
||||
return await program.totalClaimedSupply();
|
||||
},
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../../core/types/shared";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../../core/query-utils/required-param";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { NFTMetadataInput, UploadProgressEvent } from "@thirdweb-dev/sdk";
|
||||
import type { NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/**
|
||||
* Lazy mint NFTs on an NFT Drop program
|
||||
@@ -34,7 +36,7 @@ export function useLazyMint(
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
async (data: { metadatas: NFTMetadataInput[] }) => {
|
||||
invariant(program, "program is required");
|
||||
requiredParamInvariant(program, "program is required");
|
||||
let options;
|
||||
if (onProgress) {
|
||||
options = {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../../core/types/shared";
|
||||
import { RequiredParam } from "../../../../core/query-utils/required-param";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { NFTDrop, NFTDropConditionsInput } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../../core/types/shared";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../../core/query-utils/required-param";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
export function dropUnclaimedSupplyQuery(program: RequiredParam<NFTDrop>) {
|
||||
return {
|
||||
@@ -11,7 +13,7 @@ export function dropUnclaimedSupplyQuery(program: RequiredParam<NFTDrop>) {
|
||||
] as const),
|
||||
|
||||
queryFn: async () => {
|
||||
invariant(program, "program is required");
|
||||
requiredParamInvariant(program, "program is required");
|
||||
|
||||
return await program.totalUnclaimedSupply();
|
||||
},
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/**
|
||||
* Burn an NFT owned by the connected wallet
|
||||
@@ -32,7 +34,7 @@ export function useBurnNFT(program: RequiredParam<NFTCollection | NFTDrop>) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
async (nftAddress: string) => {
|
||||
invariant(program, "program is required");
|
||||
requiredParamInvariant(program, "program is required");
|
||||
return await program.burn(nftAddress);
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
export function nftCreatorsQuery(
|
||||
program: RequiredParam<NFTCollection | NFTDrop>,
|
||||
) {
|
||||
return {
|
||||
queryKey: createSOLProgramQueryKey(program, ["creators"] as const),
|
||||
|
||||
queryFn: async () => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
return await program.getCreators();
|
||||
},
|
||||
enabled: !!program,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the creators for an NFT program
|
||||
* @param program - The NFT program to get the creators for
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useCreators } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { data: creators, isLoading } = useCreators(program);
|
||||
*
|
||||
* return (
|
||||
* <pre>{JSON.stringify(creators)}</pre>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useCreators(program: RequiredParam<NFTCollection | NFTDrop>) {
|
||||
return useQuery(nftCreatorsQuery(program));
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
export function nftGetOneQuery(
|
||||
program: RequiredParam<NFTCollection | NFTDrop>,
|
||||
@@ -15,8 +17,8 @@ export function nftGetOneQuery(
|
||||
] as const),
|
||||
|
||||
queryFn: async () => {
|
||||
invariant(program, "program is required");
|
||||
invariant(tokenAddress, "tokenAddress is required");
|
||||
requiredParamInvariant(program, "program is required");
|
||||
requiredParamInvariant(tokenAddress, "tokenAddress is required");
|
||||
return await program.get(tokenAddress);
|
||||
},
|
||||
enabled: !!program && !!tokenAddress,
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
export function nftGetAllQuery(
|
||||
program: RequiredParam<NFTCollection | NFTDrop>,
|
||||
@@ -11,7 +13,7 @@ export function nftGetAllQuery(
|
||||
queryKey: createSOLProgramQueryKey(program, ["getAll"] as const),
|
||||
|
||||
queryFn: async () => {
|
||||
invariant(program, "program is required");
|
||||
requiredParamInvariant(program, "program is required");
|
||||
return await program.getAll();
|
||||
},
|
||||
enabled: !!program,
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
export function nftRoyaltyQuery(
|
||||
program: RequiredParam<NFTCollection | NFTDrop>,
|
||||
) {
|
||||
return {
|
||||
queryKey: createSOLProgramQueryKey(program, ["royalty"] as const),
|
||||
|
||||
queryFn: async () => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
return await program.getRoyalty();
|
||||
},
|
||||
enabled: !!program,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the royalty for an NFT program
|
||||
* @param program - The NFT program to get the royalty for
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useRoyalty } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { data: royalty, isLoading } = useRoyalty(program);
|
||||
*
|
||||
* return (
|
||||
* <p>{royalty}</p>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useRoyalty(program: RequiredParam<NFTCollection | NFTDrop>) {
|
||||
return useQuery(nftRoyaltyQuery(program));
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
export type TransferNFTMutationParams = {
|
||||
receiverAddress: string;
|
||||
@@ -42,7 +44,7 @@ export function useTransferNFT(
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
async ({ tokenAddress, receiverAddress }: TransferNFTMutationParams) => {
|
||||
invariant(program, "program is required");
|
||||
requiredParamInvariant(program, "program is required");
|
||||
return await program.transfer(receiverAddress, tokenAddress);
|
||||
},
|
||||
{
|
||||
|
||||
@@ -2,7 +2,10 @@ import {
|
||||
createSOLQueryKeyWithNetwork,
|
||||
neverPersist,
|
||||
} from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDK } from "../../providers/base";
|
||||
import { programAccountTypeQuery } from "./useProgramAccountType";
|
||||
import {
|
||||
@@ -17,7 +20,6 @@ import type {
|
||||
ThirdwebSDK,
|
||||
Token,
|
||||
} from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
type ProgramMap = Readonly<{
|
||||
"nft-collection": NFTCollection;
|
||||
@@ -42,8 +44,8 @@ export function programQuery<TProgramType extends ProgramType>(
|
||||
),
|
||||
),
|
||||
queryFn: (async () => {
|
||||
invariant(sdk, "sdk is required");
|
||||
invariant(address, "Address is required");
|
||||
requiredParamInvariant(sdk, "sdk is required");
|
||||
requiredParamInvariant(address, "Address is required");
|
||||
// if the type is not passed in explicitly then we'll try to resolve it
|
||||
if (!type) {
|
||||
// why do we call `fetchQuery` here instead of calling the sdk directly?
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { createSOLQueryKeyWithNetwork } from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDK } from "../../providers/base";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { ThirdwebSDK } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
export function programAccountTypeQuery(
|
||||
sdk: RequiredParam<ThirdwebSDK>,
|
||||
@@ -16,8 +18,8 @@ export function programAccountTypeQuery(
|
||||
network || null,
|
||||
),
|
||||
queryFn: async () => {
|
||||
invariant(sdk, "sdk is required");
|
||||
invariant(address, "Address is required");
|
||||
requiredParamInvariant(sdk, "sdk is required");
|
||||
requiredParamInvariant(address, "Address is required");
|
||||
|
||||
return await sdk.registry.getProgramType(address);
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { RequiredParam } from "../../../core/query-utils/required-param";
|
||||
import { UseProgramResult } from "./useProgram";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import type { TokenParams } from "../../../evm";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { Token } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/**
|
||||
* Mint tokens on your token program
|
||||
@@ -31,7 +33,7 @@ export function useMintToken(program: RequiredParam<Token>) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
async (params: TokenParams) => {
|
||||
invariant(program, "program is required");
|
||||
requiredParamInvariant(program, "program is required");
|
||||
// TODO switch this to use mintTo once that is exposed
|
||||
return await program.mint(params.amount);
|
||||
},
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Token } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
export function tokenBalanceQuery(
|
||||
program: RequiredParam<Token>,
|
||||
@@ -14,9 +16,8 @@ export function tokenBalanceQuery(
|
||||
{ walletAddress },
|
||||
] as const),
|
||||
queryFn: async () => {
|
||||
invariant(program, "program is required");
|
||||
|
||||
invariant(walletAddress, "Wallet address is required");
|
||||
requiredParamInvariant(program, "program is required");
|
||||
requiredParamInvariant(walletAddress, "Wallet address is required");
|
||||
return await program.balanceOf(walletAddress);
|
||||
},
|
||||
enabled: !!program && !!walletAddress,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { RequiredParam } from "../../../core/query-utils/required-param";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Token } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { Amount, Token } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
export type TransferTokenMutationParams = {
|
||||
amount: Amount;
|
||||
@@ -35,7 +37,7 @@ export function useTransferToken(program: RequiredParam<Token>) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
async ({ amount, receiverAddress }: TransferTokenMutationParams) => {
|
||||
invariant(program, "program is required");
|
||||
requiredParamInvariant(program, "program is required");
|
||||
return await program.transfer(receiverAddress, amount);
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import { useSDK } from "../../providers/base";
|
||||
|
||||
/**
|
||||
* Get the currently connected wallet address
|
||||
*
|
||||
* @returns the address of the connected wallet (in base58 string format)
|
||||
*/
|
||||
export function useAddress() {
|
||||
const sdk = useSDK();
|
||||
return sdk?.wallet?.getAddress();
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createSOLQueryKeyWithNetwork } from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { RequiredParam } from "../../../core/query-utils/required-param";
|
||||
import { useSDK } from "../../providers/base";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { ThirdwebSDK } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
@@ -12,11 +12,13 @@ export * from "./hooks/program/useProgramAccountType";
|
||||
|
||||
// NFT Shared
|
||||
export * from "./hooks/nft/useNFTs";
|
||||
export * from "./hooks/nft/useMintNFT";
|
||||
export * from "./hooks/nft/useNFT";
|
||||
export * from "./hooks/nft/useTransferNFT";
|
||||
export * from "./hooks/nft/useBurnNFT";
|
||||
|
||||
// NFT Collection
|
||||
export * from "./hooks/nft/collection/useMintNFT";
|
||||
export * from "./hooks/nft/collection/useMintNFTSupply";
|
||||
|
||||
// NFT Drop
|
||||
export * from "./hooks/nft/drop/useLazyMint";
|
||||
export * from "./hooks/nft/drop/useClaimedSupply";
|
||||
@@ -35,5 +37,4 @@ export * from "./hooks/token/useTransferToken";
|
||||
export * from "./hooks/auth";
|
||||
|
||||
//Wallet
|
||||
export * from "./hooks/wallet/useAddress";
|
||||
export * from "./hooks/wallet/useBalance";
|
||||
|
||||
@@ -2,8 +2,8 @@ import {
|
||||
QueryClientProviderProps,
|
||||
QueryClientProviderWithDefault,
|
||||
} from "../../core/providers/query-client";
|
||||
import { RequiredParam } from "../../core/query-utils/required-param";
|
||||
import { ComponentWithChildren } from "../../core/types/component";
|
||||
import { RequiredParam } from "../../core/types/shared";
|
||||
import {
|
||||
ThirdwebAuthConfig,
|
||||
ThirdwebAuthConfigProvider,
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
import { Amount } from "@thirdweb-dev/sdk";
|
||||
import { Amount, NFTMetadataOrUri } from "@thirdweb-dev/sdk";
|
||||
|
||||
/**
|
||||
* The params for the {@link useMintNFT} hook mutation.
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
export type MintNFTParams = {
|
||||
to?: string;
|
||||
metadata: NFTMetadataOrUri;
|
||||
amount?: Amount;
|
||||
};
|
||||
|
||||
/**
|
||||
* The params for the {@link useClaimNFT} hook mutation.
|
||||
@@ -9,3 +20,13 @@ export type ClaimNFTParams = {
|
||||
to?: string;
|
||||
amount: Amount;
|
||||
};
|
||||
|
||||
/**
|
||||
* The params to pass to {@link useMintNFTSupply} hook mutation
|
||||
* @beta
|
||||
*/
|
||||
export type MintNFTSupplyParams = {
|
||||
to?: string;
|
||||
nftAddress: string;
|
||||
amount: Amount;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,37 @@
|
||||
# @thirdweb-dev/sdk
|
||||
|
||||
## 3.2.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#317](https://github.com/thirdweb-dev/js/pull/317) [`4f867e1`](https://github.com/thirdweb-dev/js/commit/4f867e15edbe5757afbf54cab207458711a8986c) Thanks [@adam-maj](https://github.com/adam-maj)! - Add supply to nft.get
|
||||
|
||||
- [#312](https://github.com/thirdweb-dev/js/pull/312) [`b6eec61`](https://github.com/thirdweb-dev/js/commit/b6eec6146c23b66a3681bbb48b173b9019254214) Thanks [@adam-maj](https://github.com/adam-maj)! - Add quantity to mint additional supply
|
||||
|
||||
- [#310](https://github.com/thirdweb-dev/js/pull/310) [`9727502`](https://github.com/thirdweb-dev/js/commit/9727502eb30ac139382b7c7c8e8fc0967cbfbcf1) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - [SOL] - add useMintNFTSupply hook in react and accomodate inputs for it in SDK
|
||||
|
||||
- [#307](https://github.com/thirdweb-dev/js/pull/307) [`782b58d`](https://github.com/thirdweb-dev/js/commit/782b58d3f6a3b49ff9b3d837551db5161f96171a) Thanks [@kumaryash90](https://github.com/kumaryash90)! - fix multicall gasless
|
||||
|
||||
- [#320](https://github.com/thirdweb-dev/js/pull/320) [`f41a443`](https://github.com/thirdweb-dev/js/commit/f41a443c5785240197607b5bf93ff18a1c8e8307) Thanks [@adam-maj](https://github.com/adam-maj)! - Add update creators and update royalty
|
||||
|
||||
- [#313](https://github.com/thirdweb-dev/js/pull/313) [`f45ef62`](https://github.com/thirdweb-dev/js/commit/f45ef62128cfefe06275a38440c90d45e9f3cef7) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Return default metadata when failing to fetch a given tokenId on NFT contracts
|
||||
|
||||
- [#319](https://github.com/thirdweb-dev/js/pull/319) [`2f8ec89`](https://github.com/thirdweb-dev/js/commit/2f8ec89c4c83ae577092c840c198e6fcfb114e69) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Expose total claimed and unclaimed supply for erc721 drop contracts
|
||||
|
||||
- [#322](https://github.com/thirdweb-dev/js/pull/322) [`b7cd744`](https://github.com/thirdweb-dev/js/commit/b7cd744cd0482a6c3fe5ae0c858f20cd380d4114) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - [SOL] Allow signing multiple claims at once
|
||||
|
||||
- [#306](https://github.com/thirdweb-dev/js/pull/306) [`53c6507`](https://github.com/thirdweb-dev/js/commit/53c65076696a43bd9a7e58a7493d4e65c172900f) Thanks [@adam-maj](https://github.com/adam-maj)! - Add contract deploy listener
|
||||
|
||||
## 3.2.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#303](https://github.com/thirdweb-dev/js/pull/303) [`712b11a`](https://github.com/thirdweb-dev/js/commit/712b11a43e389ae10b7f09648779a69c05b2c913) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - [SOL] Fix getting real NFT owners
|
||||
|
||||
## 3.2.4
|
||||
|
||||
## 3.2.3
|
||||
|
||||
## 3.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/sdk",
|
||||
"version": "3.2.2",
|
||||
"version": "3.2.6",
|
||||
"description": "The main thirdweb SDK.",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/sdk",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -179,7 +179,7 @@ export function extractEventsFromAbi(
|
||||
abi: z.input<typeof AbiSchema>,
|
||||
metadata?: Record<string, any>,
|
||||
): AbiEvent[] {
|
||||
const events = abi.filter((el) => el.type === "event");
|
||||
const events = (abi || []).filter((el) => el.type === "event");
|
||||
const parsed: AbiEvent[] = [];
|
||||
for (const e of events) {
|
||||
const doc = extractCommentFromMetadata(e.name, metadata, "events");
|
||||
|
||||
@@ -24,7 +24,7 @@ import type {
|
||||
} from "@thirdweb-dev/storage";
|
||||
import { BigNumber, BigNumberish, Contract, ethers, providers } from "ethers";
|
||||
|
||||
const FALLBACK_METADATA = {
|
||||
export const FALLBACK_METADATA = {
|
||||
name: "Failed to load NFT metadata",
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { SignerOrProvider } from "../core/types";
|
||||
import { StaticJsonRpcBatchProvider } from "../lib/static-batch-rpc";
|
||||
import { ChainId, SUPPORTED_CHAIN_ID, SUPPORTED_CHAIN_IDS } from "./chains";
|
||||
import { ethers, providers } from "ethers";
|
||||
|
||||
/**
|
||||
@@ -26,13 +27,15 @@ export const PINATA_IPFS_URL = `https://api.pinata.cloud/pinning/pinFileToIPFS`;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* This is a community API key that is subject to rate limiting. Please use your own key.
|
||||
*/
|
||||
export type ChainOrRpc =
|
||||
const DEFAULT_API_KEY = "_gg7wSSi0KMBsdKnGVfHDueq6xMB9EkC";
|
||||
|
||||
type ChainNames =
|
||||
| "mumbai"
|
||||
| "polygon"
|
||||
// common alias for `polygon`
|
||||
| "matic"
|
||||
| "rinkeby"
|
||||
| "goerli"
|
||||
| "mainnet"
|
||||
// common alias for `mainnet`
|
||||
@@ -44,21 +47,53 @@ export type ChainOrRpc =
|
||||
// actual name
|
||||
| "avalanche-fuji"
|
||||
| "optimism"
|
||||
| "optimism-kovan"
|
||||
| "optimism-goerli"
|
||||
| "arbitrum"
|
||||
| "arbitrum-rinkeby"
|
||||
| "arbitrum-goerli"
|
||||
| "binance"
|
||||
| "binance-testnet"
|
||||
// ideally we could use `https://${string}` notation here, but doing that causes anything that is a generic string to throw a type error => not worth the hassle for now
|
||||
| (string & {});
|
||||
|
||||
| "binance-testnet";
|
||||
/**
|
||||
* @internal
|
||||
* This is a community API key that is subject to rate limiting. Please use your own key.
|
||||
*/
|
||||
const DEFAULT_API_KEY = "_gg7wSSi0KMBsdKnGVfHDueq6xMB9EkC";
|
||||
export type ChainOrRpc =
|
||||
// ideally we could use `https://${string}` notation here, but doing that causes anything that is a generic string to throw a type error => not worth the hassle for now
|
||||
ChainNames | (string & {});
|
||||
|
||||
export const CHAIN_NAME_TO_ID: Record<ChainNames, SUPPORTED_CHAIN_ID> = {
|
||||
"avalanche-fuji": ChainId.AvalancheFujiTestnet,
|
||||
"avalanche-testnet": ChainId.AvalancheFujiTestnet,
|
||||
"fantom-testnet": ChainId.FantomTestnet,
|
||||
ethereum: ChainId.Mainnet,
|
||||
matic: ChainId.Polygon,
|
||||
mumbai: ChainId.Mumbai,
|
||||
goerli: ChainId.Goerli,
|
||||
polygon: ChainId.Polygon,
|
||||
mainnet: ChainId.Mainnet,
|
||||
optimism: ChainId.Optimism,
|
||||
"optimism-goerli": ChainId.OptimismGoerli,
|
||||
arbitrum: ChainId.Arbitrum,
|
||||
"arbitrum-goerli": ChainId.ArbitrumGoerli,
|
||||
fantom: ChainId.Fantom,
|
||||
avalanche: ChainId.Avalanche,
|
||||
binance: ChainId.BinanceSmartChainMainnet,
|
||||
"binance-testnet": ChainId.BinanceSmartChainTestnet,
|
||||
};
|
||||
|
||||
export const CHAIN_ID_TO_NAME = Object.fromEntries(
|
||||
Object.entries(CHAIN_NAME_TO_ID).map(([name, id]) => [id, name]),
|
||||
) as Record<ChainId, ChainNames>;
|
||||
|
||||
function buildDefaultMap() {
|
||||
return SUPPORTED_CHAIN_IDS.reduce((previousValue, currentValue) => {
|
||||
previousValue[currentValue] = getProviderForNetwork(
|
||||
CHAIN_ID_TO_NAME[currentValue],
|
||||
) as string;
|
||||
return previousValue;
|
||||
}, {} as Record<SUPPORTED_CHAIN_ID, string>);
|
||||
}
|
||||
|
||||
export const DEFAULT_RPC_URLS: Record<SUPPORTED_CHAIN_ID, string> =
|
||||
buildDefaultMap();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
|
||||
@@ -319,7 +319,7 @@ export class NFTDrop extends StandardErc721<DropERC721> {
|
||||
* @returns the unclaimed supply
|
||||
*/
|
||||
public async totalClaimedSupply(): Promise<BigNumber> {
|
||||
return await this.contractWrapper.readContract.nextTokenIdToClaim();
|
||||
return this.erc721.totalClaimedSupply();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -335,9 +335,7 @@ export class NFTDrop extends StandardErc721<DropERC721> {
|
||||
* @returns the unclaimed supply
|
||||
*/
|
||||
public async totalUnclaimedSupply(): Promise<BigNumber> {
|
||||
return (await this.contractWrapper.readContract.nextTokenIdToMint()).sub(
|
||||
await this.totalClaimedSupply(),
|
||||
);
|
||||
return this.erc721.totalUnclaimedSupply();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -328,7 +328,7 @@ export class SignatureDrop extends StandardErc721<SignatureDropContract> {
|
||||
* @returns the claimed supply
|
||||
*/
|
||||
public async totalClaimedSupply(): Promise<BigNumber> {
|
||||
return await this.contractWrapper.readContract.totalMinted();
|
||||
return this.erc721.totalClaimedSupply();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -344,10 +344,7 @@ export class SignatureDrop extends StandardErc721<SignatureDropContract> {
|
||||
* @returns the unclaimed supply
|
||||
*/
|
||||
public async totalUnclaimedSupply(): Promise<BigNumber> {
|
||||
const maxSupply =
|
||||
await this.contractWrapper.readContract.nextTokenIdToMint();
|
||||
|
||||
return maxSupply.sub(await this.totalClaimedSupply());
|
||||
return this.erc721.totalUnclaimedSupply();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
PrebuiltContractType,
|
||||
} from "../types";
|
||||
import { ContractFactory } from "./factory";
|
||||
import { FactoryEvents } from "./factory-events";
|
||||
import { ContractRegistry } from "./registry";
|
||||
import { RPCConnectionHandler } from "./rpc-connection-handler";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
@@ -65,6 +66,7 @@ export class ContractDeployer extends RPCConnectionHandler {
|
||||
* should never be accessed directly, use {@link ContractDeployer.getRegistry} instead
|
||||
*/
|
||||
private _registry: Promise<ContractRegistry> | undefined;
|
||||
public events: FactoryEvents | undefined;
|
||||
private storage: ThirdwebStorage;
|
||||
|
||||
constructor(
|
||||
@@ -74,6 +76,10 @@ export class ContractDeployer extends RPCConnectionHandler {
|
||||
) {
|
||||
super(network, options);
|
||||
this.storage = storage;
|
||||
|
||||
// Initialize factory and registry (we don't need to make these calls async)
|
||||
this.getFactory();
|
||||
this.getRegistry();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -527,12 +533,15 @@ export class ContractDeployer extends RPCConnectionHandler {
|
||||
chainId,
|
||||
"twFactory",
|
||||
);
|
||||
return new ContractFactory(
|
||||
const factory = new ContractFactory(
|
||||
factoryAddress,
|
||||
this.getSignerOrProvider(),
|
||||
this.storage,
|
||||
this.options,
|
||||
);
|
||||
this.events = new FactoryEvents(factory);
|
||||
|
||||
return factory;
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { ListenerFn } from "eventemitter3";
|
||||
* @public
|
||||
*/
|
||||
export class ContractEvents<TContract extends BaseContract> {
|
||||
private contractWrapper;
|
||||
protected contractWrapper;
|
||||
|
||||
constructor(contractWrapper: ContractWrapper<TContract>) {
|
||||
this.contractWrapper = contractWrapper;
|
||||
|
||||
@@ -343,6 +343,13 @@ export class ContractWrapper<
|
||||
("openzeppelin" in this.options.gasless ||
|
||||
"biconomy" in this.options.gasless)
|
||||
) {
|
||||
if (fn === "multicall" && Array.isArray(args[0]) && args[0].length > 0) {
|
||||
const from = await this.getSignerAddress();
|
||||
args[0] = args[0].map((tx: any) =>
|
||||
ethers.utils.solidityPack(["bytes", "address"], [tx, from]),
|
||||
);
|
||||
}
|
||||
|
||||
const provider = this.getProvider();
|
||||
const txHash = await this.sendGaslessTransaction(fn, args, callOverrides);
|
||||
this.emitTransactionEvent("submitted", txHash);
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
hasFunction,
|
||||
NotFoundError,
|
||||
} from "../../common";
|
||||
import { fetchTokenMetadata } from "../../common/nft";
|
||||
import { FALLBACK_METADATA, fetchTokenMetadata } from "../../common/nft";
|
||||
import {
|
||||
FEATURE_EDITION,
|
||||
FEATURE_EDITION_BATCH_MINTABLE,
|
||||
@@ -128,7 +128,11 @@ export class Erc1155<
|
||||
this.contractWrapper.readContract
|
||||
.totalSupply(tokenId)
|
||||
.catch(() => BigNumber.from(0)),
|
||||
this.getTokenMetadata(tokenId),
|
||||
this.getTokenMetadata(tokenId).catch(() => ({
|
||||
id: tokenId.toString(),
|
||||
uri: "",
|
||||
...FALLBACK_METADATA,
|
||||
})),
|
||||
]);
|
||||
return {
|
||||
owner: ethers.constants.AddressZero,
|
||||
|
||||
@@ -98,7 +98,7 @@ export class Erc721ClaimableWithConditions implements DetectableFeature {
|
||||
quantity,
|
||||
options?.checkERC20Allowance === undefined
|
||||
? true
|
||||
: options.checkERC20Allowance
|
||||
: options.checkERC20Allowance,
|
||||
);
|
||||
|
||||
return TransactionTask.make({
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
hasFunction,
|
||||
NotFoundError,
|
||||
} from "../../common";
|
||||
import { fetchTokenMetadata } from "../../common/nft";
|
||||
import { FALLBACK_METADATA, fetchTokenMetadata } from "../../common/nft";
|
||||
import {
|
||||
FEATURE_NFT,
|
||||
FEATURE_NFT_BATCH_MINTABLE,
|
||||
@@ -124,7 +124,11 @@ export class Erc721<
|
||||
public async get(tokenId: BigNumberish): Promise<NFT> {
|
||||
const [owner, metadata] = await Promise.all([
|
||||
this.ownerOf(tokenId).catch(() => constants.AddressZero),
|
||||
this.getTokenMetadata(tokenId),
|
||||
this.getTokenMetadata(tokenId).catch(() => ({
|
||||
id: tokenId.toString(),
|
||||
uri: "",
|
||||
...FALLBACK_METADATA,
|
||||
})),
|
||||
]);
|
||||
return { owner, metadata, type: "ERC721", supply: 1 };
|
||||
}
|
||||
@@ -574,6 +578,7 @@ export class Erc721<
|
||||
*
|
||||
* @param destinationAddress - Address you want to send the token to
|
||||
* @param quantity - Quantity of the tokens you want to claim
|
||||
* @param options
|
||||
* @twfeature ERC721Claimable
|
||||
* @returns - an array of results containing the id of the token claimed, the transaction receipt and a promise to optionally fetch the nft metadata
|
||||
*/
|
||||
@@ -598,6 +603,7 @@ export class Erc721<
|
||||
* This is useful for estimating the gas cost of a claim transaction, overriding transaction options and having fine grained control over the transaction execution.
|
||||
* @param destinationAddress
|
||||
* @param quantity
|
||||
* @param options
|
||||
*/
|
||||
public async getClaimTransaction(
|
||||
destinationAddress: string,
|
||||
@@ -619,6 +625,37 @@ export class Erc721<
|
||||
throw new ExtensionNotImplementedError(FEATURE_NFT_CLAIMABLE);
|
||||
}
|
||||
|
||||
public async totalClaimedSupply(): Promise<BigNumber> {
|
||||
const contract = this.contractWrapper;
|
||||
if (hasFunction<DropERC721>("nextTokenIdToClaim", contract)) {
|
||||
return contract.readContract.nextTokenIdToClaim();
|
||||
}
|
||||
if (hasFunction<SignatureDrop>("totalMinted", contract)) {
|
||||
return contract.readContract.totalMinted();
|
||||
}
|
||||
throw new Error(
|
||||
"No function found on contract to get total claimed supply",
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the unclaimed supply
|
||||
*
|
||||
* @remarks Get the number of unclaimed NFTs in this Drop.
|
||||
*
|
||||
* * @example
|
||||
* ```javascript
|
||||
* const unclaimedNFTCount = await contract.totalUnclaimedSupply();
|
||||
* console.log(`NFTs left to claim: ${unclaimedNFTCount}`);
|
||||
* ```
|
||||
* @returns the unclaimed supply
|
||||
*/
|
||||
public async totalUnclaimedSupply(): Promise<BigNumber> {
|
||||
return (await this.nextTokenIdToMint()).sub(
|
||||
await this.totalClaimedSupply(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure claim conditions
|
||||
* @remarks Define who can claim NFTs in the collection, when and how many.
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { ContractEvents } from "./contract-events";
|
||||
import { ContractWrapper } from "./contract-wrapper";
|
||||
import type { TWFactory } from "@thirdweb-dev/contracts-js";
|
||||
import { ProxyDeployedEvent } from "@thirdweb-dev/contracts-js/dist/declarations/src/TWFactory";
|
||||
|
||||
interface DeployEvent {
|
||||
transactionHash: string;
|
||||
contractAddress: string;
|
||||
}
|
||||
|
||||
export class FactoryEvents extends ContractEvents<TWFactory> {
|
||||
constructor(contractWrapper: ContractWrapper<TWFactory>) {
|
||||
super(contractWrapper);
|
||||
}
|
||||
|
||||
public addDeployListener(listener: (event: DeployEvent) => void) {
|
||||
this.addTransactionListener(async (event) => {
|
||||
if (!event.transactionHash) {
|
||||
return;
|
||||
}
|
||||
|
||||
const receipt = await this.contractWrapper
|
||||
.getProvider()
|
||||
.getTransactionReceipt(event.transactionHash);
|
||||
const events = this.contractWrapper.parseLogs<ProxyDeployedEvent>(
|
||||
"ProxyDeployed",
|
||||
receipt.logs,
|
||||
);
|
||||
|
||||
if (events.length > 0) {
|
||||
listener({
|
||||
...event,
|
||||
contractAddress: events[0].args.proxy,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -78,6 +78,7 @@ export class ContractFactory extends ContractWrapper<TWFactory> {
|
||||
encodedFunc,
|
||||
]);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
// if the error is caused by user cancelling the transaction, just re-throw it
|
||||
if (
|
||||
(e as TransactionError).message
|
||||
|
||||
@@ -200,7 +200,7 @@ export class Deployer {
|
||||
* const metadata = {
|
||||
* name: "My NFT Drop",
|
||||
* symbol: "NFT",
|
||||
* totalSuppply: 5,
|
||||
* totalSupply: 5,
|
||||
* };
|
||||
*
|
||||
* const address = await sdk.deployer.createNftDrop(metadata);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CreatorInput } from "../../types/programs";
|
||||
import { CreatorInput, CreatorOutput } from "../../types/programs";
|
||||
import type { Creator } from "@metaplex-foundation/js";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
@@ -23,3 +23,13 @@ export function enforceCreator(
|
||||
share: creator.sharePercentage,
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function parseCreators(creators: Creator[]): CreatorOutput[] {
|
||||
return creators.map((creator) => ({
|
||||
...creator,
|
||||
address: creator.address.toBase58(),
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@ import {
|
||||
METAPLEX_PROGRAM_ID,
|
||||
} from "../../constants/addresses";
|
||||
import { TransactionResult } from "../../types/common";
|
||||
import { getPublicRpc } from "../../utils/urls";
|
||||
import {
|
||||
findMasterEditionV2Pda,
|
||||
GmaBuilder,
|
||||
JsonMetadata,
|
||||
Metadata,
|
||||
@@ -21,9 +23,16 @@ import {
|
||||
token,
|
||||
toMetadata,
|
||||
toMetadataAccount,
|
||||
toNftOriginalEdition,
|
||||
toOriginalEditionAccount,
|
||||
} from "@metaplex-foundation/js";
|
||||
import { getAccount, getAssociatedTokenAddress } from "@solana/spl-token";
|
||||
import { ConfirmedSignatureInfo, Connection, PublicKey } from "@solana/web3.js";
|
||||
import {
|
||||
ConfirmedSignatureInfo,
|
||||
Connection,
|
||||
ParsedAccountData,
|
||||
PublicKey,
|
||||
} from "@solana/web3.js";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@@ -80,6 +89,27 @@ export class NFTHelper {
|
||||
}
|
||||
}
|
||||
|
||||
async ownerOf(nftAddress: string): Promise<string | undefined> {
|
||||
try {
|
||||
// TODO switch back to normal connection when alchemy supports getTokenLargestAccounts
|
||||
const connection = new Connection(
|
||||
getPublicRpc(this.metaplex),
|
||||
"confirmed",
|
||||
);
|
||||
const largestAccounts = await connection.getTokenLargestAccounts(
|
||||
new PublicKey(nftAddress),
|
||||
);
|
||||
const largestAccountInfo = await connection.getParsedAccountInfo(
|
||||
largestAccounts.value[0].address,
|
||||
);
|
||||
const parsedData = largestAccountInfo?.value?.data as ParsedAccountData;
|
||||
const owner = parsedData ? parsedData.parsed.info.owner : undefined;
|
||||
return owner;
|
||||
} catch (err) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async getAll(
|
||||
collectionAddress: string,
|
||||
queryParams?: QueryAllParams,
|
||||
@@ -193,6 +223,25 @@ export class NFTHelper {
|
||||
return nfts;
|
||||
}
|
||||
|
||||
async supplyOf(nftAddress: string): Promise<number> {
|
||||
let originalEdition;
|
||||
|
||||
const originalEditionAccount = await this.metaplex
|
||||
.rpc()
|
||||
.getAccount(findMasterEditionV2Pda(new PublicKey(nftAddress)));
|
||||
|
||||
if (originalEditionAccount.exists) {
|
||||
originalEdition = toNftOriginalEdition(
|
||||
toOriginalEditionAccount(originalEditionAccount),
|
||||
);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Add one to supply to account for the master edition
|
||||
return originalEdition.supply.toNumber() + 1;
|
||||
}
|
||||
|
||||
async toNFTMetadata(
|
||||
meta:
|
||||
| Nft
|
||||
@@ -213,18 +262,24 @@ export class NFTHelper {
|
||||
if (!mint) {
|
||||
throw new Error("No mint found for NFT");
|
||||
}
|
||||
return this.toNFTMetadataResolved(mint, fullModel);
|
||||
const [owner, supply] = await Promise.all([
|
||||
this.ownerOf(mint.address.toBase58()),
|
||||
this.supplyOf(mint.address.toBase58()),
|
||||
]);
|
||||
return this.toNFTMetadataResolved(mint, owner, supply, fullModel);
|
||||
}
|
||||
|
||||
private toNFTMetadataResolved(
|
||||
private async toNFTMetadataResolved(
|
||||
mint: Mint,
|
||||
owner: string | undefined,
|
||||
supply: number,
|
||||
fullModel:
|
||||
| Nft
|
||||
| Sft
|
||||
| NftWithToken
|
||||
| SftWithToken
|
||||
| Metadata<JsonMetadata<string>>,
|
||||
): NFT {
|
||||
): Promise<NFT> {
|
||||
return {
|
||||
metadata: {
|
||||
id: mint.address.toBase58(),
|
||||
@@ -233,8 +288,8 @@ export class NFTHelper {
|
||||
symbol: fullModel.symbol,
|
||||
...fullModel.json,
|
||||
},
|
||||
owner: fullModel.updateAuthorityAddress.toBase58(),
|
||||
supply: mint.supply.basisPoints.toNumber(),
|
||||
owner: owner || PublicKey.default.toBase58(),
|
||||
supply: supply,
|
||||
type: "metaplex",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
import { QueryAllParams } from "../../core/schema/QueryParams";
|
||||
import { NFT, NFTMetadata, NFTMetadataOrUri } from "../../core/schema/nft";
|
||||
import {
|
||||
NFT,
|
||||
NFTMetadata,
|
||||
NFTMetadataInput,
|
||||
NFTMetadataOrUri,
|
||||
} from "../../core/schema/nft";
|
||||
import { enforceCreator } from "../classes/helpers/creators-helper";
|
||||
enforceCreator,
|
||||
parseCreators,
|
||||
} from "../classes/helpers/creators-helper";
|
||||
import { NFTHelper } from "../classes/helpers/nft-helper";
|
||||
import { TransactionResult } from "../types/common";
|
||||
import { CreatorInput } from "../types/programs";
|
||||
import { Amount, TransactionResult } from "../types/common";
|
||||
import { CreatorInput, CreatorOutput } from "../types/programs";
|
||||
import { sendMultipartTransaction } from "../utils/transactions";
|
||||
import { getNework } from "../utils/urls";
|
||||
import {
|
||||
findEditionMarkerPda,
|
||||
findMasterEditionV2Pda,
|
||||
Metaplex,
|
||||
toBigNumber,
|
||||
toNftOriginalEdition,
|
||||
toOriginalEditionAccount,
|
||||
} from "@metaplex-foundation/js";
|
||||
import { EditionMarker } from "@metaplex-foundation/mpl-token-metadata";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/**
|
||||
* A collection of associated NFTs
|
||||
@@ -41,15 +43,7 @@ export class NFTCollection {
|
||||
public publicKey: PublicKey;
|
||||
public accountType = "nft-collection" as const;
|
||||
public get network() {
|
||||
const url = new URL(this.metaplex.connection.rpcEndpoint);
|
||||
// try this first to avoid hitting `custom` network for alchemy urls
|
||||
if (url.hostname.includes("devnet")) {
|
||||
return "devnet";
|
||||
}
|
||||
if (url.hostname.includes("mainnet")) {
|
||||
return "mainnet-beta";
|
||||
}
|
||||
return this.metaplex.cluster;
|
||||
return getNework(this.metaplex);
|
||||
}
|
||||
|
||||
constructor(
|
||||
@@ -70,18 +64,44 @@ export class NFTCollection {
|
||||
* @example
|
||||
* ```jsx
|
||||
* const metadata = await program.getMetadata();
|
||||
* console.log(metadata.name);
|
||||
* console.log(metadata);
|
||||
* ```
|
||||
*/
|
||||
async getMetadata(): Promise<NFTMetadata> {
|
||||
const metadata = await this.metaplex
|
||||
.nfts()
|
||||
.findByMint({ mintAddress: this.publicKey })
|
||||
.run();
|
||||
|
||||
const metadata = await this.getCollection();
|
||||
return (await this.nft.toNFTMetadata(metadata)).metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the creators of this program.
|
||||
* @returns program metadata
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* const creators = await program.getCreators();
|
||||
* console.log(creators);
|
||||
* ```
|
||||
*/
|
||||
async getCreators(): Promise<CreatorOutput[]> {
|
||||
const metadata = await this.getCollection();
|
||||
return parseCreators(metadata.creators);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the royalty basis points for this collection
|
||||
* @returns royalty basis points
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* const royalty = await program.getRoyalty();
|
||||
* console.log(royalty);
|
||||
* ```
|
||||
*/
|
||||
async getRoyalty(): Promise<number> {
|
||||
const metadata = await this.getCollection();
|
||||
return metadata.sellerFeeBasisPoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the metadata for a specific NFT
|
||||
* @param nftAddress - the mint address of the NFT to get
|
||||
@@ -155,6 +175,21 @@ export class NFTCollection {
|
||||
return this.nft.balanceOf(walletAddress, nftAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current owner of the given NFT
|
||||
* @param nftAddress - the mint address of the NFT to get the owner of
|
||||
* @returns the owner of the NFT
|
||||
* @example
|
||||
* ```jsx
|
||||
* const nftAddress = "..."
|
||||
* const owner = await program.ownerOf(nftAddress);
|
||||
* console.log(owner);
|
||||
* ```
|
||||
*/
|
||||
async ownerOf(nftAddress: string): Promise<string | undefined> {
|
||||
return this.nft.ownerOf(nftAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the supply of NFT editions minted from a specific NFT
|
||||
* @param nftAddress - the mint address of the NFT to check the supply of
|
||||
@@ -163,58 +198,11 @@ export class NFTCollection {
|
||||
* @example
|
||||
* ```jsx
|
||||
* const address = "...";
|
||||
* const supply = await program.supplyOf(addres);
|
||||
* const supply = await program.supplyOf(address);
|
||||
* ```
|
||||
*/
|
||||
async supplyOf(nftAddress: string): Promise<bigint> {
|
||||
let editionMarkerNumber = 0;
|
||||
let totalSupply = 1;
|
||||
|
||||
cursedBitwiseLogicLoop: while (true) {
|
||||
const editionMarkerAddress = findEditionMarkerPda(
|
||||
new PublicKey(nftAddress),
|
||||
toBigNumber(editionMarkerNumber * 248),
|
||||
);
|
||||
const editionMarker = await EditionMarker.fromAccountAddress(
|
||||
this.metaplex.connection,
|
||||
editionMarkerAddress,
|
||||
);
|
||||
|
||||
// WARNING: Ugly bitwise operations because of Rust :(
|
||||
const indexCap = editionMarkerNumber === 0 ? 247 : 248;
|
||||
for (let editionIndex = 0; editionIndex < indexCap; editionIndex++) {
|
||||
const ledgerIndex =
|
||||
editionMarkerNumber > 0
|
||||
? Math.floor(editionIndex / 8)
|
||||
: editionIndex < 7
|
||||
? 0
|
||||
: Math.floor((editionIndex - 7) / 8) + 1;
|
||||
const size = editionMarkerNumber === 0 && ledgerIndex === 0 ? 7 : 8;
|
||||
const shiftBase = 0b1 << (size - 1);
|
||||
|
||||
const bitmask =
|
||||
ledgerIndex === 0
|
||||
? shiftBase >> editionIndex
|
||||
: editionMarkerNumber > 0
|
||||
? shiftBase >> editionIndex % (ledgerIndex * 8)
|
||||
: ledgerIndex === 1
|
||||
? shiftBase >> (editionIndex - 7)
|
||||
: shiftBase >> (editionIndex - 7) % ((ledgerIndex - 1) * 8);
|
||||
|
||||
const editionExists =
|
||||
(editionMarker.ledger[ledgerIndex] & bitmask) !== 0;
|
||||
|
||||
if (editionExists) {
|
||||
totalSupply += 1;
|
||||
} else {
|
||||
break cursedBitwiseLogicLoop;
|
||||
}
|
||||
}
|
||||
|
||||
editionMarkerNumber++;
|
||||
}
|
||||
|
||||
return BigInt(totalSupply);
|
||||
async supplyOf(nftAddress: string): Promise<number> {
|
||||
return this.nft.supplyOf(nftAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,7 +252,7 @@ export class NFTCollection {
|
||||
* console.log(address);
|
||||
* ```
|
||||
*/
|
||||
async mint(metadata: NFTMetadataInput): Promise<string> {
|
||||
async mint(metadata: NFTMetadataOrUri): Promise<string> {
|
||||
const address = this.metaplex.identity().publicKey.toBase58();
|
||||
return this.mintTo(address, metadata);
|
||||
}
|
||||
@@ -326,25 +314,29 @@ export class NFTCollection {
|
||||
/**
|
||||
* Mint additional supply of an NFT to the connected wallet
|
||||
* @param nftAddress - the mint address to mint additional supply to
|
||||
* @param amount - the amount of additional NFTs to mint
|
||||
* @returns the mint address of the minted NFT
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* // The address of the already minted NFT
|
||||
* const nftAddress = "..."
|
||||
* // The amount of additional NFTs to mint
|
||||
* const amount = 1;
|
||||
* // Mint an additional NFT of the original NFT
|
||||
* const address = await program.mintAdditionalSupply(nftAddress);
|
||||
* const addresses = await program.mintAdditionalSupply(nftAddress, amount);
|
||||
* ```
|
||||
*/
|
||||
async mintAdditionalSupply(nftAddress: string) {
|
||||
async mintAdditionalSupply(nftAddress: string, amount: Amount) {
|
||||
const address = this.metaplex.identity().publicKey.toBase58();
|
||||
return this.mintAdditionalSupplyTo(address, nftAddress);
|
||||
return this.mintAdditionalSupplyTo(address, nftAddress, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mint additional supply of an NFT to the specified wallet
|
||||
* @param to - the address to mint the NFT to
|
||||
* @param nftAddress - the mint address to mint additional supply to
|
||||
* @param amount - the amount of NFTs to mint
|
||||
* @returns the mint address of the minted NFT
|
||||
*
|
||||
* @example
|
||||
@@ -353,23 +345,52 @@ export class NFTCollection {
|
||||
* const to = "..."
|
||||
* // The address of the already minted NFT
|
||||
* const nftAddress = "..."
|
||||
* * // The amount of additional NFTs to mint
|
||||
* const amount = 1;
|
||||
* // Mint an additional NFT of the original NFT
|
||||
* const address = await program.mintAdditionalSupplyTo(to, nftAddress);
|
||||
* const addresses = await program.mintAdditionalSupplyTo(to, nftAddress, amount);
|
||||
* ```
|
||||
*/
|
||||
async mintAdditionalSupplyTo(
|
||||
to: string,
|
||||
nftAddress: string,
|
||||
): Promise<string> {
|
||||
// TODO add quantity param
|
||||
const result = await this.metaplex
|
||||
.nfts()
|
||||
.printNewEdition({
|
||||
originalMint: new PublicKey(nftAddress),
|
||||
newOwner: new PublicKey(to),
|
||||
})
|
||||
.run();
|
||||
return result.nft.address.toBase58();
|
||||
amount: Amount,
|
||||
): Promise<string[]> {
|
||||
// need to coerce amount to number always (to make the Array(<number>) work)
|
||||
amount = typeof amount === "string" ? parseInt(amount) : amount;
|
||||
// ensure that whatever got passed actually is a number now
|
||||
invariant(
|
||||
isNaN(amount) === false,
|
||||
"amount must be possible to convert to a number",
|
||||
);
|
||||
|
||||
// Better to use metaplex functions directly then our supplyOf function for types/consistency
|
||||
const originalEditionAccount = await this.metaplex
|
||||
.rpc()
|
||||
.getAccount(findMasterEditionV2Pda(new PublicKey(nftAddress)));
|
||||
const originalEdition = toNftOriginalEdition(
|
||||
toOriginalEditionAccount(originalEditionAccount),
|
||||
);
|
||||
|
||||
const builders = await Promise.all(
|
||||
[...Array(amount).keys()].map(async (_, i) => {
|
||||
return await this.metaplex
|
||||
.nfts()
|
||||
.builders()
|
||||
.printNewEdition({
|
||||
originalSupply: toBigNumber(
|
||||
originalEdition.supply.add(toBigNumber(i)),
|
||||
),
|
||||
originalMint: new PublicKey(nftAddress),
|
||||
newOwner: new PublicKey(to),
|
||||
});
|
||||
}),
|
||||
);
|
||||
const mintAddresses = builders.map((builder) =>
|
||||
builder.getContext().mintSigner.publicKey.toBase58(),
|
||||
);
|
||||
await sendMultipartTransaction(builders, this.metaplex);
|
||||
return mintAddresses;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -399,22 +420,41 @@ export class NFTCollection {
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the settings of the collection
|
||||
* @param settings - the settings to update
|
||||
* SETTINGS
|
||||
*/
|
||||
async updateSettings(settings: { creators?: CreatorInput[] }) {
|
||||
const updateData = {
|
||||
...(settings.creators && {
|
||||
creators: enforceCreator(
|
||||
settings.creators,
|
||||
this.metaplex.identity().publicKey,
|
||||
),
|
||||
}),
|
||||
|
||||
/**
|
||||
* Update the creators of the collection
|
||||
* @param creators - the creators to update
|
||||
*/
|
||||
async updateCreators(creators: CreatorInput[]) {
|
||||
const tx = await this.metaplex
|
||||
.nfts()
|
||||
.update({
|
||||
nftOrSft: await this.getCollection(),
|
||||
creators: enforceCreator(creators, this.metaplex.identity().publicKey),
|
||||
})
|
||||
.run();
|
||||
return {
|
||||
signature: tx.response.signature,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the royalty basis points of the collection
|
||||
* @param sellerFeeBasisPoints - the royalty basis points of the collection
|
||||
*/
|
||||
async updateRoyalty(sellerFeeBasisPoints: number) {
|
||||
const tx = await this.metaplex
|
||||
.nfts()
|
||||
.update({
|
||||
nftOrSft: await this.getCollection(),
|
||||
sellerFeeBasisPoints,
|
||||
})
|
||||
.run();
|
||||
return {
|
||||
signature: tx.response.signature,
|
||||
};
|
||||
this.metaplex.nfts().update({
|
||||
nftOrSft: await this.getCollection(),
|
||||
...updateData,
|
||||
});
|
||||
}
|
||||
|
||||
private async getCollection() {
|
||||
|
||||
@@ -5,12 +5,18 @@ import {
|
||||
NFTMetadataInput,
|
||||
} from "../../core/schema/nft";
|
||||
import { ClaimConditions } from "../classes/claim-conditions";
|
||||
import {
|
||||
enforceCreator,
|
||||
parseCreators,
|
||||
} from "../classes/helpers/creators-helper";
|
||||
import { NFTHelper } from "../classes/helpers/nft-helper";
|
||||
import { Amount, TransactionResult } from "../types/common";
|
||||
import { CreatorInput, CreatorOutput } from "../types/programs";
|
||||
import { sendMultipartTransaction } from "../utils/transactions";
|
||||
import { getNework } from "../utils/urls";
|
||||
import {
|
||||
CandyMachineItem,
|
||||
Metaplex,
|
||||
MintCandyMachineOutput,
|
||||
toBigNumber,
|
||||
} from "@metaplex-foundation/js";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
@@ -41,19 +47,30 @@ export class NFTDrop {
|
||||
private nft: NFTHelper;
|
||||
public accountType = "nft-drop" as const;
|
||||
public publicKey: PublicKey;
|
||||
public claimConditions: ClaimConditions;
|
||||
public get network() {
|
||||
const url = new URL(this.metaplex.connection.rpcEndpoint);
|
||||
// try this first to avoid hitting `custom` network for alchemy urls
|
||||
if (url.hostname.includes("devnet")) {
|
||||
return "devnet";
|
||||
}
|
||||
if (url.hostname.includes("mainnet")) {
|
||||
return "mainnet-beta";
|
||||
}
|
||||
return this.metaplex.cluster;
|
||||
return getNework(this.metaplex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage the claim conditions for this drop
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* // set your claim conditions
|
||||
* await program.claimConditions.set({
|
||||
* maxClaimable: 100,
|
||||
* price: 0.5,
|
||||
* startTime: new Date(),
|
||||
* });
|
||||
*
|
||||
* // get your claim conditions
|
||||
* const conditions = await program.claimConditions.get();
|
||||
* console.log(conditions.maxClaimable);
|
||||
* console.log(conditions.claimedSupply);
|
||||
* ```
|
||||
*/
|
||||
public claimConditions: ClaimConditions;
|
||||
|
||||
constructor(
|
||||
dropAddress: string,
|
||||
metaplex: Metaplex,
|
||||
@@ -83,9 +100,40 @@ export class NFTDrop {
|
||||
.nfts()
|
||||
.findByMint({ mintAddress: info.collectionMintAddress })
|
||||
.run();
|
||||
|
||||
return (await this.nft.toNFTMetadata(metadata)).metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the creators of this program.
|
||||
* @returns program metadata
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* const creators = await program.getCreators();
|
||||
* console.log(creators);
|
||||
* ```
|
||||
*/
|
||||
async getCreators(): Promise<CreatorOutput[]> {
|
||||
const info = await this.getCandyMachine();
|
||||
return parseCreators(info.creators);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the royalty basis points for this collection
|
||||
* @returns royalty basis points
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* const royalty = await program.getRoyalty();
|
||||
* console.log(royalty);
|
||||
* ```
|
||||
*/
|
||||
async getRoyalty(): Promise<number> {
|
||||
const info = await this.getCandyMachine();
|
||||
return info.sellerFeeBasisPoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the metadata for a specific NFT
|
||||
* @param nftAddress - the mint address of the NFT to get
|
||||
@@ -204,6 +252,21 @@ export class NFTDrop {
|
||||
return this.nft.balanceOf(walletAddress, nftAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current owner of the given NFT
|
||||
* @param nftAddress - the mint address of the NFT to get the owner of
|
||||
* @returns the owner of the NFT
|
||||
* @example
|
||||
* ```jsx
|
||||
* const nftAddress = "..."
|
||||
* const owner = await program.ownerOf(nftAddress);
|
||||
* console.log(owner);
|
||||
* ```
|
||||
*/
|
||||
async ownerOf(nftAddress: string): Promise<string | undefined> {
|
||||
return this.nft.ownerOf(nftAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total unclaimed supply of this drop
|
||||
* @returns the total supply
|
||||
@@ -262,6 +325,7 @@ export class NFTDrop {
|
||||
/**
|
||||
* Lazy mint NFTs to be claimed later
|
||||
* @param metadatas - The metadata of the NFTs to lazy mint
|
||||
* @param options
|
||||
* @returns the transaction result of the lazy mint
|
||||
*
|
||||
* @example
|
||||
@@ -307,9 +371,7 @@ export class NFTDrop {
|
||||
batches.push(items.splice(0, LAZY_MINT_BATCH_SIZE));
|
||||
}
|
||||
|
||||
const block = await this.metaplex.connection.getLatestBlockhash();
|
||||
|
||||
const txns = batches.map((batch, i) =>
|
||||
const builders = batches.map((batch, i) =>
|
||||
this.metaplex
|
||||
.candyMachines()
|
||||
.builders()
|
||||
@@ -320,38 +382,9 @@ export class NFTDrop {
|
||||
index: toBigNumber(
|
||||
i * LAZY_MINT_BATCH_SIZE + candyMachine.itemsLoaded.toNumber(),
|
||||
),
|
||||
})
|
||||
.setTransactionOptions({
|
||||
blockhash: block.blockhash,
|
||||
feePayer: this.metaplex.identity().publicKey,
|
||||
lastValidBlockHeight: block.lastValidBlockHeight,
|
||||
})
|
||||
.setFeePayer(this.metaplex.identity())
|
||||
.toTransaction(),
|
||||
}),
|
||||
);
|
||||
|
||||
// make the connected wallet sign both candyMachine + registry transactions
|
||||
const signedTx = await this.metaplex.identity().signAllTransactions(txns);
|
||||
|
||||
// send the signed transactions
|
||||
const signatures = await Promise.all(
|
||||
signedTx.map((tx) =>
|
||||
this.metaplex.connection.sendRawTransaction(tx.serialize()),
|
||||
),
|
||||
);
|
||||
|
||||
// wait for confirmations in parallel
|
||||
const confirmations = await Promise.all(
|
||||
signatures.map((sig) => {
|
||||
return this.metaplex.rpc().confirmTransaction(sig);
|
||||
}),
|
||||
);
|
||||
|
||||
if (confirmations.length === 0) {
|
||||
throw new Error("Transaction failed");
|
||||
}
|
||||
|
||||
return signatures.map((signature) => ({ signature }));
|
||||
return await sendMultipartTransaction(builders, this.metaplex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -385,20 +418,25 @@ export class NFTDrop {
|
||||
* console.log("Claimed NFT at address", claimedAddresses[0]);
|
||||
* ```
|
||||
*/
|
||||
async claimTo(receiverAddress: string, quantity: Amount): Promise<string[]> {
|
||||
async claimTo(receiverAddress: string, amount: Amount): Promise<string[]> {
|
||||
const candyMachine = await this.getCandyMachine();
|
||||
await this.claimConditions.assertCanClaimable(Number(quantity));
|
||||
const results: MintCandyMachineOutput[] = [];
|
||||
// has to claim sequentially
|
||||
for (let i = 0; i < quantity; i++) {
|
||||
results.push(
|
||||
await this.metaplex
|
||||
await this.claimConditions.assertCanClaimable(Number(amount));
|
||||
const builders = await Promise.all(
|
||||
[...Array(amount).keys()].map(async () => {
|
||||
return await this.metaplex
|
||||
.candyMachines()
|
||||
.mint({ candyMachine, newOwner: new PublicKey(receiverAddress) })
|
||||
.run(),
|
||||
);
|
||||
}
|
||||
return results.map((result) => result.nft.address.toBase58());
|
||||
.builders()
|
||||
.mint({
|
||||
candyMachine,
|
||||
newOwner: new PublicKey(receiverAddress),
|
||||
});
|
||||
}),
|
||||
);
|
||||
const mintAddresses = builders.map((builder) =>
|
||||
builder.getContext().mintSigner.publicKey.toBase58(),
|
||||
);
|
||||
await sendMultipartTransaction(builders, this.metaplex);
|
||||
return mintAddresses;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -431,6 +469,40 @@ export class NFTDrop {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the creators of the collection
|
||||
* @param creators - the creators to update
|
||||
*/
|
||||
async updateCreators(creators: CreatorInput[]) {
|
||||
const tx = await this.metaplex
|
||||
.candyMachines()
|
||||
.update({
|
||||
candyMachine: await this.getCandyMachine(),
|
||||
creators: enforceCreator(creators, this.metaplex.identity().publicKey),
|
||||
})
|
||||
.run();
|
||||
return {
|
||||
signature: tx.response.signature,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the royalty basis points of the collection
|
||||
* @param sellerFeeBasisPoints - the royalty basis points of the collection
|
||||
*/
|
||||
async updateRoyalty(sellerFeeBasisPoints: number) {
|
||||
const tx = await this.metaplex
|
||||
.candyMachines()
|
||||
.update({
|
||||
candyMachine: await this.getCandyMachine(),
|
||||
sellerFeeBasisPoints,
|
||||
})
|
||||
.run();
|
||||
return {
|
||||
signature: tx.response.signature,
|
||||
};
|
||||
}
|
||||
|
||||
private async getCandyMachine() {
|
||||
return this.metaplex
|
||||
.candyMachines()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { CurrencyValue, TokenMetadata } from "../../core/schema/token";
|
||||
import { Amount, AmountSchema, TransactionResult } from "../types/common";
|
||||
import { toCurrencyValue } from "../utils/token";
|
||||
import { getNework } from "../utils/urls";
|
||||
import {
|
||||
findMetadataPda,
|
||||
Metaplex,
|
||||
@@ -36,15 +37,7 @@ export class Token {
|
||||
public accountType = "token" as const;
|
||||
public publicKey: PublicKey;
|
||||
public get network() {
|
||||
const url = new URL(this.metaplex.connection.rpcEndpoint);
|
||||
// try this first to avoid hitting `custom` network for alchemy urls
|
||||
if (url.hostname.includes("devnet")) {
|
||||
return "devnet";
|
||||
}
|
||||
if (url.hostname.includes("mainnet")) {
|
||||
return "mainnet-beta";
|
||||
}
|
||||
return this.metaplex.cluster;
|
||||
return getNework(this.metaplex);
|
||||
}
|
||||
|
||||
constructor(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { AmountSchema, FileOrBufferOrStringSchema } from "../common";
|
||||
import { Creator } from "@metaplex-foundation/js";
|
||||
import { z } from "zod";
|
||||
|
||||
/**
|
||||
@@ -64,6 +65,13 @@ export type TokenMetadataInput = z.input<typeof TokenMetadataInputSchema>;
|
||||
*/
|
||||
export type CreatorInput = z.input<typeof CreatorInputSchema>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type CreatorOutput = Omit<Creator, "address"> & {
|
||||
readonly address: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { TransactionResult } from "../types/common";
|
||||
import {
|
||||
getSignerHistogram,
|
||||
Metaplex,
|
||||
TransactionBuilder,
|
||||
} from "@metaplex-foundation/js";
|
||||
|
||||
export async function sendMultipartTransaction(
|
||||
builders: TransactionBuilder[],
|
||||
metaplex: Metaplex,
|
||||
): Promise<TransactionResult[]> {
|
||||
const block = await metaplex.connection.getLatestBlockhash();
|
||||
const txns = builders.map((builder) => {
|
||||
const builderTx = builder
|
||||
.setTransactionOptions({
|
||||
blockhash: block.blockhash,
|
||||
feePayer: metaplex.identity().publicKey,
|
||||
lastValidBlockHeight: block.lastValidBlockHeight,
|
||||
})
|
||||
.setFeePayer(metaplex.identity());
|
||||
|
||||
const dropSigners = [metaplex.identity(), ...builderTx.getSigners()];
|
||||
const { keypairs } = getSignerHistogram(dropSigners);
|
||||
const tx = builderTx.toTransaction();
|
||||
|
||||
if (keypairs.length > 0) {
|
||||
tx.partialSign(...keypairs);
|
||||
}
|
||||
return tx;
|
||||
});
|
||||
|
||||
// make the connected wallet sign all transactions
|
||||
const signedTx = await metaplex.identity().signAllTransactions(txns);
|
||||
|
||||
// send the signed transactions
|
||||
let signatures = [];
|
||||
for (const tx of signedTx) {
|
||||
const signature = await metaplex.connection.sendRawTransaction(
|
||||
tx.serialize(),
|
||||
);
|
||||
signatures.push(signature);
|
||||
}
|
||||
|
||||
// wait for confirmations in parallel
|
||||
const confirmations = await Promise.all(
|
||||
signatures.map((sig) => {
|
||||
return metaplex.rpc().confirmTransaction(sig);
|
||||
}),
|
||||
);
|
||||
|
||||
if (confirmations.length === 0) {
|
||||
throw new Error("Transaction failed");
|
||||
}
|
||||
|
||||
return signatures.map((signature) => ({ signature }));
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Network } from "../types/index";
|
||||
import { Metaplex } from "@metaplex-foundation/js";
|
||||
import { Cluster, clusterApiUrl } from "@solana/web3.js";
|
||||
|
||||
/**
|
||||
@@ -24,3 +25,26 @@ export function getUrlForNetwork(network: Network) {
|
||||
return network;
|
||||
}
|
||||
}
|
||||
|
||||
export function getNework(metaplex: Metaplex) {
|
||||
const url = new URL(metaplex.connection.rpcEndpoint);
|
||||
// try this first to avoid hitting `custom` network for alchemy urls
|
||||
if (url.hostname.includes("devnet")) {
|
||||
return "devnet";
|
||||
}
|
||||
if (url.hostname.includes("mainnet")) {
|
||||
return "mainnet-beta";
|
||||
}
|
||||
return metaplex.cluster;
|
||||
}
|
||||
|
||||
export function getPublicRpc(metaplex: Metaplex) {
|
||||
const url = new URL(metaplex.connection.rpcEndpoint);
|
||||
if (url.hostname.includes("devnet")) {
|
||||
return "https://api.devnet.solana.com";
|
||||
}
|
||||
if (url.hostname.includes("mainnet")) {
|
||||
return "https://api.mainnet-beta.solana.com";
|
||||
}
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
@@ -90,6 +90,21 @@ describe("Events", async () => {
|
||||
dropContract.events.removeAllListeners();
|
||||
});
|
||||
|
||||
it("Should emit deploy events", async () => {
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
expect(sdk.deployer.events).to.not.be.undefined;
|
||||
let txAddress = "";
|
||||
sdk.deployer.events?.addDeployListener((event) => {
|
||||
txAddress = event.contractAddress;
|
||||
});
|
||||
const address = await sdk.deployer.deployMarketplace({
|
||||
name: "Marketplace",
|
||||
});
|
||||
// Wait for the async listener to get called
|
||||
await new Promise((res) => setTimeout(res, 2000));
|
||||
expect(txAddress).to.equal(address);
|
||||
});
|
||||
|
||||
it("should emit Contract events", async () => {
|
||||
const events: ContractEvent[] = [];
|
||||
const remove = dropContract.events.addEventListener(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable turbo/no-undeclared-env-vars */
|
||||
import { ThirdwebSDK } from "../../src/evm";
|
||||
import { assert, expect } from "chai";
|
||||
import { ethers, Wallet } from "ethers";
|
||||
|
||||
const RPC_URL = "https://rpc-mumbai.maticvigil.com/";
|
||||
@@ -47,4 +48,43 @@ describe("Gasless Forwarder", async () => {
|
||||
|
||||
await pack.open(0, 0);
|
||||
});
|
||||
|
||||
it.skip("should mint batch via multicall tx with relayer", async () => {
|
||||
const NFT_COLLECTION_ADDRESS = "0x24A5aB2878B63716B001aa9AbE816c2662192B12";
|
||||
const provider = ethers.getDefaultProvider(RPC_URL);
|
||||
// const wallet = Wallet.createRandom().connect(provider);
|
||||
const wallet = new Wallet("<PRIVATE KEY>", provider);
|
||||
const sdk = new ThirdwebSDK(wallet, {
|
||||
gasless: {
|
||||
openzeppelin: {
|
||||
relayerUrl: "<RELAYER URL>",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const nftCollection = await sdk.getContract(
|
||||
NFT_COLLECTION_ADDRESS,
|
||||
"nft-collection",
|
||||
);
|
||||
|
||||
const metas = [
|
||||
{
|
||||
name: "Test5",
|
||||
},
|
||||
{
|
||||
name: "Test6",
|
||||
},
|
||||
];
|
||||
|
||||
const batch = await nftCollection.mintBatch(metas);
|
||||
|
||||
assert.lengthOf(batch, 2);
|
||||
|
||||
for (const meta of metas) {
|
||||
const nft = batch.find(
|
||||
async (n) => (await n.data()).metadata.name === meta.name,
|
||||
);
|
||||
assert.isDefined(nft);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -42,6 +42,18 @@ describe("NFTCollection", async () => {
|
||||
expect(balance).to.eq(1);
|
||||
});
|
||||
|
||||
it("Should update supply", async () => {
|
||||
const mint = await collection.mint({
|
||||
name: "Test NFT",
|
||||
description: "Test Description",
|
||||
});
|
||||
let nft = await collection.get(mint);
|
||||
expect(nft.supply).to.eq(1);
|
||||
await collection.mintAdditionalSupply(mint, 2);
|
||||
nft = await collection.get(mint);
|
||||
expect(nft.supply).to.eq(3);
|
||||
});
|
||||
|
||||
it("should transfer NFTs", async () => {
|
||||
const all = await collection.getAll();
|
||||
const wallet = Keypair.generate();
|
||||
@@ -66,11 +78,20 @@ describe("NFTCollection", async () => {
|
||||
name: "Test NFT",
|
||||
description: "Test Description",
|
||||
});
|
||||
const printed = await collection.mintAdditionalSupply(mint);
|
||||
const [printed] = await collection.mintAdditionalSupply(mint, 1);
|
||||
let balance = await collection.balance(mint);
|
||||
expect(balance).to.equal(1);
|
||||
balance = await collection.balance(printed);
|
||||
expect(balance).to.equal(1);
|
||||
|
||||
const [nft1, nft2] = await collection.mintAdditionalSupply(mint, 2);
|
||||
balance = await collection.balance(nft1);
|
||||
expect(balance).to.equal(1);
|
||||
balance = await collection.balance(nft2);
|
||||
expect(balance).to.equal(1);
|
||||
|
||||
const supply = await collection.supplyOf(mint);
|
||||
expect(supply).to.equal(4);
|
||||
});
|
||||
|
||||
it("test supply of", async () => {
|
||||
@@ -81,11 +102,25 @@ describe("NFTCollection", async () => {
|
||||
|
||||
const amount = 2;
|
||||
for (let i = 0; i < amount; i++) {
|
||||
await collection.mintAdditionalSupply(mint);
|
||||
await collection.mintAdditionalSupply(mint, 1);
|
||||
}
|
||||
|
||||
const supply = await collection.supplyOf(mint);
|
||||
expect(supply).to.equal(BigInt(amount + 1));
|
||||
expect(supply).to.equal(amount + 1);
|
||||
});
|
||||
|
||||
it("test burn supply", async () => {
|
||||
const mint = await collection.mint({
|
||||
name: "Test NFT",
|
||||
description: "Test Description",
|
||||
});
|
||||
|
||||
let supply = await collection.supplyOf(mint);
|
||||
expect(supply).to.equal(1);
|
||||
|
||||
await collection.burn(mint);
|
||||
supply = await collection.supplyOf(mint);
|
||||
expect(supply).to.equal(0);
|
||||
});
|
||||
|
||||
it("should burn nfts", async () => {
|
||||
@@ -93,10 +128,38 @@ describe("NFTCollection", async () => {
|
||||
name: "Test NFT to burn",
|
||||
description: "Test Description",
|
||||
});
|
||||
|
||||
const all = await collection.getAll();
|
||||
expect(all.length).to.eq(4);
|
||||
await collection.burn(mint);
|
||||
const all2 = await collection.getAll();
|
||||
expect(all2.length).to.eq(3);
|
||||
expect(all2.length).to.eq(all.length - 1);
|
||||
});
|
||||
|
||||
it("should update creator settings", async () => {
|
||||
let creators = await collection.getCreators();
|
||||
expect(creators.length).to.equal(1);
|
||||
expect(creators[0].address).to.equal(sdk.wallet.getAddress());
|
||||
expect(creators[0].share).to.equal(100);
|
||||
|
||||
const newCreator = Keypair.generate().publicKey.toBase58();
|
||||
await collection.updateCreators([
|
||||
{ address: sdk.wallet.getAddress() as string, sharePercentage: 75 },
|
||||
{ address: newCreator, sharePercentage: 25 },
|
||||
]);
|
||||
|
||||
creators = await collection.getCreators();
|
||||
expect(creators.length).to.equal(2);
|
||||
expect(creators[0].address).to.equal(sdk.wallet.getAddress());
|
||||
expect(creators[0].share).to.equal(75);
|
||||
expect(creators[1].address).to.equal(newCreator);
|
||||
expect(creators[1].share).to.equal(25);
|
||||
});
|
||||
|
||||
it("Should update royalty", async () => {
|
||||
let royalty = await collection.getRoyalty();
|
||||
expect(royalty).to.equal(0);
|
||||
await collection.updateRoyalty(100);
|
||||
royalty = await collection.getRoyalty();
|
||||
expect(royalty).to.equal(100);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { NFTDrop } from "../../src/solana";
|
||||
import { sdk } from "./before-setup";
|
||||
import { Keypair } from "@solana/web3.js";
|
||||
import { expect } from "chai";
|
||||
|
||||
describe("NFTDrop", async () => {
|
||||
@@ -54,15 +55,21 @@ describe("NFTDrop", async () => {
|
||||
await drop.claimConditions.set({
|
||||
maxClaimable: 1,
|
||||
});
|
||||
const address = await drop.claim(1);
|
||||
const receiver = Keypair.generate();
|
||||
const address = await drop.claimTo(receiver.publicKey.toBase58(), 1);
|
||||
|
||||
unclaimed = await drop.totalUnclaimedSupply();
|
||||
claimed = await drop.totalClaimedSupply();
|
||||
expect(unclaimed).to.equal(4);
|
||||
expect(claimed).to.equal(1);
|
||||
|
||||
const balance = await drop.balance(address[0]);
|
||||
const balance = await drop.balanceOf(
|
||||
receiver.publicKey.toBase58(),
|
||||
address[0],
|
||||
);
|
||||
expect(balance).to.equal(1);
|
||||
const nftClaimed = await drop.get(address[0]);
|
||||
expect(nftClaimed.owner).to.equal(receiver.publicKey.toBase58());
|
||||
});
|
||||
|
||||
it("should update claim condition", async () => {
|
||||
@@ -84,7 +91,9 @@ describe("NFTDrop", async () => {
|
||||
});
|
||||
|
||||
it("should get all nfts", async () => {
|
||||
await drop.claim(2);
|
||||
const claimedAddresses = await drop.claim(2);
|
||||
const nftClaimed = await drop.get(claimedAddresses[0]);
|
||||
expect(nftClaimed.owner).to.equal(sdk.wallet.getAddress());
|
||||
|
||||
const all = await drop.getAll();
|
||||
const claimed = await drop.getAllClaimed();
|
||||
@@ -115,4 +124,32 @@ describe("NFTDrop", async () => {
|
||||
const all2 = await burnDrop.getAllClaimed();
|
||||
expect(all2.length).to.eq(1);
|
||||
});
|
||||
|
||||
it("should update creator settings", async () => {
|
||||
let creators = await drop.getCreators();
|
||||
expect(creators.length).to.equal(1);
|
||||
expect(creators[0].address).to.equal(sdk.wallet.getAddress());
|
||||
expect(creators[0].share).to.equal(100);
|
||||
|
||||
const newCreator = Keypair.generate().publicKey.toBase58();
|
||||
await drop.updateCreators([
|
||||
{ address: sdk.wallet.getAddress() as string, sharePercentage: 75 },
|
||||
{ address: newCreator, sharePercentage: 25 },
|
||||
]);
|
||||
|
||||
creators = await drop.getCreators();
|
||||
expect(creators.length).to.equal(2);
|
||||
expect(creators[0].address).to.equal(sdk.wallet.getAddress());
|
||||
expect(creators[0].share).to.equal(75);
|
||||
expect(creators[1].address).to.equal(newCreator);
|
||||
expect(creators[1].share).to.equal(25);
|
||||
});
|
||||
|
||||
it("Should update royalty", async () => {
|
||||
let royalty = await drop.getRoyalty();
|
||||
expect(royalty).to.equal(0);
|
||||
await drop.updateRoyalty(100);
|
||||
royalty = await drop.getRoyalty();
|
||||
expect(royalty).to.equal(100);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import { NFTCollection } from "../../src/solana";
|
||||
import { sdk } from "./before-setup";
|
||||
import { expect } from "chai";
|
||||
|
||||
describe("NFTCollection", async () => {
|
||||
describe("NFTCollection get all", async () => {
|
||||
let collection: NFTCollection;
|
||||
let addr: string;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user