From 4a6b09ad441d284e27eec542ad673149d3d17949 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Mon, 2 May 2022 13:26:20 -0700 Subject: [PATCH 1/5] add more features --- src/constants/contract-features.ts | 90 +++++++----------------------- src/constants/erc1155-features.ts | 26 +++++++++ src/constants/erc20-features.ts | 12 ++++ src/constants/erc721-features.ts | 67 ++++++++++++++++++++++ src/core/classes/erc-20.ts | 3 +- 5 files changed, 126 insertions(+), 72 deletions(-) create mode 100644 src/constants/erc1155-features.ts create mode 100644 src/constants/erc20-features.ts create mode 100644 src/constants/erc721-features.ts diff --git a/src/constants/contract-features.ts b/src/constants/contract-features.ts index 38b8749b0..d48461f8d 100644 --- a/src/constants/contract-features.ts +++ b/src/constants/contract-features.ts @@ -1,82 +1,28 @@ -import { - ERC721__factory, - ERC721Enumerable__factory, - ERC721Supply__factory, - IMintableERC721__factory, - Multicall__factory, -} from "contracts"; - -const FEATURE_NFT_BATCH_MINTABLE = { - name: "ERC721BatchMintable", - namespace: "nft.mint.batch", - docLinks: { - sdk: "sdk.erc721batchmintable", - contracts: "Multicall", - }, - abi: Multicall__factory.abi, - features: {}, -} as const; - -const FEATURE_NFT_MINTABLE = { - name: "ERC721Mintable", - namespace: "nft.mint", - docLinks: { - sdk: "sdk.erc721mintable", - contracts: "IMintableERC721", - }, - abi: IMintableERC721__factory.abi, - features: { - [FEATURE_NFT_BATCH_MINTABLE.name]: FEATURE_NFT_BATCH_MINTABLE, - }, -} as const; - -const FEATURE_NFT_ENUMERABLE = { - name: "ERC721Enumerable", - namespace: "nft.query.owned", - docLinks: { - sdk: "sdk.erc721enumerable", - contracts: "ERC721Enumerable", - }, - abi: ERC721Enumerable__factory.abi, - features: {}, -} as const; - -const FEATURE_NFT_SUPPLY = { - name: "ERC721Supply", - namespace: "nft.query", - docLinks: { - sdk: "sdk.erc721supply", - contracts: "ERC721Supply", - }, - abi: ERC721Supply__factory.abi, - features: { - [FEATURE_NFT_ENUMERABLE.name]: FEATURE_NFT_ENUMERABLE, - }, -} as const; - -const FEATURE_NFT = { - name: "ERC721", - namespace: "nft", - docLinks: { - sdk: "sdk.erc721", - contracts: "ERC721", - }, - abi: ERC721__factory.abi, - features: { - [FEATURE_NFT_SUPPLY.name]: FEATURE_NFT_SUPPLY, - [FEATURE_NFT_MINTABLE.name]: FEATURE_NFT_MINTABLE, - }, -} as const; - /** * @internal */ +import { + FEATURE_NFT, + FEATURE_NFT_BATCH_MINTABLE, + FEATURE_NFT_ENUMERABLE, + FEATURE_NFT_MINTABLE, + FEATURE_NFT_SUPPLY, +} from "./erc721-features"; +import { FEATURE_TOKEN } from "./erc20-features"; +import { + FEATURE_EDITION, + FEATURE_EDITION_ENUMERABLE, +} from "./erc1155-features"; + export type Feature = + | typeof FEATURE_TOKEN | typeof FEATURE_NFT | typeof FEATURE_NFT_SUPPLY | typeof FEATURE_NFT_ENUMERABLE | typeof FEATURE_NFT_MINTABLE - | typeof FEATURE_NFT_BATCH_MINTABLE; + | typeof FEATURE_NFT_BATCH_MINTABLE + | typeof FEATURE_EDITION + | typeof FEATURE_EDITION_ENUMERABLE; /** * @internal @@ -94,5 +40,7 @@ export type FeatureWithEnabled = Feature & { * @internal */ export const SUPPORTED_FEATURES: Record = { + [FEATURE_TOKEN.name]: FEATURE_TOKEN, [FEATURE_NFT.name]: FEATURE_NFT, + [FEATURE_EDITION.name]: FEATURE_EDITION, }; diff --git a/src/constants/erc1155-features.ts b/src/constants/erc1155-features.ts new file mode 100644 index 000000000..6d832e84a --- /dev/null +++ b/src/constants/erc1155-features.ts @@ -0,0 +1,26 @@ +import Erc1155EnumerableAbi from "../../abis/ERC1155Enumerable.json"; +import Erc1155Abi from "../../abis/ERC1155.json"; + +export const FEATURE_EDITION_ENUMERABLE = { + name: "ERC155Enumerable", + namespace: "edition.query", + docLinks: { + sdk: "sdk.erc1155", + contracts: "ERC1155", + }, + abi: Erc1155EnumerableAbi, + features: {}, +} as const; + +export const FEATURE_EDITION = { + name: "ERC155", + namespace: "edition", + docLinks: { + sdk: "sdk.erc1155", + contracts: "ERC1155", + }, + abi: Erc1155Abi, + features: { + [FEATURE_EDITION_ENUMERABLE.name]: FEATURE_EDITION_ENUMERABLE, + }, +} as const; diff --git a/src/constants/erc20-features.ts b/src/constants/erc20-features.ts new file mode 100644 index 000000000..ab25ad5f1 --- /dev/null +++ b/src/constants/erc20-features.ts @@ -0,0 +1,12 @@ +import ERC20Abi from "../../abis/ERC20.json"; + +export const FEATURE_TOKEN = { + name: "ERC20", + namespace: "token", + docLinks: { + sdk: "sdk.erc20", + contracts: "ERC20", + }, + abi: ERC20Abi, + features: {}, +} as const; diff --git a/src/constants/erc721-features.ts b/src/constants/erc721-features.ts new file mode 100644 index 000000000..c98c0d839 --- /dev/null +++ b/src/constants/erc721-features.ts @@ -0,0 +1,67 @@ +import Erc721Abi from "../../abis/ERC721.json"; +import Erc721EnumerableAbi from "../../abis/ERC721Enumerable.json"; +import Erc721SupplyAbi from "../../abis/ERC721Supply.json"; +import IMintableERC721Abi from "../../abis/IMintableERC721.json"; +import MulticallAbi from "../../abis/Multicall.json"; + +export const FEATURE_NFT_BATCH_MINTABLE = { + name: "ERC721BatchMintable", + namespace: "nft.mint.batch", + docLinks: { + sdk: "sdk.erc721batchmintable", + contracts: "Multicall", + }, + abi: MulticallAbi, + features: {}, +} as const; + +export const FEATURE_NFT_MINTABLE = { + name: "ERC721Mintable", + namespace: "nft.mint", + docLinks: { + sdk: "sdk.erc721mintable", + contracts: "IMintableERC721", + }, + abi: IMintableERC721Abi, + features: { + [FEATURE_NFT_BATCH_MINTABLE.name]: FEATURE_NFT_BATCH_MINTABLE, + }, +} as const; + +export const FEATURE_NFT_ENUMERABLE = { + name: "ERC721Enumerable", + namespace: "nft.query.owned", + docLinks: { + sdk: "sdk.erc721enumerable", + contracts: "ERC721Enumerable", + }, + abi: Erc721EnumerableAbi, + features: {}, +} as const; + +export const FEATURE_NFT_SUPPLY = { + name: "ERC721Supply", + namespace: "nft.query", + docLinks: { + sdk: "sdk.erc721supply", + contracts: "ERC721Supply", + }, + abi: Erc721SupplyAbi, + features: { + [FEATURE_NFT_ENUMERABLE.name]: FEATURE_NFT_ENUMERABLE, + }, +} as const; + +export const FEATURE_NFT = { + name: "ERC721", + namespace: "nft", + docLinks: { + sdk: "sdk.erc721", + contracts: "ERC721", + }, + abi: Erc721Abi, + features: { + [FEATURE_NFT_SUPPLY.name]: FEATURE_NFT_SUPPLY, + [FEATURE_NFT_MINTABLE.name]: FEATURE_NFT_MINTABLE, + }, +} as const; diff --git a/src/core/classes/erc-20.ts b/src/core/classes/erc-20.ts index dd820ca21..1e733d1eb 100644 --- a/src/core/classes/erc-20.ts +++ b/src/core/classes/erc-20.ts @@ -12,12 +12,13 @@ import { } from "../../common/currency"; import { TokenMintInput } from "../../schema/tokens/token"; import { PriceSchema } from "../../schema"; +import { BaseERC20 } from "../../types/eips"; /** * Standard ERC20 functions * @public */ -export class Erc20 +export class Erc20 implements UpdateableNetwork { protected contractWrapper: ContractWrapper; From 501014d04c223d3e0eba9845b8df054318101315 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Mon, 2 May 2022 13:55:53 -0700 Subject: [PATCH 2/5] add ERC20 features --- docs/sdk.erc20.md | 4 +- docs/sdk.erc20.mint.md | 13 ++ docs/sdk.erc20.normalizeamount.md | 22 --- docs/sdk.erc721batchmintable._constructor_.md | 4 +- docs/sdk.erc721mintable._constructor_.md | 4 +- docs/sdk.thirdwebsdk.getcontractlist.md | 4 +- docs/sdk.token.md | 2 +- ....token.mint.md => sdk.token.minttoself.md} | 6 +- etc/sdk.api.md | 128 ++++++++++-------- src/common/currency.ts | 11 +- src/constants/contract-features.ts | 8 +- src/constants/erc1155-features.ts | 8 +- src/constants/erc20-features.ts | 30 +++- src/contracts/smart-contract.ts | 16 +-- src/contracts/token.ts | 27 ++-- src/core/classes/erc-20-batch-mintable.ts | 54 ++++++++ src/core/classes/erc-20-mintable.ts | 61 +++++++++ src/core/classes/erc-20.ts | 24 +++- src/core/classes/erc-721-batch-mintable.ts | 7 +- src/core/classes/erc-721-mintable.ts | 7 +- src/schema/tokens/common/index.ts | 2 +- test/custom.test.ts | 6 +- test/token.test.ts | 10 +- 23 files changed, 307 insertions(+), 151 deletions(-) create mode 100644 docs/sdk.erc20.mint.md delete mode 100644 docs/sdk.erc20.normalizeamount.md rename docs/{sdk.token.mint.md => sdk.token.minttoself.md} (73%) create mode 100644 src/core/classes/erc-20-batch-mintable.ts create mode 100644 src/core/classes/erc-20-mintable.ts diff --git a/docs/sdk.erc20.md b/docs/sdk.erc20.md index 84c7ba56b..41fa3395a 100644 --- a/docs/sdk.erc20.md +++ b/docs/sdk.erc20.md @@ -9,7 +9,7 @@ Standard ERC20 functions Signature: ```typescript -export declare class Erc20 implements UpdateableNetwork +export declare class Erc20 implements UpdateableNetwork ``` Implements: UpdateableNetwork @@ -24,6 +24,7 @@ export declare class Erc20spender wallet to transfer the given amount of tokens to another wallet | | [totalSupply()](./sdk.erc20.totalsupply.md) | | The total supply for this Token | | [transfer(to, amount)](./sdk.erc20.transfer.md) | | Transfer Tokens | diff --git a/docs/sdk.erc20.mint.md b/docs/sdk.erc20.mint.md new file mode 100644 index 000000000..13dd7e240 --- /dev/null +++ b/docs/sdk.erc20.mint.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@thirdweb-dev/sdk](./sdk.md) > [Erc20](./sdk.erc20.md) > [mint](./sdk.erc20.mint.md) + +## Erc20.mint property + +Mint tokens + +Signature: + +```typescript +mint: Erc20Mintable | undefined; +``` diff --git a/docs/sdk.erc20.normalizeamount.md b/docs/sdk.erc20.normalizeamount.md deleted file mode 100644 index 26a8613d5..000000000 --- a/docs/sdk.erc20.normalizeamount.md +++ /dev/null @@ -1,22 +0,0 @@ - - -[Home](./index.md) > [@thirdweb-dev/sdk](./sdk.md) > [Erc20](./sdk.erc20.md) > [normalizeAmount](./sdk.erc20.normalizeamount.md) - -## Erc20.normalizeAmount() method - -Signature: - -```typescript -protected normalizeAmount(amount: Amount): Promise; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| amount | [Amount](./sdk.amount.md) | | - -Returns: - -Promise<BigNumber> - diff --git a/docs/sdk.erc721batchmintable._constructor_.md b/docs/sdk.erc721batchmintable._constructor_.md index 60ab210f0..53d03c489 100644 --- a/docs/sdk.erc721batchmintable._constructor_.md +++ b/docs/sdk.erc721batchmintable._constructor_.md @@ -9,14 +9,14 @@ Constructs a new instance of the `Erc721BatchMintable` class Signature: ```typescript -constructor(erc721: Erc721, contractWrapper: ContractWrapper, storage: IStorage); +constructor(erc721: Erc721, contractWrapper: ContractWrapper, storage: IStorage); ``` ## Parameters | Parameter | Type | Description | | --- | --- | --- | -| erc721 | [Erc721](./sdk.erc721.md)<ERC721Metadata & ERC721> | | +| erc721 | [Erc721](./sdk.erc721.md)<BaseERC721> | | | contractWrapper | ContractWrapper<IMintableERC721 & Multicall> | | | storage | [IStorage](./sdk.istorage.md) | | diff --git a/docs/sdk.erc721mintable._constructor_.md b/docs/sdk.erc721mintable._constructor_.md index ddfa0859c..5b4d3227b 100644 --- a/docs/sdk.erc721mintable._constructor_.md +++ b/docs/sdk.erc721mintable._constructor_.md @@ -9,14 +9,14 @@ Constructs a new instance of the `Erc721Mintable` class Signature: ```typescript -constructor(erc721: Erc721, contractWrapper: ContractWrapper, storage: IStorage); +constructor(erc721: Erc721, contractWrapper: ContractWrapper, storage: IStorage); ``` ## Parameters | Parameter | Type | Description | | --- | --- | --- | -| erc721 | [Erc721](./sdk.erc721.md)<ERC721Metadata & ERC721> | | +| erc721 | [Erc721](./sdk.erc721.md)<BaseERC721> | | | contractWrapper | ContractWrapper<IMintableERC721> | | | storage | [IStorage](./sdk.istorage.md) | | diff --git a/docs/sdk.thirdwebsdk.getcontractlist.md b/docs/sdk.thirdwebsdk.getcontractlist.md index da8bbcc43..cb67fc16f 100644 --- a/docs/sdk.thirdwebsdk.getcontractlist.md +++ b/docs/sdk.thirdwebsdk.getcontractlist.md @@ -11,7 +11,7 @@ Return all the contracts deployed by the specified address ```typescript getContractList(walletAddress: string): Promise<{ address: string; - contractType: "custom" | "token" | "pack" | "split" | "edition-drop" | "edition" | "token-drop" | "vote" | "marketplace" | "nft-drop" | "nft-collection"; + contractType: "custom" | "token" | "pack" | "split" | "edition" | "edition-drop" | "token-drop" | "vote" | "marketplace" | "nft-drop" | "nft-collection"; metadata: () => Promise; }[]>; ``` @@ -24,5 +24,5 @@ getContractList(walletAddress: string): Promise<{ Returns: -Promise<{ address: string; contractType: "custom" \| "token" \| "pack" \| "split" \| "edition-drop" \| "edition" \| "token-drop" \| "vote" \| "marketplace" \| "nft-drop" \| "nft-collection"; metadata: () => Promise<any>; }\[\]> +Promise<{ address: string; contractType: "custom" \| "token" \| "pack" \| "split" \| "edition" \| "edition-drop" \| "token-drop" \| "vote" \| "marketplace" \| "nft-drop" \| "nft-collection"; metadata: () => Promise<any>; }\[\]> diff --git a/docs/sdk.token.md b/docs/sdk.token.md index aaa32cf35..20e91a09c 100644 --- a/docs/sdk.token.md +++ b/docs/sdk.token.md @@ -58,7 +58,7 @@ const contract = sdk.getToken("{{contract_address}}"); | [getVoteBalance()](./sdk.token.getvotebalance.md) | | Get your wallet voting power for the current checkpoints | | [getVoteBalanceOf(account)](./sdk.token.getvotebalanceof.md) | | | | [isTransferRestricted()](./sdk.token.istransferrestricted.md) | | Get whether users can transfer tokens from this contract | -| [mint(amount)](./sdk.token.mint.md) | | Mint Tokens for the connected wallet | | [mintBatchTo(args)](./sdk.token.mintbatchto.md) | | Mint Tokens To Many Wallets | | [mintTo(to, amount)](./sdk.token.mintto.md) | | Mint Tokens | +| [mintToSelf(amount)](./sdk.token.minttoself.md) | | Mint Tokens for the connected wallet | diff --git a/docs/sdk.token.mint.md b/docs/sdk.token.minttoself.md similarity index 73% rename from docs/sdk.token.mint.md rename to docs/sdk.token.minttoself.md index 8a04930d3..92f9bacf3 100644 --- a/docs/sdk.token.mint.md +++ b/docs/sdk.token.minttoself.md @@ -1,15 +1,15 @@ -[Home](./index.md) > [@thirdweb-dev/sdk](./sdk.md) > [Token](./sdk.token.md) > [mint](./sdk.token.mint.md) +[Home](./index.md) > [@thirdweb-dev/sdk](./sdk.md) > [Token](./sdk.token.md) > [mintToSelf](./sdk.token.minttoself.md) -## Token.mint() method +## Token.mintToSelf() method Mint Tokens for the connected wallet Signature: ```typescript -mint(amount: Amount): Promise; +mintToSelf(amount: Amount): Promise; ``` ## Parameters diff --git a/etc/sdk.api.md b/etc/sdk.api.md index 8e525d7b0..f3d874af5 100644 --- a/etc/sdk.api.md +++ b/etc/sdk.api.md @@ -1226,7 +1226,7 @@ export type EditionMetadataInput = z.input; export const EditionMetadataInputOrUriSchema: z.ZodObject<{ supply: z.ZodEffects]>, BigNumber, string | number | bigint | BigNumber>, string, string | number | bigint | BigNumber>; metadata: z.ZodUnion<[z.ZodObject; description: z.ZodOptional; image: z.ZodOptional>; external_url: z.ZodOptional>; @@ -1237,6 +1237,7 @@ export const EditionMetadataInputOrUriSchema: z.ZodObject<{ attributes: z.ZodOptional>, "many">, z.ZodRecord>]>>; }>, "strip", z.ZodLazy>, { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: any; external_url?: any; @@ -1244,9 +1245,9 @@ export const EditionMetadataInputOrUriSchema: z.ZodObject<{ background_color?: string | undefined; properties?: Record | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }, { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: any; external_url?: any; @@ -1254,11 +1255,11 @@ export const EditionMetadataInputOrUriSchema: z.ZodObject<{ background_color?: string | undefined; properties?: Record | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }>, z.ZodString]>; }, "strip", z.ZodTypeAny, { metadata: string | { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: any; external_url?: any; @@ -1266,12 +1267,12 @@ export const EditionMetadataInputOrUriSchema: z.ZodObject<{ background_color?: string | undefined; properties?: Record | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }; supply: string; }, { metadata: string | { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: any; external_url?: any; @@ -1279,7 +1280,6 @@ export const EditionMetadataInputOrUriSchema: z.ZodObject<{ background_color?: string | undefined; properties?: Record | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }; supply: string | number | bigint | BigNumber; }>; @@ -1290,7 +1290,7 @@ export const EditionMetadataInputOrUriSchema: z.ZodObject<{ export const EditionMetadataInputSchema: z.ZodObject<{ supply: z.ZodEffects]>, BigNumber, string | number | bigint | BigNumber>, string, string | number | bigint | BigNumber>; metadata: z.ZodObject; description: z.ZodOptional; image: z.ZodOptional>; external_url: z.ZodOptional>; @@ -1301,6 +1301,7 @@ export const EditionMetadataInputSchema: z.ZodObject<{ attributes: z.ZodOptional>, "many">, z.ZodRecord>]>>; }>, "strip", z.ZodLazy>, { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: any; external_url?: any; @@ -1308,9 +1309,9 @@ export const EditionMetadataInputSchema: z.ZodObject<{ background_color?: string | undefined; properties?: Record | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }, { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: any; external_url?: any; @@ -1318,11 +1319,11 @@ export const EditionMetadataInputSchema: z.ZodObject<{ background_color?: string | undefined; properties?: Record | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }>; }, "strip", z.ZodTypeAny, { metadata: { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: any; external_url?: any; @@ -1330,12 +1331,12 @@ export const EditionMetadataInputSchema: z.ZodObject<{ background_color?: string | undefined; properties?: Record | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }; supply: string; }, { metadata: { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: any; external_url?: any; @@ -1343,7 +1344,6 @@ export const EditionMetadataInputSchema: z.ZodObject<{ background_color?: string | undefined; properties?: Record | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }; supply: string | number | bigint | BigNumber; }>; @@ -1359,7 +1359,7 @@ export type EditionMetadataOrUri = z.input]>, BigNumber, string | number | bigint | BigNumber>; metadata: z.ZodObject; description: z.ZodOptional; image: z.ZodOptional>; external_url: z.ZodOptional>; @@ -1372,31 +1372,31 @@ export const EditionMetadataOutputSchema: z.ZodObject<{ animation_url: z.ZodOptional; }>, "strip", z.ZodLazy>, { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: string | undefined; external_url?: string | undefined; animation_url?: string | undefined; - name: string; id: BigNumber; uri: string; }, { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: string | undefined; external_url?: string | undefined; animation_url?: string | undefined; - name: string; id: string | number | bigint | BigNumber; uri: string; }>; }, "strip", z.ZodTypeAny, { metadata: { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: string | undefined; external_url?: string | undefined; animation_url?: string | undefined; - name: string; id: BigNumber; uri: string; }; @@ -1404,11 +1404,11 @@ export const EditionMetadataOutputSchema: z.ZodObject<{ }, { metadata: { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: string | undefined; external_url?: string | undefined; animation_url?: string | undefined; - name: string; id: string | number | bigint | BigNumber; uri: string; }; @@ -1426,7 +1426,7 @@ export type EditionMetadataOwner = z.output]>, BigNumber, string | number | bigint | BigNumber>; metadata: z.ZodObject; description: z.ZodOptional; image: z.ZodOptional>; external_url: z.ZodOptional>; @@ -1439,20 +1439,20 @@ export const EditionMetadataWithOwnerOutputSchema: z.ZodObject; }>, "strip", z.ZodLazy>, { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: string | undefined; external_url?: string | undefined; animation_url?: string | undefined; - name: string; id: BigNumber; uri: string; }, { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: string | undefined; external_url?: string | undefined; animation_url?: string | undefined; - name: string; id: string | number | bigint | BigNumber; uri: string; }>; @@ -1462,11 +1462,11 @@ export const EditionMetadataWithOwnerOutputSchema: z.ZodObject, "strip", z.ZodTypeAny, { metadata: { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: string | undefined; external_url?: string | undefined; animation_url?: string | undefined; - name: string; id: BigNumber; uri: string; }; @@ -1476,11 +1476,11 @@ export const EditionMetadataWithOwnerOutputSchema: z.ZodObject implements UpdateableNetwork { +export class Erc20 implements UpdateableNetwork { constructor(contractWrapper: ContractWrapper, storage: IStorage, options?: SDKOptions); allowance(spender: string): Promise; allowanceOf(owner: string, spender: string): Promise; @@ -1557,8 +1556,10 @@ export class Erc20 i getAddress(): string; // @internal (undocumented) protected getValue(value: BigNumberish): Promise; - // (undocumented) - protected normalizeAmount(amount: Amount): Promise; + // Warning: (ae-forgotten-export) The symbol "Erc20Mintable" needs to be exported by the entry point index.d.ts + mint: Erc20Mintable | undefined; + // @internal + normalizeAmount(amount: Amount): Promise; // @internal (undocumented) onNetworkUpdated(network: NetworkOrSignerOrProvider): void; // (undocumented) @@ -1616,11 +1617,9 @@ export class Erc721 implements // @public (undocumented) export class Erc721BatchMintable { - // Warning: (ae-forgotten-export) The symbol "ERC721Metadata" needs to be exported by the entry point index.d.ts - // Warning: (ae-forgotten-export) The symbol "ERC721" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "IMintableERC721" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "Multicall" needs to be exported by the entry point index.d.ts - constructor(erc721: Erc721, contractWrapper: ContractWrapper, storage: IStorage); + constructor(erc721: Erc721, contractWrapper: ContractWrapper, storage: IStorage); // Warning: (ae-forgotten-export) The symbol "NFTMetadataOrUri" needs to be exported by the entry point index.d.ts to(to: string, metadatas: NFTMetadataOrUri[]): Promise[]>; } @@ -1635,7 +1634,7 @@ export class Erc721Enumerable { // @public (undocumented) export class Erc721Mintable { - constructor(erc721: Erc721, contractWrapper: ContractWrapper, storage: IStorage); + constructor(erc721: Erc721, contractWrapper: ContractWrapper, storage: IStorage); // (undocumented) batch: Erc721BatchMintable | undefined; to(to: string, metadata: NFTMetadataOrUri): Promise>; @@ -3124,17 +3123,20 @@ export const Signature1155PayloadInput: z.ZodObject; }, { metadata: z.ZodUnion<[z.ZodObject; description: z.ZodOptional; image: z.ZodOptional>; external_url: z.ZodOptional>; }, { animation_url: z.ZodOptional>; background_color: z.ZodOptional, z.ZodString]>>; - properties: z.ZodOptional>, "many">, z.ZodRecord>]>>; + properties: z.ZodOptional>, "many">, z.ZodRecord>]>>; /** + * @internal + */ attributes: z.ZodOptional>, "many">, z.ZodRecord>]>>; }>, "strip", z.ZodLazy>, { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: any; external_url?: any; @@ -3142,9 +3144,9 @@ export const Signature1155PayloadInput: z.ZodObject | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }, { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: any; external_url?: any; @@ -3152,23 +3154,25 @@ export const Signature1155PayloadInput: z.ZodObject | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }>, z.ZodString]>; royaltyRecipient: z.ZodDefault; royaltyBps: z.ZodDefault; }>, { metadata: z.ZodDefault; description: z.ZodOptional; image: z.ZodOptional>; external_url: z.ZodOptional>; }, { animation_url: z.ZodOptional>; background_color: z.ZodOptional, z.ZodString]>>; - properties: z.ZodOptional>, "many">, z.ZodRecord>]>>; + properties: z.ZodOptional>, "many">, z.ZodRecord>]>>; /** + * @internal + */ attributes: z.ZodOptional>, "many">, z.ZodRecord>]>>; }>, "strip", z.ZodLazy>, { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: any; external_url?: any; @@ -3176,9 +3180,9 @@ export const Signature1155PayloadInput: z.ZodObject | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }, { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: any; external_url?: any; @@ -3186,7 +3190,6 @@ export const Signature1155PayloadInput: z.ZodObject | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }>, z.ZodString]>>; tokenId: z.ZodDefault]>, ethers.BigNumber, string | number | bigint | ethers.BigNumber>, string, string | number | bigint | ethers.BigNumber>>; quantity: z.ZodEffects]>, ethers.BigNumber, string | number | bigint | ethers.BigNumber>, string, string | number | bigint | ethers.BigNumber>; @@ -3201,6 +3204,7 @@ export const Signature1155PayloadInput: z.ZodObject | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }; royaltyRecipient: string; royaltyBps: number; @@ -3223,6 +3226,7 @@ export const Signature1155PayloadInput: z.ZodObject | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; } | undefined; royaltyRecipient?: string | undefined; royaltyBps?: number | undefined; @@ -3251,17 +3254,20 @@ export const Signature1155PayloadOutput: z.ZodObject; }, { metadata: z.ZodUnion<[z.ZodObject; description: z.ZodOptional; image: z.ZodOptional>; external_url: z.ZodOptional>; }, { animation_url: z.ZodOptional>; background_color: z.ZodOptional, z.ZodString]>>; - properties: z.ZodOptional>, "many">, z.ZodRecord>]>>; + properties: z.ZodOptional>, "many">, z.ZodRecord>]>>; /** + * @internal + */ attributes: z.ZodOptional>, "many">, z.ZodRecord>]>>; }>, "strip", z.ZodLazy>, { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: any; external_url?: any; @@ -3269,9 +3275,9 @@ export const Signature1155PayloadOutput: z.ZodObject | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }, { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: any; external_url?: any; @@ -3279,7 +3285,6 @@ export const Signature1155PayloadOutput: z.ZodObject | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }>, z.ZodString]>; royaltyRecipient: z.ZodDefault; royaltyBps: z.ZodDefault; @@ -3303,6 +3308,7 @@ export const Signature1155PayloadOutput: z.ZodObject | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }; royaltyRecipient: string; royaltyBps: ethers.BigNumber; @@ -3328,6 +3333,7 @@ export const Signature1155PayloadOutput: z.ZodObject | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }; royaltyBps: string | number | bigint | ethers.BigNumber; tokenId: string | number | bigint | ethers.BigNumber; @@ -3423,17 +3428,20 @@ export const Signature721PayloadInput: z.ZodObject; }, { metadata: z.ZodUnion<[z.ZodObject; description: z.ZodOptional; image: z.ZodOptional>; external_url: z.ZodOptional>; }, { animation_url: z.ZodOptional>; background_color: z.ZodOptional, z.ZodString]>>; - properties: z.ZodOptional>, "many">, z.ZodRecord>]>>; + properties: z.ZodOptional>, "many">, z.ZodRecord>]>>; /** + * @internal + */ attributes: z.ZodOptional>, "many">, z.ZodRecord>]>>; }>, "strip", z.ZodLazy>, { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: any; external_url?: any; @@ -3441,9 +3449,9 @@ export const Signature721PayloadInput: z.ZodObject | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }, { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: any; external_url?: any; @@ -3451,7 +3459,6 @@ export const Signature721PayloadInput: z.ZodObject | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }>, z.ZodString]>; royaltyRecipient: z.ZodDefault; royaltyBps: z.ZodDefault; @@ -3465,6 +3472,7 @@ export const Signature721PayloadInput: z.ZodObject | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }; royaltyRecipient: string; royaltyBps: number; @@ -3488,6 +3495,7 @@ export const Signature721PayloadInput: z.ZodObject | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }; }>; @@ -3512,17 +3519,20 @@ export const Signature721PayloadOutput: z.ZodObject; }, { metadata: z.ZodUnion<[z.ZodObject; description: z.ZodOptional; image: z.ZodOptional>; external_url: z.ZodOptional>; }, { animation_url: z.ZodOptional>; background_color: z.ZodOptional, z.ZodString]>>; - properties: z.ZodOptional>, "many">, z.ZodRecord>]>>; + properties: z.ZodOptional>, "many">, z.ZodRecord>]>>; /** + * @internal + */ attributes: z.ZodOptional>, "many">, z.ZodRecord>]>>; }>, "strip", z.ZodLazy>, { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: any; external_url?: any; @@ -3530,9 +3540,9 @@ export const Signature721PayloadOutput: z.ZodObject | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }, { [x: string]: Json; + name?: string | undefined; description?: string | undefined; image?: any; external_url?: any; @@ -3540,7 +3550,6 @@ export const Signature721PayloadOutput: z.ZodObject | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }>, z.ZodString]>; royaltyRecipient: z.ZodDefault; royaltyBps: z.ZodDefault; @@ -3560,6 +3569,7 @@ export const Signature721PayloadOutput: z.ZodObject | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }; royaltyRecipient: string; royaltyBps: ethers.BigNumber; @@ -3583,6 +3592,7 @@ export const Signature721PayloadOutput: z.ZodObject | Record[] | undefined; attributes?: Record | Record[] | undefined; - name: string; }; royaltyBps: string | number | bigint | ethers.BigNumber; }>; @@ -3979,7 +3988,6 @@ export class SmartContract; }; - // Warning: (ae-forgotten-export) The symbol "BaseERC20" needs to be exported by the entry point index.d.ts token: Erc20 | undefined; } @@ -4370,7 +4378,7 @@ export class ThirdwebSDK extends RPCConnectionHandler { getContractFromAbi(address: string, abi: ContractInterface): SmartContract; getContractList(walletAddress: string): Promise<{ address: string; - contractType: "custom" | "token" | "pack" | "split" | "edition-drop" | "edition" | "token-drop" | "vote" | "marketplace" | "nft-drop" | "nft-collection"; + contractType: "custom" | "token" | "pack" | "split" | "edition" | "edition-drop" | "token-drop" | "vote" | "marketplace" | "nft-drop" | "nft-collection"; metadata: () => Promise; }[]>; getEdition(address: string): Edition; @@ -4425,9 +4433,9 @@ export class Token extends Erc20 { isTransferRestricted(): Promise; // (undocumented) metadata: ContractMetadata; - mint(amount: Amount): Promise; mintBatchTo(args: TokenMintInput[]): Promise; mintTo(to: string, amount: Amount): Promise; + mintToSelf(amount: Amount): Promise; // (undocumented) platformFee: ContractPlatformFee; // (undocumented) diff --git a/src/common/currency.ts b/src/common/currency.ts index a18c7b2a1..047396df8 100644 --- a/src/common/currency.ts +++ b/src/common/currency.ts @@ -8,9 +8,10 @@ import { } from "../constants/currency"; import { Provider } from "@ethersproject/providers"; import { formatUnits } from "ethers/lib/utils"; -import { Currency, CurrencyValue, Price } from "../types/currency"; +import { Amount, Currency, CurrencyValue, Price } from "../types/currency"; import { PriceSchema } from "../schema/shared"; import ERC20Abi from "../../abis/ERC20.json"; +import { BaseERC20 } from "../types/eips"; export function isNativeToken(tokenAddress: string): boolean { return ( @@ -125,3 +126,11 @@ export async function approveErc20Allowance( ]); } } + +export async function normalizeAmount( + contractWrapper: ContractWrapper, + amount: Amount, +): Promise { + const decimals = await contractWrapper.readContract.decimals(); + return ethers.utils.parseUnits(PriceSchema.parse(amount), decimals); +} diff --git a/src/constants/contract-features.ts b/src/constants/contract-features.ts index d48461f8d..c60a46b81 100644 --- a/src/constants/contract-features.ts +++ b/src/constants/contract-features.ts @@ -8,7 +8,11 @@ import { FEATURE_NFT_MINTABLE, FEATURE_NFT_SUPPLY, } from "./erc721-features"; -import { FEATURE_TOKEN } from "./erc20-features"; +import { + FEATURE_TOKEN, + FEATURE_TOKEN_BATCH_MINTABLE, + FEATURE_TOKEN_MINTABLE, +} from "./erc20-features"; import { FEATURE_EDITION, FEATURE_EDITION_ENUMERABLE, @@ -16,6 +20,8 @@ import { export type Feature = | typeof FEATURE_TOKEN + | typeof FEATURE_TOKEN_MINTABLE + | typeof FEATURE_TOKEN_BATCH_MINTABLE | typeof FEATURE_NFT | typeof FEATURE_NFT_SUPPLY | typeof FEATURE_NFT_ENUMERABLE diff --git a/src/constants/erc1155-features.ts b/src/constants/erc1155-features.ts index 6d832e84a..4eeba3f31 100644 --- a/src/constants/erc1155-features.ts +++ b/src/constants/erc1155-features.ts @@ -2,7 +2,7 @@ import Erc1155EnumerableAbi from "../../abis/ERC1155Enumerable.json"; import Erc1155Abi from "../../abis/ERC1155.json"; export const FEATURE_EDITION_ENUMERABLE = { - name: "ERC155Enumerable", + name: "ERC1155Enumerable", namespace: "edition.query", docLinks: { sdk: "sdk.erc1155", @@ -13,11 +13,11 @@ export const FEATURE_EDITION_ENUMERABLE = { } as const; export const FEATURE_EDITION = { - name: "ERC155", + name: "ERC1155", namespace: "edition", docLinks: { - sdk: "sdk.erc1155", - contracts: "ERC1155", + sdk: "sdk.erc1155enumerable", + contracts: "ERC1155Enumerable", }, abi: Erc1155Abi, features: { diff --git a/src/constants/erc20-features.ts b/src/constants/erc20-features.ts index ab25ad5f1..32306fbd4 100644 --- a/src/constants/erc20-features.ts +++ b/src/constants/erc20-features.ts @@ -1,4 +1,30 @@ import ERC20Abi from "../../abis/ERC20.json"; +import IMintableERC20Abi from "../../abis/IMintableERC20.json"; +import MulticallAbi from "../../abis/Multicall.json"; + +export const FEATURE_TOKEN_BATCH_MINTABLE = { + name: "ERC20BatchMintable", + namespace: "token.mint.batch", + docLinks: { + sdk: "sdk.erc20batchmintable", + contracts: "Multicall", + }, + abi: MulticallAbi, + features: {}, +} as const; + +export const FEATURE_TOKEN_MINTABLE = { + name: "ERC20Mintable", + namespace: "token.mint", + docLinks: { + sdk: "sdk.erc20mintable", + contracts: "IMintableERC20", + }, + abi: IMintableERC20Abi, + features: { + [FEATURE_TOKEN_BATCH_MINTABLE.name]: FEATURE_TOKEN_BATCH_MINTABLE, + }, +} as const; export const FEATURE_TOKEN = { name: "ERC20", @@ -8,5 +34,7 @@ export const FEATURE_TOKEN = { contracts: "ERC20", }, abi: ERC20Abi, - features: {}, + features: { + [FEATURE_TOKEN_MINTABLE.name]: FEATURE_TOKEN_MINTABLE, + }, } as const; diff --git a/src/contracts/smart-contract.ts b/src/contracts/smart-contract.ts index 03e201c0c..9cd31e49f 100644 --- a/src/contracts/smart-contract.ts +++ b/src/contracts/smart-contract.ts @@ -17,8 +17,6 @@ import { ContractWrapper } from "../core/classes/contract-wrapper"; import { AccessControlEnumerable, AccessControlEnumerable__factory, - ERC1155Metadata__factory, - ERC20Metadata__factory, IThirdwebContract, IThirdwebPlatformFee, IThirdwebPlatformFee__factory, @@ -224,12 +222,7 @@ export class SmartContract< } private detectErc20() { - if ( - implementsInterface( - this.contractWrapper, - ERC20Metadata__factory.createInterface(), - ) - ) { + if (detectContractFeature(this.contractWrapper, "ERC20")) { return new Erc20(this.contractWrapper, this.storage, this.options); } return undefined; @@ -243,12 +236,7 @@ export class SmartContract< } private detectErc1155() { - if ( - implementsInterface( - this.contractWrapper, - ERC1155Metadata__factory.createInterface(), // TODO should probably be more generic here to support multi interfaces - ) - ) { + if (detectContractFeature(this.contractWrapper, "ERC1155")) { return new Erc1155(this.contractWrapper, this.storage, this.options); } return undefined; diff --git a/src/contracts/token.ts b/src/contracts/token.ts index e61e0593f..1e2b090fa 100644 --- a/src/contracts/token.ts +++ b/src/contracts/token.ts @@ -49,6 +49,11 @@ export class Token extends Erc20 { */ static schema = TokenErc20ContractSchema; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + private _mint = this.mint!; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + private _batchMint = this.mint!.batch!; + public metadata: ContractMetadata; public roles: ContractRoles; public encoder: ContractEncoder; @@ -168,8 +173,8 @@ export class Token extends Erc20 { * * @remarks See {@link Token.mintTo} */ - public async mint(amount: Amount): Promise { - return this.mintTo(await this.contractWrapper.getSignerAddress(), amount); + public async mintToSelf(amount: Amount): Promise { + return this._mint.to(await this.contractWrapper.getSignerAddress(), amount); } /** @@ -186,12 +191,7 @@ export class Token extends Erc20 { * ``` */ public async mintTo(to: string, amount: Amount): Promise { - return { - receipt: await this.contractWrapper.sendTransaction("mintTo", [ - to, - await this.normalizeAmount(amount), - ]), - }; + return this._mint.to(to, amount); } /** @@ -217,16 +217,7 @@ export class Token extends Erc20 { * ``` */ public async mintBatchTo(args: TokenMintInput[]): Promise { - const encoded = []; - for (const arg of args) { - encoded.push( - this.contractWrapper.readContract.interface.encodeFunctionData( - "mintTo", - [arg.toAddress, await this.normalizeAmount(arg.amount)], - ), - ); - } - return { receipt: await this.contractWrapper.multiCall(encoded) }; + return this._batchMint.to(args); } /** diff --git a/src/core/classes/erc-20-batch-mintable.ts b/src/core/classes/erc-20-batch-mintable.ts new file mode 100644 index 000000000..d94506c1d --- /dev/null +++ b/src/core/classes/erc-20-batch-mintable.ts @@ -0,0 +1,54 @@ +import { ContractWrapper } from "./contract-wrapper"; +import { IMintableERC20, Multicall } from "contracts"; +import { Erc20 } from "./erc-20"; +import { BaseERC20 } from "../../types/eips"; +import { TokenMintInput } from "../../schema"; +import { TransactionResult } from "../types"; + +export class Erc20BatchMintable { + private contractWrapper: ContractWrapper; + private erc20: Erc20; + + constructor( + erc20: Erc20, + contractWrapper: ContractWrapper, + ) { + this.erc20 = erc20; + this.contractWrapper = contractWrapper; + } + + /** + * Mint Tokens To Many Wallets + * + * @remarks Mint tokens to many wallets in one transaction. + * + * @example + * ```javascript + * // Data of the tokens you want to mint + * const data = [ + * { + * toAddress: "{{wallet_address}}", // Address to mint tokens to + * amount: 0.2, // How many tokens to mint to specified address + * }, + * { + * toAddress: "0x...", + * amount: 1.4, + * } + * ] + * + * await contract.mintBatchTo(data); + * ``` + */ + public async to(args: TokenMintInput[]): Promise { + const encoded = []; + for (const arg of args) { + encoded.push( + this.contractWrapper.readContract.interface.encodeFunctionData( + "mintTo", + [arg.toAddress, await this.erc20.normalizeAmount(arg.amount)], + ), + ); + } + return { receipt: await this.contractWrapper.multiCall(encoded) }; + } +} diff --git a/src/core/classes/erc-20-mintable.ts b/src/core/classes/erc-20-mintable.ts new file mode 100644 index 000000000..eda6db3ba --- /dev/null +++ b/src/core/classes/erc-20-mintable.ts @@ -0,0 +1,61 @@ +import { ContractWrapper } from "./contract-wrapper"; +import { IMintableERC20, Multicall } from "contracts"; +import { TransactionResult } from "../types"; +import { detectContractFeature } from "../../common"; +import { BaseERC20 } from "../../types/eips"; +import { Erc20 } from "./erc-20"; +import { Amount } from "../../types"; +import { Erc20BatchMintable } from "./erc-20-batch-mintable"; + +export class Erc20Mintable { + private contractWrapper: ContractWrapper; + private erc20: Erc20; + + /** + * Batch mint Tokens to many addresses + */ + public batch: Erc20BatchMintable | undefined; + + constructor( + erc20: Erc20, + contractWrapper: ContractWrapper, + ) { + this.erc20 = erc20; + this.contractWrapper = contractWrapper; + this.batch = this.detectErc20BatchMintable(); + } + + /** + * Mint Tokens + * + * @remarks Mint tokens to a specified address. + * + * @example + * ```javascript + * const toAddress = "{{wallet_address}}"; // Address of the wallet you want to mint the tokens to + * const amount = "1.5"; // The amount of this token you want to mint + * + * await contract.mintTo(toAddress, amount); + * ``` + */ + public async to(to: string, amount: Amount): Promise { + return { + receipt: await this.contractWrapper.sendTransaction("mintTo", [ + to, + await this.erc20.normalizeAmount(amount), + ]), + }; + } + + private detectErc20BatchMintable() { + if ( + detectContractFeature( + this.contractWrapper, + "ERC20BatchMintable", + ) + ) { + return new Erc20BatchMintable(this.erc20, this.contractWrapper); + } + return undefined; + } +} diff --git a/src/core/classes/erc-20.ts b/src/core/classes/erc-20.ts index 1e733d1eb..b7194e2c0 100644 --- a/src/core/classes/erc-20.ts +++ b/src/core/classes/erc-20.ts @@ -1,5 +1,5 @@ import { ContractWrapper } from "./contract-wrapper"; -import { DropERC20, ERC20, ERC20Metadata, TokenERC20 } from "contracts"; +import { DropERC20, IMintableERC20, TokenERC20 } from "contracts"; import { BigNumber, BigNumberish, ethers } from "ethers"; import { IStorage } from "../interfaces"; import { NetworkOrSignerOrProvider, TransactionResult } from "../types"; @@ -13,6 +13,8 @@ import { import { TokenMintInput } from "../../schema/tokens/token"; import { PriceSchema } from "../../schema"; import { BaseERC20 } from "../../types/eips"; +import { detectContractFeature } from "../../common"; +import { Erc20Mintable } from "./erc-20-mintable"; /** * Standard ERC20 functions @@ -25,6 +27,11 @@ export class Erc20 protected storage: IStorage; protected options: SDKOptions; + /** + * Mint tokens + */ + public mint: Erc20Mintable | undefined; + constructor( contractWrapper: ContractWrapper, storage: IStorage, @@ -41,6 +48,7 @@ export class Erc20 ); this.options = SDKOptionsSchema.parse({}); } + this.mint = this.detectErc20Mintable(); } /** @@ -316,8 +324,20 @@ export class Erc20 ); } - protected async normalizeAmount(amount: Amount): Promise { + /** + * returns the wei amount from a token amount + * @internal + * @param amount + */ + public async normalizeAmount(amount: Amount): Promise { const decimals = await this.contractWrapper.readContract.decimals(); return ethers.utils.parseUnits(PriceSchema.parse(amount), decimals); } + + private detectErc20Mintable(): Erc20Mintable | undefined { + if (detectContractFeature(this.contractWrapper, "ERC20")) { + return new Erc20Mintable(this, this.contractWrapper); + } + return undefined; + } } diff --git a/src/core/classes/erc-721-batch-mintable.ts b/src/core/classes/erc-721-batch-mintable.ts index c858e3aac..f36c7f92e 100644 --- a/src/core/classes/erc-721-batch-mintable.ts +++ b/src/core/classes/erc-721-batch-mintable.ts @@ -1,19 +1,20 @@ import { ContractWrapper } from "./contract-wrapper"; -import { ERC721, ERC721Metadata, IMintableERC721, Multicall } from "contracts"; +import { IMintableERC721, Multicall } from "contracts"; import { NFTMetadataOrUri, NFTMetadataOwner } from "../../schema"; import { TransactionResultWithId } from "../types"; import { uploadOrExtractURIs } from "../../common/nft"; import { IStorage } from "../interfaces"; import { Erc721 } from "./erc-721"; import { TokensMintedEvent } from "contracts/IMintableERC721"; +import { BaseERC721 } from "../../types/eips"; export class Erc721BatchMintable { private contractWrapper: ContractWrapper; private storage: IStorage; - private erc721: Erc721; + private erc721: Erc721; constructor( - erc721: Erc721, + erc721: Erc721, contractWrapper: ContractWrapper, storage: IStorage, ) { diff --git a/src/core/classes/erc-721-mintable.ts b/src/core/classes/erc-721-mintable.ts index a2e1aebe3..1e591d042 100644 --- a/src/core/classes/erc-721-mintable.ts +++ b/src/core/classes/erc-721-mintable.ts @@ -1,5 +1,5 @@ import { ContractWrapper } from "./contract-wrapper"; -import { ERC721, ERC721Metadata, IMintableERC721, Multicall } from "contracts"; +import { IMintableERC721, Multicall } from "contracts"; import { NFTMetadataOrUri, NFTMetadataOwner } from "../../schema"; import { TransactionResultWithId } from "../types"; import { uploadOrExtractURI } from "../../common/nft"; @@ -8,16 +8,17 @@ import { Erc721 } from "./erc-721"; import { TokensMintedEvent } from "contracts/IMintableERC721"; import { Erc721BatchMintable } from "./erc-721-batch-mintable"; import { detectContractFeature } from "../../common"; +import { BaseERC721 } from "../../types/eips"; export class Erc721Mintable { private contractWrapper: ContractWrapper; private storage: IStorage; - private erc721: Erc721; + private erc721: Erc721; public batch: Erc721BatchMintable | undefined; constructor( - erc721: Erc721, + erc721: Erc721, contractWrapper: ContractWrapper, storage: IStorage, ) { diff --git a/src/schema/tokens/common/index.ts b/src/schema/tokens/common/index.ts index f64aac5e3..7c5569a89 100644 --- a/src/schema/tokens/common/index.ts +++ b/src/schema/tokens/common/index.ts @@ -12,7 +12,7 @@ import { OptionalPropertiesInput } from "./properties"; */ export const CommonTokenInput = z .object({ - name: z.string().nonempty({ message: "A name is required." }), + name: z.string().optional(), description: z.string().optional(), image: FileBufferOrStringSchema.optional(), external_url: FileBufferOrStringSchema.optional(), diff --git a/test/custom.test.ts b/test/custom.test.ts index 2b3bff329..9e728dd01 100644 --- a/test/custom.test.ts +++ b/test/custom.test.ts @@ -183,10 +183,8 @@ describe("Custom Contracts", async () => { const token = await c.token.get(); expect(token.name).to.eq("Token"); expect(token.decimals).to.eq(18); - await c.functions.mintTo( - adminWallet.address, - ethers.utils.parseEther("100"), - ); + invariant(c.token.mint, "ERC20Mintable undefined"); + await c.token.mint.to(adminWallet.address, 100); const balance = await c.token.balance(); expect(balance.displayValue).to.eq("100.0"); await c.token.transfer(samWallet.address, 25); diff --git a/test/token.test.ts b/test/token.test.ts index 5d8ac6128..4c57bce5d 100644 --- a/test/token.test.ts +++ b/test/token.test.ts @@ -35,7 +35,7 @@ describe("Token Contract", async () => { }); it("should mint tokens", async () => { - await currencyContract.mint("20"); + await currencyContract.mintToSelf("20"); assert.deepEqual( (await currencyContract.totalSupply()).value, ethers.utils.parseEther("20"), @@ -49,7 +49,7 @@ describe("Token Contract", async () => { }); it("should transfer tokens", async () => { - await currencyContract.mint(20.2); + await currencyContract.mintToSelf(20.2); await currencyContract.transfer(samWallet.address, 10.1); assert.deepEqual( (await currencyContract.balanceOf(adminWallet.address)).value, @@ -64,7 +64,7 @@ describe("Token Contract", async () => { }); it("should list current holders", async () => { - await currencyContract.mint(20); + await currencyContract.mintToSelf(20); await currencyContract.transfer(samWallet.address, "10"); await currencyContract.transfer(bobWallet.address, "5"); sdk.updateSignerOrProvider(samWallet); @@ -85,7 +85,7 @@ describe("Token Contract", async () => { }); it("should burn tokens", async () => { - await currencyContract.mint(20); + await currencyContract.mintToSelf(20); assert.deepEqual( (await currencyContract.balanceOf(adminWallet.address)).value, ethers.utils.parseEther("20"), @@ -137,7 +137,7 @@ describe("Token Contract", async () => { amount: 10, }, ]; - await currencyContract.mint(20); + await currencyContract.mintToSelf(20); await currencyContract.transferBatch(batch); for (const b of batch) { From 7a2312d0b470b1c36961c153eb69b75b9530f197 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Mon, 2 May 2022 14:29:27 -0700 Subject: [PATCH 3/5] add 1155 feature detection --- src/constants/contract-features.ts | 12 +- src/constants/erc1155-features.ts | 27 ++++ src/contracts/edition.ts | 83 ++---------- src/core/classes/erc-1155-batch-mintable.ts | 92 ++++++++++++++ src/core/classes/erc-1155-mintable.ts | 133 ++++++++++++++++++++ src/core/classes/erc-1155.ts | 27 ++-- src/core/classes/erc-721-supply.ts | 12 +- test/custom.test.ts | 33 +++++ 8 files changed, 330 insertions(+), 89 deletions(-) create mode 100644 src/core/classes/erc-1155-batch-mintable.ts create mode 100644 src/core/classes/erc-1155-mintable.ts diff --git a/src/constants/contract-features.ts b/src/constants/contract-features.ts index c60a46b81..1b15231b3 100644 --- a/src/constants/contract-features.ts +++ b/src/constants/contract-features.ts @@ -1,6 +1,3 @@ -/** - * @internal - */ import { FEATURE_NFT, FEATURE_NFT_BATCH_MINTABLE, @@ -15,9 +12,14 @@ import { } from "./erc20-features"; import { FEATURE_EDITION, + FEATURE_EDITION_BATCH_MINTABLE, FEATURE_EDITION_ENUMERABLE, + FEATURE_EDITION_MINTABLE, } from "./erc1155-features"; +/** + * @internal + */ export type Feature = | typeof FEATURE_TOKEN | typeof FEATURE_TOKEN_MINTABLE @@ -28,7 +30,9 @@ export type Feature = | typeof FEATURE_NFT_MINTABLE | typeof FEATURE_NFT_BATCH_MINTABLE | typeof FEATURE_EDITION - | typeof FEATURE_EDITION_ENUMERABLE; + | typeof FEATURE_EDITION_ENUMERABLE + | typeof FEATURE_EDITION_MINTABLE + | typeof FEATURE_EDITION_BATCH_MINTABLE; /** * @internal diff --git a/src/constants/erc1155-features.ts b/src/constants/erc1155-features.ts index 4eeba3f31..1ff5c9da9 100644 --- a/src/constants/erc1155-features.ts +++ b/src/constants/erc1155-features.ts @@ -1,5 +1,31 @@ import Erc1155EnumerableAbi from "../../abis/ERC1155Enumerable.json"; import Erc1155Abi from "../../abis/ERC1155.json"; +import MulticallAbi from "../../abis/Multicall.json"; +import IMintableERC1155Abi from "../../abis/IMintableERC1155.json"; + +export const FEATURE_EDITION_BATCH_MINTABLE = { + name: "ERC1155BatchMintable", + namespace: "token.mint.batch", + docLinks: { + sdk: "sdk.erc1155batchmintable", + contracts: "Multicall", + }, + abi: MulticallAbi, + features: {}, +} as const; + +export const FEATURE_EDITION_MINTABLE = { + name: "ERC1155Mintable", + namespace: "token.mint", + docLinks: { + sdk: "sdk.erc1155mintable", + contracts: "IMintableERC1155", + }, + abi: IMintableERC1155Abi, + features: { + [FEATURE_EDITION_BATCH_MINTABLE.name]: FEATURE_EDITION_BATCH_MINTABLE, + }, +} as const; export const FEATURE_EDITION_ENUMERABLE = { name: "ERC1155Enumerable", @@ -22,5 +48,6 @@ export const FEATURE_EDITION = { abi: Erc1155Abi, features: { [FEATURE_EDITION_ENUMERABLE.name]: FEATURE_EDITION_ENUMERABLE, + [FEATURE_EDITION_MINTABLE.name]: FEATURE_EDITION_MINTABLE, }, } as const; diff --git a/src/contracts/edition.ts b/src/contracts/edition.ts index a362dc0dd..59fddc635 100644 --- a/src/contracts/edition.ts +++ b/src/contracts/edition.ts @@ -19,16 +19,14 @@ import { EditionMetadataOwner, } from "../schema/tokens/edition"; import { - ContractInterceptor, ContractEncoder, ContractEvents, + ContractInterceptor, ContractPlatformFee, } from "../core/classes"; -import { BigNumber, BigNumberish, ethers } from "ethers"; +import { BigNumber, BigNumberish } from "ethers"; import { Erc1155SignatureMinting } from "../core/classes/erc-1155-signature-minting"; import { GasCostEstimator } from "../core/classes/gas-cost-estimator"; -import { uploadOrExtractURI, uploadOrExtractURIs } from "../common/nft"; -import { TokensMintedEvent } from "contracts/TokenERC1155"; import { getRoleHash } from "../common"; import { AddressZero } from "@ethersproject/constants"; import { QueryAllParams } from "../types"; @@ -56,6 +54,10 @@ export class Edition extends Erc1155 { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion private _query = this.query!; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + private _mint = this.mint!; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + private _batchMint = this.mint!.batch!; /** * @internal */ @@ -191,10 +193,10 @@ export class Edition extends Erc1155 { * * @remarks See {@link Edition.mintTo} */ - public async mint( + public async mintToSelf( metadataWithSupply: EditionMetadataOrUri, ): Promise> { - return this.mintTo( + return this._mint.to( await this.contractWrapper.getSignerAddress(), metadataWithSupply, ); @@ -232,29 +234,7 @@ export class Edition extends Erc1155 { to: string, metadataWithSupply: EditionMetadataOrUri, ): Promise> { - const uri = await uploadOrExtractURI( - metadataWithSupply.metadata, - this.storage, - ); - const receipt = await this.contractWrapper.sendTransaction("mintTo", [ - to, - ethers.constants.MaxUint256, - uri, - metadataWithSupply.supply, - ]); - const event = this.contractWrapper.parseLogs( - "TokensMinted", - receipt?.logs, - ); - if (event.length === 0) { - throw new Error("TokenMinted event not found"); - } - const id = event[0].args.tokenIdMinted; - return { - id, - receipt, - data: () => this.get(id.toString()), - }; + return this._mint.to(to, metadataWithSupply); } /** @@ -267,7 +247,7 @@ export class Edition extends Erc1155 { tokenId: BigNumberish, additionalSupply: BigNumberish, ): Promise> { - return this.mintAdditionalSupplyTo( + return this._mint.additionalSupplyTo( await this.contractWrapper.getSignerAddress(), tokenId, additionalSupply, @@ -286,18 +266,7 @@ export class Edition extends Erc1155 { tokenId: BigNumberish, additionalSupply: BigNumberish, ): Promise> { - const metadata = await this.getTokenMetadata(tokenId); - const receipt = await this.contractWrapper.sendTransaction("mintTo", [ - to, - tokenId, - metadata.uri, - additionalSupply, - ]); - return { - id: BigNumber.from(tokenId), - receipt, - data: () => this.get(tokenId), - }; + return this._mint.additionalSupplyTo(to, tokenId, additionalSupply); } /** @@ -308,7 +277,7 @@ export class Edition extends Erc1155 { public async mintBatch( metadatas: EditionMetadataOrUri[], ): Promise[]> { - return this.mintBatchTo( + return this._batchMint.to( await this.contractWrapper.getSignerAddress(), metadatas, ); @@ -351,33 +320,7 @@ export class Edition extends Erc1155 { to: string, metadataWithSupply: EditionMetadataOrUri[], ): Promise[]> { - const metadatas = metadataWithSupply.map((a) => a.metadata); - const supplies = metadataWithSupply.map((a) => a.supply); - const uris = await uploadOrExtractURIs(metadatas, this.storage); - const encoded = uris.map((uri, index) => - this.contractWrapper.readContract.interface.encodeFunctionData("mintTo", [ - to, - ethers.constants.MaxUint256, - uri, - supplies[index], - ]), - ); - const receipt = await this.contractWrapper.multiCall(encoded); - const events = this.contractWrapper.parseLogs( - "TokensMinted", - receipt.logs, - ); - if (events.length === 0 || events.length < metadatas.length) { - throw new Error("TokenMinted event not found, minting failed"); - } - return events.map((e) => { - const id = e.args.tokenIdMinted; - return { - id, - receipt, - data: () => this.get(id), - }; - }); + return this._batchMint.to(to, metadataWithSupply); } /** diff --git a/src/core/classes/erc-1155-batch-mintable.ts b/src/core/classes/erc-1155-batch-mintable.ts new file mode 100644 index 000000000..99f74e954 --- /dev/null +++ b/src/core/classes/erc-1155-batch-mintable.ts @@ -0,0 +1,92 @@ +import { ContractWrapper } from "./contract-wrapper"; +import { IMintableERC1155, Multicall } from "contracts"; +import { TransactionResultWithId } from "../types"; +import { BaseERC1155 } from "../../types/eips"; +import { Erc1155 } from "./erc-1155"; +import { EditionMetadata, EditionMetadataOrUri } from "../../schema"; +import { uploadOrExtractURIs } from "../../common/nft"; +import { ethers } from "ethers"; +import { TokensMintedEvent } from "contracts/TokenERC1155"; +import { IStorage } from "../interfaces"; + +export class Erc1155BatchMintable { + private contractWrapper: ContractWrapper; + private erc1155: Erc1155; + private storage: IStorage; + + constructor( + erc1155: Erc1155, + contractWrapper: ContractWrapper, + storage: IStorage, + ) { + this.erc1155 = erc1155; + this.contractWrapper = contractWrapper; + this.storage = storage; + } + + /** + * Mint Many NFTs with limited supplies + * + * @remarks Mint many different NFTs with limited supplies to a specified wallet. + * + * @example + * ```javascript + * // Address of the wallet you want to mint the NFT to + * const toAddress = "{{wallet_address}}" + * + * // Custom metadata and supplies of your NFTs + * const metadataWithSupply = [{ + * supply: 50, // The number of this NFT you want to mint + * metadata: { + * name: "Cool NFT #1", + * description: "This is a cool NFT", + * image: fs.readFileSync("path/to/image.png"), // This can be an image url or file + * }, + * }, { + * supply: 100, + * metadata: { + * name: "Cool NFT #2", + * description: "This is a cool NFT", + * image: fs.readFileSync("path/to/image.png"), // This can be an image url or file + * }, + * }]; + * + * const tx = await contract.mintBatchTo(toAddress, metadataWithSupply); + * const receipt = tx[0].receipt; // same transaction receipt for all minted NFTs + * const firstTokenId = tx[0].id; // token id of the first minted NFT + * const firstNFT = await tx[0].data(); // (optional) fetch details of the first minted NFT + * ``` + */ + public async to( + to: string, + metadataWithSupply: EditionMetadataOrUri[], + ): Promise[]> { + const metadatas = metadataWithSupply.map((a) => a.metadata); + const supplies = metadataWithSupply.map((a) => a.supply); + const uris = await uploadOrExtractURIs(metadatas, this.storage); + const encoded = uris.map((uri, index) => + this.contractWrapper.readContract.interface.encodeFunctionData("mintTo", [ + to, + ethers.constants.MaxUint256, + uri, + supplies[index], + ]), + ); + const receipt = await this.contractWrapper.multiCall(encoded); + const events = this.contractWrapper.parseLogs( + "TokensMinted", + receipt.logs, + ); + if (events.length === 0 || events.length < metadatas.length) { + throw new Error("TokenMinted event not found, minting failed"); + } + return events.map((e) => { + const id = e.args.tokenIdMinted; + return { + id, + receipt, + data: () => this.erc1155.get(id), + }; + }); + } +} diff --git a/src/core/classes/erc-1155-mintable.ts b/src/core/classes/erc-1155-mintable.ts new file mode 100644 index 000000000..6aecc8135 --- /dev/null +++ b/src/core/classes/erc-1155-mintable.ts @@ -0,0 +1,133 @@ +import { ContractWrapper } from "./contract-wrapper"; +import { IMintableERC1155, Multicall } from "contracts"; +import { detectContractFeature } from "../../common"; +import { BaseERC1155 } from "../../types/eips"; +import { Erc1155 } from "./erc-1155"; +import { Erc1155BatchMintable } from "./erc-1155-batch-mintable"; +import { EditionMetadata, EditionMetadataOrUri } from "../../schema"; +import { TransactionResultWithId } from "../types"; +import { uploadOrExtractURI } from "../../common/nft"; +import { BigNumber, BigNumberish, ethers } from "ethers"; +import { TokensMintedEvent } from "contracts/TokenERC1155"; +import { IStorage } from "../interfaces"; + +export class Erc1155Mintable { + private contractWrapper: ContractWrapper; + private erc1155: Erc1155; + private storage: IStorage; + + /** + * Batch mint Tokens to many addresses + */ + public batch: Erc1155BatchMintable | undefined; + + constructor( + erc1155: Erc1155, + contractWrapper: ContractWrapper, + storage: IStorage, + ) { + this.erc1155 = erc1155; + this.contractWrapper = contractWrapper; + this.storage = storage; + this.batch = this.detectErc1155BatchMintable(); + } + + /** + * Mint an NFT with a limited supply + * + * @remarks Mint an NFT with a limited supply to a specified wallet. + * + * @example + * ```javascript + * // Address of the wallet you want to mint the NFT to + * const toAddress = "{{wallet_address}}" + * + * // Custom metadata of the NFT, note that you can fully customize this metadata with other properties. + * const metadata = { + * name: "Cool NFT", + * description: "This is a cool NFT", + * image: fs.readFileSync("path/to/image.png"), // This can be an image url or file + * } + * + * const metadataWithSupply = { + * metadata, + * supply: 1000, // The number of this NFT you want to mint + * } + * + * const tx = await contract.mintTo(toAddress, metadataWithSupply); + * const receipt = tx.receipt; // the transaction receipt + * const tokenId = tx.id; // the id of the NFT minted + * const nft = await tx.data(); // (optional) fetch details of minted NFT + * ``` + */ + public async to( + to: string, + metadataWithSupply: EditionMetadataOrUri, + ): Promise> { + const uri = await uploadOrExtractURI( + metadataWithSupply.metadata, + this.storage, + ); + const receipt = await this.contractWrapper.sendTransaction("mintTo", [ + to, + ethers.constants.MaxUint256, + uri, + metadataWithSupply.supply, + ]); + const event = this.contractWrapper.parseLogs( + "TokensMinted", + receipt?.logs, + ); + if (event.length === 0) { + throw new Error("TokenMinted event not found"); + } + const id = event[0].args.tokenIdMinted; + return { + id, + receipt, + data: () => this.erc1155.get(id.toString()), + }; + } + + /** + * Increase the supply of an existing NFT and mint it to a given wallet address + * + * @param to - the address to mint to + * @param tokenId - the token id of the NFT to increase supply of + * @param additionalSupply - the additional amount to mint + */ + public async additionalSupplyTo( + to: string, + tokenId: BigNumberish, + additionalSupply: BigNumberish, + ): Promise> { + const metadata = await this.erc1155.getTokenMetadata(tokenId); + const receipt = await this.contractWrapper.sendTransaction("mintTo", [ + to, + tokenId, + metadata.uri, + additionalSupply, + ]); + return { + id: BigNumber.from(tokenId), + receipt, + data: () => this.erc1155.get(tokenId), + }; + } + + private detectErc1155BatchMintable() { + if ( + detectContractFeature( + this.contractWrapper, + "ERC1155BatchMintable", + ) + ) { + return new Erc1155BatchMintable( + this.erc1155, + this.contractWrapper, + this.storage, + ); + } + return undefined; + } +} diff --git a/src/core/classes/erc-1155.ts b/src/core/classes/erc-1155.ts index af83de680..06937d113 100644 --- a/src/core/classes/erc-1155.ts +++ b/src/core/classes/erc-1155.ts @@ -2,7 +2,7 @@ import { ContractWrapper } from "./contract-wrapper"; import { DropERC1155, ERC1155Enumerable, - ERC1155Enumerable__factory, + IMintableERC1155, TokenERC1155, } from "contracts"; import { BigNumber, BigNumberish, BytesLike } from "ethers"; @@ -16,11 +16,12 @@ import { EditionMetadataOutputSchema, } from "../../schema/tokens/edition"; import { fetchTokenMetadata } from "../../common/nft"; -import { implementsInterface, NotFoundError } from "../../common"; +import { detectContractFeature, NotFoundError } from "../../common"; import { AirdropInput } from "../../types/airdrop/airdrop"; import { AirdropInputSchema } from "../../schema/contracts/common/airdrop"; import { BaseERC1155 } from "../../types/eips"; import { Erc1155Enumerable } from "./erc-1155-enumerable"; +import { Erc1155Mintable } from "./erc-1155-mintable"; /** * Standard ERC1155 functions @@ -34,6 +35,7 @@ export class Erc1155 protected options: SDKOptions; public query: Erc1155Enumerable | undefined; + public mint: Erc1155Mintable | undefined; constructor( contractWrapper: ContractWrapper, @@ -52,6 +54,7 @@ export class Erc1155 this.options = SDKOptionsSchema.parse({}); } this.query = this.detectErc1155Enumerable(); + this.mint = this.detectErc1155Mintable(); } /** @@ -280,9 +283,7 @@ export class Erc1155 * @internal * @param tokenId - the token Id to fetch */ - protected async getTokenMetadata( - tokenId: BigNumberish, - ): Promise { + public async getTokenMetadata(tokenId: BigNumberish): Promise { const tokenUri = await this.contractWrapper.readContract.uri(tokenId); if (!tokenUri) { throw new NotFoundError(); @@ -292,13 +293,25 @@ export class Erc1155 private detectErc1155Enumerable(): Erc1155Enumerable | undefined { if ( - implementsInterface( + detectContractFeature( this.contractWrapper, - ERC1155Enumerable__factory.createInterface(), + "ERC1155Enumerable", ) ) { return new Erc1155Enumerable(this, this.contractWrapper); } return undefined; } + + private detectErc1155Mintable(): Erc1155Mintable | undefined { + if ( + detectContractFeature( + this.contractWrapper, + "ERC1155Mintable", + ) + ) { + return new Erc1155Mintable(this, this.contractWrapper, this.storage); + } + return undefined; + } } diff --git a/src/core/classes/erc-721-supply.ts b/src/core/classes/erc-721-supply.ts index 8a14fcd45..40dc2ed9f 100644 --- a/src/core/classes/erc-721-supply.ts +++ b/src/core/classes/erc-721-supply.ts @@ -1,15 +1,11 @@ import { ContractWrapper } from "./contract-wrapper"; -import { - ERC721Enumerable, - ERC721Enumerable__factory, - ERC721Supply, -} from "contracts"; +import { ERC721Enumerable, ERC721Supply } from "contracts"; import { BigNumber } from "ethers"; import { DEFAULT_QUERY_ALL_COUNT, QueryAllParams } from "../../types"; import { NFTMetadataOwner } from "../../schema"; import { Erc721 } from "./erc-721"; import { BaseERC721 } from "../../types/eips"; -import { implementsInterface } from "../../common"; +import { detectContractFeature } from "../../common"; import { Erc721Enumerable } from "./erc-721-enumerable"; export class Erc721Supply { @@ -69,9 +65,9 @@ export class Erc721Supply { private detectErc721Owned(): Erc721Enumerable | undefined { if ( - implementsInterface( + detectContractFeature( this.contractWrapper, - ERC721Enumerable__factory.createInterface(), + "ERC721Enumerable", ) ) { return new Erc721Enumerable(this.erc721, this.contractWrapper); diff --git a/test/custom.test.ts b/test/custom.test.ts index 9e728dd01..b1e426bc2 100644 --- a/test/custom.test.ts +++ b/test/custom.test.ts @@ -2,6 +2,7 @@ import { sdk, signers } from "./before-setup"; import { expect } from "chai"; import invariant from "tiny-invariant"; import { + TokenERC1155__factory, TokenERC20__factory, TokenERC721__factory, VoteERC20__factory, @@ -18,6 +19,7 @@ describe("Custom Contracts", async () => { let customContractAddress: string; let nftContractAddress: string; let tokenContractAddress: string; + let editionContractAddress: string; let adminWallet: SignerWithAddress, samWallet: SignerWithAddress, bobWallet: SignerWithAddress; @@ -53,6 +55,17 @@ describe("Custom Contracts", async () => { platform_fee_basis_points: 10, platform_fee_recipient: adminWallet.address, }); + editionContractAddress = await sdk.deployer.deployEdition({ + name: `Edition`, + description: "Test contract from tests", + image: + "https://pbs.twimg.com/profile_images/1433508973215367176/XBCfBn3g_400x400.jpg", + primary_sale_recipient: samWallet.address, + seller_fee_basis_points: 500, + fee_recipient: bobWallet.address, + platform_fee_basis_points: 10, + platform_fee_recipient: adminWallet.address, + }); tokenContractAddress = await sdk.deployer.deployToken({ name: `Token`, description: "Test contract from tests", @@ -210,4 +223,24 @@ describe("Custom Contracts", async () => { expect(nfts.length).to.eq(1); expect(nfts[0].metadata.name).to.eq("Custom NFT"); }); + + it("should detect feature: erc1155", async () => { + const c = await sdk.getContractFromAbi( + editionContractAddress, + TokenERC1155__factory.abi, + ); + invariant(c, "Contract undefined"); + invariant(c.edition, "ERC1155 undefined"); + invariant(c.edition.query, "ERC1155 query undefined"); + invariant(c.edition.mint, "ERC1155 minter undefined"); + await c.edition.mint.to(adminWallet.address, { + metadata: { + name: "Custom NFT", + }, + supply: 100, + }); + const nfts = await c.edition.query.all(); + expect(nfts.length).to.eq(1); + expect(nfts[0].metadata.name).to.eq("Custom NFT"); + }); }); From b7c3360868555fcc5d97801f831c15a8a9206501 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Mon, 2 May 2022 14:39:30 -0700 Subject: [PATCH 4/5] build docs --- docs/sdk.edition.md | 2 +- ...{sdk.edition.mint.md => sdk.edition.minttoself.md} | 6 +++--- docs/sdk.erc1155.md | 1 + docs/sdk.erc1155.mint.md | 11 +++++++++++ etc/sdk.api.md | 8 ++++++-- src/constants/erc1155-features.ts | 4 ++-- 6 files changed, 24 insertions(+), 8 deletions(-) rename docs/{sdk.edition.mint.md => sdk.edition.minttoself.md} (71%) create mode 100644 docs/sdk.erc1155.mint.md diff --git a/docs/sdk.edition.md b/docs/sdk.edition.md index 978524e6a..1ba88f07b 100644 --- a/docs/sdk.edition.md +++ b/docs/sdk.edition.md @@ -57,10 +57,10 @@ const contract = sdk.getEdition("{{contract_address}}"); | [getOwned(walletAddress)](./sdk.edition.getowned.md) | | Get Owned NFTs | | [getTotalCount()](./sdk.edition.gettotalcount.md) | | Get the number of NFTs minted | | [isTransferRestricted()](./sdk.edition.istransferrestricted.md) | | Get whether users can transfer NFTs from this contract | -| [mint(metadataWithSupply)](./sdk.edition.mint.md) | | Mint NFT for the connected wallet | | [mintAdditionalSupply(tokenId, additionalSupply)](./sdk.edition.mintadditionalsupply.md) | | Increase the supply of an existing NFT and mint it to the connected wallet | | [mintAdditionalSupplyTo(to, tokenId, additionalSupply)](./sdk.edition.mintadditionalsupplyto.md) | | Increase the supply of an existing NFT and mint it to a given wallet address | | [mintBatch(metadatas)](./sdk.edition.mintbatch.md) | | Mint Many NFTs for the connected wallet | | [mintBatchTo(to, metadataWithSupply)](./sdk.edition.mintbatchto.md) | | Mint Many NFTs with limited supplies | | [mintTo(to, metadataWithSupply)](./sdk.edition.mintto.md) | | Mint an NFT with a limited supply | +| [mintToSelf(metadataWithSupply)](./sdk.edition.minttoself.md) | | Mint NFT for the connected wallet | diff --git a/docs/sdk.edition.mint.md b/docs/sdk.edition.minttoself.md similarity index 71% rename from docs/sdk.edition.mint.md rename to docs/sdk.edition.minttoself.md index edb5bda61..b3ef002b9 100644 --- a/docs/sdk.edition.mint.md +++ b/docs/sdk.edition.minttoself.md @@ -1,15 +1,15 @@ -[Home](./index.md) > [@thirdweb-dev/sdk](./sdk.md) > [Edition](./sdk.edition.md) > [mint](./sdk.edition.mint.md) +[Home](./index.md) > [@thirdweb-dev/sdk](./sdk.md) > [Edition](./sdk.edition.md) > [mintToSelf](./sdk.edition.minttoself.md) -## Edition.mint() method +## Edition.mintToSelf() method Mint NFT for the connected wallet Signature: ```typescript -mint(metadataWithSupply: EditionMetadataOrUri): Promise>; +mintToSelf(metadataWithSupply: EditionMetadataOrUri): Promise>; ``` ## Parameters diff --git a/docs/sdk.erc1155.md b/docs/sdk.erc1155.md index 38a5704bf..fde88a00c 100644 --- a/docs/sdk.erc1155.md +++ b/docs/sdk.erc1155.md @@ -24,6 +24,7 @@ export declare class Erc1155 | Property | Modifiers | Type | Description | | --- | --- | --- | --- | | [contractWrapper](./sdk.erc1155.contractwrapper.md) | | ContractWrapper<T> | | +| [mint](./sdk.erc1155.mint.md) | | Erc1155Mintable \| undefined | | | [options](./sdk.erc1155.options.md) | | [SDKOptions](./sdk.sdkoptions.md) | | | [query](./sdk.erc1155.query.md) | | [Erc1155Enumerable](./sdk.erc1155enumerable.md) \| undefined | | | [storage](./sdk.erc1155.storage.md) | | [IStorage](./sdk.istorage.md) | | diff --git a/docs/sdk.erc1155.mint.md b/docs/sdk.erc1155.mint.md new file mode 100644 index 000000000..724511061 --- /dev/null +++ b/docs/sdk.erc1155.mint.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@thirdweb-dev/sdk](./sdk.md) > [Erc1155](./sdk.erc1155.md) > [mint](./sdk.erc1155.mint.md) + +## Erc1155.mint property + +Signature: + +```typescript +mint: Erc1155Mintable | undefined; +``` diff --git a/etc/sdk.api.md b/etc/sdk.api.md index f3d874af5..1c073e454 100644 --- a/etc/sdk.api.md +++ b/etc/sdk.api.md @@ -937,12 +937,12 @@ export class Edition extends Erc1155 { isTransferRestricted(): Promise; // (undocumented) metadata: ContractMetadata; - mint(metadataWithSupply: EditionMetadataOrUri): Promise>; mintAdditionalSupply(tokenId: BigNumberish, additionalSupply: BigNumberish): Promise>; mintAdditionalSupplyTo(to: string, tokenId: BigNumberish, additionalSupply: BigNumberish): Promise>; mintBatch(metadatas: EditionMetadataOrUri[]): Promise[]>; mintBatchTo(to: string, metadataWithSupply: EditionMetadataOrUri[]): Promise[]>; mintTo(to: string, metadataWithSupply: EditionMetadataOrUri): Promise>; + mintToSelf(metadataWithSupply: EditionMetadataOrUri): Promise>; // (undocumented) platformFee: ContractPlatformFee; // (undocumented) @@ -1504,8 +1504,12 @@ export class Erc1155 impleme // (undocumented) getAddress(): string; // @internal (undocumented) - protected getTokenMetadata(tokenId: BigNumberish): Promise; + getTokenMetadata(tokenId: BigNumberish): Promise; isApproved(address: string, operator: string): Promise; + // Warning: (ae-forgotten-export) The symbol "Erc1155Mintable" needs to be exported by the entry point index.d.ts + // + // (undocumented) + mint: Erc1155Mintable | undefined; // @internal (undocumented) onNetworkUpdated(network: NetworkOrSignerOrProvider): void; // (undocumented) diff --git a/src/constants/erc1155-features.ts b/src/constants/erc1155-features.ts index 1ff5c9da9..b3176620b 100644 --- a/src/constants/erc1155-features.ts +++ b/src/constants/erc1155-features.ts @@ -5,7 +5,7 @@ import IMintableERC1155Abi from "../../abis/IMintableERC1155.json"; export const FEATURE_EDITION_BATCH_MINTABLE = { name: "ERC1155BatchMintable", - namespace: "token.mint.batch", + namespace: "edition.mint.batch", docLinks: { sdk: "sdk.erc1155batchmintable", contracts: "Multicall", @@ -16,7 +16,7 @@ export const FEATURE_EDITION_BATCH_MINTABLE = { export const FEATURE_EDITION_MINTABLE = { name: "ERC1155Mintable", - namespace: "token.mint", + namespace: "edition.mint", docLinks: { sdk: "sdk.erc1155mintable", contracts: "IMintableERC1155", From 6e4a14331880bf656073068dce87dc711755df25 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Mon, 2 May 2022 14:59:36 -0700 Subject: [PATCH 5/5] fix tests --- test/edition.test.ts | 10 +++++----- test/royalty.test.ts | 2 +- test/signature-mint-1155.test.ts | 10 +++++++--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/test/edition.test.ts b/test/edition.test.ts index fb846997e..aad34d941 100644 --- a/test/edition.test.ts +++ b/test/edition.test.ts @@ -73,7 +73,7 @@ describe("Bundle Contract (aka Collection Contract)", async () => { }); it("mint additional suply", async () => { - const tx = await bundleContract.mint({ + const tx = await bundleContract.mintToSelf({ metadata: { name: "Bundle 1", description: "Bundle 1", @@ -92,7 +92,7 @@ describe("Bundle Contract (aka Collection Contract)", async () => { const uri = await storage.uploadMetadata({ name: "Test1", }); - await bundleContract.mint({ + await bundleContract.mintToSelf({ metadata: uri, supply: 10, }); @@ -117,7 +117,7 @@ describe("Bundle Contract (aka Collection Contract)", async () => { }); it("should return all owned collection tokens", async () => { - await bundleContract.mint({ + await bundleContract.mintToSelf({ metadata: { name: "Bundle 1", description: "Bundle 1", @@ -147,7 +147,7 @@ describe("Bundle Contract (aka Collection Contract)", async () => { }); it("should airdrop edition tokens to different wallets", async () => { - await bundleContract.mint({ + await bundleContract.mintToSelf({ metadata: { name: "Bundle 1", description: "Bundle 1", @@ -175,7 +175,7 @@ describe("Bundle Contract (aka Collection Contract)", async () => { }); it("should fail airdrop because not enough NFTs owned", async () => { - await bundleContract.mint({ + await bundleContract.mintToSelf({ metadata: { name: "Bundle 1", description: "Bundle 1", diff --git a/test/royalty.test.ts b/test/royalty.test.ts index 952166ee8..b13807d0b 100644 --- a/test/royalty.test.ts +++ b/test/royalty.test.ts @@ -29,7 +29,7 @@ describe("Royalties", async () => { }), ); - await bundleContract.mint({ + await bundleContract.mintToSelf({ metadata: { name: "Cool NFT", }, diff --git a/test/signature-mint-1155.test.ts b/test/signature-mint-1155.test.ts index 36ec24d86..0009622d8 100644 --- a/test/signature-mint-1155.test.ts +++ b/test/signature-mint-1155.test.ts @@ -125,8 +125,9 @@ describe("Edition sig minting", async () => { ]; const batch = await editionContract.signature.generateBatch(input); - for (const [i, v] of batch.entries()) { - const tx = await editionContract.signature.mint(v); + for (let i = 0; i < batch.length; i++) { + const entry = batch[i]; + const tx = await editionContract.signature.mint(entry); const mintedId = (await editionContract.get(tx.id)).metadata.id; const nft = await editionContract.get(mintedId); assert.equal(input[i].metadata.name, nft.metadata.name); @@ -240,7 +241,10 @@ describe("Edition sig minting", async () => { samWallet.address, "0", ); - await editionContract.mint({ metadata: { name: "test" }, supply: 0 }); + await editionContract.mintToSelf({ + metadata: { name: "test" }, + supply: 0, + }); const payload = await editionContract.signature.generate({ tokenId: "0", quantity: "1",