Fetch minter creation fees prior to collection creation

This commit is contained in:
Serkan Reis 2023-04-01 16:45:49 +03:00
parent babdb5fb94
commit 1d1c35135f
8 changed files with 144 additions and 88 deletions

View File

@ -1,4 +1,4 @@
APP_VERSION=0.5.3 APP_VERSION=0.5.4
NEXT_PUBLIC_PINATA_ENDPOINT_URL=https://api.pinata.cloud/pinning/pinFileToIPFS NEXT_PUBLIC_PINATA_ENDPOINT_URL=https://api.pinata.cloud/pinning/pinFileToIPFS
NEXT_PUBLIC_SG721_CODE_ID=1911 NEXT_PUBLIC_SG721_CODE_ID=1911
@ -7,7 +7,7 @@ NEXT_PUBLIC_VENDING_MINTER_CODE_ID=1909
NEXT_PUBLIC_BASE_MINTER_CODE_ID=1910 NEXT_PUBLIC_BASE_MINTER_CODE_ID=1910
NEXT_PUBLIC_VENDING_FACTORY_ADDRESS="stars1ynec878x5phexq3hj4zdgvp6r5ayfmxks38kvunwyjugqn3hqeqq3cgtuw" NEXT_PUBLIC_VENDING_FACTORY_ADDRESS="stars1ynec878x5phexq3hj4zdgvp6r5ayfmxks38kvunwyjugqn3hqeqq3cgtuw"
NEXT_PUBLIC_VENDING_FACTORY_UPDATABLE_ADDRESS="stars1fnfywcnzzwledr93at65qm8gf953tjxgh6u2u4r8n9vsdv7u75eqe7ecn3" NEXT_PUBLIC_VENDING_FACTORY_UPDATABLE_ADDRESS="stars1fnfywcnzzwledr93at65qm8gf953tjxgh6u2u4r8n9vsdv7u75eqe7ecn3"
NEXT_PUBLIC_BASE_FACTORY_ADDRESS="stars1l0ylnyytlake550wyue5km77zzrqwfas3hna9agavjrzs73h33nqrx8zlg" NEXT_PUBLIC_BASE_FACTORY_ADDRESS="stars10rmaxgnjvskuumgv7e2awqkhdqdcygkwrz8a8vvt88szj7fc7xlq5jcs3f"
NEXT_PUBLIC_BASE_FACTORY_UPDATABLE_ADDRESS="stars13pw8r33dsnghlxfj2upaywf38z2fc6npuw9maq9e5cpet4v285sscgzjp2" NEXT_PUBLIC_BASE_FACTORY_UPDATABLE_ADDRESS="stars13pw8r33dsnghlxfj2upaywf38z2fc6npuw9maq9e5cpet4v285sscgzjp2"
NEXT_PUBLIC_SG721_NAME_ADDRESS="stars1fx74nkqkw2748av8j7ew7r3xt9cgjqduwn8m0ur5lhe49uhlsasszc5fhr" NEXT_PUBLIC_SG721_NAME_ADDRESS="stars1fx74nkqkw2748av8j7ew7r3xt9cgjqduwn8m0ur5lhe49uhlsasszc5fhr"
NEXT_PUBLIC_WHITELIST_CODE_ID=1913 NEXT_PUBLIC_WHITELIST_CODE_ID=1913

View File

