Compare commits

..

No commits in common. "develop" and "fix-factory-validation" have entirely different histories.

48 changed files with 1357 additions and 24551 deletions

1
.env
View File

@ -1 +0,0 @@
CERC_MAX_GENERATE_TIME=180

View File

@ -16,10 +16,8 @@ NEXT_PUBLIC_VENDING_FACTORY_ADDRESS="stars18h7ugh8eaug7wr0w4yjw0ls5s937z35pnkg93
NEXT_PUBLIC_FEATURED_VENDING_FACTORY_ADDRESS="stars14pd96yk3t6gq9l6uyrkg0n5dr09n8rt5y9v3at8x4wl4lrkxhlzq4trqmh" NEXT_PUBLIC_FEATURED_VENDING_FACTORY_ADDRESS="stars14pd96yk3t6gq9l6uyrkg0n5dr09n8rt5y9v3at8x4wl4lrkxhlzq4trqmh"
NEXT_PUBLIC_VENDING_FACTORY_UPDATABLE_ADDRESS="stars1h65nms9gwg4vdktyqj84tu50gwlm34e0eczl5w2ezllxuzfxy9esa9qlt0" NEXT_PUBLIC_VENDING_FACTORY_UPDATABLE_ADDRESS="stars1h65nms9gwg4vdktyqj84tu50gwlm34e0eczl5w2ezllxuzfxy9esa9qlt0"
NEXT_PUBLIC_VENDING_FACTORY_FLEX_ADDRESS="stars1hvu2ghqkcnvhtj2fc6wuazxt4dqcftslp2rwkkkcxy269a35a9pq60ug2q" NEXT_PUBLIC_VENDING_FACTORY_FLEX_ADDRESS="stars1hvu2ghqkcnvhtj2fc6wuazxt4dqcftslp2rwkkkcxy269a35a9pq60ug2q"
NEXT_PUBLIC_VENDING_FACTORY_MERKLE_TREE_ADDRESS="stars167tudcsr9n2y9ljgk4cwxhs0cvkfkk0hh6c3dzngsz7m5s9jmqnsdgr3jy"
NEXT_PUBLIC_FEATURED_VENDING_FACTORY_MERKLE_TREE_ADDRESS="stars167tudcsr9n2y9ljgk4cwxhs0cvkfkk0hh6c3dzngsz7m5s9jmqnsdgr3jy"
NEXT_PUBLIC_FEATURED_VENDING_FACTORY_FLEX_ADDRESS="stars1udlmmnmmnnqamh36hy6d7azn3ycv23yymkmg6558ntalvyt2pz7s8lhgcd" NEXT_PUBLIC_FEATURED_VENDING_FACTORY_FLEX_ADDRESS="stars1udlmmnmmnnqamh36hy6d7azn3ycv23yymkmg6558ntalvyt2pz7s8lhgcd"
# NEXT_PUBLIC_VENDING_FACTORY_UPDATABLE_FLEX_ADDRESS= NEXT_PUBLIC_VENDING_FACTORY_UPDATABLE_FLEX_ADDRESS=
# NEXT_PUBLIC_VENDING_IBC_ATOM_FACTORY_ADDRESS= # NEXT_PUBLIC_VENDING_IBC_ATOM_FACTORY_ADDRESS=
# NEXT_PUBLIC_VENDING_IBC_ATOM_UPDATABLE_FACTORY_ADDRESS= # NEXT_PUBLIC_VENDING_IBC_ATOM_UPDATABLE_FACTORY_ADDRESS=
@ -27,10 +25,8 @@ NEXT_PUBLIC_FEATURED_VENDING_FACTORY_FLEX_ADDRESS="stars1udlmmnmmnnqamh36hy6d7az
# NEXT_PUBLIC_VENDING_IBC_ATOM_UPDATABLE_FACTORY_FLEX_ADDRESS= # NEXT_PUBLIC_VENDING_IBC_ATOM_UPDATABLE_FACTORY_FLEX_ADDRESS=
# NEXT_PUBLIC_VENDING_IBC_USDC_FACTORY_ADDRESS= # NEXT_PUBLIC_VENDING_IBC_USDC_FACTORY_ADDRESS=
# NEXT_PUBLIC_FEATURED_VENDING_IBC_USDC_FACTORY_ADDRESS=
# NEXT_PUBLIC_VENDING_IBC_USDC_UPDATABLE_FACTORY_ADDRESS= # NEXT_PUBLIC_VENDING_IBC_USDC_UPDATABLE_FACTORY_ADDRESS=
# NEXT_PUBLIC_VENDING_IBC_USDC_FACTORY_FLEX_ADDRESS= # NEXT_PUBLIC_VENDING_IBC_USDC_FACTORY_FLEX_ADDRESS=
# NEXT_PUBLIC_FEATURED_VENDING_IBC_USDC_FACTORY_FLEX_ADDRESS=
# NEXT_PUBLIC_VENDING_IBC_USDC_UPDATABLE_FACTORY_FLEX_ADDRESS= # NEXT_PUBLIC_VENDING_IBC_USDC_UPDATABLE_FACTORY_FLEX_ADDRESS=
# NEXT_PUBLIC_VENDING_IBC_USK_FACTORY_ADDRESS= # NEXT_PUBLIC_VENDING_IBC_USK_FACTORY_ADDRESS=
@ -38,15 +34,6 @@ NEXT_PUBLIC_FEATURED_VENDING_FACTORY_FLEX_ADDRESS="stars1udlmmnmmnnqamh36hy6d7az
# NEXT_PUBLIC_VENDING_IBC_USK_FACTORY_FLEX_ADDRESS= # NEXT_PUBLIC_VENDING_IBC_USK_FACTORY_FLEX_ADDRESS=
# NEXT_PUBLIC_VENDING_IBC_USK_UPDATABLE_FACTORY_FLEX_ADDRESS= # NEXT_PUBLIC_VENDING_IBC_USK_UPDATABLE_FACTORY_FLEX_ADDRESS=
# NEXT_PUBLIC_VENDING_IBC_TIA_FACTORY_ADDRESS=
# NEXT_PUBLIC_FEATURED_VENDING_IBC_TIA_FACTORY_ADDRESS=
# NEXT_PUBLIC_VENDING_IBC_TIA_UPDATABLE_FACTORY_ADDRESS=
# NEXT_PUBLIC_VENDING_IBC_TIA_FACTORY_FLEX_ADDRESS=
# NEXT_PUBLIC_VENDING_IBC_TIA_FACTORY_MERKLE_TREE_ADDRESS=
# NEXT_PUBLIC_FEATURED_VENDING_IBC_TIA_FACTORY_MERKLE_TREE_ADDRESS=
# NEXT_PUBLIC_FEATURED_VENDING_IBC_TIA_FACTORY_FLEX_ADDRESS=
# NEXT_PUBLIC_VENDING_IBC_TIA_UPDATABLE_FACTORY_FLEX_ADDRESS=
NEXT_PUBLIC_VENDING_NATIVE_STARDUST_FACTORY_ADDRESS="stars1mxwf2hjcjvqnlw0v3j7m0u34975qesp325wzrgz0ht7vr8ys2zmsenjutf" NEXT_PUBLIC_VENDING_NATIVE_STARDUST_FACTORY_ADDRESS="stars1mxwf2hjcjvqnlw0v3j7m0u34975qesp325wzrgz0ht7vr8ys2zmsenjutf"
NEXT_PUBLIC_VENDING_NATIVE_STARDUST_UPDATABLE_FACTORY_ADDRESS="stars18gjczf88jd4z3a3megwj9g5c9famu654csxfnnq59mkqeszuzy4ssdgr46" NEXT_PUBLIC_VENDING_NATIVE_STARDUST_UPDATABLE_FACTORY_ADDRESS="stars18gjczf88jd4z3a3megwj9g5c9famu654csxfnnq59mkqeszuzy4ssdgr46"
NEXT_PUBLIC_VENDING_NATIVE_STRDST_FLEX_FACTORY_ADDRESS="stars1eluqmr6x78ehl4plrln6khxc0qrspfhc7rt3whmr59escpve0r4swcacjh" NEXT_PUBLIC_VENDING_NATIVE_STRDST_FLEX_FACTORY_ADDRESS="stars1eluqmr6x78ehl4plrln6khxc0qrspfhc7rt3whmr59escpve0r4swcacjh"
@ -59,7 +46,6 @@ NEXT_PUBLIC_BASE_FACTORY_ADDRESS="stars1a45hcxty3spnmm2f0papl8v4dk5ew29s4syhn4ef
NEXT_PUBLIC_BASE_FACTORY_UPDATABLE_ADDRESS="stars100xegx2syry4tclkmejjwxk4nfqahvcqhm9qxut5wxuzhj5d9qfsh5nmym" NEXT_PUBLIC_BASE_FACTORY_UPDATABLE_ADDRESS="stars100xegx2syry4tclkmejjwxk4nfqahvcqhm9qxut5wxuzhj5d9qfsh5nmym"
NEXT_PUBLIC_OPEN_EDITION_FACTORY_ADDRESS="stars1sqweqcxlf2f7qhf27gn5naqusk5q52fkzewmy63c4sglvle3s7ls6k828e" 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_OPEN_EDITION_UPDATABLE_FACTORY_ADDRESS="stars1fk5dkzcylam8mcpqrn8y9spauvc3d4navtaqurcc49dc3p9f8d3qdkvymx"
NEXT_PUBLIC_VENDING_IBC_KUJI_FACTORY_ADDRESS="stars1yyje87e0h9mqg34kp3x75yesa78ve4glc3dstdrn6nscw3zjfanqkj95f0" NEXT_PUBLIC_VENDING_IBC_KUJI_FACTORY_ADDRESS="stars1yyje87e0h9mqg34kp3x75yesa78ve4glc3dstdrn6nscw3zjfanqkj95f0"
@ -73,12 +59,8 @@ NEXT_PUBLIC_VENDING_IBC_CRBRUS_FACTORY_FLEX_ADDRESS="stars1halhp674yxwgn3p4gpkl8
# NEXT_PUBLIC_OPEN_EDITION_IBC_ATOM_FACTORY_ADDRESS= # NEXT_PUBLIC_OPEN_EDITION_IBC_ATOM_FACTORY_ADDRESS=
# NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_ATOM_FACTORY_ADDRESS= # NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_ATOM_FACTORY_ADDRESS=
# NEXT_PUBLIC_OPEN_EDITION_IBC_USDC_FACTORY_ADDRESS="stars152a40mmd3k2kk90add606vrqxcvzdp29qrjx4pjv33cjl6svksfscrrtuk" # NEXT_PUBLIC_OPEN_EDITION_IBC_USDC_FACTORY_ADDRESS=
# NEXT_PUBLIC_OPEN_EDITION_IBC_USDC_FACTORY_FLEX_ADDRESS="stars10sz9mup3a548l34k83q5w59nrklrnvv2gdsdkr2xref4zl5j3d4q0efamx"
# NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_USDC_FACTORY_ADDRESS= # NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_USDC_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_IBC_FRNZ_FACTORY_ADDRESS="stars1vzffawsjhvspstu5lvtzz2x5n7zh07hnw09c9dfxcj78un05rcms5n3q3e"
NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_FRNZ_FACTORY_ADDRESS="stars1tc09vlgdg8rqyapcxwm9qdq8naj4gym9px4ntue9cs0kse5rvess0nee3a" NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_FRNZ_FACTORY_ADDRESS="stars1tc09vlgdg8rqyapcxwm9qdq8naj4gym9px4ntue9cs0kse5rvess0nee3a"
@ -105,14 +87,13 @@ NEXT_PUBLIC_VENDING_IBC_NBTC_UPDATABLE_FACTORY_ADDRESS="stars1k6ee8qgwvumguqnqqr
NEXT_PUBLIC_SG721_NAME_ADDRESS="stars1fx74nkqkw2748av8j7ew7r3xt9cgjqduwn8m0ur5lhe49uhlsasszc5fhr" NEXT_PUBLIC_SG721_NAME_ADDRESS="stars1fx74nkqkw2748av8j7ew7r3xt9cgjqduwn8m0ur5lhe49uhlsasszc5fhr"
NEXT_PUBLIC_ROYALTY_REGISTRY_ADDRESS="stars1crgx0f70fzksa57hq87wtl8f04h0qyk5la0hk0fu8dyhl67ju80qaxzr5z" NEXT_PUBLIC_ROYALTY_REGISTRY_ADDRESS="stars1crgx0f70fzksa57hq87wtl8f04h0qyk5la0hk0fu8dyhl67ju80qaxzr5z"
NEXT_PUBLIC_INFINITY_SWAP_PROTOCOL_ADDRESS="stars136yp6fl9h66m0cwv8weu4w4aawveuz40992ty0atj5ecjd8z0thqv9xpy5" NEXT_PUBLIC_INFINITY_SWAP_PROTOCOL_ADDRESS="stars136yp6fl9h66m0cwv8weu4w4aawveuz40992ty0atj5ecjd8z0thqv9xpy5"
NEXT_PUBLIC_WHITELIST_CODE_ID=4008 NEXT_PUBLIC_WHITELIST_CODE_ID=3131
NEXT_PUBLIC_WHITELIST_FLEX_CODE_ID=4009 NEXT_PUBLIC_WHITELIST_FLEX_CODE_ID=3130
NEXT_PUBLIC_WHITELIST_MERKLE_TREE_CODE_ID=3911
NEXT_PUBLIC_BADGE_HUB_CODE_ID=1336 NEXT_PUBLIC_BADGE_HUB_CODE_ID=1336
NEXT_PUBLIC_BADGE_HUB_ADDRESS="stars1dacun0xn7z73qzdcmq27q3xn6xuprg8e2ugj364784al2v27tklqynhuqa" NEXT_PUBLIC_BADGE_HUB_ADDRESS="stars1dacun0xn7z73qzdcmq27q3xn6xuprg8e2ugj364784al2v27tklqynhuqa"
NEXT_PUBLIC_BADGE_NFT_CODE_ID=1337 NEXT_PUBLIC_BADGE_NFT_CODE_ID=1337
NEXT_PUBLIC_BADGE_NFT_ADDRESS="stars1vlw4y54dyzt3zg7phj8yey9fg4zj49czknssngwmgrnwymyktztstalg7t" NEXT_PUBLIC_BADGE_NFT_ADDRESS="stars1vlw4y54dyzt3zg7phj8yey9fg4zj49czknssngwmgrnwymyktztstalg7t"
NEXT_PUBLIC_SPLITS_CODE_ID=4010 NEXT_PUBLIC_SPLITS_CODE_ID=1905
NEXT_PUBLIC_CW4_GROUP_CODE_ID=1904 NEXT_PUBLIC_CW4_GROUP_CODE_ID=1904
NEXT_PUBLIC_API_URL=https://nft-api.elgafar-1.stargaze-apis.com NEXT_PUBLIC_API_URL=https://nft-api.elgafar-1.stargaze-apis.com
@ -122,8 +103,6 @@ NEXT_PUBLIC_STARGAZE_WEBSITE_URL=https://testnet.publicawesome.dev
NEXT_PUBLIC_BADGES_URL=https://badges.publicawesome.dev NEXT_PUBLIC_BADGES_URL=https://badges.publicawesome.dev
NEXT_PUBLIC_WEBSITE_URL=https:// NEXT_PUBLIC_WEBSITE_URL=https://
NEXT_PUBLIC_SYNC_COLLECTIONS_API_URL="https://..." NEXT_PUBLIC_SYNC_COLLECTIONS_API_URL="https://..."
NEXT_PUBLIC_WHITELIST_MERKLE_TREE_API_URL="https://..."
NEXT_PUBLIC_NFT_STORAGE_DEFAULT_API_KEY="..."
NEXT_PUBLIC_MEILISEARCH_HOST="https://search.publicawesome.dev" NEXT_PUBLIC_MEILISEARCH_HOST="https://search.publicawesome.dev"
NEXT_PUBLIC_MEILISEARCH_API_KEY= "..." NEXT_PUBLIC_MEILISEARCH_API_KEY= "..."

View File

@ -1,45 +0,0 @@
name: Publish ApplicationRecord to Registry
on:
release:
types: [published]
push:
branches:
- main
- '*'
env:
CERC_REGISTRY_USER_KEY: ${{ secrets.CICD_LACONIC_USER_KEY }}
CERC_REGISTRY_BOND_ID: ${{ secrets.CICD_LACONIC_BOND_ID }}
jobs:
cns_publish:
runs-on: ubuntu-latest
steps:
- name: "Clone project repository"
uses: actions/checkout@v3
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: 18 # though you need version 14 with geojson
# - name: "Install exiftool"
# run: |
# apt-get update -y
# apt-get upgrade -y
# apt-get install exiftool -y
#- name: "Exiftool Version"
# run: |
# exiftool -ver
- name: "Install Yarn"
run: npm install -g yarn
- name: "Install registry CLI"
run: |
npm config set @cerc-io:registry https://git.vdb.to/api/packages/cerc-io/npm/
yarn global add @cerc-io/laconic-registry-cli
- name: "Install jq"
uses: dcarbone/install-jq-action@v2.1.0
- name: "Publish App Record"
run: scripts/publish-app-record.sh
#- name: "Create Metadata Record"
# run: scripts/create-metadata-record.sh
- name: "Request Deployment"
run: scripts/request-app-deployment.sh

View File

