Merge branch 'develop' into main
This commit is contained in:
commit
83835dfba2
@ -59,6 +59,7 @@ NEXT_PUBLIC_BASE_FACTORY_ADDRESS="stars1a45hcxty3spnmm2f0papl8v4dk5ew29s4syhn4ef
|
||||
NEXT_PUBLIC_BASE_FACTORY_UPDATABLE_ADDRESS="stars100xegx2syry4tclkmejjwxk4nfqahvcqhm9qxut5wxuzhj5d9qfsh5nmym"
|
||||
|
||||
NEXT_PUBLIC_OPEN_EDITION_FACTORY_ADDRESS="stars1sqweqcxlf2f7qhf27gn5naqusk5q52fkzewmy63c4sglvle3s7ls6k828e"
|
||||
NEXT_PUBLIC_OPEN_EDITION_FACTORY_FLEX_ADDRESS="stars1nc59ddaa8xcx9mu8jladza82dznhxrta3njal3xylkqlsfqa7g4s9s5q02"
|
||||
NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_FACTORY_ADDRESS="stars1fk5dkzcylam8mcpqrn8y9spauvc3d4navtaqurcc49dc3p9f8d3qdkvymx"
|
||||
|
||||
NEXT_PUBLIC_VENDING_IBC_KUJI_FACTORY_ADDRESS="stars1yyje87e0h9mqg34kp3x75yesa78ve4glc3dstdrn6nscw3zjfanqkj95f0"
|
||||
@ -72,9 +73,11 @@ NEXT_PUBLIC_VENDING_IBC_CRBRUS_FACTORY_FLEX_ADDRESS="stars1halhp674yxwgn3p4gpkl8
|
||||
|
||||
# NEXT_PUBLIC_OPEN_EDITION_IBC_ATOM_FACTORY_ADDRESS=
|
||||
# NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_ATOM_FACTORY_ADDRESS=
|
||||
# NEXT_PUBLIC_OPEN_EDITION_IBC_USDC_FACTORY_ADDRESS=
|
||||
# NEXT_PUBLIC_OPEN_EDITION_IBC_USDC_FACTORY_ADDRESS="stars152a40mmd3k2kk90add606vrqxcvzdp29qrjx4pjv33cjl6svksfscrrtuk"
|
||||
# NEXT_PUBLIC_OPEN_EDITION_IBC_USDC_FACTORY_FLEX_ADDRESS="stars10sz9mup3a548l34k83q5w59nrklrnvv2gdsdkr2xref4zl5j3d4q0efamx"
|
||||
# NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_USDC_FACTORY_ADDRESS=
|
||||
# NEXT_PUBLIC_OPEN_EDITION_IBC_TIA_FACTORY_ADDRESS=
|
||||
# NEXT_PUBLIC_OPEN_EDITION_IBC_TIA_FACTORY_ADDRESS="stars1vza7k890fkejxz3mqwau0u2m89k9y76w94vvxe4d42ya9862ryfq0damns"
|
||||
# NEXT_PUBLIC_OPEN_EDITION_IBC_TIA_FACTORY_FLEX_ADDRESS="stars1jgn0ntt5tut93yn756rrqa60794qdsrn6dwhl8vhfx0yxgpr44qsfzhmrt"
|
||||
# NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_TIA_FACTORY_ADDRESS=
|
||||
NEXT_PUBLIC_OPEN_EDITION_IBC_FRNZ_FACTORY_ADDRESS="stars1vzffawsjhvspstu5lvtzz2x5n7zh07hnw09c9dfxcj78un05rcms5n3q3e"
|
||||
NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_FRNZ_FACTORY_ADDRESS="stars1tc09vlgdg8rqyapcxwm9qdq8naj4gym9px4ntue9cs0kse5rvess0nee3a"
|
||||
|
@ -17,7 +17,7 @@ import { useWallet } from 'utils/wallet'
|
||||
import { NumberInput, TextInput } from '../forms/FormInput'
|
||||
import type { UploadMethod } from './OffChainMetadataUploadDetails'
|
||||
|
||||
export type LimitType = 'count_limited' | 'time_limited'
|
||||
export type LimitType = 'count_limited' | 'time_limited' | 'time_and_count_limited'
|
||||
|
||||
interface MintingDetailsProps {
|
||||
onChange: (data: MintingDetailsDataProps) => void
|
||||
@ -25,6 +25,8 @@ interface MintingDetailsProps {
|
||||
minimumMintPrice: number
|
||||
mintTokenFromFactory?: TokenInfo | undefined
|
||||
importedMintingDetails?: MintingDetailsDataProps
|
||||
isPresale: boolean
|
||||
whitelistStartDate?: string
|
||||
}
|
||||
|
||||
export interface MintingDetailsDataProps {
|
||||
@ -44,6 +46,8 @@ export const MintingDetails = ({
|
||||
minimumMintPrice,
|
||||
mintTokenFromFactory,
|
||||
importedMintingDetails,
|
||||
isPresale,
|
||||
whitelistStartDate,
|
||||
}: MintingDetailsProps) => {
|
||||
const wallet = useWallet()
|
||||
|
||||
@ -109,11 +113,19 @@ export const MintingDetails = ({
|
||||
: '',
|
||||
perAddressLimit: perAddressLimitState.value,
|
||||
startTime: timestamp ? (timestamp.getTime() * 1_000_000).toString() : '',
|
||||
endTime: endTimestamp ? (endTimestamp.getTime() * 1_000_000).toString() : '',
|
||||
endTime:
|
||||
limitType === 'time_limited' || limitType === 'time_and_count_limited'
|
||||
? endTimestamp
|
||||
? (endTimestamp.getTime() * 1_000_000).toString()
|
||||
: ''
|
||||
: undefined,
|
||||
paymentAddress: paymentAddressState.value.trim(),
|
||||
selectedMintToken,
|
||||
limitType,
|
||||
tokenCountLimit: limitType === 'count_limited' ? tokenCountLimitState.value : undefined,
|
||||
tokenCountLimit:
|
||||
limitType === 'count_limited' || limitType === 'time_and_count_limited'
|
||||
? tokenCountLimitState.value
|
||||
: undefined,
|
||||
}
|
||||
onChange(data)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
@ -144,6 +156,12 @@ export const MintingDetails = ({
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [importedMintingDetails])
|
||||
|
||||
useEffect(() => {
|
||||
if (isPresale) {
|
||||
setTimestamp(whitelistStartDate ? new Date(Number(whitelistStartDate) / 1_000_000) : undefined)
|
||||
}
|
||||
}, [whitelistStartDate, isPresale])
|
||||
|
||||
return (
|
||||
<div className="border-l-[1px] border-gray-500 border-opacity-20">
|
||||
<FormGroup subtitle="Information about your minting settings" title="Minting Details">
|
||||
@ -172,6 +190,7 @@ export const MintingDetails = ({
|
||||
title="Start Time"
|
||||
>
|
||||
<InputDateTime
|
||||
disabled={isPresale}
|
||||
minDate={
|
||||
timezone === 'Local' ? new Date() : new Date(Date.now() + new Date().getTimezoneOffset() * 60 * 1000)
|
||||
}
|
||||
@ -197,10 +216,12 @@ export const MintingDetails = ({
|
||||
<label className="justify-start ml-6 cursor-pointer label">
|
||||
<span className="mr-2">Time</span>
|
||||
<input
|
||||
checked={limitType === 'time_limited'}
|
||||
checked={limitType === 'time_limited' || limitType === 'time_and_count_limited'}
|
||||
className={`${limitType === 'time_limited' ? `bg-stargaze` : `bg-gray-600`} checkbox`}
|
||||
onClick={() => {
|
||||
setLimitType('time_limited' as LimitType)
|
||||
if (limitType === 'time_and_count_limited') setLimitType('count_limited' as LimitType)
|
||||
else if (limitType === 'count_limited') setLimitType('time_and_count_limited' as LimitType)
|
||||
else setLimitType('count_limited' as LimitType)
|
||||
}}
|
||||
type="checkbox"
|
||||
/>
|
||||
@ -208,16 +229,18 @@ export const MintingDetails = ({
|
||||
<label className="justify-start ml-4 cursor-pointer label">
|
||||
<span className="mr-2">Token Count</span>
|
||||
<input
|
||||
checked={limitType === 'count_limited'}
|
||||
checked={limitType === 'count_limited' || limitType === 'time_and_count_limited'}
|
||||
className={`${limitType === 'count_limited' ? `bg-stargaze` : `bg-gray-600`} checkbox`}
|
||||
onClick={() => {
|
||||
setLimitType('count_limited' as LimitType)
|
||||
if (limitType === 'time_and_count_limited') setLimitType('time_limited' as LimitType)
|
||||
else if (limitType === 'time_limited') setLimitType('time_and_count_limited' as LimitType)
|
||||
else setLimitType('time_limited' as LimitType)
|
||||
}}
|
||||
type="checkbox"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<Conditional test={limitType === 'time_limited'}>
|
||||
<Conditional test={limitType === 'time_limited' || limitType === 'time_and_count_limited'}>
|
||||
<FormControl
|
||||
htmlId="endTimestamp"
|
||||
isRequired
|
||||
@ -247,7 +270,7 @@ export const MintingDetails = ({
|
||||
/>
|
||||
</FormControl>
|
||||
</Conditional>
|
||||
<Conditional test={limitType === 'count_limited'}>
|
||||
<Conditional test={limitType === 'count_limited' || limitType === 'time_and_count_limited'}>
|
||||
<NumberInput {...tokenCountLimitState} isRequired />
|
||||
</Conditional>
|
||||
</FormGroup>
|
||||
|
@ -6,13 +6,13 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
import { toUtf8 } from '@cosmjs/encoding'
|
||||
import { coin } from '@cosmjs/proto-signing'
|
||||
import axios from 'axios'
|
||||
import clsx from 'clsx'
|
||||
import { Button } from 'components/Button'
|
||||
import type { MinterType } from 'components/collections/actions/Combobox'
|
||||
import { Conditional } from 'components/Conditional'
|
||||
import { ConfirmationModal } from 'components/ConfirmationModal'
|
||||
import { LoadingModal } from 'components/LoadingModal'
|
||||
import { openEditionMinterList } from 'config/minter'
|
||||
import { type TokenInfo } from 'config/token'
|
||||
import { useContracts } from 'contexts/contracts'
|
||||
import { addLogItem } from 'contexts/log'
|
||||
@ -22,12 +22,15 @@ import React, { useEffect, useMemo, useState } from 'react'
|
||||
import { toast } from 'react-hot-toast'
|
||||
import { upload } from 'services/upload'
|
||||
import {
|
||||
OPEN_EDITION_FACTORY_ADDRESS,
|
||||
OPEN_EDITION_UPDATABLE_FACTORY_ADDRESS,
|
||||
SG721_OPEN_EDITION_CODE_ID,
|
||||
SG721_OPEN_EDITION_UPDATABLE_CODE_ID,
|
||||
STRDST_SG721_CODE_ID,
|
||||
WHITELIST_CODE_ID,
|
||||
WHITELIST_FLEX_CODE_ID,
|
||||
WHITELIST_MERKLE_TREE_API_URL,
|
||||
WHITELIST_MERKLE_TREE_CODE_ID,
|
||||
} from 'utils/constants'
|
||||
import { useDebounce } from 'utils/debounce'
|
||||
import type { AssetType } from 'utils/getAssetType'
|
||||
import { isValidAddress } from 'utils/isValidAddress'
|
||||
import { checkTokenUri } from 'utils/isValidTokenUri'
|
||||
@ -47,12 +50,14 @@ import {
|
||||
import type { OnChainMetadataInputDetailsDataProps } from './OnChainMetadataInputDetails'
|
||||
import { OnChainMetadataInputDetails } from './OnChainMetadataInputDetails'
|
||||
import { type RoyaltyDetailsDataProps, RoyaltyDetails } from './RoyaltyDetails'
|
||||
import { type WhitelistDetailsDataProps, WhitelistDetails } from './WhitelistDetails'
|
||||
|
||||
export type MetadataStorageMethod = 'off-chain' | 'on-chain'
|
||||
|
||||
export interface OpenEditionMinterDetailsDataProps {
|
||||
imageUploadDetails?: ImageUploadDetailsDataProps
|
||||
collectionDetails?: CollectionDetailsDataProps
|
||||
whitelistDetails?: WhitelistDetailsDataProps
|
||||
royaltyDetails?: RoyaltyDetailsDataProps
|
||||
onChainMetadataInputDetails?: OnChainMetadataInputDetailsDataProps
|
||||
offChainMetadataUploadDetails?: OffChainMetadataUploadDetailsDataProps
|
||||
@ -62,24 +67,26 @@ export interface OpenEditionMinterDetailsDataProps {
|
||||
coverImageUrl?: string | null
|
||||
tokenUri?: string | null
|
||||
tokenImageUri?: string | null
|
||||
isRefreshed?: boolean
|
||||
}
|
||||
|
||||
interface OpenEditionMinterCreatorProps {
|
||||
onChange: (data: OpenEditionMinterCreatorDataProps) => void
|
||||
onDetailsChange: (data: OpenEditionMinterDetailsDataProps) => void
|
||||
openEditionMinterUpdatableCreationFee?: string
|
||||
openEditionMinterCreationFee?: string
|
||||
minimumMintPrice?: string
|
||||
minimumUpdatableMintPrice?: string
|
||||
minterType?: MinterType
|
||||
mintTokenFromFactory?: TokenInfo | undefined
|
||||
importedOpenEditionMinterDetails?: OpenEditionMinterDetailsDataProps
|
||||
isMatchingFactoryPresent?: boolean
|
||||
openEditionFactoryAddress?: string
|
||||
}
|
||||
|
||||
export interface OpenEditionMinterCreatorDataProps {
|
||||
metadataStorageMethod: MetadataStorageMethod
|
||||
openEditionMinterContractAddress: string | null
|
||||
sg721ContractAddress: string | null
|
||||
whitelistContractAddress: string | null
|
||||
transactionHash: string | null
|
||||
}
|
||||
|
||||
@ -87,21 +94,27 @@ export const OpenEditionMinterCreator = ({
|
||||
onChange,
|
||||
onDetailsChange,
|
||||
openEditionMinterCreationFee,
|
||||
openEditionMinterUpdatableCreationFee,
|
||||
minimumMintPrice,
|
||||
minimumUpdatableMintPrice,
|
||||
minterType,
|
||||
mintTokenFromFactory,
|
||||
importedOpenEditionMinterDetails,
|
||||
isMatchingFactoryPresent,
|
||||
openEditionFactoryAddress,
|
||||
}: OpenEditionMinterCreatorProps) => {
|
||||
const wallet = useWallet()
|
||||
const { openEditionMinter: openEditionMinterContract, openEditionFactory: openEditionFactoryContract } =
|
||||
useContracts()
|
||||
const {
|
||||
openEditionMinter: openEditionMinterContract,
|
||||
openEditionFactory: openEditionFactoryContract,
|
||||
whitelist: whitelistContract,
|
||||
whitelistMerkleTree: whitelistMerkleTreeContract,
|
||||
} = useContracts()
|
||||
|
||||
const [metadataStorageMethod, setMetadataStorageMethod] = useState<MetadataStorageMethod>('off-chain')
|
||||
const [imageUploadDetails, setImageUploadDetails] = useState<ImageUploadDetailsDataProps | null>(null)
|
||||
const [collectionDetails, setCollectionDetails] = useState<CollectionDetailsDataProps | null>(null)
|
||||
const [whitelistDetails, setWhitelistDetails] = useState<WhitelistDetailsDataProps | null>(null)
|
||||
const [royaltyDetails, setRoyaltyDetails] = useState<RoyaltyDetailsDataProps | null>(null)
|
||||
const [isRefreshed, setIsRefreshed] = useState(false)
|
||||
const [onChainMetadataInputDetails, setOnChainMetadataInputDetails] =
|
||||
useState<OnChainMetadataInputDetailsDataProps | null>(null)
|
||||
const [offChainMetadataUploadDetails, setOffChainMetadataUploadDetails] =
|
||||
@ -116,29 +129,19 @@ export const OpenEditionMinterCreator = ({
|
||||
const [coverImageUrl, setCoverImageUrl] = useState<string | null>(null)
|
||||
const [openEditionMinterContractAddress, setOpenEditionMinterContractAddress] = useState<string | null>(null)
|
||||
const [sg721ContractAddress, setSg721ContractAddress] = useState<string | null>(null)
|
||||
const [whitelistContractAddress, setWhitelistContractAddress] = useState<string | null>(null)
|
||||
const [transactionHash, setTransactionHash] = useState<string | null>(null)
|
||||
const [thumbnailImageUri, setThumbnailImageUri] = useState<string | undefined>(undefined)
|
||||
|
||||
const thumbnailCompatibleAssetTypes: AssetType[] = ['video', 'audio', 'html']
|
||||
|
||||
const factoryAddressForSelectedDenom =
|
||||
openEditionMinterList.find((minter) => minter.supportedToken === mintTokenFromFactory && minter.updatable === false)
|
||||
?.factoryAddress || OPEN_EDITION_FACTORY_ADDRESS
|
||||
const updatableFactoryAddressForSelectedDenom =
|
||||
openEditionMinterList.find((minter) => minter.supportedToken === mintTokenFromFactory && minter.updatable === true)
|
||||
?.factoryAddress || OPEN_EDITION_UPDATABLE_FACTORY_ADDRESS
|
||||
|
||||
const openEditionFactoryMessages = useMemo(
|
||||
() =>
|
||||
openEditionFactoryContract?.use(
|
||||
collectionDetails?.updatable ? updatableFactoryAddressForSelectedDenom : factoryAddressForSelectedDenom,
|
||||
),
|
||||
() => openEditionFactoryContract?.use(openEditionFactoryAddress as string),
|
||||
[
|
||||
openEditionFactoryContract,
|
||||
wallet.address,
|
||||
collectionDetails?.updatable,
|
||||
factoryAddressForSelectedDenom,
|
||||
updatableFactoryAddressForSelectedDenom,
|
||||
openEditionFactoryAddress,
|
||||
wallet.isWalletConnected,
|
||||
],
|
||||
)
|
||||
@ -152,13 +155,26 @@ export const OpenEditionMinterCreator = ({
|
||||
.then(() => {
|
||||
void checkRoyaltyDetails()
|
||||
.then(() => {
|
||||
void checkwalletBalance()
|
||||
checkWhitelistDetails()
|
||||
.then(() => {
|
||||
setReadyToCreate(true)
|
||||
void checkwalletBalance()
|
||||
.then(() => {
|
||||
setReadyToCreate(true)
|
||||
})
|
||||
.catch((error: any) => {
|
||||
toast.error(`Error in Wallet Balance: ${error.message}`, { style: { maxWidth: 'none' } })
|
||||
addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() })
|
||||
setReadyToCreate(false)
|
||||
})
|
||||
})
|
||||
.catch((error: any) => {
|
||||
toast.error(`Error in Wallet Balance: ${error.message}`, { style: { maxWidth: 'none' } })
|
||||
addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() })
|
||||
.catch((error) => {
|
||||
if (String(error.message).includes('Insufficient wallet balance')) {
|
||||
toast.error(`${error.message}`, { style: { maxWidth: 'none' } })
|
||||
addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() })
|
||||
} else {
|
||||
toast.error(`Error in Whitelist Configuration: ${error.message}`, { style: { maxWidth: 'none' } })
|
||||
addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() })
|
||||
}
|
||||
setReadyToCreate(false)
|
||||
})
|
||||
})
|
||||
@ -299,9 +315,9 @@ export const OpenEditionMinterCreator = ({
|
||||
if (!mintingDetails) throw new Error('Please fill out the minting details')
|
||||
if (mintingDetails.unitPrice === '') throw new Error('Mint price is required')
|
||||
if (collectionDetails?.updatable) {
|
||||
if (Number(mintingDetails.unitPrice) < Number(minimumUpdatableMintPrice))
|
||||
if (Number(mintingDetails.unitPrice) < Number(minimumMintPrice))
|
||||
throw new Error(
|
||||
`Invalid mint price: The minimum mint price is ${Number(minimumUpdatableMintPrice) / 1000000} ${
|
||||
`Invalid mint price: The minimum mint price is ${Number(minimumMintPrice) / 1000000} ${
|
||||
mintTokenFromFactory?.displayName
|
||||
}`,
|
||||
)
|
||||
@ -342,6 +358,92 @@ export const OpenEditionMinterCreator = ({
|
||||
(!isValidAddress(mintingDetails.paymentAddress) || !mintingDetails.paymentAddress.startsWith('stars1'))
|
||||
)
|
||||
throw new Error('Invalid payment address')
|
||||
|
||||
if (!isMatchingFactoryPresent)
|
||||
throw new Error(
|
||||
`No matching open edition factory contract found for the selected parameters (Mint Price Denom: ${mintingDetails.selectedMintToken?.displayName}, Whitelist Type: ${whitelistDetails?.whitelistType})`,
|
||||
)
|
||||
}
|
||||
|
||||
const checkWhitelistDetails = async () => {
|
||||
if (!whitelistDetails) throw new Error('Please fill out the whitelist details')
|
||||
if (whitelistDetails.whitelistState === 'existing') {
|
||||
if (whitelistDetails.contractAddress === '') throw new Error('Whitelist contract address is required')
|
||||
else {
|
||||
const contract = whitelistContract?.use(whitelistDetails.contractAddress)
|
||||
//check if the address belongs to a whitelist contract (see performChecks())
|
||||
const config = await contract?.config()
|
||||
if (JSON.stringify(config).includes('whale_cap')) whitelistDetails.whitelistType = 'flex'
|
||||
else if (!JSON.stringify(config).includes('member_limit') || config?.member_limit === 0) {
|
||||
// whitelistDetails.whitelistType = 'merkletree'
|
||||
throw new Error(
|
||||
'Whitelist Merkle Tree is not supported yet. Please use a standard or flexible whitelist contract.',
|
||||
)
|
||||
} else whitelistDetails.whitelistType = 'standard'
|
||||
if (Number(config?.start_time) !== Number(mintingDetails?.startTime)) {
|
||||
const whitelistStartDate = new Date(Number(config?.start_time) / 1000000)
|
||||
throw Error(`Whitelist start time (${whitelistStartDate.toLocaleString()}) does not match minting start time`)
|
||||
}
|
||||
|
||||
if (mintingDetails?.tokenCountLimit && config?.per_address_limit) {
|
||||
if (mintingDetails.tokenCountLimit >= 100 && Number(config.per_address_limit) > 50) {
|
||||
throw Error(
|
||||
`Invalid limit for tokens per address (${config.per_address_limit} tokens). Tokens per address limit cannot exceed 50 regardless of the total number of tokens.`,
|
||||
)
|
||||
} else if (
|
||||
mintingDetails.tokenCountLimit >= 100 &&
|
||||
Number(config.per_address_limit) > Math.ceil((mintingDetails.tokenCountLimit / 100) * 3)
|
||||
) {
|
||||
throw Error(
|
||||
`Invalid limit for tokens per address (${config.per_address_limit} tokens). Tokens per address limit cannot exceed 3% of the total number of tokens in the collection.`,
|
||||
)
|
||||
} else if (mintingDetails.tokenCountLimit < 100 && Number(config.per_address_limit) > 3) {
|
||||
throw Error(
|
||||
`Invalid limit for tokens per address (${config.per_address_limit} tokens). Tokens per address limit cannot exceed 3 for collections with a token count limit smaller than 100 tokens.`,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (whitelistDetails.whitelistState === 'new') {
|
||||
if (whitelistDetails.members?.length === 0) throw new Error('Whitelist member list cannot be empty')
|
||||
if (whitelistDetails.unitPrice === undefined) throw new Error('Whitelist unit price is required')
|
||||
if (Number(whitelistDetails.unitPrice) < 0)
|
||||
throw new Error('Invalid unit price: The unit price cannot be negative')
|
||||
if (whitelistDetails.startTime === '') throw new Error('Start time is required')
|
||||
if (whitelistDetails.endTime === '') throw new Error('End time is required')
|
||||
if (
|
||||
whitelistDetails.whitelistType === 'standard' &&
|
||||
(!whitelistDetails.perAddressLimit || whitelistDetails.perAddressLimit === 0)
|
||||
)
|
||||
throw new Error('Per address limit is required')
|
||||
if (
|
||||
whitelistDetails.whitelistType !== 'merkletree' &&
|
||||
(!whitelistDetails.memberLimit || whitelistDetails.memberLimit === 0)
|
||||
)
|
||||
throw new Error('Member limit is required')
|
||||
if (Number(whitelistDetails.startTime) >= Number(whitelistDetails.endTime))
|
||||
throw new Error('Whitelist start time cannot be equal to or later than the whitelist end time')
|
||||
if (Number(whitelistDetails.startTime) !== Number(mintingDetails?.startTime))
|
||||
throw new Error('Whitelist start time must be the same as the minting start time')
|
||||
if (whitelistDetails.perAddressLimit && mintingDetails?.tokenCountLimit) {
|
||||
if (mintingDetails.tokenCountLimit >= 100 && whitelistDetails.perAddressLimit > 50) {
|
||||
throw Error(
|
||||
`Invalid limit for tokens per address. Tokens per address limit cannot exceed 50 regardless of the total number of tokens.`,
|
||||
)
|
||||
} else if (
|
||||
mintingDetails.tokenCountLimit >= 100 &&
|
||||
whitelistDetails.perAddressLimit > Math.ceil((mintingDetails.tokenCountLimit / 100) * 3)
|
||||
) {
|
||||
throw Error(
|
||||
`Invalid limit for tokens per address. Tokens per address limit cannot exceed 3% of the total number of tokens in the collection.`,
|
||||
)
|
||||
} else if (mintingDetails.tokenCountLimit < 100 && whitelistDetails.perAddressLimit > 3) {
|
||||
throw Error(
|
||||
`Invalid limit for tokens per address. Tokens per address limit cannot exceed 3 for collections with a token count limit smaller than 100 tokens.`,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const checkRoyaltyDetails = async () => {
|
||||
@ -378,9 +480,13 @@ export const OpenEditionMinterCreator = ({
|
||||
|
||||
const checkwalletBalance = async () => {
|
||||
if (!wallet.isWalletConnected) throw new Error('Wallet not connected.')
|
||||
const amountNeeded = collectionDetails?.updatable
|
||||
? Number(openEditionMinterUpdatableCreationFee)
|
||||
: Number(openEditionMinterCreationFee)
|
||||
let amountNeeded = 0
|
||||
if (whitelistDetails?.whitelistState === 'new' && whitelistDetails.memberLimit) {
|
||||
amountNeeded =
|
||||
Math.ceil(Number(whitelistDetails.memberLimit) / 1000) * 100000000 + Number(openEditionMinterCreationFee)
|
||||
} else {
|
||||
amountNeeded = openEditionMinterCreationFee ? Number(openEditionMinterCreationFee) : 0
|
||||
}
|
||||
await (await wallet.getCosmWasmClient()).getBalance(wallet.address || '', 'ustars').then((balance) => {
|
||||
if (amountNeeded >= Number(balance.amount))
|
||||
throw new Error(
|
||||
@ -399,6 +505,7 @@ export const OpenEditionMinterCreator = ({
|
||||
setTokenImageUri(null)
|
||||
setOpenEditionMinterContractAddress(null)
|
||||
setSg721ContractAddress(null)
|
||||
setWhitelistContractAddress(null)
|
||||
setTransactionHash(null)
|
||||
if (metadataStorageMethod === 'off-chain') {
|
||||
if (offChainMetadataUploadDetails?.uploadMethod === 'new') {
|
||||
@ -423,13 +530,27 @@ export const OpenEditionMinterCreator = ({
|
||||
setTokenUri(metadataUriWithBase)
|
||||
setCoverImageUrl(coverImageUriWithBase)
|
||||
setUploading(false)
|
||||
await instantiateOpenEditionMinter(metadataUriWithBase, coverImageUriWithBase)
|
||||
|
||||
let whitelist: string | undefined
|
||||
if (whitelistDetails?.whitelistState === 'existing') whitelist = whitelistDetails.contractAddress
|
||||
else if (whitelistDetails?.whitelistState === 'new') whitelist = await instantiateWhitelist()
|
||||
setWhitelistContractAddress(whitelist as string)
|
||||
|
||||
await instantiateOpenEditionMinter(metadataUriWithBase, coverImageUriWithBase, undefined, whitelist)
|
||||
} else {
|
||||
setTokenUri(offChainMetadataUploadDetails?.tokenURI as string)
|
||||
setCoverImageUrl(offChainMetadataUploadDetails?.imageUrl as string)
|
||||
|
||||
let whitelist: string | undefined
|
||||
if (whitelistDetails?.whitelistState === 'existing') whitelist = whitelistDetails.contractAddress
|
||||
else if (whitelistDetails?.whitelistState === 'new') whitelist = await instantiateWhitelist()
|
||||
setWhitelistContractAddress(whitelist as string)
|
||||
|
||||
await instantiateOpenEditionMinter(
|
||||
offChainMetadataUploadDetails?.tokenURI as string,
|
||||
offChainMetadataUploadDetails?.imageUrl as string,
|
||||
undefined,
|
||||
whitelist,
|
||||
)
|
||||
}
|
||||
} else if (metadataStorageMethod === 'on-chain') {
|
||||
@ -471,15 +592,27 @@ export const OpenEditionMinterCreator = ({
|
||||
? `ipfs://${thumbnailUri}/${(imageUploadDetails.thumbnailFile as File).name}`
|
||||
: undefined
|
||||
setThumbnailImageUri(thumbnailUriWithBase)
|
||||
|
||||
setUploading(false)
|
||||
await instantiateOpenEditionMinter(imageUriWithBase, coverImageUriWithBase, thumbnailUriWithBase)
|
||||
|
||||
let whitelist: string | undefined
|
||||
if (whitelistDetails?.whitelistState === 'existing') whitelist = whitelistDetails.contractAddress
|
||||
else if (whitelistDetails?.whitelistState === 'new') whitelist = await instantiateWhitelist()
|
||||
setWhitelistContractAddress(whitelist as string)
|
||||
|
||||
await instantiateOpenEditionMinter(imageUriWithBase, coverImageUriWithBase, thumbnailUriWithBase, whitelist)
|
||||
} else if (imageUploadDetails?.uploadMethod === 'existing') {
|
||||
setTokenImageUri(imageUploadDetails.imageUrl as string)
|
||||
setCoverImageUrl(imageUploadDetails.coverImageUrl as string)
|
||||
|
||||
let whitelist: string | undefined
|
||||
if (whitelistDetails?.whitelistState === 'existing') whitelist = whitelistDetails.contractAddress
|
||||
else if (whitelistDetails?.whitelistState === 'new') whitelist = await instantiateWhitelist()
|
||||
setWhitelistContractAddress(whitelist as string)
|
||||
|
||||
await instantiateOpenEditionMinter(
|
||||
imageUploadDetails.imageUrl as string,
|
||||
imageUploadDetails.coverImageUrl as string,
|
||||
whitelist,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -578,7 +711,104 @@ export const OpenEditionMinterCreator = ({
|
||||
})
|
||||
}
|
||||
|
||||
const instantiateOpenEditionMinter = async (uri: string, coverImageUri: string, thumbnailUri?: string) => {
|
||||
const instantiateWhitelist = async () => {
|
||||
if (!wallet.isWalletConnected) throw new Error('Wallet not connected')
|
||||
if (!whitelistContract) throw new Error('Contract not found')
|
||||
|
||||
if (whitelistDetails?.whitelistType === 'standard' || whitelistDetails?.whitelistType === 'flex') {
|
||||
const standardMsg = {
|
||||
members: whitelistDetails.members,
|
||||
start_time: whitelistDetails.startTime,
|
||||
end_time: whitelistDetails.endTime,
|
||||
mint_price: coin(
|
||||
String(Number(whitelistDetails.unitPrice)),
|
||||
mintTokenFromFactory ? mintTokenFromFactory.denom : 'ustars',
|
||||
),
|
||||
per_address_limit: whitelistDetails.perAddressLimit,
|
||||
member_limit: whitelistDetails.memberLimit,
|
||||
admins: whitelistDetails.admins || [wallet.address],
|
||||
admins_mutable: whitelistDetails.adminsMutable,
|
||||
}
|
||||
|
||||
const flexMsg = {
|
||||
members: whitelistDetails.members,
|
||||
start_time: whitelistDetails.startTime,
|
||||
end_time: whitelistDetails.endTime,
|
||||
mint_price: coin(
|
||||
String(Number(whitelistDetails.unitPrice)),
|
||||
mintTokenFromFactory ? mintTokenFromFactory.denom : 'ustars',
|
||||
),
|
||||
member_limit: whitelistDetails.memberLimit,
|
||||
admins: whitelistDetails.admins || [wallet.address],
|
||||
admins_mutable: whitelistDetails.adminsMutable,
|
||||
}
|
||||
|
||||
const data = await whitelistContract.instantiate(
|
||||
whitelistDetails.whitelistType === 'standard' ? WHITELIST_CODE_ID : WHITELIST_FLEX_CODE_ID,
|
||||
whitelistDetails.whitelistType === 'standard' ? standardMsg : flexMsg,
|
||||
'Stargaze Whitelist Contract',
|
||||
wallet.address,
|
||||
)
|
||||
|
||||
return data.contractAddress
|
||||
} else if (whitelistDetails?.whitelistType === 'merkletree') {
|
||||
const members = whitelistDetails.members as string[]
|
||||
const membersCsv = members.join('\n')
|
||||
const membersBlob = new Blob([membersCsv], { type: 'text/csv' })
|
||||
const membersFile = new File([membersBlob], 'members.csv', { type: 'text/csv' })
|
||||
const formData = new FormData()
|
||||
formData.append('whitelist', membersFile)
|
||||
const response = await toast
|
||||
.promise(
|
||||
axios.post(`${WHITELIST_MERKLE_TREE_API_URL}/create_whitelist`, formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
}),
|
||||
{
|
||||
loading: 'Fetching merkle root hash...',
|
||||
success: 'Merkle root fetched successfully.',
|
||||
error: 'Error fetching root hash from Whitelist Merkle Tree API.',
|
||||
},
|
||||
)
|
||||
.catch((error) => {
|
||||
console.log('error', error)
|
||||
throw new Error('Whitelist instantiation failed.')
|
||||
})
|
||||
|
||||
const rootHash = response.data.root_hash
|
||||
console.log('rootHash', rootHash)
|
||||
|
||||
const merkleTreeMsg = {
|
||||
merkle_root: rootHash,
|
||||
merkle_tree_uri: null,
|
||||
start_time: whitelistDetails.startTime,
|
||||
end_time: whitelistDetails.endTime,
|
||||
mint_price: coin(
|
||||
String(Number(whitelistDetails.unitPrice)),
|
||||
mintTokenFromFactory ? mintTokenFromFactory.denom : 'ustars',
|
||||
),
|
||||
per_address_limit: whitelistDetails.perAddressLimit,
|
||||
admins: whitelistDetails.admins || [wallet.address],
|
||||
admins_mutable: whitelistDetails.adminsMutable,
|
||||
}
|
||||
|
||||
const data = await whitelistMerkleTreeContract?.instantiate(
|
||||
WHITELIST_MERKLE_TREE_CODE_ID,
|
||||
merkleTreeMsg,
|
||||
'Stargaze Whitelist Merkle Tree Contract',
|
||||
wallet.address,
|
||||
)
|
||||
return data?.contractAddress
|
||||
}
|
||||
}
|
||||
|
||||
const instantiateOpenEditionMinter = async (
|
||||
uri: string,
|
||||
coverImageUri: string,
|
||||
thumbnailUri?: string,
|
||||
whitelist?: string,
|
||||
) => {
|
||||
if (!wallet.isWalletConnected) throw new Error('Wallet not connected')
|
||||
if (!openEditionFactoryContract) throw new Error('Contract not found')
|
||||
if (!openEditionMinterContract) throw new Error('Contract not found')
|
||||
@ -619,16 +849,23 @@ export const OpenEditionMinterCreator = ({
|
||||
: null,
|
||||
},
|
||||
start_time: mintingDetails?.startTime,
|
||||
end_time: mintingDetails?.limitType === ('time_limited' as LimitType) ? mintingDetails.endTime : null,
|
||||
end_time:
|
||||
mintingDetails?.limitType === ('time_limited' as LimitType) ||
|
||||
mintingDetails?.limitType === ('time_and_count_limited' as LimitType)
|
||||
? mintingDetails.endTime
|
||||
: null,
|
||||
mint_price: {
|
||||
amount: Number(mintingDetails?.unitPrice).toString(),
|
||||
denom: (mintTokenFromFactory?.denom as string) || 'ustars',
|
||||
},
|
||||
per_address_limit: mintingDetails?.perAddressLimit,
|
||||
num_tokens:
|
||||
mintingDetails?.limitType === ('count_limited' as LimitType) ? mintingDetails.tokenCountLimit : null,
|
||||
mintingDetails?.limitType === ('count_limited' as LimitType) ||
|
||||
mintingDetails?.limitType === ('time_and_count_limited' as LimitType)
|
||||
? mintingDetails.tokenCountLimit
|
||||
: null,
|
||||
payment_address: mintingDetails?.paymentAddress || null,
|
||||
// whitelist: null,
|
||||
whitelist,
|
||||
},
|
||||
collection_params: {
|
||||
code_id: collectionDetails?.updatable
|
||||
@ -658,18 +895,11 @@ export const OpenEditionMinterCreator = ({
|
||||
}
|
||||
|
||||
const payload: OpenEditionFactoryDispatchExecuteArgs = {
|
||||
contract: collectionDetails?.updatable ? updatableFactoryAddressForSelectedDenom : factoryAddressForSelectedDenom,
|
||||
contract: openEditionFactoryAddress as string,
|
||||
messages: openEditionFactoryMessages,
|
||||
txSigner: wallet.address || '',
|
||||
msg,
|
||||
funds: [
|
||||
coin(
|
||||
collectionDetails?.updatable
|
||||
? (openEditionMinterUpdatableCreationFee as string)
|
||||
: (openEditionMinterCreationFee as string),
|
||||
'ustars',
|
||||
),
|
||||
],
|
||||
funds: [coin(openEditionMinterCreationFee as string, 'ustars')],
|
||||
updatable: collectionDetails?.updatable,
|
||||
}
|
||||
await openEditionFactoryDispatchExecute(payload)
|
||||
@ -700,16 +930,24 @@ export const OpenEditionMinterCreator = ({
|
||||
metadataStorageMethod,
|
||||
openEditionMinterContractAddress,
|
||||
sg721ContractAddress,
|
||||
whitelistContractAddress,
|
||||
transactionHash,
|
||||
}
|
||||
onChange(data)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [metadataStorageMethod, openEditionMinterContractAddress, sg721ContractAddress, transactionHash])
|
||||
}, [
|
||||
metadataStorageMethod,
|
||||
openEditionMinterContractAddress,
|
||||
sg721ContractAddress,
|
||||
whitelistContractAddress,
|
||||
transactionHash,
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
const data: OpenEditionMinterDetailsDataProps = {
|
||||
imageUploadDetails: imageUploadDetails ? imageUploadDetails : undefined,
|
||||
collectionDetails: collectionDetails ? collectionDetails : undefined,
|
||||
whitelistDetails: whitelistDetails ? whitelistDetails : undefined,
|
||||
royaltyDetails: royaltyDetails ? royaltyDetails : undefined,
|
||||
onChainMetadataInputDetails: onChainMetadataInputDetails ? onChainMetadataInputDetails : undefined,
|
||||
offChainMetadataUploadDetails: offChainMetadataUploadDetails ? offChainMetadataUploadDetails : undefined,
|
||||
@ -719,12 +957,14 @@ export const OpenEditionMinterCreator = ({
|
||||
coverImageUrl,
|
||||
tokenUri,
|
||||
tokenImageUri,
|
||||
isRefreshed,
|
||||
}
|
||||
onDetailsChange(data)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [
|
||||
imageUploadDetails,
|
||||
collectionDetails,
|
||||
whitelistDetails,
|
||||
royaltyDetails,
|
||||
onChainMetadataInputDetails,
|
||||
offChainMetadataUploadDetails,
|
||||
@ -734,6 +974,7 @@ export const OpenEditionMinterCreator = ({
|
||||
coverImageUrl,
|
||||
tokenUri,
|
||||
tokenImageUri,
|
||||
isRefreshed,
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
@ -742,6 +983,40 @@ export const OpenEditionMinterCreator = ({
|
||||
}
|
||||
}, [importedOpenEditionMinterDetails])
|
||||
|
||||
const fetchWhitelistConfig = async (contractAddress: string | undefined) => {
|
||||
if (contractAddress === '' || !whitelistDetails) return
|
||||
const contract = whitelistContract?.use(contractAddress)
|
||||
|
||||
await contract
|
||||
?.config()
|
||||
.then((config) => {
|
||||
if (!config) {
|
||||
whitelistDetails.whitelistType = 'standard'
|
||||
return
|
||||
}
|
||||
|
||||
if (JSON.stringify(config).includes('whale_cap')) whitelistDetails.whitelistType = 'flex'
|
||||
else if (!JSON.stringify(config).includes('member_limit') || config.member_limit === 0) {
|
||||
// whitelistDetails.whitelistType = 'merkletree'
|
||||
toast.error(
|
||||
'Whitelist Merkle Tree is not supported yet for open edition collections. Please use a standard or flexible whitelist contract.',
|
||||
)
|
||||
} else whitelistDetails.whitelistType = 'standard'
|
||||
setIsRefreshed(!isRefreshed)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('error', error)
|
||||
})
|
||||
}
|
||||
|
||||
const debouncedWhitelistContractAddress = useDebounce(whitelistDetails?.contractAddress, 300)
|
||||
|
||||
useEffect(() => {
|
||||
if (whitelistDetails?.whitelistState === 'existing' && debouncedWhitelistContractAddress !== '') {
|
||||
void fetchWhitelistConfig(debouncedWhitelistContractAddress)
|
||||
}
|
||||
}, [whitelistDetails?.whitelistState, debouncedWhitelistContractAddress])
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* TODO: Cancel once we're able to index on-chain metadata */}
|
||||
@ -830,16 +1105,22 @@ export const OpenEditionMinterCreator = ({
|
||||
/>
|
||||
<MintingDetails
|
||||
importedMintingDetails={importedOpenEditionMinterDetails?.mintingDetails}
|
||||
minimumMintPrice={
|
||||
collectionDetails?.updatable
|
||||
? Number(minimumUpdatableMintPrice) / 1000000
|
||||
: Number(minimumMintPrice) / 1000000
|
||||
}
|
||||
isPresale={whitelistDetails?.whitelistState === 'new'}
|
||||
minimumMintPrice={Number(minimumMintPrice) / 1000000}
|
||||
mintTokenFromFactory={mintTokenFromFactory}
|
||||
onChange={setMintingDetails}
|
||||
uploadMethod={offChainMetadataUploadDetails?.uploadMethod as UploadMethod}
|
||||
whitelistStartDate={whitelistDetails?.startTime}
|
||||
/>
|
||||
</div>
|
||||
<div className="my-6 mx-10">
|
||||
<WhitelistDetails
|
||||
importedWhitelistDetails={importedOpenEditionMinterDetails?.whitelistDetails}
|
||||
mintingTokenFromFactory={mintTokenFromFactory}
|
||||
onChange={setWhitelistDetails}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="my-6">
|
||||
<RoyaltyDetails
|
||||
importedRoyaltyDetails={importedOpenEditionMinterDetails?.royaltyDetails}
|
||||
|
528
components/openEdition/WhitelistDetails.tsx
Normal file
528
components/openEdition/WhitelistDetails.tsx
Normal file
@ -0,0 +1,528 @@
|
||||
/* eslint-disable eslint-comments/disable-enable-pair */
|
||||
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
||||
/* eslint-disable no-nested-ternary */
|
||||
import { Button } from 'components/Button'
|
||||
import { FormControl } from 'components/FormControl'
|
||||
import { FormGroup } from 'components/FormGroup'
|
||||
import { AddressList } from 'components/forms/AddressList'
|
||||
import { useAddressListState } from 'components/forms/AddressList.hooks'
|
||||
import { useInputState, useNumberInputState } from 'components/forms/FormInput.hooks'
|
||||
import { InputDateTime } from 'components/InputDateTime'
|
||||
import type { WhitelistFlexMember } from 'components/WhitelistFlexUpload'
|
||||
import { WhitelistFlexUpload } from 'components/WhitelistFlexUpload'
|
||||
import type { TokenInfo } from 'config/token'
|
||||
import { useGlobalSettings } from 'contexts/globalSettings'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { isValidAddress } from 'utils/isValidAddress'
|
||||
import { useWallet } from 'utils/wallet'
|
||||
|
||||
import { Conditional } from '../Conditional'
|
||||
import { AddressInput, NumberInput } from '../forms/FormInput'
|
||||
import { JsonPreview } from '../JsonPreview'
|
||||
import { WhitelistUpload } from '../WhitelistUpload'
|
||||
|
||||
interface WhitelistDetailsProps {
|
||||
onChange: (data: WhitelistDetailsDataProps) => void
|
||||
mintingTokenFromFactory?: TokenInfo
|
||||
importedWhitelistDetails?: WhitelistDetailsDataProps
|
||||
}
|
||||
|
||||
export interface WhitelistDetailsDataProps {
|
||||
whitelistState: WhitelistState
|
||||
whitelistType: WhitelistType
|
||||
contractAddress?: string
|
||||
members?: string[] | WhitelistFlexMember[]
|
||||
unitPrice?: string
|
||||
startTime?: string
|
||||
endTime?: string
|
||||
perAddressLimit?: number
|
||||
memberLimit?: number
|
||||
admins?: string[]
|
||||
adminsMutable?: boolean
|
||||
}
|
||||
|
||||
type WhitelistState = 'none' | 'existing' | 'new'
|
||||
|
||||
export type WhitelistType = 'standard' | 'flex' | 'merkletree'
|
||||
|
||||
export const WhitelistDetails = ({
|
||||
onChange,
|
||||
mintingTokenFromFactory,
|
||||
importedWhitelistDetails,
|
||||
}: WhitelistDetailsProps) => {
|
||||
const wallet = useWallet()
|
||||
const { timezone } = useGlobalSettings()
|
||||
|
||||
const [whitelistState, setWhitelistState] = useState<WhitelistState>('none')
|
||||
const [whitelistType, setWhitelistType] = useState<WhitelistType>('standard')
|
||||
const [startDate, setStartDate] = useState<Date | undefined>(undefined)
|
||||
const [endDate, setEndDate] = useState<Date | undefined>(undefined)
|
||||
const [whitelistStandardArray, setWhitelistStandardArray] = useState<string[]>([])
|
||||
const [whitelistFlexArray, setWhitelistFlexArray] = useState<WhitelistFlexMember[]>([])
|
||||
const [whitelistMerkleTreeArray, setWhitelistMerkleTreeArray] = useState<string[]>([])
|
||||
const [adminsMutable, setAdminsMutable] = useState<boolean>(true)
|
||||
|
||||
const whitelistAddressState = useInputState({
|
||||
id: 'whitelist-address',
|
||||
name: 'whitelistAddress',
|
||||
title: 'Whitelist Address',
|
||||
defaultValue: '',
|
||||
})
|
||||
|
||||
const unitPriceState = useNumberInputState({
|
||||
id: 'unit-price',
|
||||
name: 'unitPrice',
|
||||
title: 'Unit Price',
|
||||
subtitle: `Token price for whitelisted addresses \n (min. 0 ${
|
||||
mintingTokenFromFactory ? mintingTokenFromFactory.displayName : 'STARS'
|
||||
})`,
|
||||
placeholder: '25',
|
||||
})
|
||||
|
||||
const memberLimitState = useNumberInputState({
|
||||
id: 'member-limit',
|
||||
name: 'memberLimit',
|
||||
title: 'Member Limit',
|
||||
subtitle: 'Maximum number of whitelisted addresses',
|
||||
placeholder: '1000',
|
||||
})
|
||||
|
||||
const perAddressLimitState = useNumberInputState({
|
||||
id: 'per-address-limit',
|
||||
name: 'perAddressLimit',
|
||||
title: 'Per Address Limit',
|
||||
subtitle: 'Maximum number of tokens per whitelisted address',
|
||||
placeholder: '5',
|
||||
})
|
||||
|
||||
const addressListState = useAddressListState()
|
||||
|
||||
const whitelistFileOnChange = (data: string[]) => {
|
||||
if (whitelistType === 'standard') setWhitelistStandardArray(data)
|
||||
if (whitelistType === 'merkletree') setWhitelistMerkleTreeArray(data)
|
||||
}
|
||||
|
||||
const whitelistFlexFileOnChange = (whitelistData: WhitelistFlexMember[]) => {
|
||||
setWhitelistFlexArray(whitelistData)
|
||||
}
|
||||
|
||||
const downloadSampleWhitelistFlexFile = () => {
|
||||
const csvData =
|
||||
'address,mint_count\nstars153w5xhuqu3et29lgqk4dsynj6gjn96lr33wx4e,3\nstars1xkes5r2k8u3m3ayfpverlkcrq3k4jhdk8ws0uz,1\nstars1s8qx0zvz8yd6e4x0mqmqf7fr9vvfn622wtp3g3,2'
|
||||
const blob = new Blob([csvData], { type: 'text/csv' })
|
||||
const url = window.URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.setAttribute('href', url)
|
||||
a.setAttribute('download', 'sample_whitelist_flex.csv')
|
||||
a.click()
|
||||
}
|
||||
|
||||
const downloadSampleWhitelistFile = () => {
|
||||
const txtData =
|
||||
'stars153w5xhuqu3et29lgqk4dsynj6gjn96lr33wx4e\nstars1xkes5r2k8u3m3ayfpverlkcrq3k4jhdk8ws0uz\nstars1s8qx0zvz8yd6e4x0mqmqf7fr9vvfn622wtp3g3'
|
||||
const blob = new Blob([txtData], { type: 'text/txt' })
|
||||
const url = window.URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.setAttribute('href', url)
|
||||
a.setAttribute('download', 'sample_whitelist.txt')
|
||||
a.click()
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!importedWhitelistDetails) {
|
||||
setWhitelistStandardArray([])
|
||||
setWhitelistFlexArray([])
|
||||
setWhitelistMerkleTreeArray([])
|
||||
}
|
||||
}, [whitelistType])
|
||||
|
||||
useEffect(() => {
|
||||
const data: WhitelistDetailsDataProps = {
|
||||
whitelistState,
|
||||
whitelistType,
|
||||
contractAddress: whitelistAddressState.value
|
||||
.toLowerCase()
|
||||
.replace(/,/g, '')
|
||||
.replace(/"/g, '')
|
||||
.replace(/'/g, '')
|
||||
.replace(/ /g, ''),
|
||||
members:
|
||||
whitelistType === 'standard'
|
||||
? whitelistStandardArray
|
||||
: whitelistType === 'merkletree'
|
||||
? whitelistMerkleTreeArray
|
||||
: whitelistFlexArray,
|
||||
unitPrice: unitPriceState.value
|
||||
? (Number(unitPriceState.value) * 1_000_000).toString()
|
||||
: unitPriceState.value === 0
|
||||
? '0'
|
||||
: undefined,
|
||||
startTime: startDate ? (startDate.getTime() * 1_000_000).toString() : '',
|
||||
endTime: endDate ? (endDate.getTime() * 1_000_000).toString() : '',
|
||||
perAddressLimit: perAddressLimitState.value,
|
||||
memberLimit: memberLimitState.value,
|
||||
admins: [
|
||||
...new Set(
|
||||
addressListState.values
|
||||
.map((a) => a.address.trim())
|
||||
.filter((address) => address !== '' && isValidAddress(address.trim()) && address.startsWith('stars')),
|
||||
),
|
||||
],
|
||||
adminsMutable,
|
||||
}
|
||||
onChange(data)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [
|
||||
whitelistAddressState.value,
|
||||
unitPriceState.value,
|
||||
memberLimitState.value,
|
||||
perAddressLimitState.value,
|
||||
startDate,
|
||||
endDate,
|
||||
whitelistStandardArray,
|
||||
whitelistFlexArray,
|
||||
whitelistMerkleTreeArray,
|
||||
whitelistState,
|
||||
whitelistType,
|
||||
addressListState.values,
|
||||
adminsMutable,
|
||||
])
|
||||
|
||||
// make the necessary changes with respect to imported whitelist details
|
||||
useEffect(() => {
|
||||
if (importedWhitelistDetails) {
|
||||
setWhitelistState(importedWhitelistDetails.whitelistState)
|
||||
setWhitelistType(importedWhitelistDetails.whitelistType)
|
||||
whitelistAddressState.onChange(
|
||||
importedWhitelistDetails.contractAddress ? importedWhitelistDetails.contractAddress : '',
|
||||
)
|
||||
unitPriceState.onChange(
|
||||
importedWhitelistDetails.unitPrice ? Number(importedWhitelistDetails.unitPrice) / 1000000 : 0,
|
||||
)
|
||||
memberLimitState.onChange(importedWhitelistDetails.memberLimit ? importedWhitelistDetails.memberLimit : 0)
|
||||
perAddressLimitState.onChange(
|
||||
importedWhitelistDetails.perAddressLimit ? importedWhitelistDetails.perAddressLimit : 0,
|
||||
)
|
||||
setStartDate(
|
||||
importedWhitelistDetails.startTime
|
||||
? new Date(Number(importedWhitelistDetails.startTime) / 1_000_000)
|
||||
: undefined,
|
||||
)
|
||||
setEndDate(
|
||||
importedWhitelistDetails.endTime ? new Date(Number(importedWhitelistDetails.endTime) / 1_000_000) : undefined,
|
||||
)
|
||||
setAdminsMutable(importedWhitelistDetails.adminsMutable ? importedWhitelistDetails.adminsMutable : true)
|
||||
importedWhitelistDetails.admins?.forEach((admin) => {
|
||||
addressListState.reset()
|
||||
addressListState.add({ address: admin })
|
||||
})
|
||||
if (importedWhitelistDetails.whitelistType === 'standard') {
|
||||
setWhitelistStandardArray([])
|
||||
importedWhitelistDetails.members?.forEach((member) => {
|
||||
setWhitelistStandardArray((standardArray) => [...standardArray, member as string])
|
||||
})
|
||||
} else if (importedWhitelistDetails.whitelistType === 'merkletree') {
|
||||
setWhitelistMerkleTreeArray([])
|
||||
// importedWhitelistDetails.members?.forEach((member) => {
|
||||
// setWhitelistMerkleTreeArray((merkleTreeArray) => [...merkleTreeArray, member as string])
|
||||
// })
|
||||
} else if (importedWhitelistDetails.whitelistType === 'flex') {
|
||||
setWhitelistFlexArray([])
|
||||
importedWhitelistDetails.members?.forEach((member) => {
|
||||
setWhitelistFlexArray((flexArray) => [
|
||||
...flexArray,
|
||||
{
|
||||
address: (member as WhitelistFlexMember).address,
|
||||
mint_count: (member as WhitelistFlexMember).mint_count,
|
||||
},
|
||||
])
|
||||
})
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [importedWhitelistDetails])
|
||||
|
||||
useEffect(() => {
|
||||
if (whitelistState === 'new' && wallet.address) {
|
||||
addressListState.reset()
|
||||
addressListState.add({ address: wallet.address })
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [whitelistState, wallet.address])
|
||||
|
||||
return (
|
||||
<div className="py-3 px-8 rounded border-2 border-white/20">
|
||||
<div className="flex justify-center">
|
||||
<div className="ml-4 font-bold form-check form-check-inline">
|
||||
<input
|
||||
checked={whitelistState === 'none'}
|
||||
className="peer sr-only"
|
||||
id="whitelistRadio1"
|
||||
name="whitelistRadioOptions1"
|
||||
onClick={() => {
|
||||
setWhitelistState('none')
|
||||
setWhitelistType('standard')
|
||||
}}
|
||||
type="radio"
|
||||
value="None"
|
||||
/>
|
||||
<label
|
||||
className="inline-block py-1 px-2 text-gray peer-checked:text-white hover:text-white peer-checked:bg-black hover:rounded-sm peer-checked:border-b-2 hover:border-b-2 peer-checked:border-plumbus hover:border-plumbus cursor-pointer form-check-label"
|
||||
htmlFor="whitelistRadio1"
|
||||
>
|
||||
No whitelist
|
||||
</label>
|
||||
</div>
|
||||
<div className="ml-4 font-bold form-check form-check-inline">
|
||||
<input
|
||||
checked={whitelistState === 'existing'}
|
||||
className="peer sr-only"
|
||||
id="whitelistRadio2"
|
||||
name="whitelistRadioOptions2"
|
||||
onClick={() => {
|
||||
setWhitelistState('existing')
|
||||
}}
|
||||
type="radio"
|
||||
value="Existing"
|
||||
/>
|
||||
<label
|
||||
className="inline-block py-1 px-2 text-gray peer-checked:text-white hover:text-white peer-checked:bg-black hover:rounded-sm peer-checked:border-b-2 hover:border-b-2 peer-checked:border-plumbus hover:border-plumbus cursor-pointer form-check-label"
|
||||
htmlFor="whitelistRadio2"
|
||||
>
|
||||
Existing whitelist
|
||||
</label>
|
||||
</div>
|
||||
<div className="ml-4 font-bold form-check form-check-inline">
|
||||
<input
|
||||
checked={whitelistState === 'new'}
|
||||
className="peer sr-only"
|
||||
id="whitelistRadio3"
|
||||
name="whitelistRadioOptions3"
|
||||
onClick={() => {
|
||||
setWhitelistState('new')
|
||||
}}
|
||||
type="radio"
|
||||
value="New"
|
||||
/>
|
||||
<label
|
||||
className="inline-block py-1 px-2 text-gray peer-checked:text-white hover:text-white peer-checked:bg-black hover:rounded-sm peer-checked:border-b-2 hover:border-b-2 peer-checked:border-plumbus hover:border-plumbus cursor-pointer form-check-label"
|
||||
htmlFor="whitelistRadio3"
|
||||
>
|
||||
New whitelist
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Conditional test={whitelistState === 'existing'}>
|
||||
<AddressInput {...whitelistAddressState} className="pb-5" isRequired />
|
||||
</Conditional>
|
||||
|
||||
<Conditional test={whitelistState === 'new'}>
|
||||
<div className="flex justify-between mb-5 ml-6 max-w-[300px] text-lg font-bold">
|
||||
<div className="form-check form-check-inline">
|
||||
<input
|
||||
checked={whitelistType === 'standard'}
|
||||
className="peer sr-only"
|
||||
id="inlineRadio7"
|
||||
name="inlineRadioOptions7"
|
||||
onClick={() => {
|
||||
setWhitelistType('standard')
|
||||
}}
|
||||
type="radio"
|
||||
value="standard"
|
||||
/>
|
||||
<label
|
||||
className="inline-block py-1 px-2 text-gray peer-checked:text-white hover:text-white peer-checked:bg-black hover:rounded-sm peer-checked:border-b-2 hover:border-b-2 peer-checked:border-plumbus hover:border-plumbus cursor-pointer form-check-label"
|
||||
htmlFor="inlineRadio7"
|
||||
>
|
||||
Standard Whitelist
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="form-check form-check-inline">
|
||||
<input
|
||||
checked={whitelistType === 'flex'}
|
||||
className="peer sr-only"
|
||||
id="inlineRadio8"
|
||||
name="inlineRadioOptions8"
|
||||
onClick={() => {
|
||||
setWhitelistType('flex')
|
||||
}}
|
||||
type="radio"
|
||||
value="flex"
|
||||
/>
|
||||
<label
|
||||
className="inline-block py-1 px-2 text-gray peer-checked:text-white hover:text-white peer-checked:bg-black hover:rounded-sm peer-checked:border-b-2 hover:border-b-2 peer-checked:border-plumbus hover:border-plumbus cursor-pointer form-check-label"
|
||||
htmlFor="inlineRadio8"
|
||||
>
|
||||
Whitelist Flex
|
||||
</label>
|
||||
</div>
|
||||
{/* <div className="form-check form-check-inline">
|
||||
<input
|
||||
checked={whitelistType === 'merkletree'}
|
||||
className="peer sr-only"
|
||||
id="inlineRadio9"
|
||||
name="inlineRadioOptions9"
|
||||
onClick={() => {
|
||||
setWhitelistType('merkletree')
|
||||
}}
|
||||
type="radio"
|
||||
value="merkletree"
|
||||
/>
|
||||
<label
|
||||
className="inline-block py-1 px-2 text-gray peer-checked:text-white hover:text-white peer-checked:bg-black hover:rounded-sm peer-checked:border-b-2 hover:border-b-2 peer-checked:border-plumbus hover:border-plumbus cursor-pointer form-check-label"
|
||||
htmlFor="inlineRadio9"
|
||||
>
|
||||
Whitelist Merkle Tree
|
||||
</label>
|
||||
</div> */}
|
||||
</div>
|
||||
<div className="grid grid-cols-2">
|
||||
<FormGroup subtitle="Information about your minting settings" title="Whitelist Minting Details">
|
||||
<NumberInput isRequired {...unitPriceState} />
|
||||
<Conditional test={whitelistType !== 'merkletree'}>
|
||||
<NumberInput isRequired {...memberLimitState} />
|
||||
</Conditional>
|
||||
<Conditional test={whitelistType === 'standard' || whitelistType === 'merkletree'}>
|
||||
<NumberInput isRequired {...perAddressLimitState} />
|
||||
</Conditional>
|
||||
<FormControl
|
||||
htmlId="start-date"
|
||||
isRequired
|
||||
subtitle="Start time for minting tokens to whitelisted addresses"
|
||||
title={`Whitelist Start Time ${timezone === 'Local' ? '(local)' : '(UTC)'}`}
|
||||
>
|
||||
<InputDateTime
|
||||
minDate={
|
||||
timezone === 'Local' ? new Date() : new Date(Date.now() + new Date().getTimezoneOffset() * 60 * 1000)
|
||||
}
|
||||
onChange={(date) =>
|
||||
date
|
||||
? setStartDate(
|
||||
timezone === 'Local'
|
||||
? date
|
||||
: new Date(date.getTime() - new Date().getTimezoneOffset() * 60 * 1000),
|
||||
)
|
||||
: setStartDate(undefined)
|
||||
}
|
||||
value={
|
||||
timezone === 'Local'
|
||||
? startDate
|
||||
: startDate
|
||||
? new Date(startDate.getTime() + new Date().getTimezoneOffset() * 60 * 1000)
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl
|
||||
htmlId="end-date"
|
||||
isRequired
|
||||
subtitle="Whitelist End Time dictates when public sales will start"
|
||||
title={`Whitelist End Time ${timezone === 'Local' ? '(local)' : '(UTC)'}`}
|
||||
>
|
||||
<InputDateTime
|
||||
minDate={
|
||||
timezone === 'Local' ? new Date() : new Date(Date.now() + new Date().getTimezoneOffset() * 60 * 1000)
|
||||
}
|
||||
onChange={(date) =>
|
||||
date
|
||||
? setEndDate(
|
||||
timezone === 'Local'
|
||||
? date
|
||||
: new Date(date.getTime() - new Date().getTimezoneOffset() * 60 * 1000),
|
||||
)
|
||||
: setEndDate(undefined)
|
||||
}
|
||||
value={
|
||||
timezone === 'Local'
|
||||
? endDate
|
||||
: endDate
|
||||
? new Date(endDate.getTime() + new Date().getTimezoneOffset() * 60 * 1000)
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormGroup>
|
||||
<div>
|
||||
<div className="mt-2 ml-3 w-[65%] form-control">
|
||||
<label className="justify-start cursor-pointer label">
|
||||
<span className="mr-4 font-bold">Mutable Administrator Addresses</span>
|
||||
<input
|
||||
checked={adminsMutable}
|
||||
className={`toggle ${adminsMutable ? `bg-stargaze` : `bg-gray-600`}`}
|
||||
onClick={() => setAdminsMutable(!adminsMutable)}
|
||||
type="checkbox"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div className="my-4 ml-4">
|
||||
<AddressList
|
||||
entries={addressListState.entries}
|
||||
onAdd={addressListState.add}
|
||||
onChange={addressListState.update}
|
||||
onRemove={addressListState.remove}
|
||||
subtitle="The list of administrator addresses"
|
||||
title="Administrator Addresses"
|
||||
/>
|
||||
</div>
|
||||
<Conditional test={whitelistType === 'standard'}>
|
||||
<FormGroup
|
||||
subtitle={
|
||||
<div>
|
||||
<span>TXT file that contains the whitelisted addresses</span>
|
||||
<Button className="mt-2 text-sm text-white" onClick={downloadSampleWhitelistFile}>
|
||||
Download Sample File
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
title="Whitelist File"
|
||||
>
|
||||
<WhitelistUpload onChange={whitelistFileOnChange} />
|
||||
</FormGroup>
|
||||
<Conditional test={whitelistStandardArray.length > 0}>
|
||||
<JsonPreview content={whitelistStandardArray} initialState title="File Contents" />
|
||||
</Conditional>
|
||||
</Conditional>
|
||||
<Conditional test={whitelistType === 'flex'}>
|
||||
<FormGroup
|
||||
subtitle={
|
||||
<div>
|
||||
<span>CSV file that contains the whitelisted addresses and corresponding mint counts</span>
|
||||
<Button className="mt-2 text-sm text-white" onClick={downloadSampleWhitelistFlexFile}>
|
||||
Download Sample File
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
title="Whitelist File"
|
||||
>
|
||||
<WhitelistFlexUpload onChange={whitelistFlexFileOnChange} />
|
||||
</FormGroup>
|
||||
<Conditional test={whitelistFlexArray.length > 0}>
|
||||
<JsonPreview content={whitelistFlexArray} initialState={false} title="File Contents" />
|
||||
</Conditional>
|
||||
</Conditional>
|
||||
<Conditional test={whitelistType === 'merkletree'}>
|
||||
<FormGroup
|
||||
subtitle={
|
||||
<div>
|
||||
<span>TXT file that contains the whitelisted addresses</span>
|
||||
<Button className="mt-2 text-sm text-white" onClick={downloadSampleWhitelistFile}>
|
||||
Download Sample File
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
title="Whitelist File"
|
||||
>
|
||||
<WhitelistUpload onChange={whitelistFileOnChange} />
|
||||
</FormGroup>
|
||||
<Conditional test={whitelistStandardArray.length > 0}>
|
||||
<JsonPreview content={whitelistStandardArray} initialState title="File Contents" />
|
||||
</Conditional>
|
||||
</Conditional>
|
||||
</div>
|
||||
</div>
|
||||
</Conditional>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -8,13 +8,17 @@ import {
|
||||
FEATURED_VENDING_IBC_TIA_FACTORY_MERKLE_TREE_ADDRESS,
|
||||
FEATURED_VENDING_IBC_USDC_FACTORY_FLEX_ADDRESS,
|
||||
OPEN_EDITION_FACTORY_ADDRESS,
|
||||
OPEN_EDITION_FACTORY_FLEX_ADDRESS,
|
||||
OPEN_EDITION_IBC_ATOM_FACTORY_ADDRESS,
|
||||
OPEN_EDITION_IBC_ATOM_FACTORY_FLEX_ADDRESS,
|
||||
OPEN_EDITION_IBC_CRBRUS_FACTORY_ADDRESS,
|
||||
OPEN_EDITION_IBC_FRNZ_FACTORY_ADDRESS,
|
||||
OPEN_EDITION_IBC_KUJI_FACTORY_ADDRESS,
|
||||
OPEN_EDITION_IBC_NBTC_FACTORY_ADDRESS,
|
||||
OPEN_EDITION_IBC_TIA_FACTORY_ADDRESS,
|
||||
OPEN_EDITION_IBC_TIA_FACTORY_FLEX_ADDRESS,
|
||||
OPEN_EDITION_IBC_USDC_FACTORY_ADDRESS,
|
||||
OPEN_EDITION_IBC_USDC_FACTORY_FLEX_ADDRESS,
|
||||
OPEN_EDITION_IBC_USK_FACTORY_ADDRESS,
|
||||
OPEN_EDITION_NATIVE_BRNCH_FACTORY_ADDRESS,
|
||||
OPEN_EDITION_NATIVE_STRDST_FACTORY_ADDRESS,
|
||||
@ -95,6 +99,7 @@ export const openEditionStarsMinter: MinterInfo = {
|
||||
supportedToken: stars,
|
||||
updatable: false,
|
||||
featured: false,
|
||||
flexible: false,
|
||||
}
|
||||
|
||||
export const openEditionUpdatableStarsMinter: MinterInfo = {
|
||||
@ -103,6 +108,7 @@ export const openEditionUpdatableStarsMinter: MinterInfo = {
|
||||
supportedToken: stars,
|
||||
updatable: true,
|
||||
featured: false,
|
||||
flexible: false,
|
||||
}
|
||||
|
||||
export const openEditionIbcAtomMinter: MinterInfo = {
|
||||
@ -111,6 +117,7 @@ export const openEditionIbcAtomMinter: MinterInfo = {
|
||||
supportedToken: ibcAtom,
|
||||
updatable: false,
|
||||
featured: false,
|
||||
flexible: false,
|
||||
}
|
||||
|
||||
export const openEditionUpdatableIbcAtomMinter: MinterInfo = {
|
||||
@ -119,6 +126,7 @@ export const openEditionUpdatableIbcAtomMinter: MinterInfo = {
|
||||
supportedToken: ibcAtom,
|
||||
updatable: true,
|
||||
featured: false,
|
||||
flexible: false,
|
||||
}
|
||||
|
||||
export const openEditionIbcUsdcMinter: MinterInfo = {
|
||||
@ -127,6 +135,7 @@ export const openEditionIbcUsdcMinter: MinterInfo = {
|
||||
supportedToken: ibcUsdc,
|
||||
updatable: false,
|
||||
featured: false,
|
||||
flexible: false,
|
||||
}
|
||||
|
||||
export const openEditionIbcTiaMinter: MinterInfo = {
|
||||
@ -135,6 +144,7 @@ export const openEditionIbcTiaMinter: MinterInfo = {
|
||||
supportedToken: ibcTia,
|
||||
updatable: false,
|
||||
featured: false,
|
||||
flexible: false,
|
||||
}
|
||||
|
||||
export const openEditionIbcNbtcMinter: MinterInfo = {
|
||||
@ -143,6 +153,7 @@ export const openEditionIbcNbtcMinter: MinterInfo = {
|
||||
supportedToken: ibcNbtc,
|
||||
updatable: false,
|
||||
featured: false,
|
||||
flexible: false,
|
||||
}
|
||||
|
||||
export const openEditionUpdatableIbcUsdcMinter: MinterInfo = {
|
||||
@ -151,6 +162,7 @@ export const openEditionUpdatableIbcUsdcMinter: MinterInfo = {
|
||||
supportedToken: ibcUsdc,
|
||||
updatable: true,
|
||||
featured: false,
|
||||
flexible: false,
|
||||
}
|
||||
|
||||
export const openEditionUpdatableIbcTiaMinter: MinterInfo = {
|
||||
@ -159,6 +171,7 @@ export const openEditionUpdatableIbcTiaMinter: MinterInfo = {
|
||||
supportedToken: ibcTia,
|
||||
updatable: true,
|
||||
featured: false,
|
||||
flexible: false,
|
||||
}
|
||||
|
||||
export const openEditionUpdatableIbcNbtcMinter: MinterInfo = {
|
||||
@ -167,6 +180,7 @@ export const openEditionUpdatableIbcNbtcMinter: MinterInfo = {
|
||||
supportedToken: ibcNbtc,
|
||||
updatable: true,
|
||||
featured: false,
|
||||
flexible: false,
|
||||
}
|
||||
|
||||
export const openEditionIbcFrnzMinter: MinterInfo = {
|
||||
@ -175,6 +189,7 @@ export const openEditionIbcFrnzMinter: MinterInfo = {
|
||||
supportedToken: ibcFrnz,
|
||||
updatable: false,
|
||||
featured: false,
|
||||
flexible: false,
|
||||
}
|
||||
|
||||
export const openEditionUpdatableIbcFrnzMinter: MinterInfo = {
|
||||
@ -183,6 +198,7 @@ export const openEditionUpdatableIbcFrnzMinter: MinterInfo = {
|
||||
supportedToken: ibcFrnz,
|
||||
updatable: true,
|
||||
featured: false,
|
||||
flexible: false,
|
||||
}
|
||||
|
||||
export const openEditionIbcUskMinter: MinterInfo = {
|
||||
@ -191,6 +207,7 @@ export const openEditionIbcUskMinter: MinterInfo = {
|
||||
supportedToken: ibcUsk,
|
||||
updatable: false,
|
||||
featured: false,
|
||||
flexible: false,
|
||||
}
|
||||
|
||||
export const openEditionUpdatableIbcUskMinter: MinterInfo = {
|
||||
@ -199,6 +216,7 @@ export const openEditionUpdatableIbcUskMinter: MinterInfo = {
|
||||
supportedToken: ibcUsk,
|
||||
updatable: true,
|
||||
featured: false,
|
||||
flexible: false,
|
||||
}
|
||||
|
||||
export const openEditionIbcKujiMinter: MinterInfo = {
|
||||
@ -207,6 +225,7 @@ export const openEditionIbcKujiMinter: MinterInfo = {
|
||||
supportedToken: ibcKuji,
|
||||
updatable: false,
|
||||
featured: false,
|
||||
flexible: false,
|
||||
}
|
||||
|
||||
// export const openEditionIbcHuahuaMinter: MinterInfo = {
|
||||
@ -223,6 +242,7 @@ export const openEditionIbcCrbrusMinter: MinterInfo = {
|
||||
supportedToken: ibcCrbrus,
|
||||
updatable: false,
|
||||
featured: false,
|
||||
flexible: false,
|
||||
}
|
||||
|
||||
export const openEditionNativeStrdstMinter: MinterInfo = {
|
||||
@ -231,6 +251,7 @@ export const openEditionNativeStrdstMinter: MinterInfo = {
|
||||
supportedToken: nativeStardust,
|
||||
updatable: false,
|
||||
featured: false,
|
||||
flexible: false,
|
||||
}
|
||||
|
||||
export const openEditionNativeBrnchMinter: MinterInfo = {
|
||||
@ -239,6 +260,7 @@ export const openEditionNativeBrnchMinter: MinterInfo = {
|
||||
supportedToken: nativeBrnch,
|
||||
updatable: false,
|
||||
featured: false,
|
||||
flexible: false,
|
||||
}
|
||||
|
||||
export const openEditionMinterList = [
|
||||
@ -263,6 +285,49 @@ export const openEditionMinterList = [
|
||||
openEditionNativeBrnchMinter,
|
||||
]
|
||||
|
||||
export const flexibleOpenEditionStarsMinter: MinterInfo = {
|
||||
id: 'flexible-open-edition-stars-minter',
|
||||
factoryAddress: OPEN_EDITION_FACTORY_FLEX_ADDRESS,
|
||||
supportedToken: stars,
|
||||
updatable: false,
|
||||
featured: false,
|
||||
flexible: true,
|
||||
}
|
||||
|
||||
export const flexibleOpenEditionIbcAtomMinter: MinterInfo = {
|
||||
id: 'flexible-open-edition-ibc-atom-minter',
|
||||
factoryAddress: OPEN_EDITION_IBC_ATOM_FACTORY_FLEX_ADDRESS,
|
||||
supportedToken: ibcAtom,
|
||||
updatable: false,
|
||||
featured: false,
|
||||
flexible: true,
|
||||
}
|
||||
|
||||
export const flexibleOpenEditionIbcUsdcMinter: MinterInfo = {
|
||||
id: 'flexible-open-edition-ibc-usdc-minter',
|
||||
factoryAddress: OPEN_EDITION_IBC_USDC_FACTORY_FLEX_ADDRESS,
|
||||
supportedToken: ibcUsdc,
|
||||
updatable: false,
|
||||
featured: false,
|
||||
flexible: true,
|
||||
}
|
||||
|
||||
export const flexibleOpenEditionIbcTiaMinter: MinterInfo = {
|
||||
id: 'flexible-open-edition-ibc-tia-minter',
|
||||
factoryAddress: OPEN_EDITION_IBC_TIA_FACTORY_FLEX_ADDRESS,
|
||||
supportedToken: ibcTia,
|
||||
updatable: false,
|
||||
featured: false,
|
||||
flexible: true,
|
||||
}
|
||||
|
||||
export const flexibleOpenEditionMinterList = [
|
||||
flexibleOpenEditionStarsMinter,
|
||||
flexibleOpenEditionIbcAtomMinter,
|
||||
flexibleOpenEditionIbcUsdcMinter,
|
||||
flexibleOpenEditionIbcTiaMinter,
|
||||
]
|
||||
|
||||
export const vendingStarsMinter: MinterInfo = {
|
||||
id: 'vending-stars-minter',
|
||||
factoryAddress: VENDING_FACTORY_ADDRESS,
|
||||
|
4
env.d.ts
vendored
4
env.d.ts
vendored
@ -78,12 +78,16 @@ declare namespace NodeJS {
|
||||
readonly NEXT_PUBLIC_VENDING_NATIVE_BRNCH_UPDATABLE_FACTORY_ADDRESS: string
|
||||
readonly NEXT_PUBLIC_VENDING_NATIVE_BRNCH_FLEX_FACTORY_ADDRESS: string
|
||||
readonly NEXT_PUBLIC_OPEN_EDITION_FACTORY_ADDRESS: string
|
||||
readonly NEXT_PUBLIC_OPEN_EDITION_FACTORY_FLEX_ADDRESS: string
|
||||
readonly NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_FACTORY_ADDRESS: string
|
||||
readonly NEXT_PUBLIC_OPEN_EDITION_IBC_ATOM_FACTORY_ADDRESS: string
|
||||
readonly NEXT_PUBLIC_OPEN_EDITION_IBC_ATOM_FACTORY_FLEX_ADDRESS: string
|
||||
readonly NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_ATOM_FACTORY_ADDRESS: string
|
||||
readonly NEXT_PUBLIC_OPEN_EDITION_IBC_USDC_FACTORY_ADDRESS: string
|
||||
readonly NEXT_PUBLIC_OPEN_EDITION_IBC_USDC_FACTORY_FLEX_ADDRESS: string
|
||||
readonly NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_USDC_FACTORY_ADDRESS: string
|
||||
readonly NEXT_PUBLIC_OPEN_EDITION_IBC_TIA_FACTORY_ADDRESS: string
|
||||
readonly NEXT_PUBLIC_OPEN_EDITION_IBC_TIA_FACTORY_FLEX_ADDRESS: string
|
||||
readonly NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_TIA_FACTORY_ADDRESS: string
|
||||
readonly NEXT_PUBLIC_OPEN_EDITION_IBC_NBTC_FACTORY_ADDRESS: string
|
||||
readonly NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_NBTC_FACTORY_ADDRESS: string
|
||||
|
@ -35,6 +35,7 @@ import { LoadingModal } from 'components/LoadingModal'
|
||||
import type { OpenEditionMinterCreatorDataProps } from 'components/openEdition/OpenEditionMinterCreator'
|
||||
import { OpenEditionMinterCreator } from 'components/openEdition/OpenEditionMinterCreator'
|
||||
import {
|
||||
flexibleOpenEditionMinterList,
|
||||
flexibleVendingMinterList,
|
||||
merkleTreeVendingMinterList,
|
||||
openEditionMinterList,
|
||||
@ -61,7 +62,6 @@ import {
|
||||
BLOCK_EXPLORER_URL,
|
||||
NETWORK,
|
||||
OPEN_EDITION_FACTORY_ADDRESS,
|
||||
OPEN_EDITION_UPDATABLE_FACTORY_ADDRESS,
|
||||
SG721_CODE_ID,
|
||||
SG721_UPDATABLE_CODE_ID,
|
||||
STARGAZE_URL,
|
||||
@ -130,20 +130,19 @@ const CollectionCreationPage: NextPage = () => {
|
||||
const [baseMinterCreationFee, setBaseMinterCreationFee] = useState<string | null>(null)
|
||||
const [vendingMinterUpdatableCreationFee, setVendingMinterUpdatableCreationFee] = useState<string | null>(null)
|
||||
const [openEditionMinterCreationFee, setOpenEditionMinterCreationFee] = useState<string | null>(null)
|
||||
const [openEditionMinterUpdatableCreationFee, setOpenEditionMinterUpdatableCreationFee] = useState<string | null>(
|
||||
null,
|
||||
)
|
||||
const [vendingMinterFlexCreationFee, setVendingMinterFlexCreationFee] = useState<string | null>(null)
|
||||
const [baseMinterUpdatableCreationFee, setBaseMinterUpdatableCreationFee] = useState<string | null>(null)
|
||||
const [minimumMintPrice, setMinimumMintPrice] = useState<string | null>('0')
|
||||
const [minimumUpdatableMintPrice, setMinimumUpdatableMintPrice] = useState<string | null>('0')
|
||||
const [minimumOpenEditionMintPrice, setMinimumOpenEditionMintPrice] = useState<string | null>('0')
|
||||
const [minimumOpenEditionUpdatableMintPrice, setMinimumOpenEditionUpdatableMintPrice] = useState<string | null>('0')
|
||||
const [minimumFlexMintPrice, setMinimumFlexMintPrice] = useState<string | null>('0')
|
||||
|
||||
const [mintTokenFromOpenEditionFactory, setMintTokenFromOpenEditionFactory] = useState<TokenInfo | undefined>(stars)
|
||||
const [mintTokenFromVendingFactory, setMintTokenFromVendingFactory] = useState<TokenInfo | undefined>(stars)
|
||||
const [vendingFactoryAddress, setVendingFactoryAddress] = useState<string | null>(VENDING_FACTORY_ADDRESS)
|
||||
const [openEditionFactoryAddress, setOpenEditionFactoryAddress] = useState<string | undefined>(
|
||||
OPEN_EDITION_FACTORY_ADDRESS,
|
||||
)
|
||||
|
||||
const vendingFactoryMessages = useMemo(
|
||||
() => vendingFactoryContract?.use(vendingFactoryAddress as string),
|
||||
@ -170,6 +169,7 @@ const CollectionCreationPage: NextPage = () => {
|
||||
const [coverImageUrl, setCoverImageUrl] = useState<string | null>(null)
|
||||
const [transactionHash, setTransactionHash] = useState<string | null>(null)
|
||||
const [isMatchingVendingFactoryPresent, setIsMatchingVendingFactoryPresent] = useState<boolean>(true)
|
||||
const [isMatchingOpenEditionFactoryPresent, setIsMatchingOpenEditionFactoryPresent] = useState<boolean>(true)
|
||||
|
||||
const performVendingMinterChecks = () => {
|
||||
try {
|
||||
@ -1273,32 +1273,27 @@ const CollectionCreationPage: NextPage = () => {
|
||||
setOpenEditionMinterCreationFee(openEditionFactoryParameters?.params?.creation_fee?.amount)
|
||||
setMinimumOpenEditionMintPrice(openEditionFactoryParameters?.params?.min_mint_price?.amount)
|
||||
}
|
||||
if (OPEN_EDITION_UPDATABLE_FACTORY_ADDRESS) {
|
||||
const openEditionUpdatableFactoryParameters = await client
|
||||
.queryContractSmart(OPEN_EDITION_UPDATABLE_FACTORY_ADDRESS, { params: {} })
|
||||
.catch((error) => {
|
||||
toast.error(`${error.message}`, { style: { maxWidth: 'none' } })
|
||||
addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() })
|
||||
})
|
||||
setOpenEditionMinterUpdatableCreationFee(openEditionUpdatableFactoryParameters?.params?.creation_fee?.amount)
|
||||
setMinimumOpenEditionUpdatableMintPrice(openEditionUpdatableFactoryParameters?.params?.min_mint_price?.amount)
|
||||
}
|
||||
setInitialParametersFetched(true)
|
||||
}
|
||||
|
||||
const fetchOpenEditionFactoryParameters = useCallback(async () => {
|
||||
const client = await wallet.getCosmWasmClient()
|
||||
const factoryForSelectedDenom = openEditionMinterList.find(
|
||||
(minter) =>
|
||||
minter.supportedToken === openEditionMinterDetails?.mintingDetails?.selectedMintToken &&
|
||||
minter.updatable === false,
|
||||
)
|
||||
const updatableFactoryForSelectedDenom = openEditionMinterList.find(
|
||||
(minter) =>
|
||||
minter.supportedToken === openEditionMinterDetails?.mintingDetails?.selectedMintToken &&
|
||||
minter.updatable === true,
|
||||
)
|
||||
const factoryForSelectedDenom = openEditionMinterList
|
||||
.concat(flexibleOpenEditionMinterList)
|
||||
.find(
|
||||
(minter) =>
|
||||
minter.supportedToken === openEditionMinterDetails?.mintingDetails?.selectedMintToken &&
|
||||
minter.updatable === openEditionMinterDetails.collectionDetails?.updatable &&
|
||||
minter.flexible ===
|
||||
(openEditionMinterDetails.whitelistDetails?.whitelistState !== 'none' &&
|
||||
openEditionMinterDetails.whitelistDetails?.whitelistType === 'flex'),
|
||||
)
|
||||
|
||||
console.log('OE Factory: ', factoryForSelectedDenom?.factoryAddress)
|
||||
if (factoryForSelectedDenom?.factoryAddress) {
|
||||
setIsMatchingOpenEditionFactoryPresent(true)
|
||||
setOpenEditionFactoryAddress(factoryForSelectedDenom.factoryAddress)
|
||||
|
||||
const openEditionFactoryParameters = await client
|
||||
.queryContractSmart(factoryForSelectedDenom.factoryAddress, { params: {} })
|
||||
.catch((error) => {
|
||||
@ -1306,35 +1301,24 @@ const CollectionCreationPage: NextPage = () => {
|
||||
addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() })
|
||||
})
|
||||
setOpenEditionMinterCreationFee(openEditionFactoryParameters?.params?.creation_fee?.amount)
|
||||
if (!openEditionMinterDetails?.collectionDetails?.updatable) {
|
||||
setMinimumOpenEditionMintPrice(openEditionFactoryParameters?.params?.min_mint_price?.amount)
|
||||
setMintTokenFromOpenEditionFactory(
|
||||
tokensList.find((token) => token.denom === openEditionFactoryParameters?.params?.min_mint_price?.denom),
|
||||
)
|
||||
}
|
||||
}
|
||||
if (updatableFactoryForSelectedDenom?.factoryAddress) {
|
||||
const openEditionUpdatableFactoryParameters = await client
|
||||
.queryContractSmart(updatableFactoryForSelectedDenom.factoryAddress, { params: {} })
|
||||
.catch((error) => {
|
||||
toast.error(`${error.message}`, { style: { maxWidth: 'none' } })
|
||||
addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() })
|
||||
})
|
||||
setOpenEditionMinterUpdatableCreationFee(openEditionUpdatableFactoryParameters?.params?.creation_fee?.amount)
|
||||
if (openEditionMinterDetails?.collectionDetails?.updatable) {
|
||||
setMinimumOpenEditionUpdatableMintPrice(openEditionUpdatableFactoryParameters?.params?.min_mint_price?.amount)
|
||||
setMintTokenFromOpenEditionFactory(
|
||||
tokensList.find(
|
||||
(token) => token.denom === openEditionUpdatableFactoryParameters?.params?.min_mint_price?.denom,
|
||||
),
|
||||
)
|
||||
}
|
||||
setMinimumOpenEditionMintPrice(openEditionFactoryParameters?.params?.min_mint_price?.amount)
|
||||
setMintTokenFromOpenEditionFactory(
|
||||
tokensList.find((token) => token.denom === openEditionFactoryParameters?.params?.min_mint_price?.denom),
|
||||
)
|
||||
} else if (
|
||||
openEditionMinterDetails?.mintingDetails?.selectedMintToken &&
|
||||
openEditionMinterDetails.whitelistDetails?.whitelistState
|
||||
) {
|
||||
setIsMatchingOpenEditionFactoryPresent(false)
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [
|
||||
openEditionMinterDetails?.mintingDetails?.selectedMintToken,
|
||||
openEditionMinterDetails?.collectionDetails?.updatable,
|
||||
openEditionMinterDetails?.whitelistDetails?.whitelistType,
|
||||
openEditionMinterDetails?.whitelistDetails?.whitelistState,
|
||||
wallet.isWalletConnected,
|
||||
openEditionMinterDetails?.isRefreshed,
|
||||
])
|
||||
|
||||
const fetchVendingFactoryParameters = useCallback(async () => {
|
||||
@ -1622,6 +1606,19 @@ const CollectionCreationPage: NextPage = () => {
|
||||
>
|
||||
{openEditionMinterCreatorData?.sg721ContractAddress as string}
|
||||
</Anchor>
|
||||
<Conditional test={openEditionMinterCreatorData?.whitelistContractAddress !== null}>
|
||||
<br />
|
||||
Whitelist Contract Address:{' '}
|
||||
<Anchor
|
||||
className="text-stargaze hover:underline"
|
||||
external
|
||||
href={`/contracts/whitelist/query/?contractAddress=${
|
||||
openEditionMinterCreatorData?.whitelistContractAddress as string
|
||||
}`}
|
||||
>
|
||||
{openEditionMinterCreatorData?.whitelistContractAddress as string}
|
||||
</Anchor>
|
||||
</Conditional>
|
||||
<br />
|
||||
Transaction Hash: {' '}
|
||||
<Conditional test={NETWORK === 'testnet'}>
|
||||
@ -1930,14 +1927,14 @@ const CollectionCreationPage: NextPage = () => {
|
||||
<Conditional test={minterType === 'openEdition'}>
|
||||
<OpenEditionMinterCreator
|
||||
importedOpenEditionMinterDetails={importedDetails?.openEditionMinterDetails}
|
||||
isMatchingFactoryPresent={isMatchingOpenEditionFactoryPresent}
|
||||
minimumMintPrice={minimumOpenEditionMintPrice as string}
|
||||
minimumUpdatableMintPrice={minimumOpenEditionUpdatableMintPrice as string}
|
||||
mintTokenFromFactory={mintTokenFromOpenEditionFactory}
|
||||
minterType={minterType}
|
||||
onChange={setOpenEditionMinterCreatorData}
|
||||
onDetailsChange={setOpenEditionMinterDetails}
|
||||
openEditionFactoryAddress={openEditionFactoryAddress}
|
||||
openEditionMinterCreationFee={openEditionMinterCreationFee as string}
|
||||
openEditionMinterUpdatableCreationFee={openEditionMinterUpdatableCreationFee as string}
|
||||
/>
|
||||
</Conditional>
|
||||
<div className="mx-10">
|
||||
|
@ -80,14 +80,21 @@ export const VENDING_NATIVE_BRNCH_FLEX_FACTORY_ADDRESS =
|
||||
export const BASE_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_BASE_FACTORY_ADDRESS
|
||||
export const BASE_FACTORY_UPDATABLE_ADDRESS = process.env.NEXT_PUBLIC_BASE_FACTORY_UPDATABLE_ADDRESS
|
||||
export const OPEN_EDITION_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_OPEN_EDITION_FACTORY_ADDRESS
|
||||
export const OPEN_EDITION_FACTORY_FLEX_ADDRESS = process.env.NEXT_PUBLIC_OPEN_EDITION_FACTORY_FLEX_ADDRESS
|
||||
export const OPEN_EDITION_UPDATABLE_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_FACTORY_ADDRESS
|
||||
export const OPEN_EDITION_IBC_ATOM_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_OPEN_EDITION_IBC_ATOM_FACTORY_ADDRESS
|
||||
export const OPEN_EDITION_IBC_ATOM_FACTORY_FLEX_ADDRESS =
|
||||
process.env.NEXT_PUBLIC_OPEN_EDITION_IBC_ATOM_FACTORY_FLEX_ADDRESS
|
||||
export const OPEN_EDITION_UPDATABLE_IBC_ATOM_FACTORY_ADDRESS =
|
||||
process.env.NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_ATOM_FACTORY_ADDRESS
|
||||
export const OPEN_EDITION_IBC_USDC_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_OPEN_EDITION_IBC_USDC_FACTORY_ADDRESS
|
||||
export const OPEN_EDITION_IBC_USDC_FACTORY_FLEX_ADDRESS =
|
||||
process.env.NEXT_PUBLIC_OPEN_EDITION_IBC_USDC_FACTORY_FLEX_ADDRESS
|
||||
export const OPEN_EDITION_UPDATABLE_IBC_USDC_FACTORY_ADDRESS =
|
||||
process.env.NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_USDC_FACTORY_ADDRESS
|
||||
export const OPEN_EDITION_IBC_TIA_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_OPEN_EDITION_IBC_TIA_FACTORY_ADDRESS
|
||||
export const OPEN_EDITION_IBC_TIA_FACTORY_FLEX_ADDRESS =
|
||||
process.env.NEXT_PUBLIC_OPEN_EDITION_IBC_TIA_FACTORY_FLEX_ADDRESS
|
||||
export const OPEN_EDITION_UPDATABLE_IBC_TIA_FACTORY_ADDRESS =
|
||||
process.env.NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_TIA_FACTORY_ADDRESS
|
||||
export const OPEN_EDITION_IBC_NBTC_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_OPEN_EDITION_IBC_NBTC_FACTORY_ADDRESS
|
||||
|
Loading…
Reference in New Issue
Block a user