@ -13,6 +13,7 @@ import { Tooltip } from 'components/Tooltip'
import type { ChangeEvent } from 'react' 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 { SG721_CODE_ID } from 'utils/constants'
import { TextInput } from '../../forms/FormInput' import { TextInput } from '../../forms/FormInput'
import type { MinterType } from '../actions/Combobox' import type { MinterType } from '../actions/Combobox'
@ -184,7 +185,9 @@ export const CollectionDetails = ({ onChange, uploadMethod, coverImageUrl, minte
<div className="max-w-[200px] max-h-[200px] rounded border-2"> <div className="max-w-[200px] max-h-[200px] rounded border-2">
<img <img
alt="no-preview-available" alt="no-preview-available"
src={`https://ipfs.io/ipfs/${coverImageUrl.substring(coverImageUrl.lastIndexOf('ipfs://') + 7)}`} src={`https://ipfs-gw.stargaze-apis.com/ipfs/${coverImageUrl.substring(
coverImageUrl.lastIndexOf('ipfs://') + 7,
)}`}
/> />
</div> </div>
)} )}
@ -242,7 +245,7 @@ export const CollectionDetails = ({ onChange, uploadMethod, coverImageUrl, minte
</div> </div>
</div> </div>
</div> </div>
<Conditional test={false}> <Conditional test={SG721_CODE_ID > 0}>
<Tooltip <Tooltip
backgroundColor="bg-blue-500" backgroundColor="bg-blue-500"
label={ label={

View File

@ -1,6 +1,5 @@
import type { SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate' import type { SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate'
import type { Coin } from '@cosmjs/proto-signing' import type { Coin } from '@cosmjs/proto-signing'
import { coin } from '@cosmjs/proto-signing'
import type { logs } from '@cosmjs/stargate' import type { logs } from '@cosmjs/stargate'
import { BASE_FACTORY_ADDRESS } from 'utils/constants' import { BASE_FACTORY_ADDRESS } from 'utils/constants'
@ -28,7 +27,7 @@ export interface BaseFactoryInstance {
} }
export interface BaseFactoryMessages { export interface BaseFactoryMessages {
createBaseMinter: (msg: Record<string, unknown>, updatable?: boolean) => CreateBaseMinterMessage createBaseMinter: (msg: Record<string, unknown>, funds: Coin[], updatable?: boolean) => CreateBaseMinterMessage
} }
export interface CreateBaseMinterMessage { export interface CreateBaseMinterMessage {
@ -86,12 +85,16 @@ export const baseFactory = (client: SigningCosmWasmClient, txSigner: string): Ba
} }
const messages = (contractAddress: string) => { const messages = (contractAddress: string) => {
const createBaseMinter = (msg: Record<string, unknown>, updatable?: boolean): CreateBaseMinterMessage => { const createBaseMinter = (
msg: Record<string, unknown>,
funds: Coin[],
updatable?: boolean,
): CreateBaseMinterMessage => {
return { return {
sender: txSigner, sender: txSigner,
contract: contractAddress, contract: contractAddress,
msg, msg,
funds: [coin(updatable ? '3000000000' : '250000000', 'ustars')], funds,
} }
} }

View File

@ -25,5 +25,5 @@ export const previewExecutePayload = (args: DispatchExecuteArgs) => {
// eslint-disable-next-line react-hooks/rules-of-hooks // eslint-disable-next-line react-hooks/rules-of-hooks
const { messages } = useBaseFactoryContract() const { messages } = useBaseFactoryContract()
const { contract } = args const { contract } = args
return messages(contract)?.createBaseMinter(args.msg, args.updatable) return messages(contract)?.createBaseMinter(args.msg, args.funds, args.updatable)
} }

View File

@ -6,7 +6,6 @@ import type { logs } from '@cosmjs/stargate'
import type { Timestamp } from '@stargazezone/types/contracts/minter/shared-types' import type { Timestamp } from '@stargazezone/types/contracts/minter/shared-types'
import { MsgExecuteContract } from 'cosmjs-types/cosmwasm/wasm/v1/tx' import { MsgExecuteContract } from 'cosmjs-types/cosmwasm/wasm/v1/tx'
import toast from 'react-hot-toast' import toast from 'react-hot-toast'
import { BASE_FACTORY_ADDRESS } from 'utils/constants'
export interface InstantiateResponse { export interface InstantiateResponse {
readonly contractAddress: string readonly contractAddress: string
@ -114,10 +113,9 @@ export interface BaseMinterContract {
export const baseMinter = (client: SigningCosmWasmClient, txSigner: string): BaseMinterContract => { export const baseMinter = (client: SigningCosmWasmClient, txSigner: string): BaseMinterContract => {
const use = (contractAddress: string): BaseMinterInstance => { const use = (contractAddress: string): BaseMinterInstance => {
//Query //Query
const getFactoryParameters = async (): Promise<any> => { const getFactoryParameters = async (factoryAddress: string): Promise<any> => {
const res = await client.queryContractSmart(BASE_FACTORY_ADDRESS, { params: {} }) const res = await client.queryContractSmart(factoryAddress, { params: {} })
return res return res
console.log(res)
} }
const getConfig = async (): Promise<any> => { const getConfig = async (): Promise<any> => {
@ -136,34 +134,34 @@ export const baseMinter = (client: SigningCosmWasmClient, txSigner: string): Bas
//Execute //Execute
const mint = async (senderAddress: string, tokenUri: string): Promise<string> => { const mint = async (senderAddress: string, tokenUri: string): Promise<string> => {
//const factoryParameters = await baseFactory?.use(BASE_FACTORY_ADDRESS)?.getParams() const txHash = await getConfig().then(async (response) => {
const factoryParameters = await toast.promise(getFactoryParameters(response.config?.factory), {
loading: 'Querying Factory Parameters...',
error: 'Querying Factory Parameters failed!',
success: 'Query successful! Minting...',
})
console.log(factoryParameters.params.mint_fee_bps)
const factoryParameters = await toast.promise(getFactoryParameters(), { const price = response.config?.mint_price.amount
loading: 'Querying Factory Parameters...', if (!price) {
error: 'Querying Factory Parameters failed!', throw new Error(
success: 'Query successful! Minting...', 'Unable to retrieve a valid mint price. It may be that the given contract address does not belong to a Base Minter contract.',
}) )
console.log(factoryParameters.params.mint_fee_bps) }
console.log((Number(price) * Number(factoryParameters.params.mint_fee_bps)) / 100)
const price = (await getConfig()).config?.mint_price.amount const res = await client.execute(
if (!price) { senderAddress,
throw new Error( contractAddress,
'Unable to retrieve a valid mint price. It may be that the given contract address does not belong to a Base Minter contract.', {
mint: { token_uri: tokenUri },
},
'auto',
'',
[coin((Number(price) * Number(factoryParameters.params.mint_fee_bps)) / 100 / 100, 'ustars')],
) )
} return res.transactionHash
console.log((Number(price) * Number(factoryParameters.params.mint_fee_bps)) / 100) })
const res = await client.execute( return txHash
senderAddress,
contractAddress,
{
mint: { token_uri: tokenUri },
},
'auto',
'',
[coin((Number(price) * Number(factoryParameters.params.mint_fee_bps)) / 100 / 100, 'ustars')],
)
return res.transactionHash
} }
const updateStartTradingTime = async (senderAddress: string, time?: Timestamp): Promise<string> => { const updateStartTradingTime = async (senderAddress: string, time?: Timestamp): Promise<string> => {
@ -181,42 +179,45 @@ export const baseMinter = (client: SigningCosmWasmClient, txSigner: string): Bas
} }
const batchMint = async (senderAddress: string, baseUri: string, batchCount: number): Promise<string> => { const batchMint = async (senderAddress: string, baseUri: string, batchCount: number): Promise<string> => {
const factoryParameters = await toast.promise(getFactoryParameters(), { const txHash = await getConfig().then(async (response) => {
loading: 'Querying Factory Parameters...', const factoryParameters = await toast.promise(getFactoryParameters(response?.config?.factory), {
error: 'Querying Factory Parameters failed!', loading: 'Querying Factory Parameters...',
success: 'Query successful! Minting...', error: 'Querying Factory Parameters failed!',
success: 'Query successful! Minting...',
})
console.log(factoryParameters.params.mint_fee_bps)
const price = response.config?.mint_price.amount
if (!price) {
throw new Error(
'Unable to retrieve a valid mint price. It may be that the given contract address does not belong to a Base Minter contract.',
)
}
console.log((Number(price) * Number(factoryParameters.params.mint_fee_bps)) / 100)
const executeContractMsgs: MsgExecuteContractEncodeObject[] = []
for (let i = 0; i < batchCount; i++) {
const msg = {
mint: { token_uri: `${baseUri}/${i + 1}` },
}
const executeContractMsg: MsgExecuteContractEncodeObject = {
typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract',
value: MsgExecuteContract.fromPartial({
sender: senderAddress,
contract: contractAddress,
msg: toUtf8(JSON.stringify(msg)),
funds: [coin((Number(price) * Number(factoryParameters.params.mint_fee_bps)) / 100 / 100, 'ustars')],
}),
}
executeContractMsgs.push(executeContractMsg)
}
const res = await client.signAndBroadcast(senderAddress, executeContractMsgs, 'auto', 'batch mint')
return res.transactionHash
}) })
console.log(factoryParameters.params.mint_fee_bps) return txHash
const price = (await getConfig()).config?.mint_price.amount
if (!price) {
throw new Error(
'Unable to retrieve a valid mint price. It may be that the given contract address does not belong to a Base Minter contract.',
)
}
console.log((Number(price) * Number(factoryParameters.params.mint_fee_bps)) / 100)
const executeContractMsgs: MsgExecuteContractEncodeObject[] = []
for (let i = 0; i < batchCount; i++) {
const msg = {
mint: { token_uri: `${baseUri}/${i + 1}` },
}
const executeContractMsg: MsgExecuteContractEncodeObject = {
typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract',
value: MsgExecuteContract.fromPartial({
sender: senderAddress,
contract: contractAddress,
msg: toUtf8(JSON.stringify(msg)),
funds: [coin((Number(price) * Number(factoryParameters.params.mint_fee_bps)) / 100 / 100, 'ustars')],
}),
}
executeContractMsgs.push(executeContractMsg)
}
const res = await client.signAndBroadcast(senderAddress, executeContractMsgs, 'auto', 'batch mint')
return res.transactionHash
} }
return { return {

View File

@ -1,6 +1,5 @@
import type { SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate' import type { SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate'
import type { Coin } from '@cosmjs/proto-signing' import type { Coin } from '@cosmjs/proto-signing'
import { coin } from '@cosmjs/proto-signing'
import type { logs } from '@cosmjs/stargate' import type { logs } from '@cosmjs/stargate'
import { VENDING_FACTORY_ADDRESS } from 'utils/constants' import { VENDING_FACTORY_ADDRESS } from 'utils/constants'
@ -28,7 +27,7 @@ export interface VendingFactoryInstance {
} }
export interface VendingFactoryMessages { export interface VendingFactoryMessages {
createVendingMinter: (msg: Record<string, unknown>, updatable?: boolean) => CreateVendingMinterMessage createVendingMinter: (msg: Record<string, unknown>, funds: Coin[], updatable?: boolean) => CreateVendingMinterMessage
} }
export interface CreateVendingMinterMessage { export interface CreateVendingMinterMessage {
@ -79,12 +78,16 @@ export const vendingFactory = (client: SigningCosmWasmClient, txSigner: string):
} }
const messages = (contractAddress: string) => { const messages = (contractAddress: string) => {
const createVendingMinter = (msg: Record<string, unknown>, updatable?: boolean): CreateVendingMinterMessage => { const createVendingMinter = (
msg: Record<string, unknown>,
funds: Coin[],
updatable?: boolean,
): CreateVendingMinterMessage => {
return { return {
sender: txSigner, sender: txSigner,
contract: contractAddress, contract: contractAddress,
msg, msg,
funds: [coin(updatable ? '5000000000' : '3000000000', 'ustars')], funds,
} }
} }

View File

@ -25,5 +25,5 @@ export const previewExecutePayload = (args: DispatchExecuteArgs) => {
// eslint-disable-next-line react-hooks/rules-of-hooks // eslint-disable-next-line react-hooks/rules-of-hooks
const { messages } = useVendingFactoryContract() const { messages } = useVendingFactoryContract()
const { contract } = args const { contract } = args
return messages(contract)?.createVendingMinter(args.msg, args.updatable) return messages(contract)?.createVendingMinter(args.msg, args.funds, args.updatable)
} }

View File

@ -88,6 +88,11 @@ 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<string | null>(null)
const [baseMinterCreationFee, setBaseMinterCreationFee] = useState<string | null>(null)
const [vendingMinterUpdatableCreationFee, setVendingMinterUpdatableCreationFee] = useState<string | null>(null)
const [baseMinterUpdatableCreationFee, setBaseMinterUpdatableCreationFee] = useState<string | null>(null)
const [uploading, setUploading] = useState(false) const [uploading, setUploading] = useState(false)
const [isMintingComplete, setIsMintingComplete] = useState(false) const [isMintingComplete, setIsMintingComplete] = useState(false)
const [creatingCollection, setCreatingCollection] = useState(false) const [creatingCollection, setCreatingCollection] = useState(false)
@ -452,7 +457,14 @@ const CollectionCreationPage: NextPage = () => {
messages: vendingFactoryMessages, messages: vendingFactoryMessages,
txSigner: wallet.address, txSigner: wallet.address,
msg, msg,
funds: [coin(collectionDetails?.updatable ? '5000000000' : '3000000000', 'ustars')], funds: [
coin(
collectionDetails?.updatable
? (vendingMinterUpdatableCreationFee as string)
: (vendingMinterCreationFee as string),
'ustars',
),
],
updatable: collectionDetails?.updatable, updatable: collectionDetails?.updatable,
} }
const data = await vendingFactoryDispatchExecute(payload) const data = await vendingFactoryDispatchExecute(payload)
@ -503,7 +515,12 @@ const CollectionCreationPage: NextPage = () => {
messages: baseFactoryMessages, messages: baseFactoryMessages,
txSigner: wallet.address, txSigner: wallet.address,
msg, msg,
funds: [coin(collectionDetails?.updatable ? '3000000000' : '250000000', 'ustars')], funds: [
coin(
collectionDetails?.updatable ? (baseMinterUpdatableCreationFee as string) : (baseMinterCreationFee as string),
'ustars',
),
],
updatable: collectionDetails?.updatable, updatable: collectionDetails?.updatable,
} }
await baseFactoryDispatchExecute(payload) await baseFactoryDispatchExecute(payload)
@ -864,12 +881,37 @@ const CollectionCreationPage: NextPage = () => {
} }
} }
const fetchFactoryParameters = async () => {
const client = wallet.client
if (!client) return
if (BASE_FACTORY_ADDRESS) {
const baseFactoryParameters = await client.queryContractSmart(BASE_FACTORY_ADDRESS, { params: {} })
setBaseMinterCreationFee(baseFactoryParameters?.params?.creation_fee?.amount)
}
if (BASE_FACTORY_UPDATABLE_ADDRESS) {
const baseFactoryUpdatableParameters = await client.queryContractSmart(BASE_FACTORY_UPDATABLE_ADDRESS, {
params: {},
})
setBaseMinterUpdatableCreationFee(baseFactoryUpdatableParameters?.params?.creation_fee?.amount)
}
if (VENDING_FACTORY_ADDRESS) {
const vendingFactoryParameters = await client.queryContractSmart(VENDING_FACTORY_ADDRESS, { params: {} })
setVendingMinterCreationFee(vendingFactoryParameters?.params?.creation_fee?.amount)
}
if (VENDING_FACTORY_UPDATABLE_ADDRESS) {
const vendingFactoryUpdatableParameters = await client.queryContractSmart(VENDING_FACTORY_UPDATABLE_ADDRESS, {
params: {},
})
setVendingMinterUpdatableCreationFee(vendingFactoryUpdatableParameters?.params?.creation_fee?.amount)
}
}
const checkwalletBalance = () => { const checkwalletBalance = () => {
if (!wallet.initialized) throw new Error('Wallet not connected.') if (!wallet.initialized) throw new Error('Wallet not connected.')
if (minterType === 'vending' && whitelistDetails?.whitelistType === 'new' && whitelistDetails.memberLimit) { if (minterType === 'vending' && whitelistDetails?.whitelistType === 'new' && whitelistDetails.memberLimit) {
const amountNeeded = const amountNeeded =
Math.ceil(Number(whitelistDetails.memberLimit) / 1000) * 100000000 + Math.ceil(Number(whitelistDetails.memberLimit) / 1000) * 100000000 +
(collectionDetails?.updatable ? 5000000000 : 3000000000) (collectionDetails?.updatable ? Number(vendingMinterUpdatableCreationFee) : Number(vendingMinterCreationFee))
if (amountNeeded >= Number(wallet.balance[0].amount)) if (amountNeeded >= Number(wallet.balance[0].amount))
throw new Error( throw new Error(
`Insufficient wallet balance to instantiate the required contracts. Needed amount: ${( `Insufficient wallet balance to instantiate the required contracts. Needed amount: ${(
@ -880,11 +922,11 @@ const CollectionCreationPage: NextPage = () => {
const amountNeeded = const amountNeeded =
minterType === 'vending' minterType === 'vending'
? collectionDetails?.updatable ? collectionDetails?.updatable
? 5000000000 ? Number(vendingMinterUpdatableCreationFee)
: 3000000000 : Number(vendingMinterCreationFee)
: collectionDetails?.updatable : collectionDetails?.updatable
? 3000000000 ? Number(baseMinterUpdatableCreationFee)
: 1000000000 : Number(baseMinterCreationFee)
if (amountNeeded >= Number(wallet.balance[0].amount)) if (amountNeeded >= Number(wallet.balance[0].amount))
throw new Error( throw new Error(
`Insufficient wallet balance to instantiate the required contracts. Needed amount: ${( `Insufficient wallet balance to instantiate the required contracts. Needed amount: ${(
@ -908,6 +950,10 @@ const CollectionCreationPage: NextPage = () => {
setIsMintingComplete(false) setIsMintingComplete(false)
}, [minterType, baseMinterDetails?.baseMinterAcquisitionMethod, uploadDetails?.uploadMethod]) }, [minterType, baseMinterDetails?.baseMinterAcquisitionMethod, uploadDetails?.uploadMethod])
useEffect(() => {
void fetchFactoryParameters()
}, [wallet.client])
return ( return (
<div> <div>
<NextSeo <NextSeo
@ -947,7 +993,7 @@ const CollectionCreationPage: NextPage = () => {
<Anchor <Anchor
className="text-stargaze hover:underline" className="text-stargaze hover:underline"
external external
href={`https://ipfs.stargaze.zone/ipfs/${baseTokenUri as string}`} href={`https://ipfs-gw.stargaze-apis.com/ipfs/${baseTokenUri as string}`}
> >
ipfs://{baseTokenUri as string} ipfs://{baseTokenUri as string}
</Anchor> </Anchor>
@ -956,7 +1002,7 @@ const CollectionCreationPage: NextPage = () => {
<Anchor <Anchor
className="text-stargaze hover:underline" className="text-stargaze hover:underline"
external external
href={`https://ipfs.stargaze.zone/ipfs/${baseTokenUri?.substring( href={`https://ipfs-gw.stargaze-apis.com/ipfs/${baseTokenUri?.substring(
baseTokenUri.lastIndexOf('ipfs://') + 7, baseTokenUri.lastIndexOf('ipfs://') + 7,
)}/`} )}/`}
> >