diff --git a/.env.example b/.env.example index 86d57a2..e98f503 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,4 @@ -APP_VERSION=0.4.6 +APP_VERSION=0.4.7 NEXT_PUBLIC_PINATA_ENDPOINT_URL=https://api.pinata.cloud/pinning/pinFileToIPFS NEXT_PUBLIC_SG721_CODE_ID=793 diff --git a/components/collections/actions/Action.tsx b/components/collections/actions/Action.tsx index 68b0750..98cb7c3 100644 --- a/components/collections/actions/Action.tsx +++ b/components/collections/actions/Action.tsx @@ -114,8 +114,8 @@ export const CollectionActions = ({ const priceState = useNumberInputState({ id: 'update-mint-price', name: 'updateMintPrice', - title: 'Update Mint Price', - subtitle: 'New minting price in STARS', + title: type === 'update_discount_price' ? 'Discount Price' : 'Update Mint Price', + subtitle: type === 'update_discount_price' ? 'New discount price in STARS' : 'New minting price in STARS', }) const descriptionState = useInputState({ @@ -170,7 +170,7 @@ export const CollectionActions = ({ 'batch_mint_for', ]) const showAirdropFileField = type === 'airdrop' - const showPriceField = type === 'update_mint_price' + const showPriceField = isEitherType(type, ['update_mint_price', 'update_discount_price']) const showDescriptionField = type === 'update_collection_info' const showImageField = type === 'update_collection_info' const showExternalLinkField = type === 'update_collection_info' @@ -357,8 +357,8 @@ export const CollectionActions = ({ {showLimitField && } {showTokenIdField && } {showTokenIdListField && } - {showNumberOfTokensField && } - {showPriceField && } + {showNumberOfTokensField && } + {showPriceField && } {showDescriptionField && } {showImageField && } {showExternalLinkField && } diff --git a/components/collections/actions/actions.ts b/components/collections/actions/actions.ts index 98bff3f..021e83c 100644 --- a/components/collections/actions/actions.ts +++ b/components/collections/actions/actions.ts @@ -13,6 +13,8 @@ export const ACTION_TYPES = [ 'mint_token_uri', 'purge', 'update_mint_price', + 'update_discount_price', + 'remove_discount_price', 'mint_to', 'mint_for', 'batch_mint', @@ -87,16 +89,21 @@ export const VENDING_ACTION_LIST: ActionListItem[] = [ name: 'Mint', description: `Mint a token`, }, - { - id: 'purge', - name: 'Purge', - description: `Purge`, - }, { id: 'update_mint_price', name: 'Update Mint Price', description: `Update mint price`, }, + { + id: 'update_discount_price', + name: 'Update Discount Price', + description: `Update discount price`, + }, + { + id: 'remove_discount_price', + name: 'Remove Discount Price', + description: `Remove discount price`, + }, { id: 'mint_to', name: 'Mint To', @@ -182,6 +189,11 @@ export const VENDING_ACTION_LIST: ActionListItem[] = [ name: 'Burn Remaining Tokens', description: 'Burn remaining tokens', }, + { + id: 'purge', + name: 'Purge', + description: `Purge`, + }, ] export interface DispatchExecuteProps { @@ -205,6 +217,8 @@ export type DispatchExecuteArgs = { | { type: Select<'mint_token_uri'>; tokenUri: string } | { type: Select<'purge'> } | { type: Select<'update_mint_price'>; price: string } + | { type: Select<'update_discount_price'>; price: string } + | { type: Select<'remove_discount_price'> } | { type: Select<'mint_to'>; recipient: string } | { type: Select<'mint_for'>; recipient: string; tokenId: number } | { type: Select<'batch_mint'>; recipient: string; batchNumber: number } @@ -242,6 +256,12 @@ export const dispatchExecute = async (args: DispatchExecuteArgs) => { case 'update_mint_price': { return vendingMinterMessages.updateMintPrice(txSigner, args.price) } + case 'update_discount_price': { + return vendingMinterMessages.updateDiscountPrice(txSigner, args.price) + } + case 'remove_discount_price': { + return vendingMinterMessages.removeDiscountPrice(txSigner) + } case 'mint_to': { return vendingMinterMessages.mintTo(txSigner, args.recipient) } @@ -320,6 +340,12 @@ export const previewExecutePayload = (args: DispatchExecuteArgs) => { case 'update_mint_price': { return vendingMinterMessages(minterContract)?.updateMintPrice(args.price) } + case 'update_discount_price': { + return vendingMinterMessages(minterContract)?.updateDiscountPrice(args.price) + } + case 'remove_discount_price': { + return vendingMinterMessages(minterContract)?.removeDiscountPrice() + } case 'mint_to': { return vendingMinterMessages(minterContract)?.mintTo(args.recipient) } diff --git a/config/favicons.json b/config/favicons.json index 4cea67d..b7943a0 100644 --- a/config/favicons.json +++ b/config/favicons.json @@ -2,7 +2,7 @@ "path": "/assets/", "appName": "StargazeStudio", "appShortName": "StargazeStudio", - "appDescription": "Stargaze Studio is built to provide useful smart contract interfaces that helps you build and deploy your own NFT collection in no time.", + "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", "developerURL": "https://", "background": "#FFC27D", diff --git a/contracts/vendingMinter/contract.ts b/contracts/vendingMinter/contract.ts index f159f44..8483fa3 100644 --- a/contracts/vendingMinter/contract.ts +++ b/contracts/vendingMinter/contract.ts @@ -48,6 +48,8 @@ export interface VendingMinterInstance { withdraw: (senderAddress: string) => Promise airdrop: (senderAddress: string, recipients: string[]) => Promise burnRemaining: (senderAddress: string) => Promise + updateDiscountPrice: (senderAddress: string, price: string) => Promise + removeDiscountPrice: (senderAddress: string) => Promise } export interface VendingMinterMessages { @@ -66,6 +68,8 @@ export interface VendingMinterMessages { withdraw: () => WithdrawMessage airdrop: (recipients: string[]) => CustomMessage burnRemaining: () => BurnRemainingMessage + updateDiscountPrice: (price: string) => UpdateDiscountPriceMessage + removeDiscountPrice: () => RemoveDiscountPriceMessage } export interface MintMessage { @@ -97,6 +101,26 @@ export interface UpdateMintPriceMessage { funds: Coin[] } +export interface UpdateDiscountPriceMessage { + sender: string + contract: string + msg: { + update_discount_price: { + price: string + } + } + funds: Coin[] +} + +export interface RemoveDiscountPriceMessage { + sender: string + contract: string + msg: { + remove_discount_price: Record + } + funds: Coin[] +} + export interface SetWhitelistMessage { sender: string contract: string @@ -326,6 +350,36 @@ export const vendingMinter = (client: SigningCosmWasmClient, txSigner: string): return res.transactionHash } + const updateDiscountPrice = async (senderAddress: string, price: string): Promise => { + const res = await client.execute( + senderAddress, + contractAddress, + { + update_discount_price: { + price: (Number(price) * 1000000).toString(), + }, + }, + 'auto', + '', + ) + + return res.transactionHash + } + + const removeDiscountPrice = async (senderAddress: string): Promise => { + const res = await client.execute( + senderAddress, + contractAddress, + { + remove_discount_price: {}, + }, + 'auto', + '', + ) + + return res.transactionHash + } + const setWhitelist = async (senderAddress: string, whitelist: string): Promise => { const res = await client.execute( senderAddress, @@ -552,6 +606,8 @@ export const vendingMinter = (client: SigningCosmWasmClient, txSigner: string): mint, purge, updateMintPrice, + updateDiscountPrice, + removeDiscountPrice, setWhitelist, updateStartTime, updateStartTradingTime, @@ -633,6 +689,30 @@ export const vendingMinter = (client: SigningCosmWasmClient, txSigner: string): } } + const updateDiscountPrice = (price: string): UpdateDiscountPriceMessage => { + return { + sender: txSigner, + contract: contractAddress, + msg: { + update_discount_price: { + price: (Number(price) * 1000000).toString(), + }, + }, + funds: [], + } + } + + const removeDiscountPrice = (): RemoveDiscountPriceMessage => { + return { + sender: txSigner, + contract: contractAddress, + msg: { + remove_discount_price: {}, + }, + funds: [], + } + } + const setWhitelist = (whitelist: string): SetWhitelistMessage => { return { sender: txSigner, @@ -795,6 +875,8 @@ export const vendingMinter = (client: SigningCosmWasmClient, txSigner: string): mint, purge, updateMintPrice, + updateDiscountPrice, + removeDiscountPrice, setWhitelist, updateStartTime, updateStartTradingTime, diff --git a/contracts/vendingMinter/messages/execute.ts b/contracts/vendingMinter/messages/execute.ts index 391178f..d75f4e6 100644 --- a/contracts/vendingMinter/messages/execute.ts +++ b/contracts/vendingMinter/messages/execute.ts @@ -7,6 +7,8 @@ export const EXECUTE_TYPES = [ 'mint', 'purge', 'update_mint_price', + 'update_discount_price', + 'remove_discount_price', 'set_whitelist', 'update_start_time', 'update_start_trading_time', @@ -39,6 +41,16 @@ export const EXECUTE_LIST: ExecuteListItem[] = [ name: 'Update Mint Price', description: `Update mint price`, }, + { + id: 'update_discount_price', + name: 'Update Discount Price', + description: `Update discount price`, + }, + { + id: 'remove_discount_price', + name: 'Remove Discount Price', + description: `Remove discount price`, + }, { id: 'set_whitelist', name: 'Set Whitelist', @@ -98,6 +110,8 @@ export type DispatchExecuteArgs = { | { type: Select<'mint'> } | { type: Select<'purge'> } | { type: Select<'update_mint_price'>; price: string } + | { type: Select<'update_discount_price'>; price: string } + | { type: Select<'remove_discount_price'> } | { type: Select<'set_whitelist'>; whitelist: string } | { type: Select<'update_start_time'>; startTime: string } | { type: Select<'update_start_trading_time'>; startTime?: string } @@ -123,6 +137,12 @@ export const dispatchExecute = async (args: DispatchExecuteArgs) => { case 'update_mint_price': { return messages.updateMintPrice(txSigner, args.price) } + case 'update_discount_price': { + return messages.updateDiscountPrice(txSigner, args.price) + } + case 'remove_discount_price': { + return messages.removeDiscountPrice(txSigner) + } case 'set_whitelist': { return messages.setWhitelist(txSigner, args.whitelist) } @@ -167,6 +187,12 @@ export const previewExecutePayload = (args: DispatchExecuteArgs) => { case 'update_mint_price': { return messages(contract)?.updateMintPrice(args.price) } + case 'update_discount_price': { + return messages(contract)?.updateDiscountPrice(args.price) + } + case 'remove_discount_price': { + return messages(contract)?.removeDiscountPrice() + } case 'set_whitelist': { return messages(contract)?.setWhitelist(args.whitelist) } diff --git a/package.json b/package.json index 74fead5..213d0ac 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "stargaze-studio", - "version": "0.4.6", + "version": "0.4.7", "workspaces": [ "packages/*" ], diff --git a/pages/collections/create.tsx b/pages/collections/create.tsx index 1116be5..25dd566 100644 --- a/pages/collections/create.tsx +++ b/pages/collections/create.tsx @@ -748,12 +748,17 @@ const CollectionCreationPage: NextPage = () => { mintingDetails.perAddressLimit > mintingDetails.numTokens ) throw new Error('Invalid limit for tokens per address') + if (mintingDetails.numTokens < 100 && mintingDetails.perAddressLimit > 3) + throw new Error( + 'Invalid limit for tokens per address. Tokens per address limit cannot exceed 3 for collections with less than 100 tokens in total.', + ) if ( - mintingDetails.numTokens > 100 && - mintingDetails.numTokens < 100 * mintingDetails.perAddressLimit && - mintingDetails.perAddressLimit > mintingDetails.numTokens / 100 + mintingDetails.numTokens >= 100 && + mintingDetails.perAddressLimit > Math.ceil((mintingDetails.numTokens / 100) * 3) ) - throw new Error('Invalid limit for tokens per address. The limit cannot exceed 1% of the total number of tokens.') + throw new Error( + 'Invalid limit for tokens per address. Tokens per address limit cannot exceed 3% of the total number of tokens in the collection.', + ) if (mintingDetails.startTime === '') throw new Error('Start time is required') if (Number(mintingDetails.startTime) < new Date().getTime() * 1000000) throw new Error('Invalid start time') } diff --git a/pages/contracts/vendingMinter/execute.tsx b/pages/contracts/vendingMinter/execute.tsx index de73e62..17787e2 100644 --- a/pages/contracts/vendingMinter/execute.tsx +++ b/pages/contracts/vendingMinter/execute.tsx @@ -55,8 +55,8 @@ const VendingMinterExecutePage: NextPage = () => { const priceState = useNumberInputState({ id: 'price', name: 'price', - title: 'Price', - subtitle: 'Enter the token price', + title: type === 'update_discount_price' ? 'Discount Price' : 'Price', + subtitle: type === 'update_discount_price' ? 'New discount price in STARS' : 'Enter the token price', }) const contractState = useInputState({ @@ -86,7 +86,7 @@ const VendingMinterExecutePage: NextPage = () => { const showLimitField = type === 'update_per_address_limit' const showTokenIdField = type === 'mint_for' const showRecipientField = isEitherType(type, ['mint_to', 'mint_for']) - const showPriceField = type === 'update_mint_price' + const showPriceField = isEitherType(type, ['update_mint_price', 'update_discount_price']) const messages = useMemo(() => contract?.use(contractState.value), [contract, wallet.address, contractState.value]) const payload: DispatchExecuteArgs = { diff --git a/pages/index.tsx b/pages/index.tsx index d208893..22c0ac6 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -15,8 +15,8 @@ const HomePage: NextPage = () => { Looking for a fast and efficient way to build an NFT collection? Stargaze Studio is the solution.

- Stargaze Studio is built to provide useful smart contract interfaces that helps you build and deploy your own - NFT collections in no time. + Stargaze Studio is built to provide useful smart contract interfaces that help you build and deploy your own NFT + collections in no time.