diff --git a/src/contracts/token-drop.ts b/src/contracts/token-drop.ts index fb0afc796..5d2a68a9c 100644 --- a/src/contracts/token-drop.ts +++ b/src/contracts/token-drop.ts @@ -17,7 +17,7 @@ import { Amount, CurrencyValue } from "../types"; import { DropErc20ContractSchema } from "../schema/contracts/drop-erc20"; import { getRoleHash } from "../common"; import { Erc20Burnable } from "../core/classes/erc-20-burnable"; -import { Erc20Droppable } from "../core/classes/erc-20-droppable"; +import { Erc20Claimable } from "../core/classes/erc-20-claimable"; /** * Create a Drop contract for a standard crypto token or cryptocurrency. @@ -42,7 +42,7 @@ export class TokenDrop extends Erc20 { static schema = DropErc20ContractSchema; private _burn = this.burn as Erc20Burnable; - private _drop = this.drop as Erc20Droppable; + private _claim = this.drop?.claim as Erc20Claimable; public metadata: ContractMetadata; public roles: ContractRoles< @@ -213,7 +213,7 @@ export class TokenDrop extends Erc20 { amount: Amount, checkERC20Allowance = true, ): Promise { - return this._drop.claimTo(destinationAddress, amount, checkERC20Allowance); + return this._claim.to(destinationAddress, amount, checkERC20Allowance); } /** diff --git a/src/core/classes/erc-20-claimable.ts b/src/core/classes/erc-20-claimable.ts new file mode 100644 index 000000000..a98753a11 --- /dev/null +++ b/src/core/classes/erc-20-claimable.ts @@ -0,0 +1,126 @@ +import { CustomContractSchema } from "../../schema/contracts/custom"; +import { ClaimVerification } from "../../types"; +import { Amount } from "../../types/currency"; +import { BaseDropERC20 } from "../../types/eips"; +import { IStorage } from "@thirdweb-dev/storage"; +import { TransactionResult } from "../types"; +import { ContractMetadata } from "./contract-metadata"; +import { ContractWrapper } from "./contract-wrapper"; +import { DropClaimConditions } from "./drop-claim-conditions"; +import { Erc20 } from "./erc-20"; + +/** + * Configure and claim ERC20 tokens + * @remarks Manage claim phases and claim ERC20 tokens that have been lazily minted. + * @example + * ```javascript + * const contract = await sdk.getContract("{{contract_address}}"); + * await contract.token.drop.claim.to("0x...", quantity); + * ``` + */ +export class Erc20Claimable { + /** + * Configure claim conditions + * @remarks Define who can claim NFTs in the collection, when and how many. + * @example + * ```javascript + * const presaleStartTime = new Date(); + * const publicSaleStartTime = new Date(Date.now() + 60 * 60 * 24 * 1000); + * const claimConditions = [ + * { + * startTime: presaleStartTime, // start the presale now + * maxQuantity: 2, // limit how many mints for this presale + * price: 0.01, // presale price + * snapshot: ['0x...', '0x...'], // limit minting to only certain addresses + * }, + * { + * startTime: publicSaleStartTime, // 24h after presale, start public sale + * price: 0.08, // public sale price + * } + * ]); + * await contract.nft.drop.claim.conditions.set(claimConditions); + * ``` + */ + public conditions: DropClaimConditions; + private contractWrapper: ContractWrapper; + private erc20: Erc20; + private storage: IStorage; + + constructor( + erc20: Erc20, + contractWrapper: ContractWrapper, + storage: IStorage, + ) { + this.erc20 = erc20; + this.contractWrapper = contractWrapper; + + this.storage = storage; + const metadata = new ContractMetadata( + this.contractWrapper, + CustomContractSchema, + this.storage, + ); + this.conditions = new DropClaimConditions( + this.contractWrapper, + metadata, + this.storage, + ); + } + + /** + * Claim a certain amount of tokens to a specific Wallet + * + * @remarks Let the specified wallet claim Tokens. + * + * @example + * ```javascript + * const address = "{{wallet_address}}"; // address of the wallet you want to claim the NFTs + * const quantity = 42.69; // how many tokens you want to claim + * + * const tx = await contract.token.drop.claim.to(address, quantity); + * const receipt = tx.receipt; // the transaction receipt + * ``` + * + * @param destinationAddress - Address you want to send the token to + * @param amount - Quantity of the tokens you want to claim + * @param checkERC20Allowance - Optional, check if the wallet has enough ERC20 allowance to claim the tokens, and if not, approve the transfer + * @param claimData + * @returns - The transaction receipt + */ + public async to( + destinationAddress: string, + amount: Amount, + checkERC20Allowance = true, + claimData?: ClaimVerification, + ): Promise { + const quantity = await this.erc20.normalizeAmount(amount); + + let claimVerification = claimData; + if (this.conditions && !claimData) { + claimVerification = await this.conditions.prepareClaim( + quantity, + checkERC20Allowance, + await this.contractWrapper.readContract.decimals(), + ); + } + if (!claimVerification) { + throw new Error( + "Claim verification Data is required - either pass it in as 'claimData' or set claim conditions via 'conditions.set()'", + ); + } + + const receipt = await this.contractWrapper.sendTransaction( + "claim", + [ + destinationAddress, + quantity, + claimVerification.currencyAddress, + claimVerification.price, + claimVerification.proofs, + claimVerification.maxQuantityPerTransaction, + ], + claimVerification.overrides, + ); + return { receipt }; + } +} diff --git a/src/core/classes/erc-20-droppable.ts b/src/core/classes/erc-20-droppable.ts index bdeba5ca8..61f9827ff 100644 --- a/src/core/classes/erc-20-droppable.ts +++ b/src/core/classes/erc-20-droppable.ts @@ -1,15 +1,10 @@ import { FEATURE_TOKEN_DROPPABLE } from "../../constants/erc20-features"; -import { CustomContractSchema } from "../../schema/contracts/custom"; -import { ClaimVerification } from "../../types"; -import { Amount } from "../../types/currency"; import { BaseDropERC20 } from "../../types/eips"; import { IStorage } from "@thirdweb-dev/storage"; import { DetectableFeature } from "../interfaces/DetectableFeature"; -import { TransactionResult } from "../types"; -import { ContractMetadata } from "./contract-metadata"; import { ContractWrapper } from "./contract-wrapper"; -import { DropClaimConditions } from "./drop-claim-conditions"; import { Erc20 } from "./erc-20"; +import { Erc20Claimable } from "./erc-20-claimable"; /** * Configure and claim ERC20 tokens @@ -45,7 +40,7 @@ export class Erc20Droppable implements DetectableFeature { * await contract.nft.drop.claim.conditions.set(claimConditions); * ``` */ - public claimConditions: DropClaimConditions; + public claim: Erc20Claimable; private contractWrapper: ContractWrapper; private erc20: Erc20; private storage: IStorage; @@ -59,72 +54,10 @@ export class Erc20Droppable implements DetectableFeature { this.contractWrapper = contractWrapper; this.storage = storage; - const metadata = new ContractMetadata( + this.claim = new Erc20Claimable( + this.erc20, this.contractWrapper, - CustomContractSchema, this.storage, ); - this.claimConditions = new DropClaimConditions( - this.contractWrapper, - metadata, - this.storage, - ); - } - - /** - * Claim a certain amount of tokens to a specific Wallet - * - * @remarks Let the specified wallet claim Tokens. - * - * @example - * ```javascript - * const address = "{{wallet_address}}"; // address of the wallet you want to claim the NFTs - * const quantity = 42.69; // how many tokens you want to claim - * - * const tx = await contract.token.drop.claim.to(address, quantity); - * const receipt = tx.receipt; // the transaction receipt - * ``` - * - * @param destinationAddress - Address you want to send the token to - * @param amount - Quantity of the tokens you want to claim - * @param checkERC20Allowance - Optional, check if the wallet has enough ERC20 allowance to claim the tokens, and if not, approve the transfer - * - * @returns - The transaction receipt - */ - public async claimTo( - destinationAddress: string, - amount: Amount, - checkERC20Allowance = true, - claimData?: ClaimVerification, - ): Promise { - const quantity = await this.erc20.normalizeAmount(amount); - - let claimVerification = claimData; - if (this.claimConditions && !claimData) { - claimVerification = await this.claimConditions.prepareClaim( - quantity, - checkERC20Allowance, - await this.contractWrapper.readContract.decimals(), - ); - } - if (!claimVerification) { - throw new Error( - "Claim verification Data is required - either pass it in as 'claimData' or set claim conditions via 'conditions.set()'", - ); - } - - const receipt = await this.contractWrapper.sendTransaction( - "claim", - [ - destinationAddress, - quantity, - claimVerification.currencyAddress, - claimVerification.price, - claimVerification.proofs, - claimVerification.maxQuantityPerTransaction, - ], - claimVerification.overrides, - ); - return { receipt }; } } diff --git a/test/custom.test.ts b/test/custom.test.ts index 485b16b72..4ab960441 100644 --- a/test/custom.test.ts +++ b/test/custom.test.ts @@ -268,7 +268,7 @@ describe("Custom Contracts", async () => { invariant(c.token, "ERC20 undefined"); invariant(c.token.drop, "ERC20 drop undefined"); - await c.token.drop.claimConditions.set([ + await c.token.drop.claim.conditions.set([ { startTime: new Date(new Date().getTime() - 1000 * 60 * 60), price: 0, @@ -279,7 +279,7 @@ describe("Custom Contracts", async () => { let b = await c.token.balance(); expect(b.displayValue).to.equal("0.0"); - await c.token.drop.claimTo(adminWallet.address, 5); + await c.token.drop.claim.to(adminWallet.address, 5); b = await c.token.balance(); expect(b.displayValue).to.equal("5.0");