@ -298,16 +298,17 @@ export const Sidebar = () => {
> >
<Link href="/contracts/royaltyRegistry/">Royalty Registry</Link> <Link href="/contracts/royaltyRegistry/">Royalty Registry</Link>
</li> </li>
<Conditional test={NETWORK === 'testnet'}>
<li <li
className={clsx( className={clsx(
'text-lg font-bold hover:text-white hover:bg-stargaze-80 rounded', 'text-lg font-bold hover:text-white hover:bg-stargaze-80 rounded',
router.asPath.includes('/contracts/upload/') ? 'text-white' : 'text-gray', router.asPath.includes('/contracts/upload/') ? 'text-white' : 'text-gray',
)} )}
tabIndex={-1} tabIndex={-1}
> >
<Link href="/contracts/upload/">Upload Contract</Link> <Link href="/contracts/upload/">Upload Contract</Link>
</li> </li>
</Conditional>
</ul> </ul>
</li> </li>
</ul> </ul>

View File

@ -78,7 +78,7 @@ export const WhitelistUpload = ({ onChange }: WhitelistUploadProps) => {
const printableData = data?.map((item) => item.replace(regex, '')) const printableData = data?.map((item) => item.replace(regex, ''))
const names = printableData?.filter((address) => address !== '' && address.endsWith('.stars')) const names = printableData?.filter((address) => address !== '' && address.endsWith('.stars'))
const strippedNames = names?.map((name) => name.split('.')[0]) const strippedNames = names?.map((name) => name.split('.')[0])
console.log('names: ', names) console.log(names)
if (strippedNames?.length) { if (strippedNames?.length) {
await toast await toast
.promise(resolveAddresses(strippedNames), { .promise(resolveAddresses(strippedNames), {

View File

@ -13,7 +13,6 @@ import type { ChangeEvent } from 'react'
import { useEffect, useMemo, useRef, useState } from 'react' import { useEffect, useMemo, useRef, useState } from 'react'
import { toast } from 'react-hot-toast' import { toast } from 'react-hot-toast'
import type { UploadServiceType } from 'services/upload' import type { UploadServiceType } from 'services/upload'
import { NFT_STORAGE_DEFAULT_API_KEY } from 'utils/constants'
import { getAssetType } from 'utils/getAssetType' import { getAssetType } from 'utils/getAssetType'
export type UploadMethod = 'new' | 'existing' export type UploadMethod = 'new' | 'existing'
@ -38,7 +37,6 @@ export const ImageUploadDetails = ({ onChange, mintRule }: ImageUploadDetailsPro
const [assetFile, setAssetFile] = useState<File>() const [assetFile, setAssetFile] = useState<File>()
const [uploadMethod, setUploadMethod] = useState<UploadMethod>('new') const [uploadMethod, setUploadMethod] = useState<UploadMethod>('new')
const [uploadService, setUploadService] = useState<UploadServiceType>('nft-storage') const [uploadService, setUploadService] = useState<UploadServiceType>('nft-storage')
const [useDefaultApiKey, setUseDefaultApiKey] = useState(false)
const assetFileRef = useRef<HTMLInputElement | null>(null) const assetFileRef = useRef<HTMLInputElement | null>(null)
@ -132,14 +130,6 @@ export const ImageUploadDetails = ({ onChange, mintRule }: ImageUploadDetailsPro
imageUrlState.onChange('') imageUrlState.onChange('')
}, [uploadMethod, mintRule]) }, [uploadMethod, mintRule])
useEffect(() => {
if (useDefaultApiKey) {
nftStorageApiKeyState.onChange(NFT_STORAGE_DEFAULT_API_KEY || '')
} else {
nftStorageApiKeyState.onChange('')
}
}, [useDefaultApiKey])
const videoPreview = useMemo( const videoPreview = useMemo(
() => ( () => (
<video <video
@ -279,22 +269,7 @@ export const ImageUploadDetails = ({ onChange, mintRule }: ImageUploadDetailsPro
<div className="flex w-full"> <div className="flex w-full">
<Conditional test={uploadService === 'nft-storage'}> <Conditional test={uploadService === 'nft-storage'}>
<div className="flex-col w-full"> <TextInput {...nftStorageApiKeyState} className="w-full" />
<TextInput {...nftStorageApiKeyState} className="w-full" disabled={useDefaultApiKey} />
<div className="flex-row mt-2 w-full form-control">
<label className="cursor-pointer label">
<span className="mr-2 font-bold">Use Default API Key</span>
<input
checked={useDefaultApiKey}
className={`${useDefaultApiKey ? `bg-stargaze` : `bg-gray-600`} checkbox`}
onClick={() => {
setUseDefaultApiKey(!useDefaultApiKey)
}}
type="checkbox"
/>
</label>
</div>
</div>
</Conditional> </Conditional>
<Conditional test={uploadService === 'pinata'}> <Conditional test={uploadService === 'pinata'}>
<TextInput {...pinataApiKeyState} className="w-full" /> <TextInput {...pinataApiKeyState} className="w-full" />

View File

@ -3,7 +3,6 @@
import { toUtf8 } from '@cosmjs/encoding' import { toUtf8 } from '@cosmjs/encoding'
import clsx from 'clsx' import clsx from 'clsx'
import { AirdropUpload } from 'components/AirdropUpload' import { AirdropUpload } from 'components/AirdropUpload'
import { Alert } from 'components/Alert'
import { Button } from 'components/Button' import { Button } from 'components/Button'
import type { DispatchExecuteArgs } from 'components/collections/actions/actions' import type { DispatchExecuteArgs } from 'components/collections/actions/actions'
import { dispatchExecute, isEitherType, previewExecutePayload } from 'components/collections/actions/actions' import { dispatchExecute, isEitherType, previewExecutePayload } from 'components/collections/actions/actions'
@ -116,13 +115,6 @@ export const CollectionActions = ({
subtitle: 'Address of the recipient', subtitle: 'Address of the recipient',
}) })
const creatorState = useInputState({
id: 'creator-address',
name: 'creator',
title: 'Creator Address',
subtitle: 'Address of the creator',
})
const tokenURIState = useInputState({ const tokenURIState = useInputState({
id: 'token-uri', id: 'token-uri',
name: 'tokenURI', name: 'tokenURI',
@ -225,7 +217,6 @@ export const CollectionActions = ({
]) ])
const showPriceField = isEitherType(type, ['update_mint_price', 'update_discount_price']) const showPriceField = isEitherType(type, ['update_mint_price', 'update_discount_price'])
const showDescriptionField = type === 'update_collection_info' const showDescriptionField = type === 'update_collection_info'
const showCreatorField = type === 'update_collection_info'
const showImageField = type === 'update_collection_info' const showImageField = type === 'update_collection_info'
const showExternalLinkField = type === 'update_collection_info' const showExternalLinkField = type === 'update_collection_info'
const showRoyaltyRelatedFields = const showRoyaltyRelatedFields =
@ -298,16 +289,6 @@ export const CollectionActions = ({
void resolveRoyaltyPaymentAddress() void resolveRoyaltyPaymentAddress()
}, [royaltyPaymentAddressState.value]) }, [royaltyPaymentAddressState.value])
const resolveCreatorAddress = async () => {
await resolveAddress(creatorState.value.trim(), wallet).then((resolvedAddress) => {
creatorState.onChange(resolvedAddress)
})
}
useEffect(() => {
void resolveCreatorAddress()
}, [creatorState.value])
useEffect(() => { useEffect(() => {
setCollectionInfo({ setCollectionInfo({
description: descriptionState.value.replaceAll('\\n', '\n') || undefined, description: descriptionState.value.replaceAll('\\n', '\n') || undefined,
@ -321,7 +302,6 @@ export const CollectionActions = ({
share: (Number(royaltyShareState.value) / 100).toString(), share: (Number(royaltyShareState.value) / 100).toString(),
} }
: undefined, : undefined,
creator: creatorState.value || undefined,
}) })
}, [ }, [
descriptionState.value, descriptionState.value,
@ -330,7 +310,6 @@ export const CollectionActions = ({
externalLinkState.value, externalLinkState.value,
royaltyPaymentAddressState.value, royaltyPaymentAddressState.value,
royaltyShareState.value, royaltyShareState.value,
creatorState.value,
]) ])
useEffect(() => { useEffect(() => {
@ -459,27 +438,6 @@ export const CollectionActions = ({
} }
} }
if (type === 'update_collection_info' && creatorState.value) {
const resolvedCreatorAddress = await resolveAddress(creatorState.value.trim(), wallet)
const contractInfoResponse = await (await wallet.getCosmWasmClient())
.queryContractRaw(
resolvedCreatorAddress,
toUtf8(Buffer.from(Buffer.from('contract_info').toString('hex'), 'hex').toString()),
)
.catch((e) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
if (e.message.includes('bech32')) throw new Error('Invalid creator address.')
console.log(e.message)
})
if (contractInfoResponse !== undefined) {
const contractInfo = JSON.parse(new TextDecoder().decode(contractInfoResponse as Uint8Array))
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
if (contractInfo && !contractInfo.contract.includes('dao'))
throw new Error('The provided creator address does not belong to a compatible contract.')
else console.log(contractInfo)
}
}
const txHash = await toast.promise(dispatchExecute(payload), { const txHash = await toast.promise(dispatchExecute(payload), {
error: `${type.charAt(0).toUpperCase() + type.slice(1)} execute failed!`, error: `${type.charAt(0).toUpperCase() + type.slice(1)} execute failed!`,
loading: 'Executing message...', loading: 'Executing message...',
@ -536,7 +494,6 @@ export const CollectionActions = ({
{showBaseUriField && <TextInput className="mt-2" {...baseURIState} />} {showBaseUriField && <TextInput className="mt-2" {...baseURIState} />}
{showNumberOfTokensField && <NumberInput className="mt-2" {...batchNumberState} />} {showNumberOfTokensField && <NumberInput className="mt-2" {...batchNumberState} />}
{showPriceField && <NumberInput className="mt-2" {...priceState} />} {showPriceField && <NumberInput className="mt-2" {...priceState} />}
{showCreatorField && <AddressInput className="mt-2" {...creatorState} />}
{showDescriptionField && <TextInput className="my-2" {...descriptionState} />} {showDescriptionField && <TextInput className="my-2" {...descriptionState} />}
{showImageField && <TextInput className="mb-2" {...imageState} />} {showImageField && <TextInput className="mb-2" {...imageState} />}
{showExternalLinkField && <TextInput className="mb-2" {...externalLinkState} />} {showExternalLinkField && <TextInput className="mb-2" {...externalLinkState} />}
@ -707,17 +664,6 @@ export const CollectionActions = ({
</div> </div>
</Tooltip> </Tooltip>
</Conditional> </Conditional>
<Conditional test={type === 'update_collection_info'}>
<Alert className="mt-2 text-sm" type="info">
Please note that you are only required to fill in the fields you want to update.
</Alert>
</Conditional>
<Conditional test={type === 'update_discount_price'}>
<Alert className="mt-2 text-sm" type="warning">
Please note that discount price can only be updated every 24 hours and be removed 12 hours after its last
update.
</Alert>
</Conditional>
</div> </div>
<div className="-mt-6"> <div className="-mt-6">
<div className="relative mb-2"> <div className="relative mb-2">

View File

@ -20,7 +20,6 @@ import type { ChangeEvent } from 'react'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { toast } from 'react-hot-toast' import { toast } from 'react-hot-toast'
import type { UploadServiceType } from 'services/upload' import type { UploadServiceType } from 'services/upload'
import { NFT_STORAGE_DEFAULT_API_KEY } from 'utils/constants'
import type { AssetType } from 'utils/getAssetType' import type { AssetType } from 'utils/getAssetType'
import { getAssetType } from 'utils/getAssetType' import { getAssetType } from 'utils/getAssetType'
import { uid } from 'utils/random' import { uid } from 'utils/random'
@ -67,7 +66,6 @@ export const UploadDetails = ({
const [uploadService, setUploadService] = useState<UploadServiceType>('nft-storage') const [uploadService, setUploadService] = useState<UploadServiceType>('nft-storage')
const [metadataFileArrayIndex, setMetadataFileArrayIndex] = useState(0) const [metadataFileArrayIndex, setMetadataFileArrayIndex] = useState(0)
const [refreshMetadata, setRefreshMetadata] = useState(false) const [refreshMetadata, setRefreshMetadata] = useState(false)
const [useDefaultApiKey, setUseDefaultApiKey] = useState(false)
const [baseMinterMetadataFile, setBaseMinterMetadataFile] = useState<File | undefined>() const [baseMinterMetadataFile, setBaseMinterMetadataFile] = useState<File | undefined>()
@ -463,14 +461,6 @@ export const UploadDetails = ({
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [importedUploadDetails]) }, [importedUploadDetails])
useEffect(() => {
if (useDefaultApiKey) {
nftStorageApiKeyState.onChange(NFT_STORAGE_DEFAULT_API_KEY || '')
} else {
nftStorageApiKeyState.onChange('')
}
}, [useDefaultApiKey])
return ( return (
<div className="justify-items-start mb-3 rounded border-2 border-white/20 flex-column"> <div className="justify-items-start mb-3 rounded border-2 border-white/20 flex-column">
<div className="flex justify-center"> <div className="flex justify-center">
@ -626,22 +616,7 @@ export const UploadDetails = ({
<div className="flex w-full"> <div className="flex w-full">
<Conditional test={uploadService === 'nft-storage'}> <Conditional test={uploadService === 'nft-storage'}>
<div className="flex-col w-full"> <TextInput {...nftStorageApiKeyState} className="w-full" />
<TextInput {...nftStorageApiKeyState} className="w-full" disabled={useDefaultApiKey} />
<div className="flex-row mt-2 w-full form-control">
<label className="cursor-pointer label">
<span className="mr-2 font-bold">Use Default API Key</span>
<input
checked={useDefaultApiKey}
className={`${useDefaultApiKey ? `bg-stargaze` : `bg-gray-600`} checkbox`}
onClick={() => {
setUseDefaultApiKey(!useDefaultApiKey)
}}
type="checkbox"
/>
</label>
</div>
</div>
</Conditional> </Conditional>
<Conditional test={uploadService === 'pinata'}> <Conditional test={uploadService === 'pinata'}>
<TextInput {...pinataApiKeyState} className="w-full" /> <TextInput {...pinataApiKeyState} className="w-full" />

View File

@ -1,7 +1,6 @@
/* eslint-disable eslint-comments/disable-enable-pair */ /* eslint-disable eslint-comments/disable-enable-pair */
/* eslint-disable @typescript-eslint/no-unnecessary-condition */ /* eslint-disable @typescript-eslint/no-unnecessary-condition */
/* eslint-disable no-nested-ternary */ /* eslint-disable no-nested-ternary */
import { Button } from 'components/Button'
import { FormControl } from 'components/FormControl' import { FormControl } from 'components/FormControl'
import { FormGroup } from 'components/FormGroup' import { FormGroup } from 'components/FormGroup'
import { AddressList } from 'components/forms/AddressList' import { AddressList } from 'components/forms/AddressList'
@ -43,7 +42,7 @@ export interface WhitelistDetailsDataProps {
type WhitelistState = 'none' | 'existing' | 'new' type WhitelistState = 'none' | 'existing' | 'new'
export type WhitelistType = 'standard' | 'flex' | 'merkletree' type WhitelistType = 'standard' | 'flex'
export const WhitelistDetails = ({ export const WhitelistDetails = ({
onChange, onChange,
@ -59,7 +58,6 @@ export const WhitelistDetails = ({
const [endDate, setEndDate] = useState<Date | undefined>(undefined) const [endDate, setEndDate] = useState<Date | undefined>(undefined)
const [whitelistStandardArray, setWhitelistStandardArray] = useState<string[]>([]) const [whitelistStandardArray, setWhitelistStandardArray] = useState<string[]>([])
const [whitelistFlexArray, setWhitelistFlexArray] = useState<WhitelistFlexMember[]>([]) const [whitelistFlexArray, setWhitelistFlexArray] = useState<WhitelistFlexMember[]>([])
const [whitelistMerkleTreeArray, setWhitelistMerkleTreeArray] = useState<string[]>([])
const [adminsMutable, setAdminsMutable] = useState<boolean>(true) const [adminsMutable, setAdminsMutable] = useState<boolean>(true)
const whitelistAddressState = useInputState({ const whitelistAddressState = useInputState({
@ -98,41 +96,17 @@ export const WhitelistDetails = ({
const addressListState = useAddressListState() const addressListState = useAddressListState()
const whitelistFileOnChange = (data: string[]) => { const whitelistFileOnChange = (data: string[]) => {
if (whitelistType === 'standard') setWhitelistStandardArray(data) setWhitelistStandardArray(data)
if (whitelistType === 'merkletree') setWhitelistMerkleTreeArray(data)
} }
const whitelistFlexFileOnChange = (whitelistData: WhitelistFlexMember[]) => { const whitelistFlexFileOnChange = (whitelistData: WhitelistFlexMember[]) => {
setWhitelistFlexArray(whitelistData) 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(() => { useEffect(() => {
if (!importedWhitelistDetails) { if (!importedWhitelistDetails) {
setWhitelistStandardArray([]) setWhitelistStandardArray([])
setWhitelistFlexArray([]) setWhitelistFlexArray([])
setWhitelistMerkleTreeArray([])
} }
}, [whitelistType]) }, [whitelistType])
@ -146,12 +120,7 @@ export const WhitelistDetails = ({
.replace(/"/g, '') .replace(/"/g, '')
.replace(/'/g, '') .replace(/'/g, '')
.replace(/ /g, ''), .replace(/ /g, ''),
members: members: whitelistType === 'standard' ? whitelistStandardArray : whitelistFlexArray,
whitelistType === 'standard'
? whitelistStandardArray
: whitelistType === 'merkletree'
? whitelistMerkleTreeArray
: whitelistFlexArray,
unitPrice: unitPriceState.value unitPrice: unitPriceState.value
? (Number(unitPriceState.value) * 1_000_000).toString() ? (Number(unitPriceState.value) * 1_000_000).toString()
: unitPriceState.value === 0 : unitPriceState.value === 0
@ -181,9 +150,7 @@ export const WhitelistDetails = ({
endDate, endDate,
whitelistStandardArray, whitelistStandardArray,
whitelistFlexArray, whitelistFlexArray,
whitelistMerkleTreeArray,
whitelistState, whitelistState,
whitelistType,
addressListState.values, addressListState.values,
adminsMutable, adminsMutable,
]) ])
@ -221,12 +188,7 @@ export const WhitelistDetails = ({
importedWhitelistDetails.members?.forEach((member) => { importedWhitelistDetails.members?.forEach((member) => {
setWhitelistStandardArray((standardArray) => [...standardArray, member as string]) setWhitelistStandardArray((standardArray) => [...standardArray, member as string])
}) })
} else if (importedWhitelistDetails.whitelistType === 'merkletree') { } else {
setWhitelistMerkleTreeArray([])
// importedWhitelistDetails.members?.forEach((member) => {
// setWhitelistMerkleTreeArray((merkleTreeArray) => [...merkleTreeArray, member as string])
// })
} else if (importedWhitelistDetails.whitelistType === 'flex') {
setWhitelistFlexArray([]) setWhitelistFlexArray([])
importedWhitelistDetails.members?.forEach((member) => { importedWhitelistDetails.members?.forEach((member) => {
setWhitelistFlexArray((flexArray) => [ setWhitelistFlexArray((flexArray) => [
@ -318,7 +280,7 @@ export const WhitelistDetails = ({
</Conditional> </Conditional>
<Conditional test={whitelistState === 'new'}> <Conditional test={whitelistState === 'new'}>
<div className="flex justify-between mb-5 ml-6 max-w-[500px] text-lg font-bold"> <div className="flex justify-between mb-5 ml-6 max-w-[300px] text-lg font-bold">
<div className="form-check form-check-inline"> <div className="form-check form-check-inline">
<input <input
checked={whitelistType === 'standard'} checked={whitelistType === 'standard'}
@ -329,7 +291,7 @@ export const WhitelistDetails = ({
setWhitelistType('standard') setWhitelistType('standard')
}} }}
type="radio" type="radio"
value="standard" value="nft-storage"
/> />
<label <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" 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"
@ -358,33 +320,12 @@ export const WhitelistDetails = ({
Whitelist Flex Whitelist Flex
</label> </label>
</div> </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>
<div className="grid grid-cols-2"> <div className="grid grid-cols-2">
<FormGroup subtitle="Information about your minting settings" title="Whitelist Minting Details"> <FormGroup subtitle="Information about your minting settings" title="Whitelist Minting Details">
<NumberInput isRequired {...unitPriceState} /> <NumberInput isRequired {...unitPriceState} />
<Conditional test={whitelistType !== 'merkletree'}> <NumberInput isRequired {...memberLimitState} />
<NumberInput isRequired {...memberLimitState} /> <Conditional test={whitelistType === 'standard'}>
</Conditional>
<Conditional test={whitelistType === 'standard' || whitelistType === 'merkletree'}>
<NumberInput isRequired {...perAddressLimitState} /> <NumberInput isRequired {...perAddressLimitState} />
</Conditional> </Conditional>
<FormControl <FormControl
@ -467,17 +408,7 @@ export const WhitelistDetails = ({
/> />
</div> </div>
<Conditional test={whitelistType === 'standard'}> <Conditional test={whitelistType === 'standard'}>
<FormGroup <FormGroup subtitle="TXT file that contains the whitelisted addresses" title="Whitelist File">
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} /> <WhitelistUpload onChange={whitelistFileOnChange} />
</FormGroup> </FormGroup>
<Conditional test={whitelistStandardArray.length > 0}> <Conditional test={whitelistStandardArray.length > 0}>
@ -486,14 +417,7 @@ export const WhitelistDetails = ({
</Conditional> </Conditional>
<Conditional test={whitelistType === 'flex'}> <Conditional test={whitelistType === 'flex'}>
<FormGroup <FormGroup
subtitle={ subtitle="CSV file that contains the whitelisted addresses and their corresponding mint counts"
<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" title="Whitelist File"
> >
<WhitelistFlexUpload onChange={whitelistFlexFileOnChange} /> <WhitelistFlexUpload onChange={whitelistFlexFileOnChange} />
@ -502,24 +426,6 @@ export const WhitelistDetails = ({
<JsonPreview content={whitelistFlexArray} initialState={false} title="File Contents" /> <JsonPreview content={whitelistFlexArray} initialState={false} title="File Contents" />
</Conditional> </Conditional>
</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>
</div> </div>
</Conditional> </Conditional>

View File

@ -1,11 +1,8 @@
/* eslint-disable eslint-comments/disable-enable-pair */
/* eslint-disable no-nested-ternary */
import { Combobox, Transition } from '@headlessui/react' import { Combobox, Transition } from '@headlessui/react'
import clsx from 'clsx' import clsx from 'clsx'
import { FormControl } from 'components/FormControl' import { FormControl } from 'components/FormControl'
import type { ExecuteListItem } from 'contracts/whitelist/messages/execute' import type { ExecuteListItem } from 'contracts/whitelist/messages/execute'
import { EXECUTE_LIST } from 'contracts/whitelist/messages/execute' import { EXECUTE_LIST } from 'contracts/whitelist/messages/execute'
import { EXECUTE_LIST as WL_MERKLE_TREE_EXECUTE_LIST } from 'contracts/whitelistMerkleTree/messages/execute'
import { matchSorter } from 'match-sorter' import { matchSorter } from 'match-sorter'
import { Fragment, useState } from 'react' import { Fragment, useState } from 'react'
import { FaChevronDown, FaInfoCircle } from 'react-icons/fa' import { FaChevronDown, FaInfoCircle } from 'react-icons/fa'
@ -13,20 +10,13 @@ import { FaChevronDown, FaInfoCircle } from 'react-icons/fa'
export interface ExecuteComboboxProps { export interface ExecuteComboboxProps {
value: ExecuteListItem | null value: ExecuteListItem | null
onChange: (item: ExecuteListItem) => void onChange: (item: ExecuteListItem) => void
whitelistType?: 'standard' | 'flex' | 'merkletree'
} }
export const ExecuteCombobox = ({ value, onChange, whitelistType }: ExecuteComboboxProps) => { export const ExecuteCombobox = ({ value, onChange }: ExecuteComboboxProps) => {
const [search, setSearch] = useState('') const [search, setSearch] = useState('')
const filtered = const filtered =
whitelistType !== 'merkletree' search === '' ? EXECUTE_LIST : matchSorter(EXECUTE_LIST, search, { keys: ['id', 'name', 'description'] })
? search === ''
? EXECUTE_LIST
: matchSorter(EXECUTE_LIST, search, { keys: ['id', 'name', 'description'] })
: search === ''
? WL_MERKLE_TREE_EXECUTE_LIST
: matchSorter(WL_MERKLE_TREE_EXECUTE_LIST, search, { keys: ['id', 'name', 'description'] })
return ( return (
<Combobox <Combobox

View File

@ -14,7 +14,6 @@ import type { ChangeEvent } from 'react'
import { useEffect, useMemo, useRef, useState } from 'react' import { useEffect, useMemo, useRef, useState } from 'react'
import { toast } from 'react-hot-toast' import { toast } from 'react-hot-toast'
import type { UploadServiceType } from 'services/upload' import type { UploadServiceType } from 'services/upload'
import { NFT_STORAGE_DEFAULT_API_KEY } from 'utils/constants'
import type { AssetType } from 'utils/getAssetType' import type { AssetType } from 'utils/getAssetType'
import { getAssetType } from 'utils/getAssetType' import { getAssetType } from 'utils/getAssetType'
@ -44,7 +43,6 @@ export const ImageUploadDetails = ({ onChange, importedImageUploadDetails }: Ima
const [isThumbnailCompatible, setIsThumbnailCompatible] = useState<boolean>(false) const [isThumbnailCompatible, setIsThumbnailCompatible] = useState<boolean>(false)
const [uploadMethod, setUploadMethod] = useState<UploadMethod>('new') const [uploadMethod, setUploadMethod] = useState<UploadMethod>('new')
const [uploadService, setUploadService] = useState<UploadServiceType>('nft-storage') const [uploadService, setUploadService] = useState<UploadServiceType>('nft-storage')
const [useDefaultApiKey, setUseDefaultApiKey] = useState(false)
const assetFileRef = useRef<HTMLInputElement | null>(null) const assetFileRef = useRef<HTMLInputElement | null>(null)
const thumbnailFileRef = useRef<HTMLInputElement | null>(null) const thumbnailFileRef = useRef<HTMLInputElement | null>(null)
@ -194,14 +192,6 @@ export const ImageUploadDetails = ({ onChange, importedImageUploadDetails }: Ima
} }
}, [importedImageUploadDetails]) }, [importedImageUploadDetails])
useEffect(() => {
if (useDefaultApiKey) {
nftStorageApiKeyState.onChange(NFT_STORAGE_DEFAULT_API_KEY || '')
} else {
nftStorageApiKeyState.onChange('')
}
}, [useDefaultApiKey])
const previewUrl = imageUrlState.value.toLowerCase().trim().startsWith('ipfs://') const previewUrl = imageUrlState.value.toLowerCase().trim().startsWith('ipfs://')
? `https://ipfs-gw.stargaze-apis.com/ipfs/${imageUrlState.value.substring(7)}` ? `https://ipfs-gw.stargaze-apis.com/ipfs/${imageUrlState.value.substring(7)}`
: imageUrlState.value : imageUrlState.value
@ -353,22 +343,7 @@ export const ImageUploadDetails = ({ onChange, importedImageUploadDetails }: Ima
<div className="flex w-full"> <div className="flex w-full">
<Conditional test={uploadService === 'nft-storage'}> <Conditional test={uploadService === 'nft-storage'}>
<div className="flex-col w-full"> <TextInput {...nftStorageApiKeyState} className="w-full" />
<TextInput {...nftStorageApiKeyState} className="w-full" disabled={useDefaultApiKey} />
<div className="flex-row mt-2 w-full form-control">
<label className="cursor-pointer label">
<span className="mr-2 font-bold">Use Default API Key</span>
<input
checked={useDefaultApiKey}
className={`${useDefaultApiKey ? `bg-stargaze` : `bg-gray-600`} checkbox`}
onClick={() => {
setUseDefaultApiKey(!useDefaultApiKey)
}}
type="checkbox"
/>
</label>
</div>
</div>
</Conditional> </Conditional>
<Conditional test={uploadService === 'pinata'}> <Conditional test={uploadService === 'pinata'}>
<TextInput {...pinataApiKeyState} className="w-full" /> <TextInput {...pinataApiKeyState} className="w-full" />

View File

@ -1,7 +1,6 @@
/* eslint-disable eslint-comments/disable-enable-pair */ /* eslint-disable eslint-comments/disable-enable-pair */
/* eslint-disable @typescript-eslint/no-unnecessary-condition */ /* eslint-disable @typescript-eslint/no-unnecessary-condition */
/* eslint-disable no-nested-ternary */ /* eslint-disable no-nested-ternary */
import { Conditional } from 'components/Conditional'
import { FormControl } from 'components/FormControl' import { FormControl } from 'components/FormControl'
import { FormGroup } from 'components/FormGroup' import { FormGroup } from 'components/FormGroup'
import { useInputState, useNumberInputState } from 'components/forms/FormInput.hooks' import { useInputState, useNumberInputState } from 'components/forms/FormInput.hooks'
@ -17,27 +16,21 @@ import { useWallet } from 'utils/wallet'
import { NumberInput, TextInput } from '../forms/FormInput' import { NumberInput, TextInput } from '../forms/FormInput'
import type { UploadMethod } from './OffChainMetadataUploadDetails' import type { UploadMethod } from './OffChainMetadataUploadDetails'
export type LimitType = 'count_limited' | 'time_limited' | 'time_and_count_limited'
interface MintingDetailsProps { interface MintingDetailsProps {
onChange: (data: MintingDetailsDataProps) => void onChange: (data: MintingDetailsDataProps) => void
uploadMethod: UploadMethod uploadMethod: UploadMethod
minimumMintPrice: number minimumMintPrice: number
mintTokenFromFactory?: TokenInfo | undefined mintTokenFromFactory?: TokenInfo | undefined
importedMintingDetails?: MintingDetailsDataProps importedMintingDetails?: MintingDetailsDataProps
isPresale: boolean
whitelistStartDate?: string
} }
export interface MintingDetailsDataProps { export interface MintingDetailsDataProps {
unitPrice: string unitPrice: string
perAddressLimit: number perAddressLimit: number
startTime: string startTime: string
endTime?: string endTime: string
tokenCountLimit?: number
paymentAddress?: string paymentAddress?: string
selectedMintToken?: TokenInfo selectedMintToken?: TokenInfo
limitType: LimitType
} }
export const MintingDetails = ({ export const MintingDetails = ({
@ -46,8 +39,6 @@ export const MintingDetails = ({
minimumMintPrice, minimumMintPrice,
mintTokenFromFactory, mintTokenFromFactory,
importedMintingDetails, importedMintingDetails,
isPresale,
whitelistStartDate,
}: MintingDetailsProps) => { }: MintingDetailsProps) => {
const wallet = useWallet() const wallet = useWallet()
@ -55,7 +46,6 @@ export const MintingDetails = ({
const [endTimestamp, setEndTimestamp] = useState<Date | undefined>() const [endTimestamp, setEndTimestamp] = useState<Date | undefined>()
const [selectedMintToken, setSelectedMintToken] = useState<TokenInfo | undefined>(stars) const [selectedMintToken, setSelectedMintToken] = useState<TokenInfo | undefined>(stars)
const [mintingDetailsImported, setMintingDetailsImported] = useState(false) const [mintingDetailsImported, setMintingDetailsImported] = useState(false)
const [limitType, setLimitType] = useState<LimitType>('time_limited')
const { timezone } = useGlobalSettings() const { timezone } = useGlobalSettings()
const unitPriceState = useNumberInputState({ const unitPriceState = useNumberInputState({
@ -76,14 +66,6 @@ export const MintingDetails = ({
placeholder: '1', placeholder: '1',
}) })
const tokenCountLimitState = useNumberInputState({
id: 'tokencountlimit',
name: 'tokencountlimit',
title: 'Maximum Token Count',
subtitle: 'Total number of mintable tokens',
placeholder: '100',
})
const paymentAddressState = useInputState({ const paymentAddressState = useInputState({
id: 'payment-address', id: 'payment-address',
name: 'paymentAddress', name: 'paymentAddress',
@ -113,19 +95,9 @@ export const MintingDetails = ({
: '', : '',
perAddressLimit: perAddressLimitState.value, perAddressLimit: perAddressLimitState.value,
startTime: timestamp ? (timestamp.getTime() * 1_000_000).toString() : '', startTime: timestamp ? (timestamp.getTime() * 1_000_000).toString() : '',
endTime: endTime: endTimestamp ? (endTimestamp.getTime() * 1_000_000).toString() : '',
limitType === 'time_limited' || limitType === 'time_and_count_limited'
? endTimestamp
? (endTimestamp.getTime() * 1_000_000).toString()
: ''
: undefined,
paymentAddress: paymentAddressState.value.trim(), paymentAddress: paymentAddressState.value.trim(),
selectedMintToken, selectedMintToken,
limitType,
tokenCountLimit:
limitType === 'count_limited' || limitType === 'time_and_count_limited'
? tokenCountLimitState.value
: undefined,
} }
onChange(data) onChange(data)
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
@ -136,8 +108,6 @@ export const MintingDetails = ({
endTimestamp, endTimestamp,
paymentAddressState.value, paymentAddressState.value,
selectedMintToken, selectedMintToken,
tokenCountLimitState.value,
limitType,
]) ])
useEffect(() => { useEffect(() => {
@ -145,8 +115,6 @@ export const MintingDetails = ({
console.log('Selected Token ID: ', importedMintingDetails.selectedMintToken?.id) console.log('Selected Token ID: ', importedMintingDetails.selectedMintToken?.id)
unitPriceState.onChange(Number(importedMintingDetails.unitPrice) / 1000000) unitPriceState.onChange(Number(importedMintingDetails.unitPrice) / 1000000)
perAddressLimitState.onChange(importedMintingDetails.perAddressLimit) perAddressLimitState.onChange(importedMintingDetails.perAddressLimit)
setLimitType(importedMintingDetails.limitType)
tokenCountLimitState.onChange(importedMintingDetails.tokenCountLimit ? importedMintingDetails.tokenCountLimit : 0)
setTimestamp(new Date(Number(importedMintingDetails.startTime) / 1_000_000)) setTimestamp(new Date(Number(importedMintingDetails.startTime) / 1_000_000))
setEndTimestamp(new Date(Number(importedMintingDetails.endTime) / 1_000_000)) setEndTimestamp(new Date(Number(importedMintingDetails.endTime) / 1_000_000))
paymentAddressState.onChange(importedMintingDetails.paymentAddress ? importedMintingDetails.paymentAddress : '') paymentAddressState.onChange(importedMintingDetails.paymentAddress ? importedMintingDetails.paymentAddress : '')
@ -156,12 +124,6 @@ export const MintingDetails = ({
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [importedMintingDetails]) }, [importedMintingDetails])
useEffect(() => {
if (isPresale) {
setTimestamp(whitelistStartDate ? new Date(Number(whitelistStartDate) / 1_000_000) : undefined)
}
}, [whitelistStartDate, isPresale])
return ( return (
<div className="border-l-[1px] border-gray-500 border-opacity-20"> <div className="border-l-[1px] border-gray-500 border-opacity-20">
<FormGroup subtitle="Information about your minting settings" title="Minting Details"> <FormGroup subtitle="Information about your minting settings" title="Minting Details">
@ -190,7 +152,6 @@ export const MintingDetails = ({
title="Start Time" title="Start Time"
> >
<InputDateTime <InputDateTime
disabled={isPresale}
minDate={ minDate={
timezone === 'Local' ? new Date() : new Date(Date.now() + new Date().getTimezoneOffset() * 60 * 1000) timezone === 'Local' ? new Date() : new Date(Date.now() + new Date().getTimezoneOffset() * 60 * 1000)
} }
@ -210,69 +171,32 @@ export const MintingDetails = ({
} }
/> />
</FormControl> </FormControl>
<FormControl
<div className="flex-row mt-2 w-full form-control"> htmlId="endTimestamp"
<h1 className="mt-2 font-bold text-md">Limit Type: </h1> isRequired
<label className="justify-start ml-6 cursor-pointer label"> subtitle={`Minting end time ${timezone === 'Local' ? '(local)' : '(UTC)'}`}
<span className="mr-2">Time</span> title="End Time"
<input >
checked={limitType === 'time_limited' || limitType === 'time_and_count_limited'} <InputDateTime
className={`${limitType === 'time_limited' ? `bg-stargaze` : `bg-gray-600`} checkbox`} minDate={
onClick={() => { timezone === 'Local' ? new Date() : new Date(Date.now() + new Date().getTimezoneOffset() * 60 * 1000)
if (limitType === 'time_and_count_limited') setLimitType('count_limited' as LimitType) }
else if (limitType === 'count_limited') setLimitType('time_and_count_limited' as LimitType) onChange={(date) =>
else setLimitType('count_limited' as LimitType) date
}} ? setEndTimestamp(
type="checkbox" timezone === 'Local' ? date : new Date(date.getTime() - new Date().getTimezoneOffset() * 60 * 1000),
/> )
</label> : setEndTimestamp(undefined)
<label className="justify-start ml-4 cursor-pointer label"> }
<span className="mr-2">Token Count</span> value={
<input timezone === 'Local'
checked={limitType === 'count_limited' || limitType === 'time_and_count_limited'} ? endTimestamp
className={`${limitType === 'count_limited' ? `bg-stargaze` : `bg-gray-600`} checkbox`} : endTimestamp
onClick={() => { ? new Date(endTimestamp.getTime() + new Date().getTimezoneOffset() * 60 * 1000)
if (limitType === 'time_and_count_limited') setLimitType('time_limited' as LimitType) : undefined
else if (limitType === 'time_limited') setLimitType('time_and_count_limited' as LimitType) }
else setLimitType('time_limited' as LimitType) />
}} </FormControl>
type="checkbox"
/>
</label>
</div>
<Conditional test={limitType === 'time_limited' || limitType === 'time_and_count_limited'}>
<FormControl
htmlId="endTimestamp"
isRequired
subtitle={`Minting end time ${timezone === 'Local' ? '(local)' : '(UTC)'}`}
title="End Time"
>
<InputDateTime
minDate={
timezone === 'Local' ? new Date() : new Date(Date.now() + new Date().getTimezoneOffset() * 60 * 1000)
}
onChange={(date) =>
date
? setEndTimestamp(
timezone === 'Local'
? date
: new Date(date.getTime() - new Date().getTimezoneOffset() * 60 * 1000),
)
: setEndTimestamp(undefined)
}
value={
timezone === 'Local'
? endTimestamp
: endTimestamp
? new Date(endTimestamp.getTime() + new Date().getTimezoneOffset() * 60 * 1000)
: undefined
}
/>
</FormControl>
</Conditional>
<Conditional test={limitType === 'count_limited' || limitType === 'time_and_count_limited'}>
<NumberInput {...tokenCountLimitState} isRequired />
</Conditional>
</FormGroup> </FormGroup>
<TextInput className="pr-4 pl-4 mt-3" {...paymentAddressState} /> <TextInput className="pr-4 pl-4 mt-3" {...paymentAddressState} />
</div> </div>

View File

@ -18,7 +18,6 @@ import type { ChangeEvent } from 'react'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { toast } from 'react-hot-toast' import { toast } from 'react-hot-toast'
import type { UploadServiceType } from 'services/upload' import type { UploadServiceType } from 'services/upload'
import { NFT_STORAGE_DEFAULT_API_KEY } from 'utils/constants'
import type { AssetType } from 'utils/getAssetType' import type { AssetType } from 'utils/getAssetType'
import { getAssetType } from 'utils/getAssetType' import { getAssetType } from 'utils/getAssetType'
import { uid } from 'utils/random' import { uid } from 'utils/random'
@ -65,7 +64,6 @@ export const OffChainMetadataUploadDetails = ({
const [refreshMetadata, setRefreshMetadata] = useState(false) const [refreshMetadata, setRefreshMetadata] = useState(false)
const [exportedMetadata, setExportedMetadata] = useState(undefined) const [exportedMetadata, setExportedMetadata] = useState(undefined)
const [openEditionMinterMetadataFile, setOpenEditionMinterMetadataFile] = useState<File | undefined>() const [openEditionMinterMetadataFile, setOpenEditionMinterMetadataFile] = useState<File | undefined>()
const [useDefaultApiKey, setUseDefaultApiKey] = useState(false)
const thumbnailCompatibleAssetTypes: AssetType[] = ['video', 'audio', 'html', 'document'] const thumbnailCompatibleAssetTypes: AssetType[] = ['video', 'audio', 'html', 'document']
@ -299,14 +297,6 @@ export const OffChainMetadataUploadDetails = ({
} }
}, [importedOffChainMetadataUploadDetails]) }, [importedOffChainMetadataUploadDetails])
useEffect(() => {
if (useDefaultApiKey) {
nftStorageApiKeyState.onChange(NFT_STORAGE_DEFAULT_API_KEY || '')
} else {
nftStorageApiKeyState.onChange('')
}
}, [useDefaultApiKey])
return ( return (
<div className="justify-items-start mb-3 rounded border-2 border-white/20 flex-column"> <div className="justify-items-start mb-3 rounded border-2 border-white/20 flex-column">
<div className="flex justify-center"> <div className="flex justify-center">
@ -425,22 +415,7 @@ export const OffChainMetadataUploadDetails = ({
<div className="flex w-full"> <div className="flex w-full">
<Conditional test={uploadService === 'nft-storage'}> <Conditional test={uploadService === 'nft-storage'}>
<div className="flex-col w-full"> <TextInput {...nftStorageApiKeyState} className="w-full" />
<TextInput {...nftStorageApiKeyState} className="w-full" disabled={useDefaultApiKey} />
<div className="flex-row mt-2 w-full form-control">
<label className="cursor-pointer label">
<span className="mr-2 font-bold">Use Default API Key</span>
<input
checked={useDefaultApiKey}
className={`${useDefaultApiKey ? `bg-stargaze` : `bg-gray-600`} checkbox`}
onClick={() => {
setUseDefaultApiKey(!useDefaultApiKey)
}}
type="checkbox"
/>
</label>
</div>
</div>
</Conditional> </Conditional>
<Conditional test={uploadService === 'pinata'}> <Conditional test={uploadService === 'pinata'}>
<TextInput {...pinataApiKeyState} className="w-full" /> <TextInput {...pinataApiKeyState} className="w-full" />

View File

@ -5,16 +5,15 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { toUtf8 } from '@cosmjs/encoding' import { toUtf8 } from '@cosmjs/encoding'
import type { Coin } from '@cosmjs/proto-signing'
import { coin } from '@cosmjs/proto-signing' import { coin } from '@cosmjs/proto-signing'
import axios from 'axios'
import clsx from 'clsx' import clsx from 'clsx'
import { Button } from 'components/Button' import { Button } from 'components/Button'
import type { MinterType } from 'components/collections/actions/Combobox' import type { MinterType } from 'components/collections/actions/Combobox'
import { Conditional } from 'components/Conditional' import { Conditional } from 'components/Conditional'
import { ConfirmationModal } from 'components/ConfirmationModal' import { ConfirmationModal } from 'components/ConfirmationModal'
import { LoadingModal } from 'components/LoadingModal' import { LoadingModal } from 'components/LoadingModal'
import { type TokenInfo, tokensList } from 'config/token' import { openEditionMinterList } from 'config/minter'
import { type TokenInfo } from 'config/token'
import { useContracts } from 'contexts/contracts' import { useContracts } from 'contexts/contracts'
import { addLogItem } from 'contexts/log' import { addLogItem } from 'contexts/log'
import type { DispatchExecuteArgs as OpenEditionFactoryDispatchExecuteArgs } from 'contracts/openEditionFactory/messages/execute' import type { DispatchExecuteArgs as OpenEditionFactoryDispatchExecuteArgs } from 'contracts/openEditionFactory/messages/execute'
@ -23,15 +22,12 @@ import React, { useEffect, useMemo, useState } from 'react'
import { toast } from 'react-hot-toast' import { toast } from 'react-hot-toast'
import { upload } from 'services/upload' import { upload } from 'services/upload'
import { import {
OPEN_EDITION_FACTORY_ADDRESS,
OPEN_EDITION_UPDATABLE_FACTORY_ADDRESS,
SG721_OPEN_EDITION_CODE_ID, SG721_OPEN_EDITION_CODE_ID,
SG721_OPEN_EDITION_UPDATABLE_CODE_ID, SG721_OPEN_EDITION_UPDATABLE_CODE_ID,
STRDST_SG721_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' } from 'utils/constants'
import { useDebounce } from 'utils/debounce'
import type { AssetType } from 'utils/getAssetType' import type { AssetType } from 'utils/getAssetType'
import { isValidAddress } from 'utils/isValidAddress' import { isValidAddress } from 'utils/isValidAddress'
import { checkTokenUri } from 'utils/isValidTokenUri' import { checkTokenUri } from 'utils/isValidTokenUri'
@ -41,7 +37,7 @@ import { useWallet } from 'utils/wallet'
import { type CollectionDetailsDataProps, CollectionDetails } from './CollectionDetails' import { type CollectionDetailsDataProps, CollectionDetails } from './CollectionDetails'
import type { ImageUploadDetailsDataProps } from './ImageUploadDetails' import type { ImageUploadDetailsDataProps } from './ImageUploadDetails'
import { ImageUploadDetails } from './ImageUploadDetails' import { ImageUploadDetails } from './ImageUploadDetails'
import type { LimitType, MintingDetailsDataProps } from './MintingDetails' import type { MintingDetailsDataProps } from './MintingDetails'
import { MintingDetails } from './MintingDetails' import { MintingDetails } from './MintingDetails'
import type { UploadMethod } from './OffChainMetadataUploadDetails' import type { UploadMethod } from './OffChainMetadataUploadDetails'
import { import {
@ -51,14 +47,12 @@ import {
import type { OnChainMetadataInputDetailsDataProps } from './OnChainMetadataInputDetails' import type { OnChainMetadataInputDetailsDataProps } from './OnChainMetadataInputDetails'
import { OnChainMetadataInputDetails } from './OnChainMetadataInputDetails' import { OnChainMetadataInputDetails } from './OnChainMetadataInputDetails'
import { type RoyaltyDetailsDataProps, RoyaltyDetails } from './RoyaltyDetails' import { type RoyaltyDetailsDataProps, RoyaltyDetails } from './RoyaltyDetails'
import { type WhitelistDetailsDataProps, WhitelistDetails } from './WhitelistDetails'
export type MetadataStorageMethod = 'off-chain' | 'on-chain' export type MetadataStorageMethod = 'off-chain' | 'on-chain'
export interface OpenEditionMinterDetailsDataProps { export interface OpenEditionMinterDetailsDataProps {
imageUploadDetails?: ImageUploadDetailsDataProps imageUploadDetails?: ImageUploadDetailsDataProps
collectionDetails?: CollectionDetailsDataProps collectionDetails?: CollectionDetailsDataProps
whitelistDetails?: WhitelistDetailsDataProps
royaltyDetails?: RoyaltyDetailsDataProps royaltyDetails?: RoyaltyDetailsDataProps
onChainMetadataInputDetails?: OnChainMetadataInputDetailsDataProps onChainMetadataInputDetails?: OnChainMetadataInputDetailsDataProps
offChainMetadataUploadDetails?: OffChainMetadataUploadDetailsDataProps offChainMetadataUploadDetails?: OffChainMetadataUploadDetailsDataProps
@ -68,26 +62,24 @@ export interface OpenEditionMinterDetailsDataProps {
coverImageUrl?: string | null coverImageUrl?: string | null
tokenUri?: string | null tokenUri?: string | null
tokenImageUri?: string | null tokenImageUri?: string | null
isRefreshed?: boolean
} }
interface OpenEditionMinterCreatorProps { interface OpenEditionMinterCreatorProps {
onChange: (data: OpenEditionMinterCreatorDataProps) => void onChange: (data: OpenEditionMinterCreatorDataProps) => void
onDetailsChange: (data: OpenEditionMinterDetailsDataProps) => void onDetailsChange: (data: OpenEditionMinterDetailsDataProps) => void
openEditionMinterCreationFee?: Coin openEditionMinterUpdatableCreationFee?: string
openEditionMinterCreationFee?: string
minimumMintPrice?: string minimumMintPrice?: string
minimumUpdatableMintPrice?: string
minterType?: MinterType minterType?: MinterType
mintTokenFromFactory?: TokenInfo | undefined mintTokenFromFactory?: TokenInfo | undefined
importedOpenEditionMinterDetails?: OpenEditionMinterDetailsDataProps importedOpenEditionMinterDetails?: OpenEditionMinterDetailsDataProps
isMatchingFactoryPresent?: boolean
openEditionFactoryAddress?: string
} }
export interface OpenEditionMinterCreatorDataProps { export interface OpenEditionMinterCreatorDataProps {
metadataStorageMethod: MetadataStorageMethod metadataStorageMethod: MetadataStorageMethod
openEditionMinterContractAddress: string | null openEditionMinterContractAddress: string | null
sg721ContractAddress: string | null sg721ContractAddress: string | null
whitelistContractAddress: string | null
transactionHash: string | null transactionHash: string | null
} }
@ -95,27 +87,21 @@ export const OpenEditionMinterCreator = ({
onChange, onChange,
onDetailsChange, onDetailsChange,
openEditionMinterCreationFee, openEditionMinterCreationFee,
openEditionMinterUpdatableCreationFee,
minimumMintPrice, minimumMintPrice,
minimumUpdatableMintPrice,
minterType, minterType,
mintTokenFromFactory, mintTokenFromFactory,
importedOpenEditionMinterDetails, importedOpenEditionMinterDetails,
isMatchingFactoryPresent,
openEditionFactoryAddress,
}: OpenEditionMinterCreatorProps) => { }: OpenEditionMinterCreatorProps) => {
const wallet = useWallet() const wallet = useWallet()
const { const { openEditionMinter: openEditionMinterContract, openEditionFactory: openEditionFactoryContract } =
openEditionMinter: openEditionMinterContract, useContracts()
openEditionFactory: openEditionFactoryContract,
whitelist: whitelistContract,
whitelistMerkleTree: whitelistMerkleTreeContract,
} = useContracts()
const [metadataStorageMethod, setMetadataStorageMethod] = useState<MetadataStorageMethod>('off-chain') const [metadataStorageMethod, setMetadataStorageMethod] = useState<MetadataStorageMethod>('off-chain')
const [imageUploadDetails, setImageUploadDetails] = useState<ImageUploadDetailsDataProps | null>(null) const [imageUploadDetails, setImageUploadDetails] = useState<ImageUploadDetailsDataProps | null>(null)
const [collectionDetails, setCollectionDetails] = useState<CollectionDetailsDataProps | null>(null) const [collectionDetails, setCollectionDetails] = useState<CollectionDetailsDataProps | null>(null)
const [whitelistDetails, setWhitelistDetails] = useState<WhitelistDetailsDataProps | null>(null)
const [royaltyDetails, setRoyaltyDetails] = useState<RoyaltyDetailsDataProps | null>(null) const [royaltyDetails, setRoyaltyDetails] = useState<RoyaltyDetailsDataProps | null>(null)
const [isRefreshed, setIsRefreshed] = useState(false)
const [onChainMetadataInputDetails, setOnChainMetadataInputDetails] = const [onChainMetadataInputDetails, setOnChainMetadataInputDetails] =
useState<OnChainMetadataInputDetailsDataProps | null>(null) useState<OnChainMetadataInputDetailsDataProps | null>(null)
const [offChainMetadataUploadDetails, setOffChainMetadataUploadDetails] = const [offChainMetadataUploadDetails, setOffChainMetadataUploadDetails] =
@ -130,19 +116,29 @@ export const OpenEditionMinterCreator = ({
const [coverImageUrl, setCoverImageUrl] = useState<string | null>(null) const [coverImageUrl, setCoverImageUrl] = useState<string | null>(null)
const [openEditionMinterContractAddress, setOpenEditionMinterContractAddress] = useState<string | null>(null) const [openEditionMinterContractAddress, setOpenEditionMinterContractAddress] = useState<string | null>(null)
const [sg721ContractAddress, setSg721ContractAddress] = 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 [transactionHash, setTransactionHash] = useState<string | null>(null)
const [thumbnailImageUri, setThumbnailImageUri] = useState<string | undefined>(undefined) const [thumbnailImageUri, setThumbnailImageUri] = useState<string | undefined>(undefined)
const thumbnailCompatibleAssetTypes: AssetType[] = ['video', 'audio', 'html'] 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( const openEditionFactoryMessages = useMemo(
() => openEditionFactoryContract?.use(openEditionFactoryAddress as string), () =>
openEditionFactoryContract?.use(
collectionDetails?.updatable ? updatableFactoryAddressForSelectedDenom : factoryAddressForSelectedDenom,
),
[ [
openEditionFactoryContract, openEditionFactoryContract,
wallet.address, wallet.address,
collectionDetails?.updatable, collectionDetails?.updatable,
openEditionFactoryAddress, factoryAddressForSelectedDenom,
updatableFactoryAddressForSelectedDenom,
wallet.isWalletConnected, wallet.isWalletConnected,
], ],
) )
@ -156,26 +152,13 @@ export const OpenEditionMinterCreator = ({
.then(() => { .then(() => {
void checkRoyaltyDetails() void checkRoyaltyDetails()
.then(() => { .then(() => {
checkWhitelistDetails() void checkwalletBalance()
.then(() => { .then(() => {
void checkwalletBalance() setReadyToCreate(true)
.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) => { .catch((error: any) => {
if (String(error.message).includes('Insufficient wallet balance')) { toast.error(`Error in Wallet Balance: ${error.message}`, { style: { maxWidth: 'none' } })
toast.error(`${error.message}`, { style: { maxWidth: 'none' } }) addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() })
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) setReadyToCreate(false)
}) })
}) })
@ -316,9 +299,9 @@ export const OpenEditionMinterCreator = ({
if (!mintingDetails) throw new Error('Please fill out the minting details') if (!mintingDetails) throw new Error('Please fill out the minting details')
if (mintingDetails.unitPrice === '') throw new Error('Mint price is required') if (mintingDetails.unitPrice === '') throw new Error('Mint price is required')
if (collectionDetails?.updatable) { if (collectionDetails?.updatable) {
if (Number(mintingDetails.unitPrice) < Number(minimumMintPrice)) if (Number(mintingDetails.unitPrice) < Number(minimumUpdatableMintPrice))
throw new Error( throw new Error(
`Invalid mint price: The minimum mint price is ${Number(minimumMintPrice) / 1000000} ${ `Invalid mint price: The minimum mint price is ${Number(minimumUpdatableMintPrice) / 1000000} ${
mintTokenFromFactory?.displayName mintTokenFromFactory?.displayName
}`, }`,
) )
@ -331,27 +314,11 @@ export const OpenEditionMinterCreator = ({
if (!mintingDetails.perAddressLimit || mintingDetails.perAddressLimit < 1 || mintingDetails.perAddressLimit > 50) if (!mintingDetails.perAddressLimit || mintingDetails.perAddressLimit < 1 || mintingDetails.perAddressLimit > 50)
throw new Error('Invalid limit for tokens per address') throw new Error('Invalid limit for tokens per address')
if (mintingDetails.startTime === '') throw new Error('Start time is required') if (mintingDetails.startTime === '') throw new Error('Start time is required')
if (mintingDetails.limitType === 'time_limited' && mintingDetails.endTime === '') if (mintingDetails.endTime === '') throw new Error('End time is required')
throw new Error('End time is required')
if (mintingDetails.limitType === 'count_limited' && mintingDetails.tokenCountLimit === undefined)
throw new Error('Token count limit is required')
if (
mintingDetails.limitType === 'count_limited' &&
mintingDetails.perAddressLimit > (mintingDetails.tokenCountLimit as number)
)
throw new Error('Per address limit cannot exceed maximum token count limit')
if (mintingDetails.limitType === 'count_limited' && (mintingDetails.tokenCountLimit as number) > 10000)
throw new Error('Maximum token count cannot exceed 10000')
if (Number(mintingDetails.startTime) < new Date().getTime() * 1000000) throw new Error('Invalid start time') if (Number(mintingDetails.startTime) < new Date().getTime() * 1000000) throw new Error('Invalid start time')
if ( if (Number(mintingDetails.endTime) < Number(mintingDetails.startTime))
mintingDetails.limitType === 'time_limited' &&
Number(mintingDetails.endTime) < Number(mintingDetails.startTime)
)
throw new Error('End time cannot be earlier than start time') throw new Error('End time cannot be earlier than start time')
if ( if (Number(mintingDetails.endTime) === Number(mintingDetails.startTime))
mintingDetails.limitType === 'time_limited' &&
Number(mintingDetails.endTime) === Number(mintingDetails.startTime)
)
throw new Error('End time cannot be equal to the start time') throw new Error('End time cannot be equal to the start time')
if ( if (
@ -359,92 +326,6 @@ export const OpenEditionMinterCreator = ({
(!isValidAddress(mintingDetails.paymentAddress) || !mintingDetails.paymentAddress.startsWith('stars1')) (!isValidAddress(mintingDetails.paymentAddress) || !mintingDetails.paymentAddress.startsWith('stars1'))
) )
throw new Error('Invalid payment address') 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 () => { const checkRoyaltyDetails = async () => {
@ -481,45 +362,16 @@ export const OpenEditionMinterCreator = ({
const checkwalletBalance = async () => { const checkwalletBalance = async () => {
if (!wallet.isWalletConnected) throw new Error('Wallet not connected.') if (!wallet.isWalletConnected) throw new Error('Wallet not connected.')
const queryClient = await wallet.getCosmWasmClient() const amountNeeded = collectionDetails?.updatable
const creationFeeDenom = tokensList.find((token) => token.denom === openEditionMinterCreationFee?.denom) ? Number(openEditionMinterUpdatableCreationFee)
await queryClient.getBalance(wallet.address || '', 'ustars').then(async (starsBalance) => { : Number(openEditionMinterCreationFee)
await queryClient await (await wallet.getCosmWasmClient()).getBalance(wallet.address || '', 'ustars').then((balance) => {
.getBalance(wallet.address || '', openEditionMinterCreationFee?.denom as string) if (amountNeeded >= Number(balance.amount))
.then((creationFeeDenomBalance) => { throw new Error(
if (whitelistDetails?.whitelistState === 'new' && whitelistDetails.memberLimit) { `Insufficient wallet balance to instantiate the required contracts. Needed amount: ${(
const whitelistCreationFee = Math.ceil(Number(whitelistDetails.memberLimit) / 1000) * 100000000 amountNeeded / 1000000
if (openEditionMinterCreationFee?.denom === 'ustars') { ).toString()} STARS`,
const amountNeeded = whitelistCreationFee + Number(openEditionMinterCreationFee.amount) )
if (amountNeeded >= Number(starsBalance.amount))
throw new Error(
`Insufficient wallet balance to instantiate the required contracts. Needed amount: ${(
amountNeeded / 1000000
).toString()} STARS`,
)
} else {
if (whitelistCreationFee >= Number(starsBalance.amount))
throw new Error(
`Insufficient wallet balance to instantiate the whitelist. Needed amount: ${(
whitelistCreationFee / 1000000
).toString()} STARS`,
)
if (Number(openEditionMinterCreationFee?.amount) > Number(creationFeeDenomBalance.amount))
throw new Error(
`Insufficient wallet balance to instantiate the required contracts. Needed amount: ${(
Number(openEditionMinterCreationFee?.amount) / 1000000
).toString()} ${
creationFeeDenom ? creationFeeDenom.displayName : openEditionMinterCreationFee?.denom
}`,
)
}
} else if (Number(openEditionMinterCreationFee?.amount) > Number(creationFeeDenomBalance.amount))
throw new Error(
`Insufficient wallet balance to instantiate the required contracts. Needed amount: ${(
Number(openEditionMinterCreationFee?.amount) / 1000000
).toString()} ${creationFeeDenom ? creationFeeDenom.displayName : openEditionMinterCreationFee?.denom}`,
)
})
}) })
} }
@ -531,7 +383,6 @@ export const OpenEditionMinterCreator = ({
setTokenImageUri(null) setTokenImageUri(null)
setOpenEditionMinterContractAddress(null) setOpenEditionMinterContractAddress(null)
setSg721ContractAddress(null) setSg721ContractAddress(null)
setWhitelistContractAddress(null)
setTransactionHash(null) setTransactionHash(null)
if (metadataStorageMethod === 'off-chain') { if (metadataStorageMethod === 'off-chain') {
if (offChainMetadataUploadDetails?.uploadMethod === 'new') { if (offChainMetadataUploadDetails?.uploadMethod === 'new') {
@ -556,27 +407,13 @@ export const OpenEditionMinterCreator = ({
setTokenUri(metadataUriWithBase) setTokenUri(metadataUriWithBase)
setCoverImageUrl(coverImageUriWithBase) setCoverImageUrl(coverImageUriWithBase)
setUploading(false) 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 { } else {
setTokenUri(offChainMetadataUploadDetails?.tokenURI as string) setTokenUri(offChainMetadataUploadDetails?.tokenURI as string)
setCoverImageUrl(offChainMetadataUploadDetails?.imageUrl 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( await instantiateOpenEditionMinter(
offChainMetadataUploadDetails?.tokenURI as string, offChainMetadataUploadDetails?.tokenURI as string,
offChainMetadataUploadDetails?.imageUrl as string, offChainMetadataUploadDetails?.imageUrl as string,
undefined,
whitelist,
) )
} }
} else if (metadataStorageMethod === 'on-chain') { } else if (metadataStorageMethod === 'on-chain') {
@ -618,27 +455,15 @@ export const OpenEditionMinterCreator = ({
? `ipfs://${thumbnailUri}/${(imageUploadDetails.thumbnailFile as File).name}` ? `ipfs://${thumbnailUri}/${(imageUploadDetails.thumbnailFile as File).name}`
: undefined : undefined
setThumbnailImageUri(thumbnailUriWithBase) setThumbnailImageUri(thumbnailUriWithBase)
setUploading(false) 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') { } else if (imageUploadDetails?.uploadMethod === 'existing') {
setTokenImageUri(imageUploadDetails.imageUrl as string) setTokenImageUri(imageUploadDetails.imageUrl as string)
setCoverImageUrl(imageUploadDetails.coverImageUrl 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( await instantiateOpenEditionMinter(
imageUploadDetails.imageUrl as string, imageUploadDetails.imageUrl as string,
imageUploadDetails.coverImageUrl as string, imageUploadDetails.coverImageUrl as string,
whitelist,
) )
} }
} }
@ -737,104 +562,7 @@ export const OpenEditionMinterCreator = ({
}) })
} }
const instantiateWhitelist = async () => { const instantiateOpenEditionMinter = async (uri: string, coverImageUri: string, thumbnailUri?: string) => {
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 (!wallet.isWalletConnected) throw new Error('Wallet not connected')
if (!openEditionFactoryContract) throw new Error('Contract not found') if (!openEditionFactoryContract) throw new Error('Contract not found')
if (!openEditionMinterContract) throw new Error('Contract not found') if (!openEditionMinterContract) throw new Error('Contract not found')
@ -875,30 +603,19 @@ export const OpenEditionMinterCreator = ({
: null, : null,
}, },
start_time: mintingDetails?.startTime, start_time: mintingDetails?.startTime,
end_time: end_time: mintingDetails?.endTime,
mintingDetails?.limitType === ('time_limited' as LimitType) ||
mintingDetails?.limitType === ('time_and_count_limited' as LimitType)
? mintingDetails.endTime
: null,
mint_price: { mint_price: {
amount: Number(mintingDetails?.unitPrice).toString(), amount: Number(mintingDetails?.unitPrice).toString(),
denom: (mintTokenFromFactory?.denom as string) || 'ustars', denom: (mintTokenFromFactory?.denom as string) || 'ustars',
}, },
per_address_limit: mintingDetails?.perAddressLimit, per_address_limit: mintingDetails?.perAddressLimit,
num_tokens:
mintingDetails?.limitType === ('count_limited' as LimitType) ||
mintingDetails?.limitType === ('time_and_count_limited' as LimitType)
? mintingDetails.tokenCountLimit
: null,
payment_address: mintingDetails?.paymentAddress || null, payment_address: mintingDetails?.paymentAddress || null,
whitelist,
}, },
collection_params: { collection_params: {
code_id: collectionDetails?.updatable code_id: collectionDetails?.updatable
? SG721_OPEN_EDITION_UPDATABLE_CODE_ID ? SG721_OPEN_EDITION_UPDATABLE_CODE_ID
: mintingDetails?.selectedMintToken?.displayName === 'USK' || : mintingDetails?.selectedMintToken?.displayName === 'USK' ||
mintingDetails?.selectedMintToken?.displayName === 'USDC' || mintingDetails?.selectedMintToken?.displayName === 'USDC' ||
mintingDetails?.selectedMintToken?.displayName === 'TIA' ||
mintingDetails?.selectedMintToken?.displayName === 'STRDST' || mintingDetails?.selectedMintToken?.displayName === 'STRDST' ||
mintingDetails?.selectedMintToken?.displayName === 'KUJI' || mintingDetails?.selectedMintToken?.displayName === 'KUJI' ||
mintingDetails?.selectedMintToken?.displayName === 'HUAHUA' || mintingDetails?.selectedMintToken?.displayName === 'HUAHUA' ||
@ -921,11 +638,18 @@ export const OpenEditionMinterCreator = ({
} }
const payload: OpenEditionFactoryDispatchExecuteArgs = { const payload: OpenEditionFactoryDispatchExecuteArgs = {
contract: openEditionFactoryAddress as string, contract: collectionDetails?.updatable ? updatableFactoryAddressForSelectedDenom : factoryAddressForSelectedDenom,
messages: openEditionFactoryMessages, messages: openEditionFactoryMessages,
txSigner: wallet.address || '', txSigner: wallet.address || '',
msg, msg,
funds: [openEditionMinterCreationFee as Coin], funds: [
coin(
collectionDetails?.updatable
? (openEditionMinterUpdatableCreationFee as string)
: (openEditionMinterCreationFee as string),
'ustars',
),
],
updatable: collectionDetails?.updatable, updatable: collectionDetails?.updatable,
} }
await openEditionFactoryDispatchExecute(payload) await openEditionFactoryDispatchExecute(payload)
@ -956,24 +680,16 @@ export const OpenEditionMinterCreator = ({
metadataStorageMethod, metadataStorageMethod,
openEditionMinterContractAddress, openEditionMinterContractAddress,
sg721ContractAddress, sg721ContractAddress,
whitelistContractAddress,
transactionHash, transactionHash,
} }
onChange(data) onChange(data)
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [ }, [metadataStorageMethod, openEditionMinterContractAddress, sg721ContractAddress, transactionHash])
metadataStorageMethod,
openEditionMinterContractAddress,
sg721ContractAddress,
whitelistContractAddress,
transactionHash,
])
useEffect(() => { useEffect(() => {
const data: OpenEditionMinterDetailsDataProps = { const data: OpenEditionMinterDetailsDataProps = {
imageUploadDetails: imageUploadDetails ? imageUploadDetails : undefined, imageUploadDetails: imageUploadDetails ? imageUploadDetails : undefined,
collectionDetails: collectionDetails ? collectionDetails : undefined, collectionDetails: collectionDetails ? collectionDetails : undefined,
whitelistDetails: whitelistDetails ? whitelistDetails : undefined,
royaltyDetails: royaltyDetails ? royaltyDetails : undefined, royaltyDetails: royaltyDetails ? royaltyDetails : undefined,
onChainMetadataInputDetails: onChainMetadataInputDetails ? onChainMetadataInputDetails : undefined, onChainMetadataInputDetails: onChainMetadataInputDetails ? onChainMetadataInputDetails : undefined,
offChainMetadataUploadDetails: offChainMetadataUploadDetails ? offChainMetadataUploadDetails : undefined, offChainMetadataUploadDetails: offChainMetadataUploadDetails ? offChainMetadataUploadDetails : undefined,
@ -983,14 +699,12 @@ export const OpenEditionMinterCreator = ({
coverImageUrl, coverImageUrl,
tokenUri, tokenUri,
tokenImageUri, tokenImageUri,
isRefreshed,
} }
onDetailsChange(data) onDetailsChange(data)
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [ }, [
imageUploadDetails, imageUploadDetails,
collectionDetails, collectionDetails,
whitelistDetails,
royaltyDetails, royaltyDetails,
onChainMetadataInputDetails, onChainMetadataInputDetails,
offChainMetadataUploadDetails, offChainMetadataUploadDetails,
@ -1000,7 +714,6 @@ export const OpenEditionMinterCreator = ({
coverImageUrl, coverImageUrl,
tokenUri, tokenUri,
tokenImageUri, tokenImageUri,
isRefreshed,
]) ])
useEffect(() => { useEffect(() => {
@ -1009,40 +722,6 @@ export const OpenEditionMinterCreator = ({
} }
}, [importedOpenEditionMinterDetails]) }, [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 ( return (
<div> <div>
{/* TODO: Cancel once we're able to index on-chain metadata */} {/* TODO: Cancel once we're able to index on-chain metadata */}
@ -1131,23 +810,16 @@ export const OpenEditionMinterCreator = ({
/> />
<MintingDetails <MintingDetails
importedMintingDetails={importedOpenEditionMinterDetails?.mintingDetails} importedMintingDetails={importedOpenEditionMinterDetails?.mintingDetails}
isPresale={whitelistDetails?.whitelistState === 'new'} minimumMintPrice={
minimumMintPrice={Number(minimumMintPrice) / 1000000} collectionDetails?.updatable
? Number(minimumUpdatableMintPrice) / 1000000
: Number(minimumMintPrice) / 1000000
}
mintTokenFromFactory={mintTokenFromFactory} mintTokenFromFactory={mintTokenFromFactory}
onChange={setMintingDetails} onChange={setMintingDetails}
uploadMethod={offChainMetadataUploadDetails?.uploadMethod as UploadMethod} uploadMethod={offChainMetadataUploadDetails?.uploadMethod as UploadMethod}
whitelistStartDate={whitelistDetails?.startTime}
/> />
</div> </div>
<div className="my-6 mx-10">
<WhitelistDetails
importedWhitelistDetails={importedOpenEditionMinterDetails?.whitelistDetails}
mintingTokenFromFactory={mintTokenFromFactory}
onChange={setWhitelistDetails}
/>
</div>
<div className="my-6"> <div className="my-6">
<RoyaltyDetails <RoyaltyDetails
importedRoyaltyDetails={importedOpenEditionMinterDetails?.royaltyDetails} importedRoyaltyDetails={importedOpenEditionMinterDetails?.royaltyDetails}

View File

@ -1,528 +0,0 @@
/* 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>
)
}

View File

@ -1,24 +1,14 @@
import { import {
FEATURED_IBC_TIA_FACTORY_ADDRESS,
FEATURED_IBC_USDC_FACTORY_ADDRESS,
FEATURED_VENDING_FACTORY_ADDRESS, FEATURED_VENDING_FACTORY_ADDRESS,
FEATURED_VENDING_FACTORY_FLEX_ADDRESS, FEATURED_VENDING_FACTORY_FLEX_ADDRESS,
FEATURED_VENDING_FACTORY_MERKLE_TREE_ADDRESS,
FEATURED_VENDING_IBC_TIA_FACTORY_FLEX_ADDRESS,
FEATURED_VENDING_IBC_TIA_FACTORY_MERKLE_TREE_ADDRESS,
FEATURED_VENDING_IBC_USDC_FACTORY_FLEX_ADDRESS,
OPEN_EDITION_FACTORY_ADDRESS, OPEN_EDITION_FACTORY_ADDRESS,
OPEN_EDITION_FACTORY_FLEX_ADDRESS,
OPEN_EDITION_IBC_ATOM_FACTORY_ADDRESS, OPEN_EDITION_IBC_ATOM_FACTORY_ADDRESS,
OPEN_EDITION_IBC_ATOM_FACTORY_FLEX_ADDRESS,
OPEN_EDITION_IBC_CRBRUS_FACTORY_ADDRESS, OPEN_EDITION_IBC_CRBRUS_FACTORY_ADDRESS,
OPEN_EDITION_IBC_FRNZ_FACTORY_ADDRESS, OPEN_EDITION_IBC_FRNZ_FACTORY_ADDRESS,
OPEN_EDITION_IBC_HUAHUA_FACTORY_ADDRESS,
OPEN_EDITION_IBC_KUJI_FACTORY_ADDRESS, OPEN_EDITION_IBC_KUJI_FACTORY_ADDRESS,
OPEN_EDITION_IBC_NBTC_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_ADDRESS,
OPEN_EDITION_IBC_USDC_FACTORY_FLEX_ADDRESS,
OPEN_EDITION_IBC_USK_FACTORY_ADDRESS, OPEN_EDITION_IBC_USK_FACTORY_ADDRESS,
OPEN_EDITION_NATIVE_BRNCH_FACTORY_ADDRESS, OPEN_EDITION_NATIVE_BRNCH_FACTORY_ADDRESS,
OPEN_EDITION_NATIVE_STRDST_FACTORY_ADDRESS, OPEN_EDITION_NATIVE_STRDST_FACTORY_ADDRESS,
@ -26,12 +16,10 @@ import {
OPEN_EDITION_UPDATABLE_IBC_ATOM_FACTORY_ADDRESS, OPEN_EDITION_UPDATABLE_IBC_ATOM_FACTORY_ADDRESS,
OPEN_EDITION_UPDATABLE_IBC_FRNZ_FACTORY_ADDRESS, OPEN_EDITION_UPDATABLE_IBC_FRNZ_FACTORY_ADDRESS,
OPEN_EDITION_UPDATABLE_IBC_NBTC_FACTORY_ADDRESS, OPEN_EDITION_UPDATABLE_IBC_NBTC_FACTORY_ADDRESS,
OPEN_EDITION_UPDATABLE_IBC_TIA_FACTORY_ADDRESS,
OPEN_EDITION_UPDATABLE_IBC_USDC_FACTORY_ADDRESS, OPEN_EDITION_UPDATABLE_IBC_USDC_FACTORY_ADDRESS,
OPEN_EDITION_UPDATABLE_IBC_USK_FACTORY_ADDRESS, OPEN_EDITION_UPDATABLE_IBC_USK_FACTORY_ADDRESS,
VENDING_FACTORY_ADDRESS, VENDING_FACTORY_ADDRESS,
VENDING_FACTORY_FLEX_ADDRESS, VENDING_FACTORY_FLEX_ADDRESS,
VENDING_FACTORY_MERKLE_TREE_ADDRESS,
VENDING_FACTORY_UPDATABLE_ADDRESS, VENDING_FACTORY_UPDATABLE_ADDRESS,
VENDING_FACTORY_UPDATABLE_FLEX_ADDRESS, VENDING_FACTORY_UPDATABLE_FLEX_ADDRESS,
VENDING_IBC_ATOM_FACTORY_ADDRESS, VENDING_IBC_ATOM_FACTORY_ADDRESS,
@ -40,17 +28,14 @@ import {
VENDING_IBC_ATOM_UPDATABLE_FACTORY_FLEX_ADDRESS, VENDING_IBC_ATOM_UPDATABLE_FACTORY_FLEX_ADDRESS,
VENDING_IBC_CRBRUS_FACTORY_ADDRESS, VENDING_IBC_CRBRUS_FACTORY_ADDRESS,
VENDING_IBC_CRBRUS_FACTORY_FLEX_ADDRESS, VENDING_IBC_CRBRUS_FACTORY_FLEX_ADDRESS,
VENDING_IBC_HUAHUA_FACTORY_ADDRESS,
VENDING_IBC_HUAHUA_FACTORY_FLEX_ADDRESS,
VENDING_IBC_KUJI_FACTORY_ADDRESS, VENDING_IBC_KUJI_FACTORY_ADDRESS,
VENDING_IBC_KUJI_FACTORY_FLEX_ADDRESS, VENDING_IBC_KUJI_FACTORY_FLEX_ADDRESS,
VENDING_IBC_NBTC_FACTORY_ADDRESS, VENDING_IBC_NBTC_FACTORY_ADDRESS,
VENDING_IBC_NBTC_FACTORY_FLEX_ADDRESS, VENDING_IBC_NBTC_FACTORY_FLEX_ADDRESS,
VENDING_IBC_NBTC_UPDATABLE_FACTORY_ADDRESS, VENDING_IBC_NBTC_UPDATABLE_FACTORY_ADDRESS,
VENDING_IBC_NBTC_UPDATABLE_FACTORY_FLEX_ADDRESS, VENDING_IBC_NBTC_UPDATABLE_FACTORY_FLEX_ADDRESS,
VENDING_IBC_TIA_FACTORY_ADDRESS,
VENDING_IBC_TIA_FACTORY_FLEX_ADDRESS,
VENDING_IBC_TIA_FACTORY_MERKLE_TREE_ADDRESS,
VENDING_IBC_TIA_UPDATABLE_FACTORY_ADDRESS,
VENDING_IBC_TIA_UPDATABLE_FACTORY_FLEX_ADDRESS,
VENDING_IBC_USDC_FACTORY_ADDRESS, VENDING_IBC_USDC_FACTORY_ADDRESS,
VENDING_IBC_USDC_FACTORY_FLEX_ADDRESS, VENDING_IBC_USDC_FACTORY_FLEX_ADDRESS,
VENDING_IBC_USDC_UPDATABLE_FACTORY_ADDRESS, VENDING_IBC_USDC_UPDATABLE_FACTORY_ADDRESS,
@ -72,10 +57,9 @@ import {
ibcAtom, ibcAtom,
ibcCrbrus, ibcCrbrus,
ibcFrnz, ibcFrnz,
// ibcHuahua, ibcHuahua,
ibcKuji, ibcKuji,
ibcNbtc, ibcNbtc,
ibcTia,
ibcUsdc, ibcUsdc,
ibcUsk, ibcUsk,
nativeBrnch, nativeBrnch,
@ -89,7 +73,6 @@ export interface MinterInfo {
supportedToken: TokenInfo supportedToken: TokenInfo
updatable?: boolean updatable?: boolean
flexible?: boolean flexible?: boolean
merkleTree?: boolean
featured?: boolean featured?: boolean
} }
@ -99,7 +82,6 @@ export const openEditionStarsMinter: MinterInfo = {
supportedToken: stars, supportedToken: stars,
updatable: false, updatable: false,
featured: false, featured: false,
flexible: false,
} }
export const openEditionUpdatableStarsMinter: MinterInfo = { export const openEditionUpdatableStarsMinter: MinterInfo = {
@ -108,7 +90,6 @@ export const openEditionUpdatableStarsMinter: MinterInfo = {
supportedToken: stars, supportedToken: stars,
updatable: true, updatable: true,
featured: false, featured: false,
flexible: false,
} }
export const openEditionIbcAtomMinter: MinterInfo = { export const openEditionIbcAtomMinter: MinterInfo = {
@ -117,7 +98,6 @@ export const openEditionIbcAtomMinter: MinterInfo = {
supportedToken: ibcAtom, supportedToken: ibcAtom,
updatable: false, updatable: false,
featured: false, featured: false,
flexible: false,
} }
export const openEditionUpdatableIbcAtomMinter: MinterInfo = { export const openEditionUpdatableIbcAtomMinter: MinterInfo = {
@ -126,7 +106,6 @@ export const openEditionUpdatableIbcAtomMinter: MinterInfo = {
supportedToken: ibcAtom, supportedToken: ibcAtom,
updatable: true, updatable: true,
featured: false, featured: false,
flexible: false,
} }
export const openEditionIbcUsdcMinter: MinterInfo = { export const openEditionIbcUsdcMinter: MinterInfo = {
@ -135,16 +114,6 @@ export const openEditionIbcUsdcMinter: MinterInfo = {
supportedToken: ibcUsdc, supportedToken: ibcUsdc,
updatable: false, updatable: false,
featured: false, featured: false,
flexible: false,
}
export const openEditionIbcTiaMinter: MinterInfo = {
id: 'open-edition-ibc-tia-minter',
factoryAddress: OPEN_EDITION_IBC_TIA_FACTORY_ADDRESS,
supportedToken: ibcTia,
updatable: false,
featured: false,
flexible: false,
} }
export const openEditionIbcNbtcMinter: MinterInfo = { export const openEditionIbcNbtcMinter: MinterInfo = {
@ -153,7 +122,6 @@ export const openEditionIbcNbtcMinter: MinterInfo = {
supportedToken: ibcNbtc, supportedToken: ibcNbtc,
updatable: false, updatable: false,
featured: false, featured: false,
flexible: false,
} }
export const openEditionUpdatableIbcUsdcMinter: MinterInfo = { export const openEditionUpdatableIbcUsdcMinter: MinterInfo = {
@ -162,16 +130,6 @@ export const openEditionUpdatableIbcUsdcMinter: MinterInfo = {
supportedToken: ibcUsdc, supportedToken: ibcUsdc,
updatable: true, updatable: true,
featured: false, featured: false,
flexible: false,
}
export const openEditionUpdatableIbcTiaMinter: MinterInfo = {
id: 'open-edition-updatable-ibc-tia-minter',
factoryAddress: OPEN_EDITION_UPDATABLE_IBC_TIA_FACTORY_ADDRESS,
supportedToken: ibcTia,
updatable: true,
featured: false,
flexible: false,
} }
export const openEditionUpdatableIbcNbtcMinter: MinterInfo = { export const openEditionUpdatableIbcNbtcMinter: MinterInfo = {
@ -180,7 +138,6 @@ export const openEditionUpdatableIbcNbtcMinter: MinterInfo = {
supportedToken: ibcNbtc, supportedToken: ibcNbtc,
updatable: true, updatable: true,
featured: false, featured: false,
flexible: false,
} }
export const openEditionIbcFrnzMinter: MinterInfo = { export const openEditionIbcFrnzMinter: MinterInfo = {
@ -189,7 +146,6 @@ export const openEditionIbcFrnzMinter: MinterInfo = {
supportedToken: ibcFrnz, supportedToken: ibcFrnz,
updatable: false, updatable: false,
featured: false, featured: false,
flexible: false,
} }
export const openEditionUpdatableIbcFrnzMinter: MinterInfo = { export const openEditionUpdatableIbcFrnzMinter: MinterInfo = {
@ -198,7 +154,6 @@ export const openEditionUpdatableIbcFrnzMinter: MinterInfo = {
supportedToken: ibcFrnz, supportedToken: ibcFrnz,
updatable: true, updatable: true,
featured: false, featured: false,
flexible: false,
} }
export const openEditionIbcUskMinter: MinterInfo = { export const openEditionIbcUskMinter: MinterInfo = {
@ -207,7 +162,6 @@ export const openEditionIbcUskMinter: MinterInfo = {
supportedToken: ibcUsk, supportedToken: ibcUsk,
updatable: false, updatable: false,
featured: false, featured: false,
flexible: false,
} }
export const openEditionUpdatableIbcUskMinter: MinterInfo = { export const openEditionUpdatableIbcUskMinter: MinterInfo = {
@ -216,7 +170,6 @@ export const openEditionUpdatableIbcUskMinter: MinterInfo = {
supportedToken: ibcUsk, supportedToken: ibcUsk,
updatable: true, updatable: true,
featured: false, featured: false,
flexible: false,
} }
export const openEditionIbcKujiMinter: MinterInfo = { export const openEditionIbcKujiMinter: MinterInfo = {
@ -225,16 +178,15 @@ export const openEditionIbcKujiMinter: MinterInfo = {
supportedToken: ibcKuji, supportedToken: ibcKuji,
updatable: false, updatable: false,
featured: false, featured: false,
flexible: false,
} }
// export const openEditionIbcHuahuaMinter: MinterInfo = { export const openEditionIbcHuahuaMinter: MinterInfo = {
// id: 'open-edition-ibc-huahua-minter', id: 'open-edition-ibc-huahua-minter',
// factoryAddress: OPEN_EDITION_IBC_HUAHUA_FACTORY_ADDRESS, factoryAddress: OPEN_EDITION_IBC_HUAHUA_FACTORY_ADDRESS,
// supportedToken: ibcHuahua, supportedToken: ibcHuahua,
// updatable: false, updatable: false,
// featured: false, featured: false,
// } }
export const openEditionIbcCrbrusMinter: MinterInfo = { export const openEditionIbcCrbrusMinter: MinterInfo = {
id: 'open-edition-ibc-crbrus-minter', id: 'open-edition-ibc-crbrus-minter',
@ -242,7 +194,6 @@ export const openEditionIbcCrbrusMinter: MinterInfo = {
supportedToken: ibcCrbrus, supportedToken: ibcCrbrus,
updatable: false, updatable: false,
featured: false, featured: false,
flexible: false,
} }
export const openEditionNativeStrdstMinter: MinterInfo = { export const openEditionNativeStrdstMinter: MinterInfo = {
@ -251,7 +202,6 @@ export const openEditionNativeStrdstMinter: MinterInfo = {
supportedToken: nativeStardust, supportedToken: nativeStardust,
updatable: false, updatable: false,
featured: false, featured: false,
flexible: false,
} }
export const openEditionNativeBrnchMinter: MinterInfo = { export const openEditionNativeBrnchMinter: MinterInfo = {
@ -260,7 +210,6 @@ export const openEditionNativeBrnchMinter: MinterInfo = {
supportedToken: nativeBrnch, supportedToken: nativeBrnch,
updatable: false, updatable: false,
featured: false, featured: false,
flexible: false,
} }
export const openEditionMinterList = [ export const openEditionMinterList = [
@ -272,69 +221,23 @@ export const openEditionMinterList = [
openEditionUpdatableIbcFrnzMinter, openEditionUpdatableIbcFrnzMinter,
openEditionIbcUsdcMinter, openEditionIbcUsdcMinter,
openEditionUpdatableIbcUsdcMinter, openEditionUpdatableIbcUsdcMinter,
openEditionIbcTiaMinter,
openEditionUpdatableIbcTiaMinter,
openEditionIbcNbtcMinter, openEditionIbcNbtcMinter,
openEditionUpdatableIbcNbtcMinter, openEditionUpdatableIbcNbtcMinter,
openEditionIbcUskMinter, openEditionIbcUskMinter,
openEditionUpdatableIbcUskMinter, openEditionUpdatableIbcUskMinter,
openEditionIbcKujiMinter, openEditionIbcKujiMinter,
// openEditionIbcHuahuaMinter, openEditionIbcHuahuaMinter,
openEditionIbcCrbrusMinter, openEditionIbcCrbrusMinter,
openEditionNativeStrdstMinter, openEditionNativeStrdstMinter,
openEditionNativeBrnchMinter, 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 = { export const vendingStarsMinter: MinterInfo = {
id: 'vending-stars-minter', id: 'vending-stars-minter',
factoryAddress: VENDING_FACTORY_ADDRESS, factoryAddress: VENDING_FACTORY_ADDRESS,
supportedToken: stars, supportedToken: stars,
updatable: false, updatable: false,
flexible: false, flexible: false,
merkleTree: false,
featured: false, featured: false,
} }
@ -344,7 +247,6 @@ export const vendingFeaturedStarsMinter: MinterInfo = {
supportedToken: stars, supportedToken: stars,
updatable: false, updatable: false,
flexible: false, flexible: false,
merkleTree: false,
featured: true, featured: true,
} }
@ -354,7 +256,6 @@ export const vendingUpdatableStarsMinter: MinterInfo = {
supportedToken: stars, supportedToken: stars,
updatable: true, updatable: true,
flexible: false, flexible: false,
merkleTree: false,
featured: false, featured: false,
} }
@ -364,7 +265,6 @@ export const vendingIbcAtomMinter: MinterInfo = {
supportedToken: ibcAtom, supportedToken: ibcAtom,
updatable: false, updatable: false,
flexible: false, flexible: false,
merkleTree: false,
featured: false, featured: false,
} }
@ -374,7 +274,6 @@ export const vendingUpdatableIbcAtomMinter: MinterInfo = {
supportedToken: ibcAtom, supportedToken: ibcAtom,
updatable: true, updatable: true,
flexible: false, flexible: false,
merkleTree: false,
featured: false, featured: false,
} }
@ -384,47 +283,15 @@ export const vendingIbcUsdcMinter: MinterInfo = {
supportedToken: ibcUsdc, supportedToken: ibcUsdc,
updatable: false, updatable: false,
flexible: false, flexible: false,
merkleTree: false,
featured: false, featured: false,
} }
export const vendingFeaturedIbcUsdcMinter: MinterInfo = {
id: 'vending-featured-ibc-usdc-minter',
factoryAddress: FEATURED_IBC_USDC_FACTORY_ADDRESS,
supportedToken: ibcUsdc,
updatable: false,
flexible: false,
merkleTree: false,
featured: true,
}
export const vendingIbcTiaMinter: MinterInfo = {
id: 'vending-ibc-tia-minter',
factoryAddress: VENDING_IBC_TIA_FACTORY_ADDRESS,
supportedToken: ibcTia,
updatable: false,
flexible: false,
merkleTree: false,
featured: false,
}
export const vendingFeaturedIbcTiaMinter: MinterInfo = {
id: 'vending-featured-ibc-tia-minter',
factoryAddress: FEATURED_IBC_TIA_FACTORY_ADDRESS,
supportedToken: ibcTia,
updatable: false,
flexible: false,
merkleTree: false,
featured: true,
}
export const vendingIbcNbtcMinter: MinterInfo = { export const vendingIbcNbtcMinter: MinterInfo = {
id: 'vending-ibc-nbtc-minter', id: 'vending-ibc-nbtc-minter',
factoryAddress: VENDING_IBC_NBTC_FACTORY_ADDRESS, factoryAddress: VENDING_IBC_NBTC_FACTORY_ADDRESS,
supportedToken: ibcNbtc, supportedToken: ibcNbtc,
updatable: false, updatable: false,
flexible: false, flexible: false,
merkleTree: false,
featured: false, featured: false,
} }
@ -434,17 +301,6 @@ export const vendingUpdatableIbcUsdcMinter: MinterInfo = {
supportedToken: ibcUsdc, supportedToken: ibcUsdc,
updatable: true, updatable: true,
flexible: false, flexible: false,
merkleTree: false,
featured: false,
}
export const vendingUpdatableIbcTiaMinter: MinterInfo = {
id: 'vending-updatable-ibc-tia-minter',
factoryAddress: VENDING_IBC_TIA_UPDATABLE_FACTORY_ADDRESS,
supportedToken: ibcTia,
updatable: true,
flexible: false,
merkleTree: false,
featured: false, featured: false,
} }
@ -454,7 +310,6 @@ export const vendingUpdatableIbcNbtcMinter: MinterInfo = {
supportedToken: ibcNbtc, supportedToken: ibcNbtc,
updatable: true, updatable: true,
flexible: false, flexible: false,
merkleTree: false,
featured: false, featured: false,
} }
@ -464,7 +319,6 @@ export const vendingIbcUskMinter: MinterInfo = {
supportedToken: ibcUsk, supportedToken: ibcUsk,
updatable: false, updatable: false,
flexible: false, flexible: false,
merkleTree: false,
featured: false, featured: false,
} }
@ -474,7 +328,6 @@ export const vendingUpdatableIbcUskMinter: MinterInfo = {
supportedToken: ibcUsk, supportedToken: ibcUsk,
updatable: true, updatable: true,
flexible: false, flexible: false,
merkleTree: false,
featured: false, featured: false,
} }
@ -484,19 +337,17 @@ export const vendingIbcKujiMinter: MinterInfo = {
supportedToken: ibcKuji, supportedToken: ibcKuji,
updatable: false, updatable: false,
flexible: false, flexible: false,
merkleTree: false,
featured: false, featured: false,
} }
// export const vendingIbcHuahuaMinter: MinterInfo = { export const vendingIbcHuahuaMinter: MinterInfo = {
// id: 'vending-ibc-huahua-minter', id: 'vending-ibc-huahua-minter',
// factoryAddress: VENDING_IBC_HUAHUA_FACTORY_ADDRESS, factoryAddress: VENDING_IBC_HUAHUA_FACTORY_ADDRESS,
// supportedToken: ibcHuahua, supportedToken: ibcHuahua,
// updatable: false, updatable: false,
// flexible: false, flexible: false,
// merkleTree: false, featured: false,
// featured: false, }
// }
export const vendingIbcCrbrusMinter: MinterInfo = { export const vendingIbcCrbrusMinter: MinterInfo = {
id: 'vending-ibc-crbrus-minter', id: 'vending-ibc-crbrus-minter',
@ -504,7 +355,6 @@ export const vendingIbcCrbrusMinter: MinterInfo = {
supportedToken: ibcCrbrus, supportedToken: ibcCrbrus,
updatable: false, updatable: false,
flexible: false, flexible: false,
merkleTree: false,
featured: false, featured: false,
} }
@ -514,7 +364,6 @@ export const vendingNativeStardustMinter: MinterInfo = {
supportedToken: nativeStardust, supportedToken: nativeStardust,
updatable: false, updatable: false,
flexible: false, flexible: false,
merkleTree: false,
featured: false, featured: false,
} }
@ -524,7 +373,6 @@ export const vendingUpdatableNativeStardustMinter: MinterInfo = {
supportedToken: nativeStardust, supportedToken: nativeStardust,
updatable: true, updatable: true,
flexible: false, flexible: false,
merkleTree: false,
featured: false, featured: false,
} }
@ -534,7 +382,6 @@ export const vendingNativeBrnchMinter: MinterInfo = {
supportedToken: nativeBrnch, supportedToken: nativeBrnch,
updatable: false, updatable: false,
flexible: false, flexible: false,
merkleTree: false,
featured: false, featured: false,
} }
@ -544,7 +391,6 @@ export const vendingUpdatableNativeBrnchMinter: MinterInfo = {
supportedToken: nativeBrnch, supportedToken: nativeBrnch,
updatable: true, updatable: true,
flexible: false, flexible: false,
merkleTree: false,
featured: false, featured: false,
} }
@ -555,17 +401,13 @@ export const vendingMinterList = [
vendingIbcAtomMinter, vendingIbcAtomMinter,
vendingUpdatableIbcAtomMinter, vendingUpdatableIbcAtomMinter,
vendingIbcUsdcMinter, vendingIbcUsdcMinter,
vendingFeaturedIbcUsdcMinter,
vendingUpdatableIbcUsdcMinter, vendingUpdatableIbcUsdcMinter,
vendingIbcTiaMinter,
vendingFeaturedIbcTiaMinter,
vendingUpdatableIbcTiaMinter,
vendingIbcNbtcMinter, vendingIbcNbtcMinter,
vendingUpdatableIbcNbtcMinter, vendingUpdatableIbcNbtcMinter,
vendingIbcUskMinter, vendingIbcUskMinter,
vendingUpdatableIbcUskMinter, vendingUpdatableIbcUskMinter,
vendingIbcKujiMinter, vendingIbcKujiMinter,
// vendingIbcHuahuaMinter, vendingIbcHuahuaMinter,
vendingIbcCrbrusMinter, vendingIbcCrbrusMinter,
vendingNativeStardustMinter, vendingNativeStardustMinter,
vendingUpdatableNativeStardustMinter, vendingUpdatableNativeStardustMinter,
@ -579,7 +421,6 @@ export const flexibleVendingStarsMinter: MinterInfo = {
supportedToken: stars, supportedToken: stars,
updatable: false, updatable: false,
flexible: true, flexible: true,
merkleTree: false,
featured: false, featured: false,
} }
@ -589,7 +430,6 @@ export const flexibleFeaturedVendingStarsMinter: MinterInfo = {
supportedToken: stars, supportedToken: stars,
updatable: false, updatable: false,
flexible: true, flexible: true,
merkleTree: false,
featured: true, featured: true,
} }
@ -599,7 +439,6 @@ export const flexibleVendingUpdatableStarsMinter: MinterInfo = {
supportedToken: stars, supportedToken: stars,
updatable: true, updatable: true,
flexible: true, flexible: true,
merkleTree: false,
featured: false, featured: false,
} }
@ -609,7 +448,6 @@ export const flexibleVendingIbcAtomMinter: MinterInfo = {
supportedToken: ibcAtom, supportedToken: ibcAtom,
updatable: false, updatable: false,
flexible: true, flexible: true,
merkleTree: false,
featured: false, featured: false,
} }
@ -619,7 +457,6 @@ export const flexibleVendingUpdatableIbcAtomMinter: MinterInfo = {
supportedToken: ibcAtom, supportedToken: ibcAtom,
updatable: true, updatable: true,
flexible: true, flexible: true,
merkleTree: false,
featured: false, featured: false,
} }
@ -629,47 +466,15 @@ export const flexibleVendingIbcUsdcMinter: MinterInfo = {
supportedToken: ibcUsdc, supportedToken: ibcUsdc,
updatable: false, updatable: false,
flexible: true, flexible: true,
merkleTree: false,
featured: false, featured: false,
} }
export const flexibleFeaturedVendingIbcUsdcMinter: MinterInfo = {
id: 'flexible-featured-vending-ibc-usdc-minter',
factoryAddress: FEATURED_VENDING_IBC_USDC_FACTORY_FLEX_ADDRESS,
supportedToken: ibcUsdc,
updatable: false,
flexible: true,
merkleTree: false,
featured: true,
}
export const flexibleVendingIbcTiaMinter: MinterInfo = {
id: 'flexible-vending-ibc-tia-minter',
factoryAddress: VENDING_IBC_TIA_FACTORY_FLEX_ADDRESS,
supportedToken: ibcTia,
updatable: false,
flexible: true,
merkleTree: false,
featured: false,
}
export const flexibleFeaturedVendingIbcTiaMinter: MinterInfo = {
id: 'flexible-featured-vending-ibc-tia-minter',
factoryAddress: FEATURED_VENDING_IBC_TIA_FACTORY_FLEX_ADDRESS,
supportedToken: ibcTia,
updatable: false,
flexible: true,
merkleTree: false,
featured: true,
}
export const flexibleVendingIbcNbtcMinter: MinterInfo = { export const flexibleVendingIbcNbtcMinter: MinterInfo = {
id: 'flexible-vending-ibc-nbtc-minter', id: 'flexible-vending-ibc-nbtc-minter',
factoryAddress: VENDING_IBC_NBTC_FACTORY_FLEX_ADDRESS, factoryAddress: VENDING_IBC_NBTC_FACTORY_FLEX_ADDRESS,
supportedToken: ibcNbtc, supportedToken: ibcNbtc,
updatable: false, updatable: false,
flexible: true, flexible: true,
merkleTree: false,
featured: false, featured: false,
} }
@ -679,17 +484,6 @@ export const flexibleVendingUpdatableIbcUsdcMinter: MinterInfo = {
supportedToken: ibcUsdc, supportedToken: ibcUsdc,
updatable: true, updatable: true,
flexible: true, flexible: true,
merkleTree: false,
featured: false,
}
export const flexibleVendingUpdatableIbcTiaMinter: MinterInfo = {
id: 'flexible-vending-updatable-ibc-tia-minter',
factoryAddress: VENDING_IBC_TIA_UPDATABLE_FACTORY_FLEX_ADDRESS,
supportedToken: ibcTia,
updatable: true,
flexible: true,
merkleTree: false,
featured: false, featured: false,
} }
@ -699,7 +493,6 @@ export const flexibleVendingUpdatableIbcNbtcMinter: MinterInfo = {
supportedToken: ibcNbtc, supportedToken: ibcNbtc,
updatable: true, updatable: true,
flexible: true, flexible: true,
merkleTree: false,
featured: false, featured: false,
} }
@ -709,7 +502,6 @@ export const flexibleVendingIbcUskMinter: MinterInfo = {
supportedToken: ibcUsk, supportedToken: ibcUsk,
updatable: false, updatable: false,
flexible: true, flexible: true,
merkleTree: false,
featured: false, featured: false,
} }
@ -719,7 +511,6 @@ export const flexibleVendingUpdatableIbcUskMinter: MinterInfo = {
supportedToken: ibcUsk, supportedToken: ibcUsk,
updatable: true, updatable: true,
flexible: true, flexible: true,
merkleTree: false,
featured: false, featured: false,
} }
@ -729,19 +520,17 @@ export const flexibleVendingIbcKujiMinter: MinterInfo = {
supportedToken: ibcKuji, supportedToken: ibcKuji,
updatable: false, updatable: false,
flexible: true, flexible: true,
merkleTree: false,
featured: false, featured: false,
} }
// export const flexibleVendingIbcHuahuaMinter: MinterInfo = { export const flexibleVendingIbcHuahuaMinter: MinterInfo = {
// id: 'flexible-vending-ibc-huahua-minter', id: 'flexible-vending-ibc-huahua-minter',
// factoryAddress: VENDING_IBC_HUAHUA_FACTORY_FLEX_ADDRESS, factoryAddress: VENDING_IBC_HUAHUA_FACTORY_FLEX_ADDRESS,
// supportedToken: ibcHuahua, supportedToken: ibcHuahua,
// updatable: false, updatable: false,
// flexible: true, flexible: true,
// merkleTree: false, featured: false,
// featured: false, }
// }
export const flexibleVendingIbcCrbrusMinter: MinterInfo = { export const flexibleVendingIbcCrbrusMinter: MinterInfo = {
id: 'flexible-vending-ibc-crbrus-minter', id: 'flexible-vending-ibc-crbrus-minter',
@ -749,7 +538,6 @@ export const flexibleVendingIbcCrbrusMinter: MinterInfo = {
supportedToken: ibcCrbrus, supportedToken: ibcCrbrus,
updatable: false, updatable: false,
flexible: true, flexible: true,
merkleTree: false,
featured: false, featured: false,
} }
@ -759,7 +547,6 @@ export const flexibleVendingStrdstMinter: MinterInfo = {
supportedToken: nativeStardust, supportedToken: nativeStardust,
updatable: false, updatable: false,
flexible: true, flexible: true,
merkleTree: false,
featured: false, featured: false,
} }
@ -769,7 +556,6 @@ export const flexibleVendingBrnchMinter: MinterInfo = {
supportedToken: nativeBrnch, supportedToken: nativeBrnch,
updatable: false, updatable: false,
flexible: true, flexible: true,
merkleTree: false,
featured: false, featured: false,
} }
@ -780,65 +566,14 @@ export const flexibleVendingMinterList = [
flexibleVendingIbcAtomMinter, flexibleVendingIbcAtomMinter,
flexibleVendingUpdatableIbcAtomMinter, flexibleVendingUpdatableIbcAtomMinter,
flexibleVendingIbcUsdcMinter, flexibleVendingIbcUsdcMinter,
flexibleFeaturedVendingIbcUsdcMinter,
flexibleVendingUpdatableIbcUsdcMinter, flexibleVendingUpdatableIbcUsdcMinter,
flexibleVendingIbcTiaMinter,
flexibleFeaturedVendingIbcTiaMinter,
flexibleVendingUpdatableIbcTiaMinter,
flexibleVendingIbcNbtcMinter, flexibleVendingIbcNbtcMinter,
flexibleVendingUpdatableIbcNbtcMinter, flexibleVendingUpdatableIbcNbtcMinter,
flexibleVendingIbcUskMinter, flexibleVendingIbcUskMinter,
flexibleVendingUpdatableIbcUskMinter, flexibleVendingUpdatableIbcUskMinter,
flexibleVendingIbcKujiMinter, flexibleVendingIbcKujiMinter,
// flexibleVendingIbcHuahuaMinter, flexibleVendingIbcHuahuaMinter,
flexibleVendingIbcCrbrusMinter, flexibleVendingIbcCrbrusMinter,
flexibleVendingStrdstMinter, flexibleVendingStrdstMinter,
flexibleVendingBrnchMinter, flexibleVendingBrnchMinter,
] ]
export const merkleTreeVendingStarsMinter: MinterInfo = {
id: 'merkletree-vending-stars-minter',
factoryAddress: VENDING_FACTORY_MERKLE_TREE_ADDRESS,
supportedToken: stars,
updatable: false,
flexible: false,
merkleTree: true,
featured: false,
}
export const merkleTreeVendingFeaturedStarsMinter: MinterInfo = {
id: 'merkletree-vending-featured-stars-minter',
factoryAddress: FEATURED_VENDING_FACTORY_MERKLE_TREE_ADDRESS,
supportedToken: stars,
updatable: false,
flexible: false,
merkleTree: true,
featured: true,
}
export const merkleTreeVendingIbcTiaMinter: MinterInfo = {
id: 'merkletree-vending-ibc-tia-minter',
factoryAddress: VENDING_IBC_TIA_FACTORY_MERKLE_TREE_ADDRESS,
supportedToken: ibcTia,
updatable: false,
flexible: false,
merkleTree: true,
featured: false,
}
export const merkleTreeVendingFeaturedIbcTiaMinter: MinterInfo = {
id: 'merkletree-vending-featured-ibc-tia-minter',
factoryAddress: FEATURED_VENDING_IBC_TIA_FACTORY_MERKLE_TREE_ADDRESS,
supportedToken: ibcTia,
updatable: false,
flexible: false,
merkleTree: true,
featured: true,
}
export const merkleTreeVendingMinterList = [
merkleTreeVendingStarsMinter,
merkleTreeVendingIbcTiaMinter,
merkleTreeVendingFeaturedStarsMinter,
merkleTreeVendingFeaturedIbcTiaMinter,
]

View File

@ -69,15 +69,15 @@ export const ibcNbtc: TokenInfo = {
decimalPlaces: 6, decimalPlaces: 6,
} }
// export const ibcHuahua: TokenInfo = { export const ibcHuahua: TokenInfo = {
// id: 'ibc-huahua', id: 'ibc-huahua',
// denom: denom:
// NETWORK === 'mainnet' NETWORK === 'mainnet'
// ? 'ibc/CAD8A9F306CAAC55731C66930D6BEE539856DD12E59061C965E44D82AA26A0E7' ? 'ibc/CAD8A9F306CAAC55731C66930D6BEE539856DD12E59061C965E44D82AA26A0E7'
// : 'factory/stars153w5xhuqu3et29lgqk4dsynj6gjn96lr33wx4e/uhuahua', : 'factory/stars153w5xhuqu3et29lgqk4dsynj6gjn96lr33wx4e/uhuahua',
// displayName: 'HUAHUA', displayName: 'HUAHUA',
// decimalPlaces: 6, decimalPlaces: 6,
// } }
export const ibcCrbrus: TokenInfo = { export const ibcCrbrus: TokenInfo = {
id: 'ibc-crbrus', id: 'ibc-crbrus',
@ -89,16 +89,6 @@ export const ibcCrbrus: TokenInfo = {
decimalPlaces: 6, decimalPlaces: 6,
} }
export const ibcTia: TokenInfo = {
id: 'ibc-tia',
denom:
NETWORK === 'mainnet'
? 'ibc/14D1406D84227FDF4B055EA5CB2298095BBCA3F3BC3EF583AE6DF36F0FB179C8'
: 'factory/stars153w5xhuqu3et29lgqk4dsynj6gjn96lr33wx4e/utia',
displayName: 'TIA',
decimalPlaces: 6,
}
export const nativeStardust: TokenInfo = { export const nativeStardust: TokenInfo = {
id: 'native-strdst', id: 'native-strdst',
denom: denom:
@ -127,9 +117,8 @@ export const tokensList = [
ibcFrnz, ibcFrnz,
ibcNbtc, ibcNbtc,
ibcKuji, ibcKuji,
// ibcHuahua, ibcHuahua,
ibcCrbrus, ibcCrbrus,
ibcTia,
nativeStardust, nativeStardust,
nativeBrnch, nativeBrnch,
] ]

View File

@ -16,7 +16,6 @@ import type { UseVendingMinterContractProps } from 'contracts/vendingMinter'
import { useVendingMinterContract } from 'contracts/vendingMinter' import { useVendingMinterContract } from 'contracts/vendingMinter'
import type { UseWhiteListContractProps } from 'contracts/whitelist' import type { UseWhiteListContractProps } from 'contracts/whitelist'
import { useWhiteListContract } from 'contracts/whitelist' import { useWhiteListContract } from 'contracts/whitelist'
import { type UseWhiteListMerkleTreeContractProps, useWhiteListMerkleTreeContract } from 'contracts/whitelistMerkleTree'
import type { ReactNode, VFC } from 'react' import type { ReactNode, VFC } from 'react'
import { Fragment, useEffect } from 'react' import { Fragment, useEffect } from 'react'
import { create } from 'zustand' import { create } from 'zustand'
@ -33,7 +32,6 @@ export interface ContractsStore {
baseMinter: UseBaseMinterContractProps | null baseMinter: UseBaseMinterContractProps | null
openEditionMinter: UseOpenEditionMinterContractProps | null openEditionMinter: UseOpenEditionMinterContractProps | null
whitelist: UseWhiteListContractProps | null whitelist: UseWhiteListContractProps | null
whitelistMerkleTree: UseWhiteListMerkleTreeContractProps | null
vendingFactory: UseVendingFactoryContractProps | null vendingFactory: UseVendingFactoryContractProps | null
baseFactory: UseBaseFactoryContractProps | null baseFactory: UseBaseFactoryContractProps | null
openEditionFactory: UseOpenEditionFactoryContractProps | null openEditionFactory: UseOpenEditionFactoryContractProps | null
@ -51,7 +49,6 @@ export const defaultValues: ContractsStore = {
baseMinter: null, baseMinter: null,
openEditionMinter: null, openEditionMinter: null,
whitelist: null, whitelist: null,
whitelistMerkleTree: null,
vendingFactory: null, vendingFactory: null,
baseFactory: null, baseFactory: null,
openEditionFactory: null, openEditionFactory: null,
@ -86,7 +83,6 @@ const ContractsSubscription: VFC = () => {
const baseMinter = useBaseMinterContract() const baseMinter = useBaseMinterContract()
const openEditionMinter = useOpenEditionMinterContract() const openEditionMinter = useOpenEditionMinterContract()
const whitelist = useWhiteListContract() const whitelist = useWhiteListContract()
const whitelistMerkleTree = useWhiteListMerkleTreeContract()
const vendingFactory = useVendingFactoryContract() const vendingFactory = useVendingFactoryContract()
const baseFactory = useBaseFactoryContract() const baseFactory = useBaseFactoryContract()
const openEditionFactory = useOpenEditionFactoryContract() const openEditionFactory = useOpenEditionFactoryContract()
@ -101,7 +97,6 @@ const ContractsSubscription: VFC = () => {
baseMinter, baseMinter,
openEditionMinter, openEditionMinter,
whitelist, whitelist,
whitelistMerkleTree,
vendingFactory, vendingFactory,
baseFactory, baseFactory,
openEditionFactory, openEditionFactory,
@ -109,20 +104,7 @@ const ContractsSubscription: VFC = () => {
splits, splits,
royaltyRegistry, royaltyRegistry,
}) })
}, [ }, [sg721, vendingMinter, baseMinter, whitelist, vendingFactory, baseFactory, badgeHub, splits, royaltyRegistry])
sg721,
vendingMinter,
baseMinter,
whitelist,
whitelistMerkleTree,
vendingFactory,
baseFactory,
badgeHub,
splits,
royaltyRegistry,
openEditionMinter,
openEditionFactory,
])
return null return null
} }

View File

@ -342,8 +342,7 @@ export const badgeHub = (client: SigningCosmWasmClient, txSigner: string): Badge
}, },
'auto', 'auto',
'', '',
[coin(200000000, 'ustars')], editFee ? [coin(editFee, 'ustars')] : [],
// editFee ? [coin(editFee, 'ustars')] : [],
) )
return res.transactionHash return res.transactionHash

View File

@ -70,8 +70,8 @@ export const baseFactory = (client: SigningCosmWasmClient, txSigner: string): Ba
) )
return { return {
baseMinterAddress: result.logs[0].events[16].attributes[0].value, baseMinterAddress: result.logs[0].events[5].attributes[0].value,
sg721Address: result.logs[0].events[18].attributes[0].value, sg721Address: result.logs[0].events[5].attributes[2].value,
transactionHash: result.transactionHash, transactionHash: result.transactionHash,
logs: result.logs, logs: result.logs,
} }

View File

@ -61,8 +61,8 @@ export const openEditionFactory = (client: SigningCosmWasmClient, txSigner: stri
const result = await client.execute(senderAddress, contractAddress, msg, 'auto', '', funds) const result = await client.execute(senderAddress, contractAddress, msg, 'auto', '', funds)
return { return {
openEditionMinterAddress: result.logs[0].events[16].attributes[0].value, openEditionMinterAddress: result.logs[0].events[5].attributes[0].value,
sg721Address: result.logs[0].events[18].attributes[0].value, sg721Address: result.logs[0].events[5].attributes[2].value,
transactionHash: result.transactionHash, transactionHash: result.transactionHash,
logs: result.logs, logs: result.logs,
} }

View File

@ -25,7 +25,6 @@ export interface CollectionInfo {
external_link?: string external_link?: string
explicit_content?: boolean explicit_content?: boolean
royalty_info?: RoyaltyInfo | undefined royalty_info?: RoyaltyInfo | undefined
creator?: string
} }
export interface SG721Instance { export interface SG721Instance {

View File

@ -63,10 +63,8 @@ export const vendingFactory = (client: SigningCosmWasmClient, txSigner: string):
const result = await client.execute(senderAddress, contractAddress, msg, 'auto', '', funds) const result = await client.execute(senderAddress, contractAddress, msg, 'auto', '', funds)
return { return {
vendingMinterAddress: result.logs[0].events.filter((e) => e.type === 'instantiate')[0].attributes[0].value, vendingMinterAddress: result.logs[0].events[5].attributes[0].value,
sg721Address: result.logs[0].events sg721Address: result.logs[0].events[5].attributes[2].value,
.filter((e) => e.type === 'wasm')
.filter((e) => e.attributes[2]?.key === 'sg721_address')[0].attributes[2].value,
transactionHash: result.transactionHash, transactionHash: result.transactionHash,
logs: result.logs, logs: result.logs,
} }

View File

@ -1,375 +0,0 @@
import type { SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate'
import { type Coin, coin } from '@cosmjs/proto-signing'
import type { WhitelistFlexMember } from 'components/WhitelistFlexUpload'
export interface InstantiateResponse {
readonly contractAddress: string
readonly transactionHash: string
}
export interface ConfigResponse {
readonly per_address_limit: number
readonly start_time: string
readonly end_time: string
readonly mint_price: Coin
readonly is_active: boolean
}
export interface WhiteListMerkleTreeInstance {
readonly contractAddress: string
//Query
hasStarted: () => Promise<boolean>
hasEnded: () => Promise<boolean>
isActive: () => Promise<boolean>
hasMember: (member: string, proof_hashes: string[]) => Promise<boolean>
adminList: () => Promise<string[]>
config: () => Promise<ConfigResponse>
canExecute: (sender: string, msg: string) => Promise<boolean>
merkleRoot: () => Promise<string>
merkleTreeUri: () => Promise<string>
//Execute
updateStartTime: (startTime: string) => Promise<string>
updateEndTime: (endTime: string) => Promise<string>
addMembers: (memberList: string[] | WhitelistFlexMember[]) => Promise<string>
removeMembers: (memberList: string[]) => Promise<string>
// updatePerAddressLimit: (limit: number) => Promise<string>
updateAdmins: (admins: string[]) => Promise<string>
freeze: () => Promise<string>
}
export interface WhiteListMerkleTreeMessages {
updateStartTime: (startTime: string) => UpdateStartTimeMessage
updateEndTime: (endTime: string) => UpdateEndTimeMessage
addMembers: (memberList: string[] | WhitelistFlexMember[]) => AddMembersMessage
removeMembers: (memberList: string[]) => RemoveMembersMessage
// updatePerAddressLimit: (limit: number) => UpdatePerAddressLimitMessage
updateAdmins: (admins: string[]) => UpdateAdminsMessage
freeze: () => FreezeMessage
}
export interface UpdateStartTimeMessage {
sender: string
contract: string
msg: {
update_start_time: string
}
funds: Coin[]
}
export interface UpdateEndTimeMessage {
sender: string
contract: string
msg: {
update_end_time: string
}
funds: Coin[]
}
export interface UpdateAdminsMessage {
sender: string
contract: string
msg: {
update_admins: { admins: string[] }
}
funds: Coin[]
}
export interface FreezeMessage {
sender: string
contract: string
msg: { freeze: Record<string, never> }
funds: Coin[]
}
export interface AddMembersMessage {
sender: string
contract: string
msg: {
add_members: { to_add: string[] | WhitelistFlexMember[] }
}
funds: Coin[]
}
export interface RemoveMembersMessage {
sender: string
contract: string
msg: {
remove_members: { to_remove: string[] }
}
funds: Coin[]
}
// export interface UpdatePerAddressLimitMessage {
// sender: string
// contract: string
// msg: {
// update_per_address_limit: number
// }
// funds: Coin[]
// }
export interface WhiteListMerkleTreeContract {
instantiate: (
codeId: number,
initMsg: Record<string, unknown>,
label: string,
admin?: string,
) => Promise<InstantiateResponse>
use: (contractAddress: string) => WhiteListMerkleTreeInstance
messages: (contractAddress: string) => WhiteListMerkleTreeMessages
}
export const WhiteListMerkleTree = (client: SigningCosmWasmClient, txSigner: string): WhiteListMerkleTreeContract => {
const use = (contractAddress: string): WhiteListMerkleTreeInstance => {
///QUERY START
const hasStarted = async (): Promise<boolean> => {
return client.queryContractSmart(contractAddress, { has_started: {} })
}
const hasEnded = async (): Promise<boolean> => {
return client.queryContractSmart(contractAddress, { has_ended: {} })
}
const isActive = async (): Promise<boolean> => {
return client.queryContractSmart(contractAddress, { is_active: {} })
}
const hasMember = async (member: string, proofHashes: string[]): Promise<boolean> => {
return client.queryContractSmart(contractAddress, {
has_member: { member, proof_hashes: proofHashes },
})
}
const adminList = async (): Promise<string[]> => {
return client.queryContractSmart(contractAddress, {
admin_list: {},
})
}
const config = async (): Promise<ConfigResponse> => {
return client.queryContractSmart(contractAddress, {
config: {},
})
}
const merkleRoot = async (): Promise<string> => {
return client.queryContractSmart(contractAddress, {
merkle_root: {},
})
}
const merkleTreeUri = async (): Promise<string> => {
return client.queryContractSmart(contractAddress, {
merkle_tree_u_r_i: {},
})
}
const canExecute = async (sender: string, msg: string): Promise<boolean> => {
return client.queryContractSmart(contractAddress, {
can_execute: { sender, msg },
})
}
/// QUERY END
/// EXECUTE START
const updateStartTime = async (startTime: string): Promise<string> => {
const res = await client.execute(txSigner, contractAddress, { update_start_time: startTime }, 'auto')
return res.transactionHash
}
const updateEndTime = async (endTime: string): Promise<string> => {
const res = await client.execute(txSigner, contractAddress, { update_end_time: endTime }, 'auto')
return res.transactionHash
}
const addMembers = async (memberList: string[] | WhitelistFlexMember[]): Promise<string> => {
const res = await client.execute(
txSigner,
contractAddress,
{
add_members: {
to_add: memberList,
},
},
'auto',
)
return res.transactionHash
}
const updateAdmins = async (admins: string[]): Promise<string> => {
const res = await client.execute(
txSigner,
contractAddress,
{
update_admins: {
admins,
},
},
'auto',
)
return res.transactionHash
}
const freeze = async (): Promise<string> => {
const res = await client.execute(
txSigner,
contractAddress,
{
freeze: {},
},
'auto',
)
return res.transactionHash
}
const removeMembers = async (memberList: string[]): Promise<string> => {
const res = await client.execute(
txSigner,
contractAddress,
{
remove_members: {
to_remove: memberList,
},
},
'auto',
)
return res.transactionHash
}
// const updatePerAddressLimit = async (limit: number): Promise<string> => {
// const res = await client.execute(txSigner, contractAddress, { update_per_address_limit: limit }, 'auto')
// return res.transactionHash
// }
/// EXECUTE END
return {
contractAddress,
updateStartTime,
updateEndTime,
updateAdmins,
freeze,
addMembers,
removeMembers,
// updatePerAddressLimit,
hasStarted,
hasEnded,
isActive,
hasMember,
adminList,
config,
merkleRoot,
merkleTreeUri,
canExecute,
}
}
const instantiate = async (
codeId: number,
initMsg: Record<string, unknown>,
label: string,
admin?: string,
): Promise<InstantiateResponse> => {
const result = await client.instantiate(txSigner, codeId, initMsg, label, 'auto', {
admin,
funds: [coin(1000000000, 'ustars')],
})
return {
contractAddress: result.contractAddress,
transactionHash: result.transactionHash,
}
}
const messages = (contractAddress: string) => {
const updateStartTime = (startTime: string) => {
return {
sender: txSigner,
contract: contractAddress,
msg: {
update_start_time: startTime,
},
funds: [],
}
}
const updateEndTime = (endTime: string) => {
return {
sender: txSigner,
contract: contractAddress,
msg: {
update_end_time: endTime,
},
funds: [],
}
}
const addMembers = (memberList: string[] | WhitelistFlexMember[]) => {
return {
sender: txSigner,
contract: contractAddress,
msg: {
add_members: { to_add: memberList },
},
funds: [],
}
}
const updateAdmins = (admins: string[]) => {
return {
sender: txSigner,
contract: contractAddress,
msg: {
update_admins: { admins },
},
funds: [],
}
}
const freeze = () => {
return {
sender: txSigner,
contract: contractAddress,
msg: {
freeze: {},
},
funds: [],
}
}
const removeMembers = (memberList: string[]) => {
return {
sender: txSigner,
contract: contractAddress,
msg: {
remove_members: { to_remove: memberList },
},
funds: [],
}
}
// const updatePerAddressLimit = (limit: number) => {
// return {
// sender: txSigner,
// contract: contractAddress,
// msg: {
// update_per_address_limit: limit,
// },
// funds: [],
// }
// }
return {
updateStartTime,
updateEndTime,
updateAdmins,
addMembers,
removeMembers,
// updatePerAddressLimit,
freeze,
}
}
return { use, instantiate, messages }
}

View File

@ -1,2 +0,0 @@
export * from './contract'
export * from './useContract'

View File

@ -1,144 +0,0 @@
import type { WhitelistFlexMember } from '../../../components/WhitelistFlexUpload'
import type { WhiteListMerkleTreeInstance } from '../index'
import { useWhiteListMerkleTreeContract } from '../index'
export type ExecuteType = typeof EXECUTE_TYPES[number]
export const EXECUTE_TYPES = [
'update_start_time',
'update_end_time',
'update_admins',
'add_members',
'remove_members',
// 'update_per_address_limit',
'freeze',
] as const
export interface ExecuteListItem {
id: ExecuteType
name: string
description?: string
}
export const EXECUTE_LIST: ExecuteListItem[] = [
{
id: 'update_start_time',
name: 'Update Start Time',
description: `Update the start time of the whitelist`,
},
{
id: 'update_end_time',
name: 'Update End Time',
description: `Update the end time of the whitelist`,
},
{
id: 'update_admins',
name: 'Update Admins',
description: `Update the list of administrators for the whitelist`,
},
// {
// id: 'add_members',
// name: 'Add Members',
// description: `Add members to the whitelist`,
// },
// {
// id: 'remove_members',
// name: 'Remove Members',
// description: `Remove members from the whitelist`,
// },
// {
// id: 'update_per_address_limit',
// name: 'Update Per Address Limit',
// description: `Update tokens per address limit`,
// },
{
id: 'freeze',
name: 'Freeze',
description: `Freeze the current state of the contract admin list`,
},
]
export interface DispatchExecuteProps {
type: ExecuteType
[k: string]: unknown
}
/** @see {@link WhiteListMerkleTreeInstance} */
export interface DispatchExecuteArgs {
contract: string
messages?: WhiteListMerkleTreeInstance
type: string | undefined
timestamp: string
members: string[] | WhitelistFlexMember[]
limit: number
admins: string[]
}
export const dispatchExecute = async (args: DispatchExecuteArgs) => {
const { messages } = args
if (!messages) {
throw new Error('cannot dispatch execute, messages is not defined')
}
switch (args.type) {
case 'update_start_time': {
return messages.updateStartTime(args.timestamp)
}
case 'update_end_time': {
return messages.updateEndTime(args.timestamp)
}
case 'update_admins': {
return messages.updateAdmins(args.admins)
}
case 'add_members': {
return messages.addMembers(args.members)
}
case 'remove_members': {
return messages.removeMembers(args.members as string[])
}
// case 'update_per_address_limit': {
// return messages.updatePerAddressLimit(args.limit)
// }
case 'freeze': {
return messages.freeze()
}
default: {
throw new Error('unknown execute type')
}
}
}
export const previewExecutePayload = (args: DispatchExecuteArgs) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const { messages } = useWhiteListMerkleTreeContract()
const { contract } = args
switch (args.type) {
case 'update_start_time': {
return messages(contract)?.updateStartTime(args.timestamp)
}
case 'update_end_time': {
return messages(contract)?.updateEndTime(args.timestamp)
}
case 'update_admins': {
return messages(contract)?.updateAdmins(args.admins)
}
case 'add_members': {
return messages(contract)?.addMembers(args.members)
}
case 'remove_members': {
return messages(contract)?.removeMembers(args.members as string[])
}
// case 'update_per_address_limit': {
// return messages(contract)?.updatePerAddressLimit(args.limit)
// }
case 'freeze': {
return messages(contract)?.freeze()
}
default: {
return {}
}
}
}
export const isEitherType = <T extends ExecuteType>(type: unknown, arr: T[]): type is T => {
return arr.some((val) => type === val)
}

View File

@ -1,66 +0,0 @@
import type { WhiteListMerkleTreeInstance } from '../contract'
export type WhitelistMerkleTreeQueryType = typeof WHITELIST_MERKLE_TREE_QUERY_TYPES[number]
export const WHITELIST_MERKLE_TREE_QUERY_TYPES = [
'has_started',
'has_ended',
'is_active',
'admin_list',
'has_member',
'config',
'merkle_root',
'merkle_tree_uri',
] as const
export interface QueryListItem {
id: WhitelistMerkleTreeQueryType
name: string
description?: string
}
export const WHITELIST_MERKLE_TREE_QUERY_LIST: QueryListItem[] = [
{ id: 'has_started', name: 'Has Started', description: 'Check if the whitelist minting has started' },
{ id: 'has_ended', name: 'Has Ended', description: 'Check if the whitelist minting has ended' },
{ id: 'is_active', name: 'Is Active', description: 'Check if the whitelist minting is active' },
{ id: 'admin_list', name: 'Admin List', description: 'View the whitelist admin list' },
{ id: 'has_member', name: 'Has Member', description: 'Check if a member is in the whitelist' },
{ id: 'config', name: 'Config', description: 'View the whitelist configuration' },
{ id: 'merkle_root', name: 'Merkle Root', description: 'View the whitelist merkle root' },
{ id: 'merkle_tree_uri', name: 'Merkle Tree URI', description: 'View the whitelist merkle tree URI' },
]
export interface DispatchQueryProps {
messages: WhiteListMerkleTreeInstance | undefined
type: WhitelistMerkleTreeQueryType
address: string
startAfter?: string
limit?: number
proofHashes?: string[]
}
export const dispatchQuery = (props: DispatchQueryProps) => {
const { messages, type, address, proofHashes } = props
switch (type) {
case 'has_started':
return messages?.hasStarted()
case 'has_ended':
return messages?.hasEnded()
case 'is_active':
return messages?.isActive()
case 'admin_list':
return messages?.adminList()
case 'has_member':
return messages?.hasMember(address, proofHashes || [])
case 'config':
return messages?.config()
case 'merkle_root':
return messages?.merkleRoot()
case 'merkle_tree_uri':
return messages?.merkleTreeUri()
default: {
throw new Error('unknown query type')
}
}
}

View File

@ -1,89 +0,0 @@
import { useCallback, useEffect, useState } from 'react'
import { useWallet } from 'utils/wallet'
import type {
InstantiateResponse,
WhiteListMerkleTreeContract,
WhiteListMerkleTreeInstance,
WhiteListMerkleTreeMessages,
} from './contract'
import { WhiteListMerkleTree as initContract } from './contract'
export interface UseWhiteListMerkleTreeContractProps {
instantiate: (
codeId: number,
initMsg: Record<string, unknown>,
label: string,
admin?: string,
) => Promise<InstantiateResponse>
use: (customAddress?: string) => WhiteListMerkleTreeInstance | undefined
updateContractAddress: (contractAddress: string) => void
messages: (contractAddress: string) => WhiteListMerkleTreeMessages | undefined
}
export function useWhiteListMerkleTreeContract(): UseWhiteListMerkleTreeContractProps {
const wallet = useWallet()
const [address, setAddress] = useState<string>('')
const [whiteListMerkleTree, setWhiteListMerkleTree] = useState<WhiteListMerkleTreeContract>()
useEffect(() => {
setAddress(localStorage.getItem('contract_address') || '')
}, [])
useEffect(() => {
if (!wallet.isWalletConnected) {
return
}
const load = async () => {
const client = await wallet.getSigningCosmWasmClient()
const contract = initContract(client, wallet.address || '')
setWhiteListMerkleTree(contract)
}
load().catch(console.error)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [wallet.isWalletConnected, wallet.address])
const updateContractAddress = (contractAddress: string) => {
setAddress(contractAddress)
}
const instantiate = useCallback(
(codeId: number, initMsg: Record<string, unknown>, label: string, admin?: string): Promise<InstantiateResponse> => {
return new Promise((resolve, reject) => {
if (!whiteListMerkleTree) {
reject(new Error('Contract is not initialized.'))
return
}
whiteListMerkleTree.instantiate(codeId, initMsg, label, admin).then(resolve).catch(reject)
})
},
[whiteListMerkleTree],
)
const use = useCallback(
(customAddress = ''): WhiteListMerkleTreeInstance | undefined => {
return whiteListMerkleTree?.use(address || customAddress)
},
[whiteListMerkleTree, address],
)
const messages = useCallback(
(customAddress = ''): WhiteListMerkleTreeMessages | undefined => {
return whiteListMerkleTree?.messages(address || customAddress)
},
[whiteListMerkleTree, address],
)
return {
instantiate,
use,
updateContractAddress,
messages,
}
}

21
env.d.ts vendored
View File

@ -22,25 +22,18 @@ declare namespace NodeJS {
readonly NEXT_PUBLIC_OPEN_EDITION_SG721_UPDATABLE_CODE_ID: string readonly NEXT_PUBLIC_OPEN_EDITION_SG721_UPDATABLE_CODE_ID: string
readonly NEXT_PUBLIC_WHITELIST_CODE_ID: string readonly NEXT_PUBLIC_WHITELIST_CODE_ID: string
readonly NEXT_PUBLIC_WHITELIST_FLEX_CODE_ID: string readonly NEXT_PUBLIC_WHITELIST_FLEX_CODE_ID: string
readonly NEXT_PUBLIC_WHITELIST_MERKLE_TREE_CODE_ID: string
readonly NEXT_PUBLIC_VENDING_MINTER_CODE_ID: string readonly NEXT_PUBLIC_VENDING_MINTER_CODE_ID: string
readonly NEXT_PUBLIC_VENDING_MINTER_FLEX_CODE_ID: string readonly NEXT_PUBLIC_VENDING_MINTER_FLEX_CODE_ID: string
readonly NEXT_PUBLIC_VENDING_FACTORY_ADDRESS: string readonly NEXT_PUBLIC_VENDING_FACTORY_ADDRESS: string
readonly NEXT_PUBLIC_FEATURED_VENDING_FACTORY_ADDRESS: string readonly NEXT_PUBLIC_FEATURED_VENDING_FACTORY_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_FACTORY_UPDATABLE_ADDRESS: string readonly NEXT_PUBLIC_VENDING_FACTORY_UPDATABLE_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_FACTORY_FLEX_ADDRESS: string readonly NEXT_PUBLIC_VENDING_FACTORY_FLEX_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_FACTORY_MERKLE_TREE_ADDRESS: string
readonly NEXT_PUBLIC_FEATURED_VENDING_FACTORY_MERKLE_TREE_ADDRESS: string
readonly NEXT_PUBLIC_FEATURED_VENDING_FACTORY_FLEX_ADDRESS: string readonly NEXT_PUBLIC_FEATURED_VENDING_FACTORY_FLEX_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_FACTORY_UPDATABLE_FLEX_ADDRESS: string readonly NEXT_PUBLIC_VENDING_FACTORY_UPDATABLE_FLEX_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_IBC_ATOM_FACTORY_ADDRESS: string readonly NEXT_PUBLIC_VENDING_IBC_ATOM_FACTORY_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_IBC_ATOM_UPDATABLE_FACTORY_ADDRESS: string readonly NEXT_PUBLIC_VENDING_IBC_ATOM_UPDATABLE_FACTORY_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_IBC_USDC_FACTORY_ADDRESS: string readonly NEXT_PUBLIC_VENDING_IBC_USDC_FACTORY_ADDRESS: string
readonly NEXT_PUBLIC_FEATURED_VENDING_IBC_USDC_FACTORY_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_IBC_USDC_UPDATABLE_FACTORY_ADDRESS: string readonly NEXT_PUBLIC_VENDING_IBC_USDC_UPDATABLE_FACTORY_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_IBC_TIA_FACTORY_ADDRESS: string
readonly NEXT_PUBLIC_FEATURED_VENDING_IBC_TIA_FACTORY_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_IBC_TIA_UPDATABLE_FACTORY_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_IBC_NBTC_FACTORY_ADDRESS: string readonly NEXT_PUBLIC_VENDING_IBC_NBTC_FACTORY_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_IBC_NBTC_UPDATABLE_FACTORY_ADDRESS: string readonly NEXT_PUBLIC_VENDING_IBC_NBTC_UPDATABLE_FACTORY_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_IBC_USK_FACTORY_ADDRESS: string readonly NEXT_PUBLIC_VENDING_IBC_USK_FACTORY_ADDRESS: string
@ -54,13 +47,7 @@ declare namespace NodeJS {
readonly NEXT_PUBLIC_VENDING_IBC_ATOM_FACTORY_FLEX_ADDRESS: string readonly NEXT_PUBLIC_VENDING_IBC_ATOM_FACTORY_FLEX_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_IBC_ATOM_UPDATABLE_FACTORY_FLEX_ADDRESS: string readonly NEXT_PUBLIC_VENDING_IBC_ATOM_UPDATABLE_FACTORY_FLEX_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_IBC_USDC_FACTORY_FLEX_ADDRESS: string readonly NEXT_PUBLIC_VENDING_IBC_USDC_FACTORY_FLEX_ADDRESS: string
readonly NEXT_PUBLIC_FEATURED_VENDING_IBC_USDC_FACTORY_FLEX_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_IBC_USDC_UPDATABLE_FACTORY_FLEX_ADDRESS: string readonly NEXT_PUBLIC_VENDING_IBC_USDC_UPDATABLE_FACTORY_FLEX_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_IBC_TIA_FACTORY_FLEX_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_IBC_TIA_FACTORY_MERKLE_TREE_ADDRESS: string
readonly NEXT_PUBLIC_FEATURED_VENDING_IBC_TIA_FACTORY_MERKLE_TREE_ADDRESS: string
readonly NEXT_PUBLIC_FEATURED_VENDING_IBC_TIA_FACTORY_FLEX_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_IBC_TIA_UPDATABLE_FACTORY_FLEX_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_IBC_NBTC_FACTORY_FLEX_ADDRESS: string readonly NEXT_PUBLIC_VENDING_IBC_NBTC_FACTORY_FLEX_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_IBC_NBTC_UPDATABLE_FACTORY_FLEX_ADDRESS: string readonly NEXT_PUBLIC_VENDING_IBC_NBTC_UPDATABLE_FACTORY_FLEX_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_IBC_USK_FACTORY_FLEX_ADDRESS: string readonly NEXT_PUBLIC_VENDING_IBC_USK_FACTORY_FLEX_ADDRESS: string
@ -78,17 +65,11 @@ declare namespace NodeJS {
readonly NEXT_PUBLIC_VENDING_NATIVE_BRNCH_UPDATABLE_FACTORY_ADDRESS: string readonly NEXT_PUBLIC_VENDING_NATIVE_BRNCH_UPDATABLE_FACTORY_ADDRESS: string
readonly NEXT_PUBLIC_VENDING_NATIVE_BRNCH_FLEX_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_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_UPDATABLE_FACTORY_ADDRESS: string
readonly NEXT_PUBLIC_OPEN_EDITION_IBC_ATOM_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_UPDATABLE_IBC_ATOM_FACTORY_ADDRESS: string
readonly NEXT_PUBLIC_OPEN_EDITION_IBC_USDC_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_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_IBC_NBTC_FACTORY_ADDRESS: string
readonly NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_NBTC_FACTORY_ADDRESS: string readonly NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_NBTC_FACTORY_ADDRESS: string
readonly NEXT_PUBLIC_OPEN_EDITION_IBC_FRNZ_FACTORY_ADDRESS: string readonly NEXT_PUBLIC_OPEN_EDITION_IBC_FRNZ_FACTORY_ADDRESS: string
@ -123,8 +104,6 @@ declare namespace NodeJS {
readonly NEXT_PUBLIC_STARGAZE_WEBSITE_URL: string readonly NEXT_PUBLIC_STARGAZE_WEBSITE_URL: string
readonly NEXT_PUBLIC_WEBSITE_URL: string readonly NEXT_PUBLIC_WEBSITE_URL: string
readonly NEXT_PUBLIC_SYNC_COLLECTIONS_API_URL: string readonly NEXT_PUBLIC_SYNC_COLLECTIONS_API_URL: string
readonly NEXT_PUBLIC_WHITELIST_MERKLE_TREE_API_URL: string
readonly NEXT_PUBLIC_NFT_STORAGE_DEFAULT_API_KEY: string
readonly NEXT_PUBLIC_MEILISEARCH_HOST: string readonly NEXT_PUBLIC_MEILISEARCH_HOST: string
readonly NEXT_PUBLIC_MEILISEARCH_API_KEY: string readonly NEXT_PUBLIC_MEILISEARCH_API_KEY: string

18257
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,5 @@
{ {
"private": true, "name": "stargaze-studio",
"name": "@mito/stargaze-studio",
"repository": "https://git.vdb.to/LaconicNetwork/stargaze-studio",
"version": "0.8.7", "version": "0.8.7",
"workspaces": [ "workspaces": [
"packages/*" "packages/*"
@ -15,21 +13,18 @@
}, },
"dependencies": { "dependencies": {
"@aws-sdk/client-s3": "^3", "@aws-sdk/client-s3": "^3",
"@cosmjs/cosmwasm-stargate": "0.32.3", "@cosmjs/cosmwasm-stargate": "0.32.2",
"@cosmjs/encoding": "0.32.3", "@cosmjs/encoding": "0.32.2",
"@cosmjs/math": "0.32.3", "@cosmjs/math": "0.32.2",
"@cosmjs/proto-signing": "0.32.3", "@cosmjs/proto-signing": "0.32.2",
"@cosmjs/stargate": "0.32.3", "@cosmjs/stargate": "0.32.2",
"@cosmos-kit/keplr": "2.8.0", "cosmjs-types": "0.9.0",
"@cosmos-kit/leap": "2.8.0", "@cosmos-kit/keplr": "^2.4.4",
"@cosmos-kit/leap-metamask-cosmos-snap": "0.8.0", "@cosmos-kit/leap": "^2.4.3",
"@cosmos-kit/react": "2.12.0", "@cosmos-kit/leap-metamask-cosmos-snap": "^0.3.3",
"@cosmos-kit/react": "^2.9.3",
"@fontsource/jetbrains-mono": "^4", "@fontsource/jetbrains-mono": "^4",
"@fontsource/roboto": "^4", "@fontsource/roboto": "^4",
"@headlessui/react": "1.6.0",
"@headlessui/tailwindcss": "0.2.0",
"@heroicons/react": "2.0.18",
"@interchain-ui/react": "1.23.11",
"@leapwallet/cosmos-snap-provider": "0.1.24", "@leapwallet/cosmos-snap-provider": "0.1.24",
"@pinata/sdk": "^1.1.26", "@pinata/sdk": "^1.1.26",
"@popperjs/core": "^2", "@popperjs/core": "^2",
@ -37,23 +32,20 @@
"@tailwindcss/forms": "^0", "@tailwindcss/forms": "^0",
"@tailwindcss/line-clamp": "^0", "@tailwindcss/line-clamp": "^0",
"@typeform/embed-react": "2.21.0", "@typeform/embed-react": "2.21.0",
"@types/crypto-js": "4.2.1",
"@types/pako": "^2.0.3",
"axios": "^0", "axios": "^0",
"chain-registry": "^1.20.0", "chain-registry": "^1.20.0",
"clsx": "^1", "clsx": "^1",
"compare-versions": "^4", "compare-versions": "^4",
"cosmjs-types": "0.9.0",
"crypto-js": "4.1.1",
"daisyui": "^2.19.0", "daisyui": "^2.19.0",
"html-to-image": "1.11.11", "html-to-image": "1.11.11",
"@headlessui/react": "1.6.0",
"@headlessui/tailwindcss": "0.2.0",
"@heroicons/react": "2.0.18",
"jscrypto": "^1.0.3", "jscrypto": "^1.0.3",
"match-sorter": "^6", "match-sorter": "^6",
"merkletreejs": "0.3.11",
"next": "^12", "next": "^12",
"next-seo": "^4", "next-seo": "^4",
"nft.storage": "^6.3.0", "nft.storage": "^6.3.0",
"pako": "^2.0.2",
"qrcode.react": "3.1.0", "qrcode.react": "3.1.0",
"react": "^18", "react": "^18",
"react-datetime-picker": "^3", "react-datetime-picker": "^3",
@ -80,8 +72,8 @@
"lint-staged": "^12", "lint-staged": "^12",
"object-sizeof": "^1.6.0", "object-sizeof": "^1.6.0",
"postcss": "^8", "postcss": "^8",
"tailwind-merge": "1.14.0",
"tailwindcss": "^3", "tailwindcss": "^3",
"tailwind-merge": "1.14.0",
"typescript": "^4" "typescript": "^4"
}, },
"eslintConfig": { "eslintConfig": {

View File

@ -1,132 +0,0 @@
/* eslint-disable eslint-comments/disable-enable-pair */
import { Alert } from 'components/Alert'
import { Button } from 'components/Button'
import { Conditional } from 'components/Conditional'
import { ContractPageHeader } from 'components/ContractPageHeader'
import { AddressInput, TextInput } from 'components/forms/FormInput'
import { useInputState } from 'components/forms/FormInput.hooks'
import type { NextPage } from 'next'
import { useRouter } from 'next/router'
import { NextSeo } from 'next-seo'
import { useEffect, useState } from 'react'
import { toast } from 'react-hot-toast'
import { NETWORK } from 'utils/constants'
import { useDebounce } from 'utils/debounce'
import { withMetadata } from 'utils/layout'
import { links } from 'utils/links'
import { resolveAddress } from 'utils/resolveAddress'
import { useWallet } from 'utils/wallet'
const CancelAuctionPage: NextPage = () => {
const wallet = useWallet()
const [isLoading, setIsLoading] = useState(false)
const [txHash, setTxHash] = useState<string | undefined>(undefined)
const collectionAddressState = useInputState({
id: 'collection-address',
name: 'collectionAddress',
title: 'Collection Contract Address',
defaultValue: '',
placeholder: 'stars1...',
})
const collectionAddress = useDebounce(collectionAddressState.value, 300)
const tokenIdState = useInputState({
id: 'token-id',
name: 'tokenId',
title: 'Token ID',
defaultValue: '',
placeholder: '1',
})
const router = useRouter()
useEffect(() => {
if (collectionAddress.length > 0) {
void router.replace({ query: { contractAddress: collectionAddress } })
}
if (collectionAddress.length === 0) {
void router.replace({ query: {} })
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [collectionAddress])
useEffect(() => {
const initial = new URL(document.URL).searchParams.get('contractAddress')
if (initial && initial.length > 0) collectionAddressState.onChange(initial)
}, [])
const resolveCollectionAddress = async () => {
await resolveAddress(collectionAddressState.value.trim(), wallet).then((resolvedAddress) => {
if (resolvedAddress) {
collectionAddressState.onChange(resolvedAddress)
}
})
}
useEffect(() => {
void resolveCollectionAddress()
}, [collectionAddressState.value])
const handleCancelAuction = async () => {
if (!wallet.isWalletConnected) return toast.error('Please connect your wallet.')
if (!collectionAddressState.value) return toast.error('Please enter a collection address.')
const client = await wallet.getSigningCosmWasmClient()
setTxHash(undefined)
setIsLoading(true)
try {
const result = await client.execute(
wallet.address as string,
NETWORK === 'mainnet'
? 'stars1vvdkcn393ddyd47v9g3qv6mvne59d0ykzy9wre3ga0c58dtdg4ksm776jg'
: 'stars1dnadsd7tx0dmnpp26ms7d66zsp7tduygwjgfjzueh0lg9t5lq5vq9kn47c',
{
cancel_auction: {
collection: collectionAddressState.value,
token_id: tokenIdState.value,
},
},
'auto',
)
toast.success('Auction successfully cancelled.')
setTxHash(result.transactionHash)
} catch (error: any) {
toast.error(error.message, { style: { maxWidth: 'none' } })
setTxHash(undefined)
} finally {
setIsLoading(false)
}
}
return (
<section className="py-6 px-12 space-y-4">
<NextSeo title="Cancel Auction" />
<ContractPageHeader link={links.Documentation} title="Cancel Auction" />
<div className="space-y-2">
<AddressInput {...collectionAddressState} />
<TextInput className="w-1/4" {...tokenIdState} />
</div>
<div className="flex flex-row content-center mt-4">
<Button
isDisabled={collectionAddressState.value === ''}
isLoading={isLoading}
onClick={() => {
void handleCancelAuction()
}}
>
Cancel Auction
</Button>
</div>
<Conditional test={txHash !== undefined}>
<Alert type="info">
<b>Transaction Hash:</b> {txHash}
</Alert>
</Conditional>
</section>
)
}
export default withMetadata(CancelAuctionPage, { center: false })

View File

@ -7,7 +7,6 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */
import { toUtf8 } from '@cosmjs/encoding' import { toUtf8 } from '@cosmjs/encoding'
import type { Coin } from '@cosmjs/proto-signing'
import { coin } from '@cosmjs/proto-signing' import { coin } from '@cosmjs/proto-signing'
import { Sidetab } from '@typeform/embed-react' import { Sidetab } from '@typeform/embed-react'
import axios from 'axios' import axios from 'axios'
@ -35,13 +34,7 @@ import { FormControl } from 'components/FormControl'
import { LoadingModal } from 'components/LoadingModal' import { LoadingModal } from 'components/LoadingModal'
import type { OpenEditionMinterCreatorDataProps } from 'components/openEdition/OpenEditionMinterCreator' import type { OpenEditionMinterCreatorDataProps } from 'components/openEdition/OpenEditionMinterCreator'
import { OpenEditionMinterCreator } from 'components/openEdition/OpenEditionMinterCreator' import { OpenEditionMinterCreator } from 'components/openEdition/OpenEditionMinterCreator'
import { import { flexibleVendingMinterList, openEditionMinterList, vendingMinterList } from 'config/minter'
flexibleOpenEditionMinterList,
flexibleVendingMinterList,
merkleTreeVendingMinterList,
openEditionMinterList,
vendingMinterList,
} from 'config/minter'
import type { TokenInfo } from 'config/token' import type { TokenInfo } from 'config/token'
import { useContracts } from 'contexts/contracts' import { useContracts } from 'contexts/contracts'
import { addLogItem } from 'contexts/log' import { addLogItem } from 'contexts/log'
@ -63,6 +56,7 @@ import {
BLOCK_EXPLORER_URL, BLOCK_EXPLORER_URL,
NETWORK, NETWORK,
OPEN_EDITION_FACTORY_ADDRESS, OPEN_EDITION_FACTORY_ADDRESS,
OPEN_EDITION_UPDATABLE_FACTORY_ADDRESS,
SG721_CODE_ID, SG721_CODE_ID,
SG721_UPDATABLE_CODE_ID, SG721_UPDATABLE_CODE_ID,
STARGAZE_URL, STARGAZE_URL,
@ -73,8 +67,6 @@ import {
VENDING_FACTORY_UPDATABLE_ADDRESS, VENDING_FACTORY_UPDATABLE_ADDRESS,
WHITELIST_CODE_ID, WHITELIST_CODE_ID,
WHITELIST_FLEX_CODE_ID, WHITELIST_FLEX_CODE_ID,
WHITELIST_MERKLE_TREE_API_URL,
WHITELIST_MERKLE_TREE_CODE_ID,
} from 'utils/constants' } from 'utils/constants'
import { checkTokenUri } from 'utils/isValidTokenUri' import { checkTokenUri } from 'utils/isValidTokenUri'
import { withMetadata } from 'utils/layout' import { withMetadata } from 'utils/layout'
@ -96,7 +88,6 @@ const CollectionCreationPage: NextPage = () => {
baseMinter: baseMinterContract, baseMinter: baseMinterContract,
vendingMinter: vendingMinterContract, vendingMinter: vendingMinterContract,
whitelist: whitelistContract, whitelist: whitelistContract,
whitelistMerkleTree: whitelistMerkleTreeContract,
vendingFactory: vendingFactoryContract, vendingFactory: vendingFactoryContract,
baseFactory: baseFactoryContract, baseFactory: baseFactoryContract,
} = useContracts() } = useContracts()
@ -127,23 +118,24 @@ const CollectionCreationPage: NextPage = () => {
const [royaltyDetails, setRoyaltyDetails] = useState<RoyaltyDetailsDataProps | null>(null) const [royaltyDetails, setRoyaltyDetails] = useState<RoyaltyDetailsDataProps | null>(null)
const [minterType, setMinterType] = useState<MinterType>('vending') const [minterType, setMinterType] = useState<MinterType>('vending')
const [vendingMinterCreationFee, setVendingMinterCreationFee] = useState<Coin | null>(null) const [vendingMinterCreationFee, setVendingMinterCreationFee] = useState<string | null>(null)
const [baseMinterCreationFee, setBaseMinterCreationFee] = useState<Coin | null>(null) const [baseMinterCreationFee, setBaseMinterCreationFee] = useState<string | null>(null)
const [vendingMinterUpdatableCreationFee, setVendingMinterUpdatableCreationFee] = useState<Coin | null>(null) const [vendingMinterUpdatableCreationFee, setVendingMinterUpdatableCreationFee] = useState<string | null>(null)
const [openEditionMinterCreationFee, setOpenEditionMinterCreationFee] = useState<Coin | undefined>(undefined) const [openEditionMinterCreationFee, setOpenEditionMinterCreationFee] = useState<string | null>(null)
const [vendingMinterFlexCreationFee, setVendingMinterFlexCreationFee] = useState<Coin | null>(null) const [openEditionMinterUpdatableCreationFee, setOpenEditionMinterUpdatableCreationFee] = useState<string | null>(
const [baseMinterUpdatableCreationFee, setBaseMinterUpdatableCreationFee] = useState<Coin | null>(null) null,
)
const [vendingMinterFlexCreationFee, setVendingMinterFlexCreationFee] = useState<string | null>(null)
const [baseMinterUpdatableCreationFee, setBaseMinterUpdatableCreationFee] = useState<string | null>(null)
const [minimumMintPrice, setMinimumMintPrice] = useState<string | null>('0') const [minimumMintPrice, setMinimumMintPrice] = useState<string | null>('0')
const [minimumUpdatableMintPrice, setMinimumUpdatableMintPrice] = useState<string | null>('0') const [minimumUpdatableMintPrice, setMinimumUpdatableMintPrice] = useState<string | null>('0')
const [minimumOpenEditionMintPrice, setMinimumOpenEditionMintPrice] = 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 [minimumFlexMintPrice, setMinimumFlexMintPrice] = useState<string | null>('0')
const [mintTokenFromOpenEditionFactory, setMintTokenFromOpenEditionFactory] = useState<TokenInfo | undefined>(stars) const [mintTokenFromOpenEditionFactory, setMintTokenFromOpenEditionFactory] = useState<TokenInfo | undefined>(stars)
const [mintTokenFromVendingFactory, setMintTokenFromVendingFactory] = useState<TokenInfo | undefined>(stars) const [mintTokenFromVendingFactory, setMintTokenFromVendingFactory] = useState<TokenInfo | undefined>(stars)
const [vendingFactoryAddress, setVendingFactoryAddress] = useState<string | null>(VENDING_FACTORY_ADDRESS) const [vendingFactoryAddress, setVendingFactoryAddress] = useState<string | null>(VENDING_FACTORY_ADDRESS)
const [openEditionFactoryAddress, setOpenEditionFactoryAddress] = useState<string | undefined>(
OPEN_EDITION_FACTORY_ADDRESS,
)
const vendingFactoryMessages = useMemo( const vendingFactoryMessages = useMemo(
() => vendingFactoryContract?.use(vendingFactoryAddress as string), () => vendingFactoryContract?.use(vendingFactoryAddress as string),
@ -170,7 +162,6 @@ const CollectionCreationPage: NextPage = () => {
const [coverImageUrl, setCoverImageUrl] = useState<string | null>(null) const [coverImageUrl, setCoverImageUrl] = useState<string | null>(null)
const [transactionHash, setTransactionHash] = useState<string | null>(null) const [transactionHash, setTransactionHash] = useState<string | null>(null)
const [isMatchingVendingFactoryPresent, setIsMatchingVendingFactoryPresent] = useState<boolean>(true) const [isMatchingVendingFactoryPresent, setIsMatchingVendingFactoryPresent] = useState<boolean>(true)
const [isMatchingOpenEditionFactoryPresent, setIsMatchingOpenEditionFactoryPresent] = useState<boolean>(true)
const performVendingMinterChecks = () => { const performVendingMinterChecks = () => {
try { try {
@ -522,92 +513,41 @@ const CollectionCreationPage: NextPage = () => {
if (!wallet.isWalletConnected) throw new Error('Wallet not connected') if (!wallet.isWalletConnected) throw new Error('Wallet not connected')
if (!whitelistContract) throw new Error('Contract not found') if (!whitelistContract) throw new Error('Contract not found')
if (whitelistDetails?.whitelistType === 'standard' || whitelistDetails?.whitelistType === 'flex') { const standardMsg = {
const standardMsg = { members: whitelistDetails?.members,
members: whitelistDetails.members, start_time: whitelistDetails?.startTime,
start_time: whitelistDetails.startTime, end_time: whitelistDetails?.endTime,
end_time: whitelistDetails.endTime, mint_price: coin(
mint_price: coin( String(Number(whitelistDetails?.unitPrice)),
String(Number(whitelistDetails.unitPrice)), mintTokenFromVendingFactory ? mintTokenFromVendingFactory.denom : 'ustars',
mintTokenFromVendingFactory ? mintTokenFromVendingFactory.denom : 'ustars', ),
), per_address_limit: whitelistDetails?.perAddressLimit,
per_address_limit: whitelistDetails.perAddressLimit, member_limit: whitelistDetails?.memberLimit,
member_limit: whitelistDetails.memberLimit, admins: whitelistDetails?.admins || [wallet.address],
admins: whitelistDetails.admins || [wallet.address], admins_mutable: whitelistDetails?.adminsMutable,
admins_mutable: whitelistDetails.adminsMutable,
}
const flexMsg = {
members: whitelistDetails.members,
start_time: whitelistDetails.startTime,
end_time: whitelistDetails.endTime,
mint_price: coin(
String(Number(whitelistDetails.unitPrice)),
mintTokenFromVendingFactory ? mintTokenFromVendingFactory.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)),
mintTokenFromVendingFactory ? mintTokenFromVendingFactory.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 flexMsg = {
members: whitelistDetails?.members,
start_time: whitelistDetails?.startTime,
end_time: whitelistDetails?.endTime,
mint_price: coin(
String(Number(whitelistDetails?.unitPrice)),
mintTokenFromVendingFactory ? mintTokenFromVendingFactory.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
} }
const instantiateVendingMinter = async (baseUri: string, coverImageUri: string, whitelist?: string) => { const instantiateVendingMinter = async (baseUri: string, coverImageUri: string, whitelist?: string) => {
@ -642,7 +582,6 @@ const CollectionCreationPage: NextPage = () => {
: mintingDetails?.selectedMintToken?.displayName === 'STRDST' || : mintingDetails?.selectedMintToken?.displayName === 'STRDST' ||
mintingDetails?.selectedMintToken?.displayName === 'USK' || mintingDetails?.selectedMintToken?.displayName === 'USK' ||
mintingDetails?.selectedMintToken?.displayName === 'USDC' || mintingDetails?.selectedMintToken?.displayName === 'USDC' ||
mintingDetails?.selectedMintToken?.displayName === 'TIA' ||
mintingDetails?.selectedMintToken?.displayName === 'nBTC' || mintingDetails?.selectedMintToken?.displayName === 'nBTC' ||
mintingDetails?.selectedMintToken?.displayName === 'KUJI' || mintingDetails?.selectedMintToken?.displayName === 'KUJI' ||
mintingDetails?.selectedMintToken?.displayName === 'HUAHUA' || mintingDetails?.selectedMintToken?.displayName === 'HUAHUA' ||
@ -676,11 +615,14 @@ const CollectionCreationPage: NextPage = () => {
txSigner: wallet.address || '', txSigner: wallet.address || '',
msg, msg,
funds: [ funds: [
whitelistDetails?.whitelistState !== 'none' && whitelistDetails?.whitelistType === 'flex' coin(
? (vendingMinterFlexCreationFee as Coin) whitelistDetails?.whitelistState !== 'none' && whitelistDetails?.whitelistType === 'flex'
: collectionDetails?.updatable ? (vendingMinterFlexCreationFee as string)
? (vendingMinterUpdatableCreationFee as Coin) : collectionDetails?.updatable
: (vendingMinterCreationFee as Coin), ? (vendingMinterUpdatableCreationFee as string)
: (vendingMinterCreationFee as string),
'ustars',
),
], ],
updatable: collectionDetails?.updatable, updatable: collectionDetails?.updatable,
flex: whitelistDetails?.whitelistState !== 'none' && whitelistDetails?.whitelistType === 'flex', flex: whitelistDetails?.whitelistState !== 'none' && whitelistDetails?.whitelistType === 'flex',
@ -734,7 +676,10 @@ const CollectionCreationPage: NextPage = () => {
txSigner: wallet.address || '', txSigner: wallet.address || '',
msg, msg,
funds: [ funds: [
collectionDetails?.updatable ? (baseMinterUpdatableCreationFee as Coin) : (baseMinterCreationFee as Coin), coin(
collectionDetails?.updatable ? (baseMinterUpdatableCreationFee as string) : (baseMinterCreationFee as string),
'ustars',
),
], ],
updatable: collectionDetails?.updatable, updatable: collectionDetails?.updatable,
} }
@ -1101,8 +1046,6 @@ const CollectionCreationPage: NextPage = () => {
//check if the address belongs to a whitelist contract (see performChecks()) //check if the address belongs to a whitelist contract (see performChecks())
const config = await contract?.config() const config = await contract?.config()
if (JSON.stringify(config).includes('whale_cap')) whitelistDetails.whitelistType = 'flex' 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'
else whitelistDetails.whitelistType = 'standard' else whitelistDetails.whitelistType = 'standard'
if (Number(config?.start_time) !== Number(mintingDetails?.startTime)) { if (Number(config?.start_time) !== Number(mintingDetails?.startTime)) {
const whitelistStartDate = new Date(Number(config?.start_time) / 1000000) const whitelistStartDate = new Date(Number(config?.start_time) / 1000000)
@ -1140,10 +1083,7 @@ const CollectionCreationPage: NextPage = () => {
(!whitelistDetails.perAddressLimit || whitelistDetails.perAddressLimit === 0) (!whitelistDetails.perAddressLimit || whitelistDetails.perAddressLimit === 0)
) )
throw new Error('Per address limit is required') throw new Error('Per address limit is required')
if ( if (!whitelistDetails.memberLimit || whitelistDetails.memberLimit === 0)
whitelistDetails.whitelistType !== 'merkletree' &&
(!whitelistDetails.memberLimit || whitelistDetails.memberLimit === 0)
)
throw new Error('Member limit is required') throw new Error('Member limit is required')
if (Number(whitelistDetails.startTime) >= Number(whitelistDetails.endTime)) if (Number(whitelistDetails.startTime) >= Number(whitelistDetails.endTime))
throw new Error('Whitelist start time cannot be equal to or later than the whitelist end time') throw new Error('Whitelist start time cannot be equal to or later than the whitelist end time')
@ -1211,7 +1151,7 @@ const CollectionCreationPage: NextPage = () => {
toast.error(`${error.message}`, { style: { maxWidth: 'none' } }) toast.error(`${error.message}`, { style: { maxWidth: 'none' } })
addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() }) addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() })
}) })
setBaseMinterCreationFee(baseFactoryParameters?.params?.creation_fee) setBaseMinterCreationFee(baseFactoryParameters?.params?.creation_fee?.amount)
} }
if (BASE_FACTORY_UPDATABLE_ADDRESS) { if (BASE_FACTORY_UPDATABLE_ADDRESS) {
const baseFactoryUpdatableParameters = await client const baseFactoryUpdatableParameters = await client
@ -1222,7 +1162,7 @@ const CollectionCreationPage: NextPage = () => {
toast.error(`${error.message}`, { style: { maxWidth: 'none' } }) toast.error(`${error.message}`, { style: { maxWidth: 'none' } })
addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() }) addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() })
}) })
setBaseMinterUpdatableCreationFee(baseFactoryUpdatableParameters?.params?.creation_fee) setBaseMinterUpdatableCreationFee(baseFactoryUpdatableParameters?.params?.creation_fee?.amount)
} }
if (VENDING_FACTORY_ADDRESS) { if (VENDING_FACTORY_ADDRESS) {
const vendingFactoryParameters = await client const vendingFactoryParameters = await client
@ -1231,7 +1171,7 @@ const CollectionCreationPage: NextPage = () => {
toast.error(`${error.message}`, { style: { maxWidth: 'none' } }) toast.error(`${error.message}`, { style: { maxWidth: 'none' } })
addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() }) addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() })
}) })
setVendingMinterCreationFee(vendingFactoryParameters?.params?.creation_fee) setVendingMinterCreationFee(vendingFactoryParameters?.params?.creation_fee?.amount)
setMinimumMintPrice(vendingFactoryParameters?.params?.min_mint_price?.amount) setMinimumMintPrice(vendingFactoryParameters?.params?.min_mint_price?.amount)
} }
if (VENDING_FACTORY_UPDATABLE_ADDRESS) { if (VENDING_FACTORY_UPDATABLE_ADDRESS) {
@ -1243,7 +1183,7 @@ const CollectionCreationPage: NextPage = () => {
toast.error(`${error.message}`, { style: { maxWidth: 'none' } }) toast.error(`${error.message}`, { style: { maxWidth: 'none' } })
addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() }) addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() })
}) })
setVendingMinterUpdatableCreationFee(vendingFactoryUpdatableParameters?.params?.creation_fee) setVendingMinterUpdatableCreationFee(vendingFactoryUpdatableParameters?.params?.creation_fee?.amount)
setMinimumUpdatableMintPrice(vendingFactoryUpdatableParameters?.params?.min_mint_price?.amount) setMinimumUpdatableMintPrice(vendingFactoryUpdatableParameters?.params?.min_mint_price?.amount)
} }
if (VENDING_FACTORY_FLEX_ADDRESS) { if (VENDING_FACTORY_FLEX_ADDRESS) {
@ -1255,7 +1195,7 @@ const CollectionCreationPage: NextPage = () => {
toast.error(`${error.message}`, { style: { maxWidth: 'none' } }) toast.error(`${error.message}`, { style: { maxWidth: 'none' } })
addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() }) addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() })
}) })
setVendingMinterFlexCreationFee(vendingFactoryFlexParameters?.params?.creation_fee) setVendingMinterFlexCreationFee(vendingFactoryFlexParameters?.params?.creation_fee?.amount)
setMinimumFlexMintPrice(vendingFactoryFlexParameters?.params?.min_mint_price?.amount) setMinimumFlexMintPrice(vendingFactoryFlexParameters?.params?.min_mint_price?.amount)
} }
if (OPEN_EDITION_FACTORY_ADDRESS) { if (OPEN_EDITION_FACTORY_ADDRESS) {
@ -1265,71 +1205,84 @@ const CollectionCreationPage: NextPage = () => {
toast.error(`${error.message}`, { style: { maxWidth: 'none' } }) toast.error(`${error.message}`, { style: { maxWidth: 'none' } })
addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() }) addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() })
}) })
setOpenEditionMinterCreationFee(openEditionFactoryParameters?.params?.creation_fee) setOpenEditionMinterCreationFee(openEditionFactoryParameters?.params?.creation_fee?.amount)
setMinimumOpenEditionMintPrice(openEditionFactoryParameters?.params?.min_mint_price?.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) setInitialParametersFetched(true)
} }
const fetchOpenEditionFactoryParameters = useCallback(async () => { const fetchOpenEditionFactoryParameters = useCallback(async () => {
const client = await wallet.getCosmWasmClient() const client = await wallet.getCosmWasmClient()
const factoryForSelectedDenom = openEditionMinterList const factoryForSelectedDenom = openEditionMinterList.find(
.concat(flexibleOpenEditionMinterList) (minter) =>
.find( minter.supportedToken === openEditionMinterDetails?.mintingDetails?.selectedMintToken &&
(minter) => minter.updatable === false,
minter.supportedToken === openEditionMinterDetails?.mintingDetails?.selectedMintToken && )
minter.updatable === openEditionMinterDetails.collectionDetails?.updatable && const updatableFactoryForSelectedDenom = openEditionMinterList.find(
minter.flexible === (minter) =>
(openEditionMinterDetails.whitelistDetails?.whitelistState !== 'none' && minter.supportedToken === openEditionMinterDetails?.mintingDetails?.selectedMintToken &&
openEditionMinterDetails.whitelistDetails?.whitelistType === 'flex'), minter.updatable === true,
) )
console.log('OE Factory: ', factoryForSelectedDenom?.factoryAddress)
if (factoryForSelectedDenom?.factoryAddress) { if (factoryForSelectedDenom?.factoryAddress) {
setIsMatchingOpenEditionFactoryPresent(true)
setOpenEditionFactoryAddress(factoryForSelectedDenom.factoryAddress)
const openEditionFactoryParameters = await client const openEditionFactoryParameters = await client
.queryContractSmart(factoryForSelectedDenom.factoryAddress, { params: {} }) .queryContractSmart(factoryForSelectedDenom.factoryAddress, { params: {} })
.catch((error) => { .catch((error) => {
toast.error(`${error.message}`, { style: { maxWidth: 'none' } }) toast.error(`${error.message}`, { style: { maxWidth: 'none' } })
addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() }) addLogItem({ id: uid(), message: error.message, type: 'Error', timestamp: new Date() })
}) })
setOpenEditionMinterCreationFee(openEditionFactoryParameters?.params?.creation_fee) setOpenEditionMinterCreationFee(openEditionFactoryParameters?.params?.creation_fee?.amount)
setMinimumOpenEditionMintPrice(openEditionFactoryParameters?.params?.min_mint_price?.amount) if (!openEditionMinterDetails?.collectionDetails?.updatable) {
setMintTokenFromOpenEditionFactory( setMinimumOpenEditionMintPrice(openEditionFactoryParameters?.params?.min_mint_price?.amount)
tokensList.find((token) => token.denom === openEditionFactoryParameters?.params?.min_mint_price?.denom), setMintTokenFromOpenEditionFactory(
) tokensList.find((token) => token.denom === openEditionFactoryParameters?.params?.min_mint_price?.denom),
} else if ( )
openEditionMinterDetails?.mintingDetails?.selectedMintToken && }
openEditionMinterDetails.whitelistDetails?.whitelistState }
) { if (updatableFactoryForSelectedDenom?.factoryAddress) {
setIsMatchingOpenEditionFactoryPresent(false) 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,
),
)
}
} }
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [ }, [
openEditionMinterDetails?.mintingDetails?.selectedMintToken, openEditionMinterDetails?.mintingDetails?.selectedMintToken,
openEditionMinterDetails?.collectionDetails?.updatable, openEditionMinterDetails?.collectionDetails?.updatable,
openEditionMinterDetails?.whitelistDetails?.whitelistType,
openEditionMinterDetails?.whitelistDetails?.whitelistState,
wallet.isWalletConnected, wallet.isWalletConnected,
openEditionMinterDetails?.isRefreshed,
]) ])
const fetchVendingFactoryParameters = useCallback(async () => { const fetchVendingFactoryParameters = useCallback(async () => {
const client = await wallet.getCosmWasmClient() const client = await wallet.getCosmWasmClient()
const vendingFactoryForSelectedDenom = vendingMinterList const vendingFactoryForSelectedDenom = vendingMinterList
.concat(flexibleVendingMinterList) .concat(flexibleVendingMinterList)
.concat(merkleTreeVendingMinterList)
.find( .find(
(minter) => (minter) =>
minter.supportedToken === mintingDetails?.selectedMintToken && minter.supportedToken === mintingDetails?.selectedMintToken &&
minter.updatable === collectionDetails?.updatable && minter.updatable === collectionDetails?.updatable &&
minter.flexible === (whitelistDetails?.whitelistType === 'flex') && minter.flexible === (whitelistDetails?.whitelistType === 'flex') &&
minter.merkleTree === (whitelistDetails?.whitelistType === 'merkletree') &&
minter.featured === isFeaturedCollection, minter.featured === isFeaturedCollection,
)?.factoryAddress )?.factoryAddress
console.log('Vending Factory: ', vendingFactoryForSelectedDenom)
if (vendingFactoryForSelectedDenom) { if (vendingFactoryForSelectedDenom) {
setIsMatchingVendingFactoryPresent(true) setIsMatchingVendingFactoryPresent(true)
@ -1342,13 +1295,13 @@ const CollectionCreationPage: NextPage = () => {
}) })
if (whitelistDetails?.whitelistState !== 'none' && whitelistDetails?.whitelistType === 'flex') { if (whitelistDetails?.whitelistState !== 'none' && whitelistDetails?.whitelistType === 'flex') {
setVendingMinterFlexCreationFee(vendingFactoryParameters?.params?.creation_fee) setVendingMinterFlexCreationFee(vendingFactoryParameters?.params?.creation_fee?.amount)
setMinimumFlexMintPrice(vendingFactoryParameters?.params?.min_mint_price?.amount) setMinimumFlexMintPrice(vendingFactoryParameters?.params?.min_mint_price?.amount)
} else if (collectionDetails?.updatable) { } else if (collectionDetails?.updatable) {
setVendingMinterUpdatableCreationFee(vendingFactoryParameters?.params?.creation_fee) setVendingMinterUpdatableCreationFee(vendingFactoryParameters?.params?.creation_fee?.amount)
setMinimumUpdatableMintPrice(vendingFactoryParameters?.params?.min_mint_price?.amount) setMinimumUpdatableMintPrice(vendingFactoryParameters?.params?.min_mint_price?.amount)
} else { } else {
setVendingMinterCreationFee(vendingFactoryParameters?.params?.creation_fee) setVendingMinterCreationFee(vendingFactoryParameters?.params?.creation_fee?.amount)
setMinimumMintPrice(vendingFactoryParameters?.params?.min_mint_price?.amount) setMinimumMintPrice(vendingFactoryParameters?.params?.min_mint_price?.amount)
} }
setMintTokenFromVendingFactory( setMintTokenFromVendingFactory(
@ -1367,82 +1320,39 @@ const CollectionCreationPage: NextPage = () => {
]) ])
const checkwalletBalance = async () => { const checkwalletBalance = async () => {
const queryClient = await wallet.getCosmWasmClient() await (await wallet.getCosmWasmClient()).getBalance(wallet.address || '', 'ustars').then((balance) => {
if (minterType === 'vending' && whitelistDetails?.whitelistState === 'new' && whitelistDetails.memberLimit) {
const creationFee: Coin | null = const amountNeeded =
minterType === 'vending' Math.ceil(Number(whitelistDetails.memberLimit) / 1000) * 100000000 +
? whitelistDetails?.whitelistType === 'flex' (whitelistDetails.whitelistType === 'flex'
? vendingMinterFlexCreationFee ? Number(vendingMinterFlexCreationFee)
: collectionDetails?.updatable : collectionDetails?.updatable
? vendingMinterUpdatableCreationFee ? Number(vendingMinterUpdatableCreationFee)
: vendingMinterCreationFee : Number(vendingMinterCreationFee))
: collectionDetails?.updatable if (amountNeeded >= Number(balance.amount))
? baseMinterUpdatableCreationFee throw new Error(
: baseMinterCreationFee `Insufficient wallet balance to instantiate the required contracts. Needed amount: ${(
amountNeeded / 1000000
const creationFeeDenom = tokensList.find((token) => token.denom === creationFee?.denom) ).toString()} STARS`,
)
await queryClient.getBalance(wallet.address || '', 'ustars').then(async (starsBalance) => { } else {
await queryClient const amountNeeded =
.getBalance(wallet.address || '', creationFee?.denom as string) minterType === 'vending'
.then((creationFeeDenomBalance) => { ? whitelistDetails?.whitelistState === 'existing' && whitelistDetails.whitelistType === 'flex'
if (minterType === 'vending' && whitelistDetails?.whitelistState === 'new') { ? Number(vendingMinterFlexCreationFee)
if (whitelistDetails.whitelistType !== 'merkletree' && whitelistDetails.memberLimit) { : collectionDetails?.updatable
const whitelistCreationFee = Math.ceil(Number(whitelistDetails.memberLimit) / 1000) * 100000000 ? Number(vendingMinterUpdatableCreationFee)
if (creationFee?.denom === 'ustars') { : Number(vendingMinterCreationFee)
const amountNeeded = whitelistCreationFee + Number(creationFee.amount) : collectionDetails?.updatable
if (amountNeeded >= Number(starsBalance.amount)) ? Number(baseMinterUpdatableCreationFee)
throw new Error( : Number(baseMinterCreationFee)
`Insufficient wallet balance to instantiate the required contracts. Needed amount: ${( if (amountNeeded >= Number(balance.amount))
amountNeeded / 1000000 throw new Error(
).toString()} STARS`, `Insufficient wallet balance to instantiate the required contracts. Needed amount: ${(
) amountNeeded / 1000000
} else { ).toString()} STARS`,
if (whitelistCreationFee >= Number(starsBalance.amount)) )
throw new Error( }
`Insufficient wallet balance to instantiate the whitelist. Needed amount: ${(
whitelistCreationFee / 1000000
).toString()} STARS`,
)
if (Number(creationFee?.amount) > Number(creationFeeDenomBalance.amount))
throw new Error(
`Insufficient wallet balance to instantiate the required contracts. Needed amount: ${(
Number(creationFee?.amount) / 1000000
).toString()} ${creationFeeDenom ? creationFeeDenom.displayName : creationFee?.denom}`,
)
}
} else if (whitelistDetails.whitelistType === 'merkletree') {
const merkleWhitelistCreationFee = 1000000000
if (creationFee?.denom === 'ustars') {
const amountNeeded = merkleWhitelistCreationFee + Number(creationFee.amount)
if (amountNeeded >= Number(starsBalance.amount))
throw new Error(
`Insufficient wallet balance to instantiate the required contracts. Needed amount: ${(
amountNeeded / 1000000
).toString()} STARS`,
)
} else {
if (merkleWhitelistCreationFee >= Number(starsBalance.amount))
throw new Error(
`Insufficient wallet balance to instantiate the whitelist. Needed amount: ${(
merkleWhitelistCreationFee / 1000000
).toString()} STARS`,
)
if (Number(creationFee?.amount) > Number(creationFeeDenomBalance.amount))
throw new Error(
`Insufficient wallet balance to instantiate the required contracts. Needed amount: ${(
Number(creationFee?.amount) / 1000000
).toString()} ${creationFeeDenom ? creationFeeDenom.displayName : creationFee?.denom}`,
)
}
}
} else if (Number(creationFee?.amount) > Number(creationFeeDenomBalance.amount))
throw new Error(
`Insufficient wallet balance to instantiate the required contracts. Needed amount: ${(
Number(creationFee?.amount) / 1000000
).toString()} ${creationFeeDenom ? creationFeeDenom.displayName : creationFee?.denom}`,
)
})
}) })
} }
@ -1630,19 +1540,6 @@ const CollectionCreationPage: NextPage = () => {
> >
{openEditionMinterCreatorData?.sg721ContractAddress as string} {openEditionMinterCreatorData?.sg721ContractAddress as string}
</Anchor> </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 /> <br />
Transaction Hash: {' '} Transaction Hash: {' '}
<Conditional test={NETWORK === 'testnet'}> <Conditional test={NETWORK === 'testnet'}>
@ -1951,14 +1848,14 @@ const CollectionCreationPage: NextPage = () => {
<Conditional test={minterType === 'openEdition'}> <Conditional test={minterType === 'openEdition'}>
<OpenEditionMinterCreator <OpenEditionMinterCreator
importedOpenEditionMinterDetails={importedDetails?.openEditionMinterDetails} importedOpenEditionMinterDetails={importedDetails?.openEditionMinterDetails}
isMatchingFactoryPresent={isMatchingOpenEditionFactoryPresent}
minimumMintPrice={minimumOpenEditionMintPrice as string} minimumMintPrice={minimumOpenEditionMintPrice as string}
minimumUpdatableMintPrice={minimumOpenEditionUpdatableMintPrice as string}
mintTokenFromFactory={mintTokenFromOpenEditionFactory} mintTokenFromFactory={mintTokenFromOpenEditionFactory}
minterType={minterType} minterType={minterType}
onChange={setOpenEditionMinterCreatorData} onChange={setOpenEditionMinterCreatorData}
onDetailsChange={setOpenEditionMinterDetails} onDetailsChange={setOpenEditionMinterDetails}
openEditionFactoryAddress={openEditionFactoryAddress} openEditionMinterCreationFee={openEditionMinterCreationFee as string}
openEditionMinterCreationFee={openEditionMinterCreationFee} openEditionMinterUpdatableCreationFee={openEditionMinterUpdatableCreationFee as string}
/> />
</Conditional> </Conditional>
<div className="mx-10"> <div className="mx-10">

View File

@ -60,12 +60,6 @@ const CollectionList: NextPage = () => {
if (minterConfig?.whitelist) collection.whitelist = minterConfig.whitelist if (minterConfig?.whitelist) collection.whitelist = minterConfig.whitelist
setMyStandardCollections((prevState) => [...prevState, collection]) setMyStandardCollections((prevState) => [...prevState, collection])
} else if (contractType?.includes('open-edition')) { } else if (contractType?.includes('open-edition')) {
const minterConfig = await (await wallet.getCosmWasmClient())
.queryContractSmart(collection.minter, { config: {} })
.catch(() => {
console.log('Unable to retrieve minter config')
})
if (minterConfig?.whitelist) collection.whitelist = minterConfig.whitelist
setMyOpenEditionCollections((prevState) => [...prevState, collection]) setMyOpenEditionCollections((prevState) => [...prevState, collection])
} }
}) })
@ -435,31 +429,6 @@ const CollectionList: NextPage = () => {
</Tooltip> </Tooltip>
</span> </span>
</div> </div>
<Conditional test={collection.whitelist}>
<div className="flex flex-row items-center space-x-3">
Whitelist:
<span className="ml-2">
<Tooltip
backgroundColor="bg-blue-500"
label="Click to copy the whitelist contract address"
>
<button
className="group flex space-x-2 font-mono text-base text-white/80 hover:underline"
onClick={() => void copy(collection.whitelist as string)}
type="button"
>
<span>
{truncateMiddle(
collection.whitelist ? (collection.whitelist as string) : '',
36,
)}
</span>
<FaCopy className="opacity-0 group-hover:opacity-100" />
</button>
</Tooltip>
</span>
</div>
</Conditional>
</td> </td>
<th className="bg-black"> <th className="bg-black">
<div className="flex items-center space-x-8"> <div className="flex items-center space-x-8">
@ -476,14 +445,6 @@ const CollectionList: NextPage = () => {
> >
<FaRocket /> <FaRocket />
</Anchor> </Anchor>
<Conditional test={collection.whitelist}>
<Anchor
className="text-xl text-white"
href={`/contracts/whitelist/execute/?contractAddress=${collection.whitelist}`}
>
<FaList />
</Anchor>
</Conditional>
</div> </div>
</th> </th>
</tr> </tr>

View File

@ -1,122 +0,0 @@
/* eslint-disable eslint-comments/disable-enable-pair */
import { Alert } from 'components/Alert'
import { Button } from 'components/Button'
import { Conditional } from 'components/Conditional'
import { ContractPageHeader } from 'components/ContractPageHeader'
import { AddressInput } from 'components/forms/FormInput'
import { useInputState } from 'components/forms/FormInput.hooks'
import type { NextPage } from 'next'
import { useRouter } from 'next/router'
import { NextSeo } from 'next-seo'
import { useEffect, useState } from 'react'
import { toast } from 'react-hot-toast'
import { NETWORK } from 'utils/constants'
import { useDebounce } from 'utils/debounce'
import { withMetadata } from 'utils/layout'
import { links } from 'utils/links'
import { resolveAddress } from 'utils/resolveAddress'
import { useWallet } from 'utils/wallet'
const RemoveOfferPage: NextPage = () => {
const wallet = useWallet()
const [isLoading, setIsLoading] = useState(false)
const [txHash, setTxHash] = useState<string | undefined>(undefined)
const collectionAddressState = useInputState({
id: 'collection-address',
name: 'collectionAddress',
title: 'Collection Contract Address',
defaultValue: '',
placeholder: 'stars1...',
})
const collectionAddress = useDebounce(collectionAddressState.value, 300)
const router = useRouter()
useEffect(() => {
if (collectionAddress.length > 0) {
void router.replace({ query: { contractAddress: collectionAddress } })
}
if (collectionAddress.length === 0) {
void router.replace({ query: {} })
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [collectionAddress])
useEffect(() => {
const initial = new URL(document.URL).searchParams.get('contractAddress')
if (initial && initial.length > 0) collectionAddressState.onChange(initial)
}, [])
const resolveCollectionAddress = async () => {
await resolveAddress(collectionAddressState.value.trim(), wallet).then((resolvedAddress) => {
if (resolvedAddress) {
collectionAddressState.onChange(resolvedAddress)
}
})
}
useEffect(() => {
void resolveCollectionAddress()
}, [collectionAddressState.value])
const handleRemoveOffer = async () => {
if (!wallet.isWalletConnected) return toast.error('Please connect your wallet.')
if (!collectionAddressState.value) return toast.error('Please enter a collection address.')
const client = await wallet.getSigningCosmWasmClient()
setTxHash(undefined)
setIsLoading(true)
try {
const result = await client.execute(
wallet.address as string,
NETWORK === 'mainnet'
? 'stars1fvhcnyddukcqfnt7nlwv3thm5we22lyxyxylr9h77cvgkcn43xfsvgv0pl'
: 'stars18cszlvm6pze0x9sz32qnjq4vtd45xehqs8dq7cwy8yhq35wfnn3qgzs5gu',
{
remove_collection_bid: {
collection: collectionAddressState.value,
},
},
'auto',
)
toast.success('Offer successfully removed.')
setTxHash(result.transactionHash)
} catch (error: any) {
toast.error(error.message, { style: { maxWidth: 'none' } })
setTxHash(undefined)
} finally {
setIsLoading(false)
}
}
return (
<section className="py-6 px-12 space-y-4">
<NextSeo title="Remove Collection offer" />
<ContractPageHeader link={links.Documentation} title="Remove Collection Offer" />
<div className="space-y-8">
<AddressInput {...collectionAddressState} />
</div>
<div className="flex flex-row content-center">
<Button
isDisabled={collectionAddressState.value === ''}
isLoading={isLoading}
onClick={() => {
void handleRemoveOffer()
}}
>
Remove Collection Offer
</Button>
</div>
<Conditional test={txHash !== undefined}>
<Alert type="info">
<b>Transaction Hash:</b> {txHash}
</Alert>
</Conditional>
</section>
)
}
export default withMetadata(RemoveOfferPage, { center: false })

View File

@ -23,12 +23,13 @@ import { useEffect, useState } from 'react'
import { toast } from 'react-hot-toast' import { toast } from 'react-hot-toast'
import { FaAsterisk } from 'react-icons/fa' import { FaAsterisk } from 'react-icons/fa'
import { useMutation } from 'react-query' import { useMutation } from 'react-query'
import { BASE_FACTORY_ADDRESS, BASE_FACTORY_SG721_CODE_ID } from 'utils/constants' import { BASE_FACTORY_ADDRESS } from 'utils/constants'
import { withMetadata } from 'utils/layout' import { withMetadata } from 'utils/layout'
import { links } from 'utils/links' import { links } from 'utils/links'
import { useWallet } from 'utils/wallet' import { useWallet } from 'utils/wallet'
import type { CreateBaseMinterResponse } from '../../../contracts/baseFactory/contract' import type { CreateBaseMinterResponse } from '../../../contracts/baseFactory/contract'
import { SG721_CODE_ID } from '../../../utils/constants'
import { resolveAddress } from '../../../utils/resolveAddress' import { resolveAddress } from '../../../utils/resolveAddress'
const BaseMinterInstantiatePage: NextPage = () => { const BaseMinterInstantiatePage: NextPage = () => {
@ -61,7 +62,7 @@ const BaseMinterInstantiatePage: NextPage = () => {
title: 'Code ID', title: 'Code ID',
subtitle: 'Code ID for the sg721 contract', subtitle: 'Code ID for the sg721 contract',
placeholder: '1', placeholder: '1',
defaultValue: BASE_FACTORY_SG721_CODE_ID, defaultValue: SG721_CODE_ID,
}) })
const creatorState = useInputState({ const creatorState = useInputState({

View File

@ -1,28 +1,14 @@
/* eslint-disable eslint-comments/disable-enable-pair */ /* eslint-disable eslint-comments/disable-enable-pair */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
import type { EncodeObject } from '@cosmjs/proto-signing'
import { GasPrice, SigningStargateClient } from '@cosmjs/stargate'
import clsx from 'clsx' import clsx from 'clsx'
import { Alert } from 'components/Alert' import { Alert } from 'components/Alert'
import { Button } from 'components/Button' import { Button } from 'components/Button'
import { Conditional } from 'components/Conditional' import { Conditional } from 'components/Conditional'
import { ContractPageHeader } from 'components/ContractPageHeader' import { ContractPageHeader } from 'components/ContractPageHeader'
import { AddressList } from 'components/forms/AddressList'
import { useAddressListState } from 'components/forms/AddressList.hooks'
import { TextInput } from 'components/forms/FormInput'
import { useInputState } from 'components/forms/FormInput.hooks'
import { JsonPreview } from 'components/JsonPreview' import { JsonPreview } from 'components/JsonPreview'
import { getConfig } from 'config'
import { MsgExec } from 'cosmjs-types/cosmos/authz/v1beta1/tx'
import { MsgStoreCode } from 'cosmjs-types/cosmwasm/wasm/v1/tx'
import { AccessConfig, AccessType } from 'cosmjs-types/cosmwasm/wasm/v1/types'
import type { NextPage } from 'next' import type { NextPage } from 'next'
import { NextSeo } from 'next-seo' import { NextSeo } from 'next-seo'
import pako from 'pako'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { toast } from 'react-hot-toast' import { toast } from 'react-hot-toast'
import { FaAsterisk } from 'react-icons/fa' import { FaAsterisk } from 'react-icons/fa'
@ -37,38 +23,9 @@ const UploadContract: NextPage = () => {
const [transactionResult, setTransactionResult] = useState<any>() const [transactionResult, setTransactionResult] = useState<any>()
const [wasmFile, setWasmFile] = useState<File | null>(null) const [wasmFile, setWasmFile] = useState<File | null>(null)
const [wasmByteArray, setWasmByteArray] = useState<Uint8Array | null>(null) const [wasmByteArray, setWasmByteArray] = useState<Uint8Array | null>(null)
const [accessType, setAccessType] = useState<
'ACCESS_TYPE_UNSPECIFIED' | 'ACCESS_TYPE_EVERYBODY' | 'ACCESS_TYPE_ANY_OF_ADDRESSES' | 'ACCESS_TYPE_NOBODY'
>('ACCESS_TYPE_UNSPECIFIED')
const [accessConfig, setAccessConfig] = useState<AccessConfig | undefined>(undefined)
const [isAuthzUpload, setIsAuthzUpload] = useState(false)
const granterAddressState = useInputState({
id: 'address',
name: 'Granter Address',
title: 'Granter Address',
subtitle: 'The address that granted the authorization for contract upload',
defaultValue: '',
placeholder: 'stars1...',
})
const memoState = useInputState({
id: 'memo',
name: 'Memo',
title: 'Transaction Memo',
defaultValue: '',
placeholder: 'My contract',
})
const permittedAddressListState = useAddressListState()
const inputFile = useRef<HTMLInputElement>(null) const inputFile = useRef<HTMLInputElement>(null)
interface MsgExecAllowanceEncodeObject extends EncodeObject {
readonly typeUrl: '/cosmos.authz.v1beta1.MsgExec'
readonly value: Partial<MsgExec>
}
const onFileChange = (e: React.ChangeEvent<HTMLInputElement>) => { const onFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (!e.target.files) return if (!e.target.files) return
setWasmFile(e.target.files[0]) setWasmFile(e.target.files[0])
@ -94,70 +51,20 @@ const UploadContract: NextPage = () => {
try { try {
if (!wallet.isWalletConnected) return toast.error('Please connect your wallet.') if (!wallet.isWalletConnected) return toast.error('Please connect your wallet.')
if (!wasmFile || !wasmByteArray) return toast.error('No file selected.') if (!wasmFile || !wasmByteArray) return toast.error('No file selected.')
if (accessType === 'ACCESS_TYPE_UNSPECIFIED')
return toast.error('Please select an instantiation permission type.', { style: { maxWidth: 'none' } })
setLoading(true) setLoading(true)
const client = await wallet.getSigningCosmWasmClient() const client = await wallet.getSigningCosmWasmClient()
if (!isAuthzUpload) { const result = await client.upload(wallet.address as string, wasmByteArray, 'auto')
const result = await client.upload(
wallet.address as string,
wasmByteArray,
'auto',
memoState.value ?? undefined,
accessConfig,
)
setTransactionResult({
transactionHash: result.transactionHash,
codeId: result.codeId,
originalSize: result.originalSize,
compressedSize: result.compressedSize,
originalChecksum: result.checksum,
})
} else {
if (!granterAddressState.value) {
setLoading(false)
return toast.error('Please enter the authorization granter address.', { style: { maxWidth: 'none' } })
}
const compressed = pako.gzip(wasmByteArray, { level: 9 })
const authzExecuteContractMsg: MsgExecAllowanceEncodeObject = { setTransactionResult({
typeUrl: '/cosmos.authz.v1beta1.MsgExec', transactionHash: result.transactionHash,
value: MsgExec.fromPartial({ codeId: result.codeId,
grantee: wallet.address as string, originalSize: result.originalSize,
msgs: [ compressedSize: result.compressedSize,
{ originalChecksum: result.checksum,
typeUrl: '/cosmwasm.wasm.v1.MsgStoreCode', })
value: MsgStoreCode.encode({
sender: granterAddressState.value,
wasmByteCode: compressed,
instantiatePermission: accessConfig,
}).finish(),
},
],
}),
}
const offlineSigner = wallet.getOfflineSignerDirect()
const stargateClient = await SigningStargateClient.connectWithSigner(getConfig(NETWORK).rpcUrl, offlineSigner, {
gasPrice: GasPrice.fromString('0.025ustars'),
})
const result = await stargateClient.signAndBroadcast(
wallet.address || '',
[authzExecuteContractMsg],
'auto',
memoState.value ?? undefined,
)
setTransactionResult({
transactionHash: result.transactionHash,
codeId: result.events.filter((event) => event.type === 'store_code')[0].attributes[1].value,
originalChecksum: result.events.filter((event) => event.type === 'store_code')[0].attributes[0].value,
})
}
setLoading(false) setLoading(false)
} catch (err: any) { } catch (err: any) {
@ -166,120 +73,55 @@ const UploadContract: NextPage = () => {
} }
} }
useEffect(() => {
try {
if (accessType === 'ACCESS_TYPE_ANY_OF_ADDRESSES') {
setAccessConfig(
AccessConfig.fromPartial({
permission: AccessType.ACCESS_TYPE_ANY_OF_ADDRESSES,
addresses: permittedAddressListState.entries.map((entry) => entry[1].address).filter(Boolean),
}),
)
} else if (accessType === 'ACCESS_TYPE_NOBODY') {
setAccessConfig(AccessConfig.fromPartial({ permission: AccessType.ACCESS_TYPE_NOBODY }))
} else if (accessType === 'ACCESS_TYPE_EVERYBODY') {
setAccessConfig(AccessConfig.fromPartial({ permission: AccessType.ACCESS_TYPE_EVERYBODY }))
} else if (accessType === 'ACCESS_TYPE_UNSPECIFIED') {
setAccessConfig(undefined)
}
} catch (error: any) {
toast.error(error.message, { style: { maxWidth: 'none' } })
}
}, [accessType, permittedAddressListState.entries])
return ( return (
<section className="py-6 px-12 space-y-4"> <section className="py-6 px-12 space-y-4">
<NextSeo title="Upload Contract" /> <Conditional test={NETWORK === 'testnet'}>
<ContractPageHeader <NextSeo title="Upload Contract" />
description="Here you can upload a contract on Stargaze Testnet." <ContractPageHeader
link="" description="Here you can upload a contract on Stargaze Testnet."
title="Upload Contract" link=""
/> title="Upload Contract"
<div className="inset-x-0 bottom-0 border-b-2 border-white/25" />
<div className="flex flex-col w-1/2">
<span className="text-xl font-bold text-white">Authorization Type for Contract Instantiation</span>
<select
className="px-4 pt-2 pb-2 mt-2 w-1/2 placeholder:text-white/50 bg-white/10 rounded border-2 border-white/20 focus:ring focus:ring-plumbus-20"
onChange={(e) => setAccessType(e.target.value as any)}
value={accessType}
>
<option disabled value="ACCESS_TYPE_UNSPECIFIED">
Select Authorization Type
</option>
<option value="ACCESS_TYPE_EVERYBODY">Everybody</option>
<option value="ACCESS_TYPE_ANY_OF_ADDRESSES">Any of Addresses</option>
<option value="ACCESS_TYPE_NOBODY">Nobody</option>
</select>
</div>
<div className="my-2 w-1/2">
<TextInput {...memoState} />
</div>
<div className="flex flex-row justify-start">
<h1 className="mt-2 font-bold text-md">Authz Upload?</h1>
<label className="justify-start ml-6 cursor-pointer label">
<input
checked={isAuthzUpload}
className={`${isAuthzUpload ? `bg-stargaze` : `bg-gray-600`} checkbox`}
onClick={() => {
setIsAuthzUpload(!isAuthzUpload)
}}
type="checkbox"
/>
</label>
</div>
<Conditional test={isAuthzUpload}>
<div className="my-2 w-3/4">
<TextInput {...granterAddressState} />
</div>
</Conditional>
<Conditional test={accessType === 'ACCESS_TYPE_ANY_OF_ADDRESSES'}>
<div className="my-2 w-3/4">
<AddressList
entries={permittedAddressListState.entries}
onAdd={permittedAddressListState.add}
onChange={permittedAddressListState.update}
onRemove={permittedAddressListState.remove}
subtitle="The list of addresses permitted to instantiate the contract"
title="Permitted Addresses"
/>
</div>
</Conditional>
<Conditional test={Boolean(transactionResult)}>
<Alert type="info">
<b>Upload success!</b> Here is the transaction result containing the code ID, transaction hash and other data.
</Alert>
<JsonPreview content={transactionResult} title="Transaction Result" />
<br />
</Conditional>
<div
className={clsx(
'flex relative justify-center items-center space-y-4 h-32',
'rounded border-2 border-white/20 border-dashed',
)}
>
<input
accept=".wasm"
className={clsx(
'file:py-2 file:px-4 file:mr-4 file:bg-plumbus-light file:rounded file:border-0 cursor-pointer',
'before:absolute before:inset-0 before:hover:bg-white/5 before:transition',
)}
onChange={onFileChange}
ref={inputFile}
type="file"
/> />
</div> <div className="inset-x-0 bottom-0 border-b-2 border-white/25" />
<div className="flex justify-end pb-6"> <Conditional test={Boolean(transactionResult)}>
<Button isDisabled={!wasmFile} isLoading={loading} isWide leftIcon={<FaAsterisk />} onClick={upload}> <Alert type="info">
Upload Contract <b>Upload success!</b> Here is the transaction result containing the code ID, transaction hash and other
</Button> data.
</div> </Alert>
<JsonPreview content={transactionResult} title="Transaction Result" />
<br />
</Conditional>
<div
className={clsx(
'flex relative justify-center items-center space-y-4 h-32',
'rounded border-2 border-white/20 border-dashed',
)}
>
<input
accept=".wasm"
className={clsx(
'file:py-2 file:px-4 file:mr-4 file:bg-plumbus-light file:rounded file:border-0 cursor-pointer',
'before:absolute before:inset-0 before:hover:bg-white/5 before:transition',
)}
onChange={onFileChange}
ref={inputFile}
type="file"
/>
</div>
<div className="flex justify-end pb-6">
<Button isDisabled={!wasmFile} isLoading={loading} isWide leftIcon={<FaAsterisk />} onClick={upload}>
Upload Contract
</Button>
</div>
</Conditional>
<Conditional test={NETWORK === 'mainnet'}>
<NextSeo title="Upload Contract" />
<ContractPageHeader description="" link="" title="Upload Contract" />
<Alert type="info">Permissionless upload of contracts is only supported for testnet currently.</Alert>
</Conditional>
</section> </section>
) )
} }

View File

@ -48,7 +48,7 @@ const WhitelistExecutePage: NextPage = () => {
const [lastTx, setLastTx] = useState('') const [lastTx, setLastTx] = useState('')
const [memberList, setMemberList] = useState<string[]>([]) const [memberList, setMemberList] = useState<string[]>([])
const [flexMemberList, setFlexMemberList] = useState<WhitelistFlexMember[]>([]) const [flexMemberList, setFlexMemberList] = useState<WhitelistFlexMember[]>([])
const [whitelistType, setWhitelistType] = useState<'standard' | 'flex' | 'merkletree'>('standard') const [whitelistType, setWhitelistType] = useState<'standard' | 'flex'>('standard')
const comboboxState = useExecuteComboboxState() const comboboxState = useExecuteComboboxState()
const type = comboboxState.value?.id const type = comboboxState.value?.id
@ -211,8 +211,6 @@ const WhitelistExecutePage: NextPage = () => {
.then((contractType) => { .then((contractType) => {
if (contractType?.includes('flex')) { if (contractType?.includes('flex')) {
setWhitelistType('flex') setWhitelistType('flex')
} else if (contractType?.includes('merkle')) {
setWhitelistType('merkletree')
} else { } else {
setWhitelistType('standard') setWhitelistType('standard')
} }
@ -238,7 +236,7 @@ const WhitelistExecutePage: NextPage = () => {
<form className="grid grid-cols-2 p-4 space-x-8" onSubmit={mutate}> <form className="grid grid-cols-2 p-4 space-x-8" onSubmit={mutate}>
<div className="space-y-8"> <div className="space-y-8">
<AddressInput {...contractState} /> <AddressInput {...contractState} />
<ExecuteCombobox whitelistType={whitelistType} {...comboboxState} /> <ExecuteCombobox {...comboboxState} />
<Conditional test={showLimitState}> <Conditional test={showLimitState}>
<NumberInput {...limitState} /> <NumberInput {...limitState} />
</Conditional> </Conditional>

View File

@ -1,7 +1,6 @@
/* eslint-disable eslint-comments/disable-enable-pair */ /* eslint-disable eslint-comments/disable-enable-pair */
/* eslint-disable no-nested-ternary */ /* eslint-disable no-nested-ternary */
import { coin } from '@cosmjs/proto-signing' import { coin } from '@cosmjs/proto-signing'
import axios from 'axios'
import { Alert } from 'components/Alert' import { Alert } from 'components/Alert'
import { Button } from 'components/Button' import { Button } from 'components/Button'
import { Conditional } from 'components/Conditional' import { Conditional } from 'components/Conditional'
@ -35,22 +34,17 @@ import { withMetadata } from 'utils/layout'
import { links } from 'utils/links' import { links } from 'utils/links'
import { useWallet } from 'utils/wallet' import { useWallet } from 'utils/wallet'
import { import { WHITELIST_CODE_ID, WHITELIST_FLEX_CODE_ID } from '../../../utils/constants'
WHITELIST_CODE_ID,
WHITELIST_FLEX_CODE_ID,
WHITELIST_MERKLE_TREE_API_URL,
WHITELIST_MERKLE_TREE_CODE_ID,
} from '../../../utils/constants'
const WhitelistInstantiatePage: NextPage = () => { const WhitelistInstantiatePage: NextPage = () => {
const wallet = useWallet() const wallet = useWallet()
const { whitelist: contract, whitelistMerkleTree: whitelistMerkleTreeContract } = useContracts() const { whitelist: contract } = useContracts()
const { timezone } = useGlobalSettings() const { timezone } = useGlobalSettings()
const [startDate, setStartDate] = useState<Date | undefined>(undefined) const [startDate, setStartDate] = useState<Date | undefined>(undefined)
const [endDate, setEndDate] = useState<Date | undefined>(undefined) const [endDate, setEndDate] = useState<Date | undefined>(undefined)
const [adminsMutable, setAdminsMutable] = useState<boolean>(true) const [adminsMutable, setAdminsMutable] = useState<boolean>(true)
const [whitelistType, setWhitelistType] = useState<'standard' | 'flex' | 'merkletree'>('standard') const [whitelistType, setWhitelistType] = useState<'standard' | 'flex'>('standard')
const [whitelistStandardArray, setWhitelistStandardArray] = useState<string[]>([]) const [whitelistStandardArray, setWhitelistStandardArray] = useState<string[]>([])
const [whitelistFlexArray, setWhitelistFlexArray] = useState<WhitelistFlexMember[]>([]) const [whitelistFlexArray, setWhitelistFlexArray] = useState<WhitelistFlexMember[]>([])
@ -91,16 +85,12 @@ const WhitelistInstantiatePage: NextPage = () => {
const addressListState = useAddressListState() const addressListState = useAddressListState()
const { data, isLoading, mutate } = useMutation( const { data, isLoading, mutate } = useMutation(
async (event: FormEvent): Promise<InstantiateResponse | undefined | null> => { async (event: FormEvent): Promise<InstantiateResponse | null> => {
event.preventDefault() event.preventDefault()
if (!contract) { if (!contract) {
throw new Error('Smart contract connection failed') throw new Error('Smart contract connection failed')
} }
if (!whitelistMerkleTreeContract && whitelistType === 'merkletree') {
throw new Error('Smart contract connection failed')
}
if (!startDate) { if (!startDate) {
throw new Error('Start date is required') throw new Error('Start date is required')
} }
@ -142,79 +132,19 @@ const WhitelistInstantiatePage: NextPage = () => {
admins_mutable: adminsMutable, admins_mutable: adminsMutable,
} }
if (whitelistType !== 'merkletree') { return toast.promise(
return toast.promise( contract.instantiate(
contract.instantiate( whitelistType === 'standard' ? WHITELIST_CODE_ID : WHITELIST_FLEX_CODE_ID,
whitelistType === 'standard' ? WHITELIST_CODE_ID : WHITELIST_FLEX_CODE_ID, whitelistType === 'standard' ? standardMsg : flexMsg,
whitelistType === 'standard' ? standardMsg : flexMsg, whitelistType === 'standard' ? 'Stargaze Whitelist Contract' : 'Stargaze Whitelist Flex Contract',
whitelistType === 'standard' ? 'Stargaze Whitelist Contract' : 'Stargaze Whitelist Flex Contract', wallet.address,
wallet.address, ),
), {
{ loading: 'Instantiating contract...',
loading: 'Instantiating contract...', error: 'Instantiation failed!',
error: 'Instantiation failed!', success: 'Instantiation success!',
success: 'Instantiation success!', },
}, )
)
} else if (whitelistType === 'merkletree') {
const members = whitelistStandardArray
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: (startDate.getTime() * 1_000_000).toString(),
end_time: (endDate.getTime() * 1_000_000).toString(),
mint_price: coin(String(Number(unitPriceState.value) * 1000000), selectedMintToken?.denom || 'ustars'),
per_address_limit: perAddressLimitState.value,
admins: [
...new Set(
addressListState.values
.map((a) => a.address.trim())
.filter((address) => address !== '' && isValidAddress(address.trim()) && address.startsWith('stars')),
),
] || [wallet.address],
admins_mutable: adminsMutable,
}
return toast.promise(
whitelistMerkleTreeContract?.instantiate(
WHITELIST_MERKLE_TREE_CODE_ID,
merkleTreeMsg,
'Stargaze Whitelist Merkle Tree Contract',
wallet.address,
) as Promise<InstantiateResponse>,
{
loading: 'Instantiating contract...',
error: 'Instantiation failed!',
success: 'Instantiation success!',
},
)
}
}, },
{ {
onError: (error) => { onError: (error) => {
@ -246,7 +176,7 @@ const WhitelistInstantiatePage: NextPage = () => {
/> />
<LinkTabs activeIndex={0} data={whitelistLinkTabs} /> <LinkTabs activeIndex={0} data={whitelistLinkTabs} />
<div className="flex justify-between mb-5 ml-6 max-w-[520px] text-lg font-bold"> <div className="flex justify-between mb-5 ml-6 max-w-[300px] text-lg font-bold">
<div className="form-check form-check-inline"> <div className="form-check form-check-inline">
<input <input
checked={whitelistType === 'standard'} checked={whitelistType === 'standard'}
@ -286,26 +216,6 @@ const WhitelistInstantiatePage: NextPage = () => {
Whitelist Flex Whitelist Flex
</label> </label>
</div> </div>
<div className="form-check form-check-inline">
<input
checked={whitelistType === 'merkletree'}
className="peer sr-only"
id="inlineRadio3"
name="inlineRadioOptions3"
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="inlineRadio3"
>
Whitelist Merkle Tree
</label>
</div>
</div> </div>
<Conditional test={Boolean(data)}> <Conditional test={Boolean(data)}>
@ -341,7 +251,7 @@ const WhitelistInstantiatePage: NextPage = () => {
</div> </div>
<FormGroup subtitle="Your whitelisted addresses" title="Whitelist File"> <FormGroup subtitle="Your whitelisted addresses" title="Whitelist File">
<Conditional test={whitelistType === 'standard' || whitelistType === 'merkletree'}> <Conditional test={whitelistType === 'standard'}>
<WhitelistUpload onChange={whitelistFileOnChange} /> <WhitelistUpload onChange={whitelistFileOnChange} />
<Conditional test={whitelistStandardArray.length > 0}> <Conditional test={whitelistStandardArray.length > 0}>
<JsonPreview content={whitelistStandardArray} initialState={false} title="File Contents" /> <JsonPreview content={whitelistStandardArray} initialState={false} title="File Contents" />
@ -373,10 +283,8 @@ const WhitelistInstantiatePage: NextPage = () => {
</select> </select>
</div> </div>
<Conditional test={whitelistType !== 'merkletree'}> <NumberInput isRequired {...memberLimitState} />
<NumberInput isRequired {...memberLimitState} /> <Conditional test={whitelistType === 'standard'}>
</Conditional>
<Conditional test={whitelistType === 'standard' || whitelistType === 'merkletree'}>
<NumberInput isRequired {...perAddressLimitState} /> <NumberInput isRequired {...perAddressLimitState} />
</Conditional> </Conditional>
<Conditional test={whitelistType === 'flex'}> <Conditional test={whitelistType === 'flex'}>

View File

@ -1,6 +1,4 @@
/* eslint-disable eslint-comments/disable-enable-pair */ /* eslint-disable eslint-comments/disable-enable-pair */
/* eslint-disable @typescript-eslint/restrict-template-expressions */
/* eslint-disable no-nested-ternary */
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
/* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-unsafe-return */
@ -10,7 +8,6 @@
import { toUtf8 } from '@cosmjs/encoding' import { toUtf8 } from '@cosmjs/encoding'
import clsx from 'clsx' import clsx from 'clsx'
import { Button } from 'components/Button' import { Button } from 'components/Button'
import type { WhitelistType } from 'components/collections/creation/WhitelistDetails'
import { Conditional } from 'components/Conditional' import { Conditional } from 'components/Conditional'
import { ContractPageHeader } from 'components/ContractPageHeader' import { ContractPageHeader } from 'components/ContractPageHeader'
import { FormControl } from 'components/FormControl' import { FormControl } from 'components/FormControl'
@ -22,18 +19,12 @@ import { whitelistLinkTabs } from 'components/LinkTabs.data'
import { useContracts } from 'contexts/contracts' import { useContracts } from 'contexts/contracts'
import type { QueryType } from 'contracts/whitelist/messages/query' import type { QueryType } from 'contracts/whitelist/messages/query'
import { dispatchQuery, QUERY_LIST } from 'contracts/whitelist/messages/query' import { dispatchQuery, QUERY_LIST } from 'contracts/whitelist/messages/query'
import type { WhitelistMerkleTreeQueryType } from 'contracts/whitelistMerkleTree/messages/query'
import {
dispatchQuery as disptachWhitelistMerkleTreeQuery,
WHITELIST_MERKLE_TREE_QUERY_LIST,
} from 'contracts/whitelistMerkleTree/messages/query'
import type { NextPage } from 'next' import type { NextPage } from 'next'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import { NextSeo } from 'next-seo' import { NextSeo } from 'next-seo'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { toast } from 'react-hot-toast' import { toast } from 'react-hot-toast'
import { useQuery } from 'react-query' import { useQuery } from 'react-query'
import { WHITELIST_MERKLE_TREE_API_URL } from 'utils/constants'
import { useDebounce } from 'utils/debounce' import { useDebounce } from 'utils/debounce'
import { withMetadata } from 'utils/layout' import { withMetadata } from 'utils/layout'
import { links } from 'utils/links' import { links } from 'utils/links'
@ -42,11 +33,8 @@ import { useWallet } from 'utils/wallet'
const WhitelistQueryPage: NextPage = () => { const WhitelistQueryPage: NextPage = () => {
const { whitelist: contract } = useContracts() const { whitelist: contract } = useContracts()
const { whitelistMerkleTree: contractWhitelistMerkleTree } = useContracts()
const wallet = useWallet() const wallet = useWallet()
const [exporting, setExporting] = useState(false) const [exporting, setExporting] = useState(false)
const [whitelistType, setWhitelistType] = useState<WhitelistType>('standard')
const [proofHashes, setProofHashes] = useState<string[]>([])
const contractState = useInputState({ const contractState = useInputState({
id: 'contract-address', id: 'contract-address',
@ -56,46 +44,6 @@ const WhitelistQueryPage: NextPage = () => {
}) })
const contractAddress = contractState.value const contractAddress = contractState.value
const debouncedWhitelistContractState = useDebounce(contractAddress, 300)
useEffect(() => {
async function getWhitelistContractType() {
if (debouncedWhitelistContractState.length > 0) {
const client = await wallet.getCosmWasmClient()
const data = await toast.promise(
client.queryContractRaw(
debouncedWhitelistContractState,
toUtf8(Buffer.from(Buffer.from('contract_info').toString('hex'), 'hex').toString()),
),
{
loading: 'Retrieving whitelist type...',
error: 'Whitelist type retrieval failed.',
success: 'Whitelist type retrieved.',
},
)
const whitelistContract: string = JSON.parse(new TextDecoder().decode(data as Uint8Array)).contract
console.log(contract)
return whitelistContract
}
}
void getWhitelistContractType()
.then((whitelistContract) => {
if (whitelistContract?.includes('merkletree')) {
setWhitelistType('merkletree')
} else if (whitelistContract?.includes('flex')) {
setWhitelistType('flex')
} else {
setWhitelistType('standard')
}
})
.catch((err) => {
console.log(err)
setWhitelistType('standard')
console.log('Unable to retrieve contract type. Defaulting to "standard".')
})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [debouncedWhitelistContractState, wallet.isWalletConnected])
const addressState = useInputState({ const addressState = useInputState({
id: 'address', id: 'address',
name: 'address', name: 'address',
@ -104,47 +52,6 @@ const WhitelistQueryPage: NextPage = () => {
}) })
const address = addressState.value const address = addressState.value
const debouncedAddress = useDebounce(address, 300)
const fetchProofHashes = async (whitelistContractAddress: string, memberAddress: string): Promise<string[]> => {
if (whitelistContractAddress.length === 0 || memberAddress.length === 0)
throw new Error('Contract or member address is empty.')
const resolvedAddress = await resolveAddress(memberAddress, wallet)
const merkleRootResponse = await (
await wallet.getCosmWasmClient()
).queryContractSmart(contractAddress, { merkle_root: {} })
const proofs = await toast.promise(
fetch(`${WHITELIST_MERKLE_TREE_API_URL}/whitelist/${merkleRootResponse.merkle_root}/${resolvedAddress}`)
.then((res) => res.json())
.then((data) => data.proofs)
.catch((e) => {
console.log(e)
setProofHashes([])
}),
{
loading: 'Fetching proof hashes...',
error: 'Error fetching proof hashes from Whitelist Merkle Tree API.',
success: 'Proof hashes fetched.',
},
)
return proofs as string[] | []
}
useEffect(() => {
if (
whitelistType === 'merkletree' &&
whitelistMerkleTreeQueryType === 'has_member' &&
debouncedAddress.length > 0
) {
void fetchProofHashes(contractAddress, debouncedAddress)
.then((proofs) => setProofHashes(proofs))
.catch((e) => {
console.log(e)
setProofHashes([])
})
}
}, [debouncedAddress])
const limit = useNumberInputState({ const limit = useNumberInputState({
id: 'limit', id: 'limit',
name: 'limit', name: 'limit',
@ -173,59 +80,22 @@ const WhitelistQueryPage: NextPage = () => {
}, [debouncedLimit]) }, [debouncedLimit])
const [type, setType] = useState<QueryType>('config') const [type, setType] = useState<QueryType>('config')
const [whitelistMerkleTreeQueryType, setWhitelistMerkleTreeQueryType] =
useState<WhitelistMerkleTreeQueryType>('config')
const addressVisible = type === 'has_member' || whitelistMerkleTreeQueryType === 'has_member' const addressVisible = type === 'has_member'
const { data: response } = useQuery( const { data: response } = useQuery(
[ [contractAddress, type, contract, wallet.address, address, startAfter.value, limit.value] as const,
contractAddress,
type,
whitelistMerkleTreeQueryType,
contract,
contractWhitelistMerkleTree,
wallet.address,
address,
startAfter.value,
limit.value,
proofHashes,
whitelistType,
] as const,
async ({ queryKey }) => { async ({ queryKey }) => {
const [ const [_contractAddress, _type, _contract, _wallet, _address, _startAfter, _limit] = queryKey
_contractAddress,
_type,
_whitelistMerkleTreeQueryType,
_contract,
_contractWhitelistMerkleTree,
_wallet,
_address,
_startAfter,
_limit,
_proofHashes,
_whitelistType,
] = queryKey
const messages = contract?.use(contractAddress) const messages = contract?.use(contractAddress)
const whitelistMerkleTreeMessages = contractWhitelistMerkleTree?.use(contractAddress)
const res = await resolveAddress(_address, wallet).then(async (resolvedAddress) => { const res = await resolveAddress(_address, wallet).then(async (resolvedAddress) => {
const result = const result = await dispatchQuery({
whitelistType === 'merkletree' messages,
? await disptachWhitelistMerkleTreeQuery({ type,
messages: whitelistMerkleTreeMessages, address: resolvedAddress,
address: resolvedAddress, startAfter: _startAfter || undefined,
type: whitelistMerkleTreeQueryType, limit: _limit,
limit: _limit, })
proofHashes: _proofHashes,
})
: await dispatchQuery({
messages,
type,
address: resolvedAddress,
startAfter: _startAfter || undefined,
limit: _limit,
})
return result return result
}) })
return res return res
@ -235,7 +105,7 @@ const WhitelistQueryPage: NextPage = () => {
onError: (error: any) => { onError: (error: any) => {
toast.error(error.message, { style: { maxWidth: 'none' } }) toast.error(error.message, { style: { maxWidth: 'none' } })
}, },
enabled: Boolean(contractAddress && (contract || contractWhitelistMerkleTree)), enabled: Boolean(contractAddress && contract),
}, },
) )
@ -360,13 +230,9 @@ const WhitelistQueryPage: NextPage = () => {
defaultValue="config" defaultValue="config"
id="contract-query-type" id="contract-query-type"
name="query-type" name="query-type"
onChange={(e) => onChange={(e) => setType(e.target.value as QueryType)}
whitelistType === 'merkletree'
? setWhitelistMerkleTreeQueryType(e.target.value as WhitelistMerkleTreeQueryType)
: setType(e.target.value as QueryType)
}
> >
{(whitelistType === 'merkletree' ? WHITELIST_MERKLE_TREE_QUERY_LIST : QUERY_LIST).map(({ id, name }) => ( {QUERY_LIST.map(({ id, name }) => (
<option key={`query-${id}`} className="mt-2 text-lg bg-[#1A1A1A]" value={id}> <option key={`query-${id}`} className="mt-2 text-lg bg-[#1A1A1A]" value={id}>
{name} {name}
</option> </option>
@ -389,16 +255,7 @@ const WhitelistQueryPage: NextPage = () => {
</Button> </Button>
</Conditional> </Conditional>
</div> </div>
<JsonPreview <JsonPreview content={contractAddress ? { type, response } : null} title="Query Response" />
content={
contractAddress
? whitelistType === 'merkletree'
? { type: whitelistMerkleTreeQueryType, response }
: { type, response }
: null
}
title="Query Response"
/>
</div> </div>
</section> </section>
) )

View File

@ -30,7 +30,6 @@ const Holders: NextPage = () => {
const [includeStaked, setIncludeStaked] = useState<boolean>(true) const [includeStaked, setIncludeStaked] = useState<boolean>(true)
const [includeListed, setIncludeListed] = useState<boolean>(true) const [includeListed, setIncludeListed] = useState<boolean>(true)
const [includeInPool, setIncludeInPool] = useState<boolean>(true)
const [exportIndividualTokens, setExportIndividualTokens] = useState<boolean>(false) const [exportIndividualTokens, setExportIndividualTokens] = useState<boolean>(false)
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
@ -84,17 +83,6 @@ const Holders: NextPage = () => {
type="checkbox" type="checkbox"
/> />
</label> </label>
<label className="justify-start cursor-pointer label w-2/5">
<span className="mr-2 font-bold">Include tokens in Infinity Pools</span>
<input
checked={includeInPool}
className={`${includeInPool ? `bg-stargaze` : `bg-gray-600`} checkbox`}
onClick={() => {
setIncludeInPool(!includeInPool)
}}
type="checkbox"
/>
</label>
<label className="justify-start cursor-pointer label w-2/5"> <label className="justify-start cursor-pointer label w-2/5">
<span className="mr-2 font-bold">Export by Token ID</span> <span className="mr-2 font-bold">Export by Token ID</span>
<input <input
@ -134,8 +122,6 @@ const Holders: NextPage = () => {
?.map((row: any) => { ?.map((row: any) => {
if (!includeListed && row.is_listed) return '' if (!includeListed && row.is_listed) return ''
if (!includeStaked && row.is_staked) return '' if (!includeStaked && row.is_staked) return ''
if (!includeInPool && row.is_in_pool) return ''
if (row.owner_addr === null) return ''
return `${row.owner_addr},${row.token_id}\n` return `${row.owner_addr},${row.token_id}\n`
}) })
.join('')}` .join('')}`
@ -147,8 +133,6 @@ const Holders: NextPage = () => {
data.forEach((row: any) => { data.forEach((row: any) => {
if (!includeListed && row.is_listed) return if (!includeListed && row.is_listed) return
if (!includeStaked && row.is_staked) return if (!includeStaked && row.is_staked) return
if (!includeInPool && row.is_in_pool) return
if (row.owner_addr === null) return
const existingRow = aggregatedData.find((r) => r.address === row.owner_addr) const existingRow = aggregatedData.find((r) => r.address === row.owner_addr)
if (existingRow) { if (existingRow) {
existingRow.amount += 1 existingRow.amount += 1

View File

@ -1,11 +1,11 @@
/* eslint-disable eslint-comments/disable-enable-pair */ /* eslint-disable eslint-comments/disable-enable-pair */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable tailwindcss/classnames-order */ /* eslint-disable tailwindcss/classnames-order */
/* eslint-disable react/button-has-type */
import type { EncodeObject } from '@cosmjs/proto-signing' import type { EncodeObject } from '@cosmjs/proto-signing'
import { Registry } from '@cosmjs/proto-signing' import { Registry } from '@cosmjs/proto-signing'
import { GasPrice, SigningStargateClient } from '@cosmjs/stargate' import { GasPrice, SigningStargateClient } from '@cosmjs/stargate'
import { Button } from 'components/Button'
import { Conditional } from 'components/Conditional' import { Conditional } from 'components/Conditional'
import { ContractPageHeader } from 'components/ContractPageHeader' import { ContractPageHeader } from 'components/ContractPageHeader'
import { DenomUnits } from 'components/forms/DenomUnits' import { DenomUnits } from 'components/forms/DenomUnits'
@ -17,7 +17,6 @@ import { NextSeo } from 'next-seo'
import { Field, Type } from 'protobufjs' import { Field, Type } from 'protobufjs'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import toast from 'react-hot-toast' import toast from 'react-hot-toast'
import { NETWORK } from 'utils/constants'
import { withMetadata } from 'utils/layout' import { withMetadata } from 'utils/layout'
import { useWallet } from 'utils/wallet' import { useWallet } from 'utils/wallet'
@ -53,13 +52,16 @@ const MsgMint = new Type('MsgMint')
.add(new Field('sender', 1, 'string', 'required')) .add(new Field('sender', 1, 'string', 'required'))
.add(new Field('amount', 2, 'Coin', 'required')) .add(new Field('amount', 2, 'Coin', 'required'))
.add(new Field('mintToAddress', 3, 'string', 'required')) .add(new Field('mintToAddress', 3, 'string', 'required'))
.add(new Type('Coin').add(new Field('denom', 1, 'string')).add(new Field('amount', 2, 'string')))
const CoinType = new Type('Coin').add(new Field('denom', 1, 'string')).add(new Field('amount', 2, 'string'))
MsgMint.add(CoinType)
const MsgSend = new Type('MsgSend') const MsgSend = new Type('MsgSend')
.add(new Field('fromAddress', 1, 'string')) .add(new Field('fromAddress', 1, 'string'))
.add(new Field('toAddress', 2, 'string')) .add(new Field('toAddress', 2, 'string'))
.add(new Field('amount', 3, 'Coin', 'repeated')) .add(new Field('amount', 3, 'Coin', 'repeated'))
.add(new Type('Coin').add(new Field('denom', 1, 'string')).add(new Field('amount', 2, 'string')))
MsgSend.add(CoinType)
const MsgChangeAdmin = new Type('MsgChangeAdmin') const MsgChangeAdmin = new Type('MsgChangeAdmin')
.add(new Field('sender', 1, 'string', 'required')) .add(new Field('sender', 1, 'string', 'required'))
@ -86,7 +88,6 @@ const Tokenfactory: NextPage = () => {
const wallet = useWallet() const wallet = useWallet()
const [messageType, setMessageType] = useState<MessageType>('MsgCreateDenom') const [messageType, setMessageType] = useState<MessageType>('MsgCreateDenom')
const [loading, setLoading] = useState(false)
const denomState = useInputState({ const denomState = useInputState({
id: 'denom', id: 'denom',
@ -117,8 +118,8 @@ const Tokenfactory: NextPage = () => {
id: 'mintToAddress', id: 'mintToAddress',
name: 'mintToAddress', name: 'mintToAddress',
title: 'Mint To Address', title: 'Mint To Address',
placeholder: 'stars1...', //placeholder: `${wallet.isWalletConnected && wallet.address ? wallet.address : 'stars1...'}`,
defaultValue: wallet.address ?? '', placeholder: 'The tokens can only be minted to the creator address currently.',
subtitle: 'The address to mint tokens to', subtitle: 'The address to mint tokens to',
}) })
@ -208,10 +209,10 @@ const Tokenfactory: NextPage = () => {
const handleSendMessage = async () => { const handleSendMessage = async () => {
try { try {
if (!wallet.isWalletConnected) return toast.error('Please connect your wallet.') if (!wallet.isWalletConnected) return toast.error('Please connect your wallet.')
setLoading(true)
const offlineSigner = wallet.getOfflineSignerDirect() const offlineSigner = wallet.getOfflineSignerDirect()
const stargateClient = await SigningStargateClient.connectWithSigner( const stargateClient = await SigningStargateClient.connectWithSigner(
NETWORK === 'testnet' ? 'https://rpc.elgafar-1.stargaze-apis.com/' : 'https://rpc.stargaze-apis.com/', 'https://rpc.elgafar-1.stargaze-apis.com/',
offlineSigner, offlineSigner,
{ {
gasPrice: GasPrice.fromString('0.025ustars'), gasPrice: GasPrice.fromString('0.025ustars'),
@ -301,10 +302,9 @@ const Tokenfactory: NextPage = () => {
'auto', 'auto',
) )
console.log('response: ', response) console.log('response: ', response)
setLoading(false)
toast.success(`${messageType} success.`, { style: { maxWidth: 'none' } }) toast.success(`${messageType} success.`, { style: { maxWidth: 'none' } })
} catch (error: any) { } catch (error: any) {
setLoading(false)
toast.error(error.message, { style: { maxWidth: 'none' } }) toast.error(error.message, { style: { maxWidth: 'none' } })
console.error('Error: ', error) console.error('Error: ', error)
} }
@ -349,7 +349,7 @@ const Tokenfactory: NextPage = () => {
<Conditional test={messageType === 'MsgMint'}> <Conditional test={messageType === 'MsgMint'}>
<TextInput className="w-3/5" {...denomState} /> <TextInput className="w-3/5" {...denomState} />
<NumberInput className="w-1/4" {...amountState} /> <NumberInput className="w-1/4" {...amountState} />
<AddressInput className="w-3/5" {...mintToAddressState} /> <AddressInput className="w-3/5" disabled {...mintToAddressState} />
</Conditional> </Conditional>
<Conditional test={messageType === 'MsgSend'}> <Conditional test={messageType === 'MsgSend'}>
<TextInput className="w-3/5" {...denomState} /> <TextInput className="w-3/5" {...denomState} />
@ -375,16 +375,15 @@ const Tokenfactory: NextPage = () => {
<TextInput className="w-1/2" {...denomState} /> <TextInput className="w-1/2" {...denomState} />
<AddressInput className="w-1/2" {...newAdminAddressState} /> <AddressInput className="w-1/2" {...newAdminAddressState} />
</Conditional> </Conditional>
<Button <button
className="px-4 py-2 font-bold text-white bg-stargaze rounded-md" className="px-4 py-2 font-bold text-white bg-stargaze rounded-md"
isLoading={loading}
onClick={() => { onClick={() => {
void handleSendMessage() void handleSendMessage()
}} }}
> >
{' '} {' '}
{getButtonName()} {getButtonName()}
</Button> </button>
</section> </section>
) )
} }

View File

@ -1,69 +0,0 @@
#!/bin/bash
set -e
RECORD_FILE=tmp.rf.$$
CONFIG_FILE=`mktemp`
CERC_APP_TYPE=${CERC_APP_TYPE:-"webapp"}
CERC_REPO_REF=${CERC_REPO_REF:-${GITHUB_SHA:-`git log -1 --format="%H"`}}
CERC_IS_LATEST_RELEASE=${CERC_IS_LATEST_RELEASE:-"true"}
rcd_name=$(jq -r '.name' package.json | sed 's/null//')
rcd_desc=$(jq -r '.description' package.json | sed 's/null//')
rcd_repository=$(jq -r '.repository' package.json | sed 's/null//')
rcd_homepage=$(jq -r '.homepage' package.json | sed 's/null//')
rcd_license=$(jq -r '.license' package.json | sed 's/null//')
rcd_author=$(jq -r '.author' package.json | sed 's/null//')
rcd_app_version=$(jq -r '.version' package.json | sed 's/null//')
cat <<EOF > "$CONFIG_FILE"
services:
cns:
restEndpoint: '${CERC_REGISTRY_REST_ENDPOINT:-http://23.111.69.218:1317}'
gqlEndpoint: '${CERC_REGISTRY_GQL_ENDPOINT:-https://lx-daemon.audubon.app/api}'
chainId: ${CERC_REGISTRY_CHAIN_ID:-laconic_9000-1}
gas: 9550000
fees: 500000aphoton
EOF
next_ver=$(laconic -c $CONFIG_FILE cns record list --type ApplicationRecord --all --name "$rcd_name" 2>/dev/null | jq -r -s ".[] | sort_by(.createTime) | reverse | [ .[] | select(.bondId == \"$CERC_REGISTRY_BOND_ID\") ] | .[0].attributes.version" | awk -F. -v OFS=. '{$NF += 1 ; print}')
if [ -z "$next_ver" ] || [ "1" == "$next_ver" ]; then
next_ver=0.0.1
fi
cat <<EOF | sed '/.*: ""$/d' > "$RECORD_FILE"
record:
type: ApplicationRecord
version: ${next_ver}
name: "$rcd_name"
description: "$rcd_desc"
homepage: "$rcd_homepage"
license: "$rcd_license"
author: "$rcd_author"
repository:
- "$rcd_repository"
repository_ref: "$CERC_REPO_REF"
app_version: "$rcd_app_version"
app_type: "$CERC_APP_TYPE"
EOF
cat $RECORD_FILE
RECORD_ID=$(laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE --user-key "${CERC_REGISTRY_USER_KEY}" --bond-id ${CERC_REGISTRY_BOND_ID} | jq -r '.id')
echo $RECORD_ID
if [ -z "$CERC_REGISTRY_APP_CRN" ]; then
authority=$(echo "$rcd_name" | cut -d'/' -f1 | sed 's/@//')
app=$(echo "$rcd_name" | cut -d'/' -f2-)
CERC_REGISTRY_APP_CRN="crn://$authority/applications/$app"
fi
laconic -c $CONFIG_FILE cns name set --user-key "${CERC_REGISTRY_USER_KEY}" --bond-id ${CERC_REGISTRY_BOND_ID} "$CERC_REGISTRY_APP_CRN@${rcd_app_version}" "$RECORD_ID"
laconic -c $CONFIG_FILE cns name set --user-key "${CERC_REGISTRY_USER_KEY}" --bond-id ${CERC_REGISTRY_BOND_ID} "$CERC_REGISTRY_APP_CRN@${CERC_REPO_REF}" "$RECORD_ID"
if [ "true" == "$CERC_IS_LATEST_RELEASE" ]; then
laconic -c $CONFIG_FILE cns name set --user-key "${CERC_REGISTRY_USER_KEY}" --bond-id ${CERC_REGISTRY_BOND_ID} "$CERC_REGISTRY_APP_CRN" "$RECORD_ID"
fi
rm -f $RECORD_FILE $CONFIG_FILE

View File

@ -1,56 +0,0 @@
#!/bin/bash
set -e
RECORD_FILE=tmp.rf.$$
CONFIG_FILE=`mktemp`
rcd_name=$(jq -r '.name' package.json | sed 's/null//' | sed 's/^@//')
rcd_app_version=$(jq -r '.version' package.json | sed 's/null//')
cat <<EOF > "$CONFIG_FILE"
services:
cns:
restEndpoint: '${CERC_REGISTRY_REST_ENDPOINT:-http://23.111.69.218:1317}'
gqlEndpoint: '${CERC_REGISTRY_GQL_ENDPOINT:-https://lx-daemon.audubon.app/api}'
chainId: ${CERC_REGISTRY_CHAIN_ID:-laconic_9000-1}
gas: 550000
fees: 200000aphoton
EOF
if [ -z "$CERC_REGISTRY_APP_CRN" ]; then
authority=$(echo "$rcd_name" | cut -d'/' -f1 | sed 's/@//')
app=$(echo "$rcd_name" | cut -d'/' -f2-)
CERC_REGISTRY_APP_CRN="crn://$authority/applications/$app"
fi
APP_RECORD=$(laconic -c $CONFIG_FILE cns name resolve "$CERC_REGISTRY_APP_CRN" | jq '.[0]')
if [ -z "$APP_RECORD" ] || [ "null" == "$APP_RECORD" ]; then
echo "No record found for $CERC_REGISTRY_APP_CRN."
exit 1
fi
cat <<EOF | sed '/.*: ""$/d' > "$RECORD_FILE"
record:
type: ApplicationDeploymentRequest
version: 1.0.0
name: "$rcd_name@$rcd_app_version"
application: "$CERC_REGISTRY_APP_CRN@$rcd_app_version"
dns: "$CERC_REGISTRY_DEPLOYMENT_SHORT_HOSTNAME"
deployment: "$CERC_REGISTRY_DEPLOYMENT_CRN"
config:
env:
# this overrides the setting in `.env`
CERC_WEBAPP_DEBUG: "$rcd_app_version"
CERC_MAX_GENERATE_TIME: "600"
meta:
note: "Added by CI @ `date`"
repository: "`git remote get-url origin`"
repository_ref: "${GITHUB_SHA:-`git log -1 --format="%H"`}"
EOF
cat $RECORD_FILE
RECORD_ID=$(laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE --user-key "${CERC_REGISTRY_USER_KEY}" --bond-id ${CERC_REGISTRY_BOND_ID} | jq -r '.id')
echo $RECORD_ID
rm -f $RECORD_FILE $CONFIG_FILE

View File

@ -11,27 +11,18 @@ export const WHITELIST_CODE_ID = parseInt(process.env.NEXT_PUBLIC_WHITELIST_CODE
export const WHITELIST_FLEX_CODE_ID = parseInt(process.env.NEXT_PUBLIC_WHITELIST_FLEX_CODE_ID, 10) export const WHITELIST_FLEX_CODE_ID = parseInt(process.env.NEXT_PUBLIC_WHITELIST_FLEX_CODE_ID, 10)
export const VENDING_MINTER_CODE_ID = parseInt(process.env.NEXT_PUBLIC_VENDING_MINTER_CODE_ID, 10) export const VENDING_MINTER_CODE_ID = parseInt(process.env.NEXT_PUBLIC_VENDING_MINTER_CODE_ID, 10)
export const VENDING_MINTER_FLEX_CODE_ID = parseInt(process.env.NEXT_PUBLIC_VENDING_MINTER_FLEX_CODE_ID, 10) export const VENDING_MINTER_FLEX_CODE_ID = parseInt(process.env.NEXT_PUBLIC_VENDING_MINTER_FLEX_CODE_ID, 10)
export const WHITELIST_MERKLE_TREE_CODE_ID = parseInt(process.env.NEXT_PUBLIC_WHITELIST_MERKLE_TREE_CODE_ID, 10)
export const VENDING_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_VENDING_FACTORY_ADDRESS export const VENDING_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_VENDING_FACTORY_ADDRESS
export const FEATURED_VENDING_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_FEATURED_VENDING_FACTORY_ADDRESS export const FEATURED_VENDING_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_FEATURED_VENDING_FACTORY_ADDRESS
export const VENDING_FACTORY_UPDATABLE_ADDRESS = process.env.NEXT_PUBLIC_VENDING_FACTORY_UPDATABLE_ADDRESS export const VENDING_FACTORY_UPDATABLE_ADDRESS = process.env.NEXT_PUBLIC_VENDING_FACTORY_UPDATABLE_ADDRESS
export const VENDING_FACTORY_FLEX_ADDRESS = process.env.NEXT_PUBLIC_VENDING_FACTORY_FLEX_ADDRESS export const VENDING_FACTORY_FLEX_ADDRESS = process.env.NEXT_PUBLIC_VENDING_FACTORY_FLEX_ADDRESS
export const VENDING_FACTORY_MERKLE_TREE_ADDRESS = process.env.NEXT_PUBLIC_VENDING_FACTORY_MERKLE_TREE_ADDRESS
export const FEATURED_VENDING_FACTORY_MERKLE_TREE_ADDRESS =
process.env.NEXT_PUBLIC_FEATURED_VENDING_FACTORY_MERKLE_TREE_ADDRESS
export const FEATURED_VENDING_FACTORY_FLEX_ADDRESS = process.env.NEXT_PUBLIC_FEATURED_VENDING_FACTORY_FLEX_ADDRESS export const FEATURED_VENDING_FACTORY_FLEX_ADDRESS = process.env.NEXT_PUBLIC_FEATURED_VENDING_FACTORY_FLEX_ADDRESS
export const VENDING_FACTORY_UPDATABLE_FLEX_ADDRESS = process.env.NEXT_PUBLIC_VENDING_FACTORY_UPDATABLE_FLEX_ADDRESS export const VENDING_FACTORY_UPDATABLE_FLEX_ADDRESS = process.env.NEXT_PUBLIC_VENDING_FACTORY_UPDATABLE_FLEX_ADDRESS
export const VENDING_IBC_ATOM_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_VENDING_IBC_ATOM_FACTORY_ADDRESS export const VENDING_IBC_ATOM_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_VENDING_IBC_ATOM_FACTORY_ADDRESS
export const VENDING_IBC_ATOM_UPDATABLE_FACTORY_ADDRESS = export const VENDING_IBC_ATOM_UPDATABLE_FACTORY_ADDRESS =
process.env.NEXT_PUBLIC_VENDING_IBC_ATOM_UPDATABLE_FACTORY_ADDRESS process.env.NEXT_PUBLIC_VENDING_IBC_ATOM_UPDATABLE_FACTORY_ADDRESS
export const VENDING_IBC_USDC_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_VENDING_IBC_USDC_FACTORY_ADDRESS export const VENDING_IBC_USDC_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_VENDING_IBC_USDC_FACTORY_ADDRESS
export const FEATURED_IBC_USDC_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_FEATURED_VENDING_IBC_USDC_FACTORY_ADDRESS
export const VENDING_IBC_USDC_UPDATABLE_FACTORY_ADDRESS = export const VENDING_IBC_USDC_UPDATABLE_FACTORY_ADDRESS =
process.env.NEXT_PUBLIC_VENDING_IBC_USDC_UPDATABLE_FACTORY_ADDRESS process.env.NEXT_PUBLIC_VENDING_IBC_USDC_UPDATABLE_FACTORY_ADDRESS
export const VENDING_IBC_TIA_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_VENDING_IBC_TIA_FACTORY_ADDRESS
export const FEATURED_IBC_TIA_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_FEATURED_VENDING_IBC_TIA_FACTORY_ADDRESS
export const VENDING_IBC_TIA_UPDATABLE_FACTORY_ADDRESS =
process.env.NEXT_PUBLIC_VENDING_IBC_TIA_UPDATABLE_FACTORY_ADDRESS
export const VENDING_IBC_NBTC_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_VENDING_IBC_NBTC_FACTORY_ADDRESS export const VENDING_IBC_NBTC_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_VENDING_IBC_NBTC_FACTORY_ADDRESS
export const VENDING_IBC_NBTC_UPDATABLE_FACTORY_ADDRESS = export const VENDING_IBC_NBTC_UPDATABLE_FACTORY_ADDRESS =
process.env.NEXT_PUBLIC_VENDING_IBC_NBTC_UPDATABLE_FACTORY_ADDRESS process.env.NEXT_PUBLIC_VENDING_IBC_NBTC_UPDATABLE_FACTORY_ADDRESS
@ -45,19 +36,8 @@ export const VENDING_IBC_ATOM_FACTORY_FLEX_ADDRESS = process.env.NEXT_PUBLIC_VEN
export const VENDING_IBC_ATOM_UPDATABLE_FACTORY_FLEX_ADDRESS = export const VENDING_IBC_ATOM_UPDATABLE_FACTORY_FLEX_ADDRESS =
process.env.NEXT_PUBLIC_VENDING_IBC_ATOM_UPDATABLE_FACTORY_FLEX_ADDRESS process.env.NEXT_PUBLIC_VENDING_IBC_ATOM_UPDATABLE_FACTORY_FLEX_ADDRESS
export const VENDING_IBC_USDC_FACTORY_FLEX_ADDRESS = process.env.NEXT_PUBLIC_VENDING_IBC_USDC_FACTORY_FLEX_ADDRESS export const VENDING_IBC_USDC_FACTORY_FLEX_ADDRESS = process.env.NEXT_PUBLIC_VENDING_IBC_USDC_FACTORY_FLEX_ADDRESS
export const FEATURED_VENDING_IBC_USDC_FACTORY_FLEX_ADDRESS =
process.env.NEXT_PUBLIC_FEATURED_VENDING_IBC_USDC_FACTORY_FLEX_ADDRESS
export const VENDING_IBC_USDC_UPDATABLE_FACTORY_FLEX_ADDRESS = export const VENDING_IBC_USDC_UPDATABLE_FACTORY_FLEX_ADDRESS =
process.env.NEXT_PUBLIC_VENDING_IBC_USDC_UPDATABLE_FACTORY_FLEX_ADDRESS process.env.NEXT_PUBLIC_VENDING_IBC_USDC_UPDATABLE_FACTORY_FLEX_ADDRESS
export const VENDING_IBC_TIA_FACTORY_FLEX_ADDRESS = process.env.NEXT_PUBLIC_VENDING_IBC_TIA_FACTORY_FLEX_ADDRESS
export const VENDING_IBC_TIA_FACTORY_MERKLE_TREE_ADDRESS =
process.env.NEXT_PUBLIC_VENDING_IBC_TIA_FACTORY_MERKLE_TREE_ADDRESS
export const FEATURED_VENDING_IBC_TIA_FACTORY_MERKLE_TREE_ADDRESS =
process.env.NEXT_PUBLIC_FEATURED_VENDING_IBC_TIA_FACTORY_MERKLE_TREE_ADDRESS
export const FEATURED_VENDING_IBC_TIA_FACTORY_FLEX_ADDRESS =
process.env.NEXT_PUBLIC_FEATURED_VENDING_IBC_TIA_FACTORY_FLEX_ADDRESS
export const VENDING_IBC_TIA_UPDATABLE_FACTORY_FLEX_ADDRESS =
process.env.NEXT_PUBLIC_VENDING_IBC_TIA_UPDATABLE_FACTORY_FLEX_ADDRESS
export const VENDING_IBC_NBTC_FACTORY_FLEX_ADDRESS = process.env.NEXT_PUBLIC_VENDING_IBC_NBTC_FACTORY_FLEX_ADDRESS export const VENDING_IBC_NBTC_FACTORY_FLEX_ADDRESS = process.env.NEXT_PUBLIC_VENDING_IBC_NBTC_FACTORY_FLEX_ADDRESS
export const VENDING_IBC_NBTC_UPDATABLE_FACTORY_FLEX_ADDRESS = export const VENDING_IBC_NBTC_UPDATABLE_FACTORY_FLEX_ADDRESS =
process.env.NEXT_PUBLIC_VENDING_IBC_NBTC_UPDATABLE_FACTORY_FLEX_ADDRESS process.env.NEXT_PUBLIC_VENDING_IBC_NBTC_UPDATABLE_FACTORY_FLEX_ADDRESS
@ -80,23 +60,13 @@ export const VENDING_NATIVE_BRNCH_FLEX_FACTORY_ADDRESS =
export const BASE_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_BASE_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 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_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_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_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 = export const OPEN_EDITION_UPDATABLE_IBC_ATOM_FACTORY_ADDRESS =
process.env.NEXT_PUBLIC_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_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 = export const OPEN_EDITION_UPDATABLE_IBC_USDC_FACTORY_ADDRESS =
process.env.NEXT_PUBLIC_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 export const OPEN_EDITION_IBC_NBTC_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_OPEN_EDITION_IBC_NBTC_FACTORY_ADDRESS
export const OPEN_EDITION_UPDATABLE_IBC_NBTC_FACTORY_ADDRESS = export const OPEN_EDITION_UPDATABLE_IBC_NBTC_FACTORY_ADDRESS =
process.env.NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_NBTC_FACTORY_ADDRESS process.env.NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_IBC_NBTC_FACTORY_ADDRESS
@ -132,8 +102,6 @@ export const STARGAZE_URL = process.env.NEXT_PUBLIC_STARGAZE_WEBSITE_URL
export const BLOCK_EXPLORER_URL = process.env.NEXT_PUBLIC_BLOCK_EXPLORER_URL export const BLOCK_EXPLORER_URL = process.env.NEXT_PUBLIC_BLOCK_EXPLORER_URL
export const WEBSITE_URL = process.env.NEXT_PUBLIC_WEBSITE_URL export const WEBSITE_URL = process.env.NEXT_PUBLIC_WEBSITE_URL
export const SYNC_COLLECTIONS_API_URL = process.env.NEXT_PUBLIC_SYNC_COLLECTIONS_API_URL export const SYNC_COLLECTIONS_API_URL = process.env.NEXT_PUBLIC_SYNC_COLLECTIONS_API_URL
export const WHITELIST_MERKLE_TREE_API_URL = process.env.NEXT_PUBLIC_WHITELIST_MERKLE_TREE_API_URL
export const NFT_STORAGE_DEFAULT_API_KEY = process.env.NEXT_PUBLIC_NFT_STORAGE_DEFAULT_API_KEY
export const MEILISEARCH_HOST = process.env.NEXT_PUBLIC_MEILISEARCH_HOST export const MEILISEARCH_HOST = process.env.NEXT_PUBLIC_MEILISEARCH_HOST
export const MEILISEARCH_API_KEY = process.env.NEXT_PUBLIC_MEILISEARCH_API_KEY export const MEILISEARCH_API_KEY = process.env.NEXT_PUBLIC_MEILISEARCH_API_KEY

View File

@ -4,14 +4,14 @@ import { toast } from 'react-hot-toast'
import { isValidAddress } from './isValidAddress' import { isValidAddress } from './isValidAddress'
export const isValidFlexListFile = (file: WhitelistFlexMember[]) => { export const isValidFlexListFile = (file: WhitelistFlexMember[]) => {
// let sumOfAmounts = 0 let sumOfAmounts = 0
// file.forEach((allocation) => { file.forEach((allocation) => {
// sumOfAmounts += Number(allocation.mint_count) sumOfAmounts += Number(allocation.mint_count)
// }) })
// if (sumOfAmounts > 10000) { if (sumOfAmounts > 10000) {
// toast.error(`Total mint count should be less than 10000 tokens (current count: ${sumOfAmounts}))`) toast.error(`Total mint count should be less than 10000 tokens (current count: ${sumOfAmounts}))`)
// return false return false
// } }
const checks = file.map((account) => { const checks = file.map((account) => {
// Check if address is valid bech32 address // Check if address is valid bech32 address

View File

@ -1,31 +0,0 @@
import sha256 from 'crypto-js/sha256'
import { MerkleTree } from 'merkletreejs'
export class WhitelistMerkleTree {
tree: MerkleTree
constructor(members: string[]) {
this.tree = new MerkleTree(
members.map((member) => sha256(member)),
sha256,
{
// sort: true,
// hashLeaves: false,
// sortLeaves: true,
sortPairs: true,
},
)
}
getMerkleRoot() {
return this.tree.getRoot().toString('hex')
}
getMerkleProof(member: string) {
console.log('this.tree.getProof(sha256(member).toString()): ', this.tree.getProof(sha256(member).toString()))
return this.tree.getProof(sha256(member).toString()).map((item) => item.data.toString('hex'))
}
verify(proof: string[], member: string) {
return this.tree.verify(proof, sha256(member).toString(), this.tree.getRoot())
}
}

3493
yarn.lock

File diff suppressed because it is too large Load Diff