diff --git a/.env.example b/.env.example index 1aae630..6f65221 100644 --- a/.env.example +++ b/.env.example @@ -3,6 +3,7 @@ APP_VERSION=0.7.11 NEXT_PUBLIC_PINATA_ENDPOINT_URL=https://api.pinata.cloud/pinning/pinFileToIPFS NEXT_PUBLIC_SG721_CODE_ID=2595 NEXT_PUBLIC_SG721_UPDATABLE_CODE_ID=2596 +NEXT_PUBLIC_STRDST_SG721_CODE_ID=2595 NEXT_PUBLIC_OPEN_EDITION_SG721_CODE_ID=2595 NEXT_PUBLIC_OPEN_EDITION_SG721_UPDATABLE_CODE_ID=2596 NEXT_PUBLIC_VENDING_MINTER_CODE_ID=2600 @@ -27,6 +28,7 @@ NEXT_PUBLIC_VENDING_FACTORY_UPDATABLE_FLEX_ADDRESS= # NEXT_PUBLIC_VENDING_NATIVE_STARDUST_FACTORY_ADDRESS="stars1mxwf2hjcjvqnlw0v3j7m0u34975qesp325wzrgz0ht7vr8ys2zmsenjutf" # NEXT_PUBLIC_VENDING_NATIVE_STARDUST_UPDATABLE_FACTORY_ADDRESS="stars18gjczf88jd4z3a3megwj9g5c9famu654csxfnnq59mkqeszuzy4ssdgr46" +# NEXT_PUBLIC_VENDING_NATIVE_STRDST_FLEX_FACTORY_ADDRESS="stars1..." NEXT_PUBLIC_BASE_FACTORY_ADDRESS="stars1a45hcxty3spnmm2f0papl8v4dk5ew29s4syhn4efte8u5haex99qlkrtnx" NEXT_PUBLIC_BASE_FACTORY_UPDATABLE_ADDRESS="stars100xegx2syry4tclkmejjwxk4nfqahvcqhm9qxut5wxuzhj5d9qfsh5nmym" diff --git a/components/FaviconsMetaTags.jsx b/components/FaviconsMetaTags.jsx index 94cc889..4fbe557 100644 --- a/components/FaviconsMetaTags.jsx +++ b/components/FaviconsMetaTags.jsx @@ -8,7 +8,7 @@ export function FaviconsMetaTags() { - + @@ -22,7 +22,7 @@ export function FaviconsMetaTags() { - + {

Unsupported Viewport

- StargazeStudio is best viewed on the big screen. + Stargaze Studio is best viewed on the big screen.
- Please open StargazeStudio on your tablet or desktop browser. + Please open Stargaze Studio on your tablet or desktop browser.

diff --git a/components/collections/actions/Action.tsx b/components/collections/actions/Action.tsx index 7667af7..e56f57a 100644 --- a/components/collections/actions/Action.tsx +++ b/components/collections/actions/Action.tsx @@ -181,7 +181,9 @@ export const CollectionActions = ({ type !== 'update_royalties_for_infinity_swap' ? 'Percentage of royalties to be paid' : 'Change in share percentage', - placeholder: '5%', + placeholder: isEitherType(type, ['set_royalties_for_infinity_swap', 'update_royalties_for_infinity_swap']) + ? '0.5%' + : '5%', }) const showTokenUriField = isEitherType(type, ['mint_token_uri', 'update_token_metadata']) @@ -310,6 +312,13 @@ export const CollectionActions = ({ royaltyShareState.value, ]) + useEffect(() => { + if (isEitherType(type, ['set_royalties_for_infinity_swap']) && Number(royaltyShareState.value) > 5) { + royaltyShareState.onChange('5') + toast.error('Royalty share cannot be greater than 5% for Infinity Swap') + } + }, [royaltyShareState.value]) + useEffect(() => { const addresses: string[] = [] airdropAllocationArray.forEach((allocation) => { diff --git a/components/collections/creation/UploadDetails.tsx b/components/collections/creation/UploadDetails.tsx index 8d78746..694ee47 100644 --- a/components/collections/creation/UploadDetails.tsx +++ b/components/collections/creation/UploadDetails.tsx @@ -119,7 +119,7 @@ export const UploadDetails = ({ if (event.target.files === null) return const thumbnailCompatibleAssetTypes: AssetType[] = ['video', 'audio', 'html'] const thumbnailCompatibleFileNamesList: string[] = [] - if (minterType === 'vending' || (minterType === 'base' && event.target.files.length > 1)) { + if (minterType === 'vending') { //sort the files const sortedFiles = Array.from(event.target.files).sort((a, b) => naturalCompare(a.name, b.name)) //check if the sorted file names are in numerical order @@ -146,6 +146,38 @@ export const UploadDetails = ({ return } } + } else if (minterType === 'base' && event.target.files.length > 1) { + //sort the files + const sortedFiles = Array.from(event.target.files).sort((a, b) => naturalCompare(a.name, b.name)) + //check if the sorted file names are in numerical order + const sortedFileNames = sortedFiles.map((file) => file.name.split('.')[0]) + sortedFiles.map((file) => { + if (thumbnailCompatibleAssetTypes.includes(getAssetType(file.name))) { + thumbnailCompatibleFileNamesList.push(file.name.split('.')[0]) + } + }) + setThumbnailCompatibleAssetFileNames(thumbnailCompatibleFileNamesList) + console.log('Thumbnail Compatible Files: ', thumbnailCompatibleFileNamesList) + + for (let i = 0; i < sortedFileNames.length - 1; i++) { + if ( + isNaN(Number(sortedFileNames[i])) || + isNaN(Number(sortedFileNames[i + 1])) || + parseInt(sortedFileNames[i]) !== parseInt(sortedFileNames[i + 1]) - 1 + ) { + toast.error('The file names should be in numerical order.') + setThumbnailCompatibleAssetFileNames([]) + addLogItem({ + id: uid(), + message: 'The file names should be in numerical order.', + type: 'Error', + timestamp: new Date(), + }) + //clear the input + event.target.value = '' + return + } + } } else if (minterType === 'base' && event.target.files.length === 1) { if (thumbnailCompatibleAssetTypes.includes(getAssetType(event.target.files[0].name))) { thumbnailCompatibleFileNamesList.push(event.target.files[0].name.split('.')[0]) @@ -186,7 +218,23 @@ export const UploadDetails = ({ event.target.value = '' return toast.error('The number of metadata files should be equal to the number of asset files.') } - if (minterType === 'vending' || (minterType === 'base' && assetFilesArray.length > 1)) { + // compare the first file name for asset and metadata files + if ( + minterType === 'base' && + assetFilesArray.length > 1 && + event.target.files[0].name.split('.')[0] !== assetFilesArray[0].name.split('.')[0] + ) { + event.target.value = '' + toast.error('The metadata file names should match the asset file names.') + addLogItem({ + id: uid(), + message: 'The metadata file names should match the asset file names.', + type: 'Error', + timestamp: new Date(), + }) + return + } + if (minterType === 'vending') { //sort the files const sortedFiles = Array.from(event.target.files).sort((a, b) => naturalCompare(a.name, b.name)) //check if the sorted file names are in numerical order @@ -204,6 +252,28 @@ export const UploadDetails = ({ return } } + } else if (minterType === 'base' && assetFilesArray.length > 1) { + //sort the files + const sortedFiles = Array.from(event.target.files).sort((a, b) => naturalCompare(a.name, b.name)) + //check if the sorted file names are in numerical order + const sortedFileNames = sortedFiles.map((file) => file.name.split('.')[0]) + for (let i = 0; i < sortedFileNames.length - 1; i++) { + if ( + isNaN(Number(sortedFileNames[i])) || + isNaN(Number(sortedFileNames[i + 1])) || + parseInt(sortedFileNames[i]) !== parseInt(sortedFileNames[i + 1]) - 1 + ) { + toast.error('The file names should be in numerical order.') + addLogItem({ + id: uid(), + message: 'The file names should be in numerical order.', + type: 'Error', + timestamp: new Date(), + }) + event.target.value = '' + return + } + } } let loadedFileCount = 0 const files: File[] = [] diff --git a/components/openEdition/CollectionDetails.tsx b/components/openEdition/CollectionDetails.tsx index e340f6a..9f71853 100644 --- a/components/openEdition/CollectionDetails.tsx +++ b/components/openEdition/CollectionDetails.tsx @@ -226,7 +226,7 @@ export const CollectionDetails = ({ {/* TODO: Cancel once we're able to index on-chain metadata */} - +
diff --git a/config/favicons.json b/config/favicons.json index b7943a0..b2d4851 100644 --- a/config/favicons.json +++ b/config/favicons.json @@ -1,9 +1,9 @@ { "path": "/assets/", - "appName": "StargazeStudio", - "appShortName": "StargazeStudio", + "appName": "Stargaze Studio", + "appShortName": "Stargaze Studio", "appDescription": "Stargaze Studio is built to provide useful smart contract interfaces that help you build and deploy your own NFT collection in no time.", - "developerName": "StargazeStudio", + "developerName": "Stargaze Studio", "developerURL": "https://", "background": "#FFC27D", "theme_color": "#FFC27D", diff --git a/config/meta.ts b/config/meta.ts index 66cbc1a..daa68f4 100644 --- a/config/meta.ts +++ b/config/meta.ts @@ -6,6 +6,6 @@ export const meta = { domain: 'stargaze.tools', url: faviconsJson.developerURL, twitter: { - username: '@stargazestudio', + username: '@StargazeZone', }, } diff --git a/config/minter.ts b/config/minter.ts index 6906b31..6a51ada 100644 --- a/config/minter.ts +++ b/config/minter.ts @@ -21,6 +21,7 @@ import { VENDING_IBC_USDC_UPDATABLE_FACTORY_FLEX_ADDRESS, VENDING_NATIVE_STARDUST_FACTORY_ADDRESS, VENDING_NATIVE_STARDUST_UPDATABLE_FACTORY_ADDRESS, + VENDING_NATIVE_STRDST_FLEX_FACTORY_ADDRESS, } from 'utils/constants' import type { TokenInfo } from './token' @@ -224,6 +225,14 @@ export const flexibleVendingUpdatableIbcUsdcMinter: MinterInfo = { flexible: true, } +export const flexibleVendingStrdstMinter: MinterInfo = { + id: 'flexible-vending-native-strdst-minter', + factoryAddress: VENDING_NATIVE_STRDST_FLEX_FACTORY_ADDRESS, + supportedToken: nativeStardust, + updatable: false, + flexible: true, +} + export const flexibleVendingMinterList = [ flexibleVendingStarsMinter, flexibleVendingUpdatableStarsMinter, @@ -231,4 +240,5 @@ export const flexibleVendingMinterList = [ flexibleVendingUpdatableIbcAtomMinter, flexibleVendingIbcUsdcMinter, flexibleVendingUpdatableIbcUsdcMinter, + flexibleVendingStrdstMinter, ] diff --git a/contracts/baseMinter/contract.ts b/contracts/baseMinter/contract.ts index 1945412..d02275a 100644 --- a/contracts/baseMinter/contract.ts +++ b/contracts/baseMinter/contract.ts @@ -33,13 +33,13 @@ export interface BaseMinterInstance { //Execute mint: (senderAddress: string, tokenUri: string) => Promise updateStartTradingTime: (senderAddress: string, time?: Timestamp) => Promise - batchMint: (senderAddress: string, recipient: string, batchCount: number) => Promise + batchMint: (senderAddress: string, recipient: string, batchCount: number, startFrom: number) => Promise } export interface BaseMinterMessages { mint: (tokenUri: string) => MintMessage updateStartTradingTime: (time: Timestamp) => UpdateStartTradingTimeMessage - batchMint: (recipient: string, batchNumber: number) => CustomMessage + batchMint: (recipient: string, batchNumber: number, startFrom: number) => CustomMessage } export interface MintMessage { @@ -178,7 +178,12 @@ export const baseMinter = (client: SigningCosmWasmClient, txSigner: string): Bas return res.transactionHash } - const batchMint = async (senderAddress: string, baseUri: string, batchCount: number): Promise => { + const batchMint = async ( + senderAddress: string, + baseUri: string, + batchCount: number, + startFrom: number, + ): Promise => { const txHash = await getConfig().then(async (response) => { const factoryParameters = await toast.promise(getFactoryParameters(response?.config?.factory), { loading: 'Querying Factory Parameters...', @@ -198,7 +203,7 @@ export const baseMinter = (client: SigningCosmWasmClient, txSigner: string): Bas const executeContractMsgs: MsgExecuteContractEncodeObject[] = [] for (let i = 0; i < batchCount; i++) { const msg = { - mint: { token_uri: `${baseUri}/${i + 1}` }, + mint: { token_uri: `${baseUri}/${i + startFrom}` }, } const executeContractMsg: MsgExecuteContractEncodeObject = { typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract', @@ -282,10 +287,10 @@ export const baseMinter = (client: SigningCosmWasmClient, txSigner: string): Bas } } - const batchMint = (baseUri: string, batchCount: number): CustomMessage => { + const batchMint = (baseUri: string, batchCount: number, startFrom: number): CustomMessage => { const msg: Record[] = [] for (let i = 0; i < batchCount; i++) { - msg.push({ mint: { token_uri: `${baseUri}/${i + 1}` } }) + msg.push({ mint: { token_uri: `${baseUri}/${i + startFrom}` } }) } return { sender: txSigner, diff --git a/env.d.ts b/env.d.ts index 15a9ca1..f221606 100644 --- a/env.d.ts +++ b/env.d.ts @@ -16,6 +16,7 @@ declare namespace NodeJS { readonly NEXT_PUBLIC_SG721_CODE_ID: string readonly NEXT_PUBLIC_SG721_UPDATABLE_CODE_ID: string + readonly NEXT_PUBLIC_STRDST_SG721_CODE_ID: string readonly NEXT_PUBLIC_OPEN_EDITION_SG721_CODE_ID: string readonly NEXT_PUBLIC_OPEN_EDITION_SG721_UPDATABLE_CODE_ID: string readonly NEXT_PUBLIC_WHITELIST_CODE_ID: string @@ -36,6 +37,7 @@ declare namespace NodeJS { readonly NEXT_PUBLIC_VENDING_IBC_USDC_UPDATABLE_FACTORY_FLEX_ADDRESS: string readonly NEXT_PUBLIC_VENDING_NATIVE_STARDUST_FACTORY_ADDRESS: string readonly NEXT_PUBLIC_VENDING_NATIVE_STARDUST_UPDATABLE_FACTORY_ADDRESS: string + readonly NEXT_PUBLIC_VENDING_NATIVE_STRDST_FLEX_FACTORY_ADDRESS: string readonly NEXT_PUBLIC_OPEN_EDITION_FACTORY_ADDRESS: string readonly NEXT_PUBLIC_OPEN_EDITION_UPDATABLE_FACTORY_ADDRESS: string readonly NEXT_PUBLIC_OPEN_EDITION_IBC_ATOM_FACTORY_ADDRESS: string diff --git a/pages/collections/create.tsx b/pages/collections/create.tsx index 0cb8db0..e08e87a 100644 --- a/pages/collections/create.tsx +++ b/pages/collections/create.tsx @@ -59,6 +59,7 @@ import { SG721_CODE_ID, SG721_UPDATABLE_CODE_ID, STARGAZE_URL, + STRDST_SG721_CODE_ID, SYNC_COLLECTIONS_API_URL, VENDING_FACTORY_ADDRESS, VENDING_FACTORY_FLEX_ADDRESS, @@ -448,7 +449,12 @@ const CollectionCreationPage: NextPage = () => { setBaseTokenUri(baseUri) const result = await baseMinterContract .use(baseMinterDetails?.existingBaseMinter as string) - ?.batchMint(wallet.address || '', `ipfs://${baseUri}`, uploadDetails.assetFiles.length) + ?.batchMint( + wallet.address || '', + `ipfs://${baseUri}`, + uploadDetails.assetFiles.length, + parseInt(uploadDetails.assetFiles[0].name.split('.')[0]), + ) console.log(result) return result }) @@ -568,7 +574,11 @@ const CollectionCreationPage: NextPage = () => { whitelist, }, collection_params: { - code_id: collectionDetails?.updatable ? SG721_UPDATABLE_CODE_ID : SG721_CODE_ID, + code_id: collectionDetails?.updatable + ? SG721_UPDATABLE_CODE_ID + : mintingDetails?.selectedMintToken?.displayName === 'STRDST' + ? STRDST_SG721_CODE_ID + : SG721_CODE_ID, name: collectionDetails?.name, symbol: collectionDetails?.symbol, info: { @@ -697,6 +707,7 @@ const CollectionCreationPage: NextPage = () => { wallet.address || '', baseUri, uploadDetails?.assetFiles.length as number, + parseInt(uploadDetails?.assetFiles[0].name.split('.')[0] as string), ) as Promise, { loading: 'Minting tokens...', diff --git a/pages/contracts/whitelist/instantiate.tsx b/pages/contracts/whitelist/instantiate.tsx index c64570c..316afd2 100644 --- a/pages/contracts/whitelist/instantiate.tsx +++ b/pages/contracts/whitelist/instantiate.tsx @@ -17,6 +17,9 @@ import { LinkTabs } from 'components/LinkTabs' import { whitelistLinkTabs } from 'components/LinkTabs.data' import { type WhitelistFlexMember, WhitelistFlexUpload } from 'components/WhitelistFlexUpload' import { WhitelistUpload } from 'components/WhitelistUpload' +import { vendingMinterList } from 'config/minter' +import type { TokenInfo } from 'config/token' +import { stars, tokensList } from 'config/token' import { useContracts } from 'contexts/contracts' import { useGlobalSettings } from 'contexts/globalSettings' import type { InstantiateResponse } from 'contracts/sg721' @@ -46,6 +49,8 @@ const WhitelistInstantiatePage: NextPage = () => { const [whitelistStandardArray, setWhitelistStandardArray] = useState([]) const [whitelistFlexArray, setWhitelistFlexArray] = useState([]) + const [selectedMintToken, setSelectedMintToken] = useState(stars) + const unitPriceState = useNumberInputState({ id: 'unit-price', name: 'unitPrice', @@ -97,7 +102,7 @@ const WhitelistInstantiatePage: NextPage = () => { members: whitelistStandardArray, start_time: (startDate.getTime() * 1_000_000).toString(), end_time: (endDate.getTime() * 1_000_000).toString(), - mint_price: coin(String(Number(unitPriceState.value) * 1000000), 'ustars'), + mint_price: coin(String(Number(unitPriceState.value) * 1000000), selectedMintToken?.denom || 'ustars'), per_address_limit: perAddressLimitState.value, member_limit: memberLimitState.value, admins: [ @@ -114,7 +119,7 @@ const WhitelistInstantiatePage: NextPage = () => { members: whitelistFlexArray, start_time: (startDate.getTime() * 1_000_000).toString(), end_time: (endDate.getTime() * 1_000_000).toString(), - mint_price: coin(String(Number(unitPriceState.value) * 1000000), 'ustars'), + mint_price: coin(String(Number(unitPriceState.value) * 1000000), selectedMintToken?.denom || 'ustars'), whale_cap: whaleCapState.value || undefined, member_limit: memberLimitState.value, admins: [ @@ -261,7 +266,23 @@ const WhitelistInstantiatePage: NextPage = () => { - +
+ + +
+ diff --git a/public/assets/manifest.webmanifest b/public/assets/manifest.webmanifest index 8cfc15a..eeee0ee 100644 --- a/public/assets/manifest.webmanifest +++ b/public/assets/manifest.webmanifest @@ -1,6 +1,6 @@ { - "name": "StargazeStudio", - "short_name": "StargazeStudio", + "name": "Stargaze Studio", + "short_name": "Stargaze Studio", "description": "Stargaze Studio is a dApp that helps you create and manage your collections on Stargaze by providing smart contract front ends", "dir": "auto", "lang": "en-US", diff --git a/utils/constants.ts b/utils/constants.ts index 12764e1..aeeef6f 100644 --- a/utils/constants.ts +++ b/utils/constants.ts @@ -1,5 +1,6 @@ export const SG721_CODE_ID = parseInt(process.env.NEXT_PUBLIC_SG721_CODE_ID, 10) export const SG721_UPDATABLE_CODE_ID = parseInt(process.env.NEXT_PUBLIC_SG721_UPDATABLE_CODE_ID, 10) +export const STRDST_SG721_CODE_ID = parseInt(process.env.NEXT_PUBLIC_STRDST_SG721_CODE_ID, 10) export const SG721_OPEN_EDITION_CODE_ID = parseInt(process.env.NEXT_PUBLIC_OPEN_EDITION_SG721_CODE_ID, 10) export const SG721_OPEN_EDITION_UPDATABLE_CODE_ID = parseInt( process.env.NEXT_PUBLIC_OPEN_EDITION_SG721_UPDATABLE_CODE_ID, @@ -28,6 +29,8 @@ export const VENDING_IBC_USDC_UPDATABLE_FACTORY_FLEX_ADDRESS = export const VENDING_NATIVE_STARDUST_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_VENDING_NATIVE_STARDUST_FACTORY_ADDRESS export const VENDING_NATIVE_STARDUST_UPDATABLE_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_VENDING_NATIVE_STARDUST_UPDATABLE_FACTORY_ADDRESS +export const VENDING_NATIVE_STRDST_FLEX_FACTORY_ADDRESS = + process.env.NEXT_PUBLIC_VENDING_NATIVE_STRDST_FLEX_FACTORY_ADDRESS export const BASE_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_BASE_FACTORY_ADDRESS export const BASE_FACTORY_UPDATABLE_ADDRESS = process.env.NEXT_PUBLIC_BASE_FACTORY_UPDATABLE_ADDRESS export const OPEN_EDITION_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_OPEN_EDITION_FACTORY_ADDRESS