Merge branch 'develop' into hardcoded-wl-code-id
This commit is contained in:
commit
88f0c7ca93
17
.env.example
17
.env.example
@ -1,13 +1,16 @@
|
|||||||
APP_VERSION=0.4.8
|
APP_VERSION=0.4.9
|
||||||
|
|
||||||
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=1702
|
NEXT_PUBLIC_SG721_CODE_ID=1911
|
||||||
NEXT_PUBLIC_VENDING_MINTER_CODE_ID=1701
|
NEXT_PUBLIC_SG721_UPDATABLE_CODE_ID=1912
|
||||||
NEXT_PUBLIC_VENDING_FACTORY_ADDRESS="stars1xz4d6wzxqn3udgsm5qnr78y032xng4r2ycv7aw6mjtsuw59s2n9s93ec0v"
|
NEXT_PUBLIC_VENDING_MINTER_CODE_ID=1909
|
||||||
NEXT_PUBLIC_BASE_FACTORY_ADDRESS="stars1c6juqgd7cm80afpmuszun66rl9zdc4kgfht8fk34tfq3zk87l78sdxngzv"
|
NEXT_PUBLIC_BASE_MINTER_CODE_ID=1910
|
||||||
|
NEXT_PUBLIC_VENDING_FACTORY_ADDRESS="stars1ynec878x5phexq3hj4zdgvp6r5ayfmxks38kvunwyjugqn3hqeqq3cgtuw"
|
||||||
|
NEXT_PUBLIC_VENDING_FACTORY_UPDATABLE_ADDRESS="stars1fnfywcnzzwledr93at65qm8gf953tjxgh6u2u4r8n9vsdv7u75eqe7ecn3"
|
||||||
|
NEXT_PUBLIC_BASE_FACTORY_ADDRESS="stars1sr37phnuahzsc6tpner9875g3fy69khlgvvyzgs2vjtuupw6lffqd7lark"
|
||||||
|
NEXT_PUBLIC_BASE_FACTORY_UPDATABLE_ADDRESS="stars13pw8r33dsnghlxfj2upaywf38z2fc6npuw9maq9e5cpet4v285sscgzjp2"
|
||||||
NEXT_PUBLIC_SG721_NAME_ADDRESS="stars1fx74nkqkw2748av8j7ew7r3xt9cgjqduwn8m0ur5lhe49uhlsasszc5fhr"
|
NEXT_PUBLIC_SG721_NAME_ADDRESS="stars1fx74nkqkw2748av8j7ew7r3xt9cgjqduwn8m0ur5lhe49uhlsasszc5fhr"
|
||||||
NEXT_PUBLIC_BASE_MINTER_CODE_ID=613
|
NEXT_PUBLIC_WHITELIST_CODE_ID=1913
|
||||||
NEXT_PUBLIC_WHITELIST_CODE_ID=1835
|
|
||||||
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
|
||||||
|
@ -26,7 +26,7 @@ import { resolveAddress } from 'utils/resolveAddress'
|
|||||||
|
|
||||||
import type { CollectionInfo } from '../../../contracts/sg721/contract'
|
import type { CollectionInfo } from '../../../contracts/sg721/contract'
|
||||||
import { TextInput } from '../../forms/FormInput'
|
import { TextInput } from '../../forms/FormInput'
|
||||||
import type { MinterType } from './Combobox'
|
import type { MinterType, Sg721Type } from './Combobox'
|
||||||
|
|
||||||
interface CollectionActionsProps {
|
interface CollectionActionsProps {
|
||||||
minterContractAddress: string
|
minterContractAddress: string
|
||||||
@ -35,6 +35,7 @@ interface CollectionActionsProps {
|
|||||||
vendingMinterMessages: VendingMinterInstance | undefined
|
vendingMinterMessages: VendingMinterInstance | undefined
|
||||||
baseMinterMessages: BaseMinterInstance | undefined
|
baseMinterMessages: BaseMinterInstance | undefined
|
||||||
minterType: MinterType
|
minterType: MinterType
|
||||||
|
sg721Type: Sg721Type
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExplicitContentType = true | false | undefined
|
type ExplicitContentType = true | false | undefined
|
||||||
@ -46,6 +47,7 @@ export const CollectionActions = ({
|
|||||||
vendingMinterMessages,
|
vendingMinterMessages,
|
||||||
baseMinterMessages,
|
baseMinterMessages,
|
||||||
minterType,
|
minterType,
|
||||||
|
sg721Type,
|
||||||
}: CollectionActionsProps) => {
|
}: CollectionActionsProps) => {
|
||||||
const wallet = useWallet()
|
const wallet = useWallet()
|
||||||
const [lastTx, setLastTx] = useState('')
|
const [lastTx, setLastTx] = useState('')
|
||||||
@ -100,7 +102,15 @@ export const CollectionActions = ({
|
|||||||
id: 'token-uri',
|
id: 'token-uri',
|
||||||
name: 'tokenURI',
|
name: 'tokenURI',
|
||||||
title: 'Token URI',
|
title: 'Token URI',
|
||||||
subtitle: 'URI for the token to be minted',
|
subtitle: 'URI for the token',
|
||||||
|
placeholder: 'ipfs://',
|
||||||
|
})
|
||||||
|
|
||||||
|
const baseURIState = useInputState({
|
||||||
|
id: 'base-uri',
|
||||||
|
name: 'baseURI',
|
||||||
|
title: 'Base URI',
|
||||||
|
subtitle: 'Base URI to batch update token metadata with',
|
||||||
placeholder: 'ipfs://',
|
placeholder: 'ipfs://',
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -154,13 +164,18 @@ export const CollectionActions = ({
|
|||||||
placeholder: '5%',
|
placeholder: '5%',
|
||||||
})
|
})
|
||||||
|
|
||||||
const showTokenUriField = type === 'mint_token_uri'
|
const showTokenUriField = isEitherType(type, ['mint_token_uri', 'update_token_metadata'])
|
||||||
const showWhitelistField = type === 'set_whitelist'
|
const showWhitelistField = type === 'set_whitelist'
|
||||||
const showDateField = isEitherType(type, ['update_start_time', 'update_start_trading_time'])
|
const showDateField = isEitherType(type, ['update_start_time', 'update_start_trading_time'])
|
||||||
const showLimitField = type === 'update_per_address_limit'
|
const showLimitField = type === 'update_per_address_limit'
|
||||||
const showTokenIdField = isEitherType(type, ['transfer', 'mint_for', 'burn'])
|
const showTokenIdField = isEitherType(type, ['transfer', 'mint_for', 'burn', 'update_token_metadata'])
|
||||||
const showNumberOfTokensField = type === 'batch_mint'
|
const showNumberOfTokensField = type === 'batch_mint'
|
||||||
const showTokenIdListField = isEitherType(type, ['batch_burn', 'batch_transfer', 'batch_mint_for'])
|
const showTokenIdListField = isEitherType(type, [
|
||||||
|
'batch_burn',
|
||||||
|
'batch_transfer',
|
||||||
|
'batch_mint_for',
|
||||||
|
'batch_update_token_metadata',
|
||||||
|
])
|
||||||
const showRecipientField = isEitherType(type, [
|
const showRecipientField = isEitherType(type, [
|
||||||
'transfer',
|
'transfer',
|
||||||
'mint_to',
|
'mint_to',
|
||||||
@ -176,6 +191,7 @@ export const CollectionActions = ({
|
|||||||
const showExternalLinkField = type === 'update_collection_info'
|
const showExternalLinkField = type === 'update_collection_info'
|
||||||
const showRoyaltyRelatedFields = type === 'update_collection_info'
|
const showRoyaltyRelatedFields = type === 'update_collection_info'
|
||||||
const showExplicitContentField = type === 'update_collection_info'
|
const showExplicitContentField = type === 'update_collection_info'
|
||||||
|
const showBaseUriField = type === 'batch_update_token_metadata'
|
||||||
|
|
||||||
const payload: DispatchExecuteArgs = {
|
const payload: DispatchExecuteArgs = {
|
||||||
whitelist: whitelistState.value,
|
whitelist: whitelistState.value,
|
||||||
@ -185,7 +201,9 @@ export const CollectionActions = ({
|
|||||||
sg721Contract: sg721ContractAddress,
|
sg721Contract: sg721ContractAddress,
|
||||||
tokenId: tokenIdState.value,
|
tokenId: tokenIdState.value,
|
||||||
tokenIds: tokenIdListState.value,
|
tokenIds: tokenIdListState.value,
|
||||||
tokenUri: tokenURIState.value,
|
tokenUri: tokenURIState.value.trim().endsWith('/')
|
||||||
|
? tokenURIState.value.trim().slice(0, -1)
|
||||||
|
: tokenURIState.value.trim(),
|
||||||
batchNumber: batchNumberState.value,
|
batchNumber: batchNumberState.value,
|
||||||
vendingMinterMessages,
|
vendingMinterMessages,
|
||||||
baseMinterMessages,
|
baseMinterMessages,
|
||||||
@ -195,6 +213,9 @@ export const CollectionActions = ({
|
|||||||
txSigner: wallet.address,
|
txSigner: wallet.address,
|
||||||
type,
|
type,
|
||||||
price: priceState.value.toString(),
|
price: priceState.value.toString(),
|
||||||
|
baseUri: baseURIState.value.trim().endsWith('/')
|
||||||
|
? baseURIState.value.trim().slice(0, -1)
|
||||||
|
: baseURIState.value.trim(),
|
||||||
collectionInfo,
|
collectionInfo,
|
||||||
}
|
}
|
||||||
const resolveRecipientAddress = async () => {
|
const resolveRecipientAddress = async () => {
|
||||||
@ -350,13 +371,14 @@ export const CollectionActions = ({
|
|||||||
<form>
|
<form>
|
||||||
<div className="grid grid-cols-2 mt-4">
|
<div className="grid grid-cols-2 mt-4">
|
||||||
<div className="mr-2">
|
<div className="mr-2">
|
||||||
<ActionsCombobox minterType={minterType} {...actionComboboxState} />
|
<ActionsCombobox minterType={minterType} sg721Type={sg721Type} {...actionComboboxState} />
|
||||||
{showRecipientField && <AddressInput {...recipientState} />}
|
{showRecipientField && <AddressInput {...recipientState} />}
|
||||||
{showTokenUriField && <TextInput className="mt-2" {...tokenURIState} />}
|
{showTokenUriField && <TextInput className="mt-2" {...tokenURIState} />}
|
||||||
{showWhitelistField && <AddressInput {...whitelistState} />}
|
{showWhitelistField && <AddressInput {...whitelistState} />}
|
||||||
{showLimitField && <NumberInput {...limitState} />}
|
{showLimitField && <NumberInput {...limitState} />}
|
||||||
{showTokenIdField && <NumberInput {...tokenIdState} />}
|
{showTokenIdField && <NumberInput className="mt-2" {...tokenIdState} />}
|
||||||
{showTokenIdListField && <TextInput className="mt-2" {...tokenIdListState} />}
|
{showTokenIdListField && <TextInput className="mt-2" {...tokenIdListState} />}
|
||||||
|
{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} />}
|
||||||
{showDescriptionField && <TextInput className="my-2" {...descriptionState} />}
|
{showDescriptionField && <TextInput className="my-2" {...descriptionState} />}
|
||||||
|
@ -6,27 +6,31 @@ import { Fragment, useEffect, useState } from 'react'
|
|||||||
import { FaChevronDown, FaInfoCircle } from 'react-icons/fa'
|
import { FaChevronDown, FaInfoCircle } from 'react-icons/fa'
|
||||||
|
|
||||||
import type { ActionListItem } from './actions'
|
import type { ActionListItem } from './actions'
|
||||||
import { BASE_ACTION_LIST, VENDING_ACTION_LIST } from './actions'
|
import { BASE_ACTION_LIST, SG721_UPDATABLE_ACTION_LIST, VENDING_ACTION_LIST } from './actions'
|
||||||
|
|
||||||
export type MinterType = 'base' | 'vending'
|
export type MinterType = 'base' | 'vending'
|
||||||
|
export type Sg721Type = 'updatable' | 'base'
|
||||||
|
|
||||||
export interface ActionsComboboxProps {
|
export interface ActionsComboboxProps {
|
||||||
value: ActionListItem | null
|
value: ActionListItem | null
|
||||||
onChange: (item: ActionListItem) => void
|
onChange: (item: ActionListItem) => void
|
||||||
minterType?: MinterType
|
minterType?: MinterType
|
||||||
|
sg721Type?: Sg721Type
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ActionsCombobox = ({ value, onChange, minterType }: ActionsComboboxProps) => {
|
export const ActionsCombobox = ({ value, onChange, minterType, sg721Type }: ActionsComboboxProps) => {
|
||||||
const [search, setSearch] = useState('')
|
const [search, setSearch] = useState('')
|
||||||
const [ACTION_LIST, SET_ACTION_LIST] = useState<ActionListItem[]>(VENDING_ACTION_LIST)
|
const [ACTION_LIST, SET_ACTION_LIST] = useState<ActionListItem[]>(VENDING_ACTION_LIST)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (minterType === 'base') {
|
if (minterType === 'base') {
|
||||||
SET_ACTION_LIST(BASE_ACTION_LIST)
|
if (sg721Type === 'updatable') SET_ACTION_LIST(BASE_ACTION_LIST.concat(SG721_UPDATABLE_ACTION_LIST))
|
||||||
} else {
|
else SET_ACTION_LIST(BASE_ACTION_LIST)
|
||||||
SET_ACTION_LIST(VENDING_ACTION_LIST)
|
} else if (minterType === 'vending') {
|
||||||
}
|
if (sg721Type === 'updatable') SET_ACTION_LIST(VENDING_ACTION_LIST.concat(SG721_UPDATABLE_ACTION_LIST))
|
||||||
}, [minterType])
|
else SET_ACTION_LIST(VENDING_ACTION_LIST)
|
||||||
|
} else SET_ACTION_LIST(VENDING_ACTION_LIST.concat(SG721_UPDATABLE_ACTION_LIST))
|
||||||
|
}, [minterType, sg721Type])
|
||||||
|
|
||||||
const filtered =
|
const filtered =
|
||||||
search === '' ? ACTION_LIST : matchSorter(ACTION_LIST, search, { keys: ['id', 'name', 'description'] })
|
search === '' ? ACTION_LIST : matchSorter(ACTION_LIST, search, { keys: ['id', 'name', 'description'] })
|
||||||
|
@ -9,9 +9,7 @@ import type { BaseMinterInstance } from '../../../contracts/baseMinter/contract'
|
|||||||
export type ActionType = typeof ACTION_TYPES[number]
|
export type ActionType = typeof ACTION_TYPES[number]
|
||||||
|
|
||||||
export const ACTION_TYPES = [
|
export const ACTION_TYPES = [
|
||||||
'mint',
|
|
||||||
'mint_token_uri',
|
'mint_token_uri',
|
||||||
'purge',
|
|
||||||
'update_mint_price',
|
'update_mint_price',
|
||||||
'update_discount_price',
|
'update_discount_price',
|
||||||
'remove_discount_price',
|
'remove_discount_price',
|
||||||
@ -32,6 +30,9 @@ export const ACTION_TYPES = [
|
|||||||
'shuffle',
|
'shuffle',
|
||||||
'airdrop',
|
'airdrop',
|
||||||
'burn_remaining',
|
'burn_remaining',
|
||||||
|
'update_token_metadata',
|
||||||
|
'batch_update_token_metadata',
|
||||||
|
'freeze_token_metadata',
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
export interface ActionListItem {
|
export interface ActionListItem {
|
||||||
@ -84,11 +85,6 @@ export const BASE_ACTION_LIST: ActionListItem[] = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
export const VENDING_ACTION_LIST: ActionListItem[] = [
|
export const VENDING_ACTION_LIST: ActionListItem[] = [
|
||||||
{
|
|
||||||
id: 'mint',
|
|
||||||
name: 'Mint',
|
|
||||||
description: `Mint a token`,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'update_mint_price',
|
id: 'update_mint_price',
|
||||||
name: 'Update Mint Price',
|
name: 'Update Mint Price',
|
||||||
@ -111,7 +107,7 @@ export const VENDING_ACTION_LIST: ActionListItem[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'batch_mint',
|
id: 'batch_mint',
|
||||||
name: 'Batch Mint',
|
name: 'Batch Mint To',
|
||||||
description: `Mint multiple tokens to a user`,
|
description: `Mint multiple tokens to a user`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -189,10 +185,23 @@ export const VENDING_ACTION_LIST: ActionListItem[] = [
|
|||||||
name: 'Burn Remaining Tokens',
|
name: 'Burn Remaining Tokens',
|
||||||
description: 'Burn remaining tokens',
|
description: 'Burn remaining tokens',
|
||||||
},
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export const SG721_UPDATABLE_ACTION_LIST: ActionListItem[] = [
|
||||||
{
|
{
|
||||||
id: 'purge',
|
id: 'update_token_metadata',
|
||||||
name: 'Purge',
|
name: 'Update Token Metadata',
|
||||||
description: `Purge`,
|
description: `Update the metadata URI for a token`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'batch_update_token_metadata',
|
||||||
|
name: 'Batch Update Token Metadata',
|
||||||
|
description: `Update the metadata URI for a range of tokens`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'freeze_token_metadata',
|
||||||
|
name: 'Freeze Token Metadata',
|
||||||
|
description: `Render the metadata for tokens no longer updatable`,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -213,9 +222,7 @@ export type DispatchExecuteArgs = {
|
|||||||
txSigner: string
|
txSigner: string
|
||||||
} & (
|
} & (
|
||||||
| { type: undefined }
|
| { type: undefined }
|
||||||
| { type: Select<'mint'> }
|
|
||||||
| { type: Select<'mint_token_uri'>; tokenUri: string }
|
| { type: Select<'mint_token_uri'>; tokenUri: string }
|
||||||
| { type: Select<'purge'> }
|
|
||||||
| { type: Select<'update_mint_price'>; price: string }
|
| { type: Select<'update_mint_price'>; price: string }
|
||||||
| { type: Select<'update_discount_price'>; price: string }
|
| { type: Select<'update_discount_price'>; price: string }
|
||||||
| { type: Select<'remove_discount_price'> }
|
| { type: Select<'remove_discount_price'> }
|
||||||
@ -236,6 +243,9 @@ export type DispatchExecuteArgs = {
|
|||||||
| { type: Select<'burn_remaining'> }
|
| { type: Select<'burn_remaining'> }
|
||||||
| { type: Select<'update_collection_info'>; collectionInfo: CollectionInfo | undefined }
|
| { type: Select<'update_collection_info'>; collectionInfo: CollectionInfo | undefined }
|
||||||
| { type: Select<'freeze_collection_info'> }
|
| { type: Select<'freeze_collection_info'> }
|
||||||
|
| { type: Select<'update_token_metadata'>; tokenId: number; tokenUri: string }
|
||||||
|
| { type: Select<'batch_update_token_metadata'>; tokenIds: string; baseUri: string }
|
||||||
|
| { type: Select<'freeze_token_metadata'> }
|
||||||
)
|
)
|
||||||
|
|
||||||
export const dispatchExecute = async (args: DispatchExecuteArgs) => {
|
export const dispatchExecute = async (args: DispatchExecuteArgs) => {
|
||||||
@ -244,15 +254,9 @@ export const dispatchExecute = async (args: DispatchExecuteArgs) => {
|
|||||||
throw new Error('Cannot execute actions')
|
throw new Error('Cannot execute actions')
|
||||||
}
|
}
|
||||||
switch (args.type) {
|
switch (args.type) {
|
||||||
case 'mint': {
|
|
||||||
return vendingMinterMessages.mint(txSigner)
|
|
||||||
}
|
|
||||||
case 'mint_token_uri': {
|
case 'mint_token_uri': {
|
||||||
return baseMinterMessages.mint(txSigner, args.tokenUri)
|
return baseMinterMessages.mint(txSigner, args.tokenUri)
|
||||||
}
|
}
|
||||||
case 'purge': {
|
|
||||||
return vendingMinterMessages.purge(txSigner)
|
|
||||||
}
|
|
||||||
case 'update_mint_price': {
|
case 'update_mint_price': {
|
||||||
return vendingMinterMessages.updateMintPrice(txSigner, args.price)
|
return vendingMinterMessages.updateMintPrice(txSigner, args.price)
|
||||||
}
|
}
|
||||||
@ -289,6 +293,15 @@ export const dispatchExecute = async (args: DispatchExecuteArgs) => {
|
|||||||
case 'freeze_collection_info': {
|
case 'freeze_collection_info': {
|
||||||
return sg721Messages.freezeCollectionInfo()
|
return sg721Messages.freezeCollectionInfo()
|
||||||
}
|
}
|
||||||
|
case 'update_token_metadata': {
|
||||||
|
return sg721Messages.updateTokenMetadata(args.tokenId.toString(), args.tokenUri)
|
||||||
|
}
|
||||||
|
case 'batch_update_token_metadata': {
|
||||||
|
return sg721Messages.batchUpdateTokenMetadata(args.tokenIds, args.baseUri)
|
||||||
|
}
|
||||||
|
case 'freeze_token_metadata': {
|
||||||
|
return sg721Messages.freezeTokenMetadata()
|
||||||
|
}
|
||||||
case 'shuffle': {
|
case 'shuffle': {
|
||||||
return vendingMinterMessages.shuffle(txSigner)
|
return vendingMinterMessages.shuffle(txSigner)
|
||||||
}
|
}
|
||||||
@ -328,15 +341,9 @@ export const previewExecutePayload = (args: DispatchExecuteArgs) => {
|
|||||||
const { messages: baseMinterMessages } = useBaseMinterContract()
|
const { messages: baseMinterMessages } = useBaseMinterContract()
|
||||||
const { minterContract, sg721Contract } = args
|
const { minterContract, sg721Contract } = args
|
||||||
switch (args.type) {
|
switch (args.type) {
|
||||||
case 'mint': {
|
|
||||||
return vendingMinterMessages(minterContract)?.mint()
|
|
||||||
}
|
|
||||||
case 'mint_token_uri': {
|
case 'mint_token_uri': {
|
||||||
return baseMinterMessages(minterContract)?.mint(args.tokenUri)
|
return baseMinterMessages(minterContract)?.mint(args.tokenUri)
|
||||||
}
|
}
|
||||||
case 'purge': {
|
|
||||||
return vendingMinterMessages(minterContract)?.purge()
|
|
||||||
}
|
|
||||||
case 'update_mint_price': {
|
case 'update_mint_price': {
|
||||||
return vendingMinterMessages(minterContract)?.updateMintPrice(args.price)
|
return vendingMinterMessages(minterContract)?.updateMintPrice(args.price)
|
||||||
}
|
}
|
||||||
@ -373,6 +380,15 @@ export const previewExecutePayload = (args: DispatchExecuteArgs) => {
|
|||||||
case 'freeze_collection_info': {
|
case 'freeze_collection_info': {
|
||||||
return sg721Messages(sg721Contract)?.freezeCollectionInfo()
|
return sg721Messages(sg721Contract)?.freezeCollectionInfo()
|
||||||
}
|
}
|
||||||
|
case 'update_token_metadata': {
|
||||||
|
return sg721Messages(sg721Contract)?.updateTokenMetadata(args.tokenId.toString(), args.tokenUri)
|
||||||
|
}
|
||||||
|
case 'batch_update_token_metadata': {
|
||||||
|
return sg721Messages(sg721Contract)?.batchUpdateTokenMetadata(args.tokenIds, args.baseUri)
|
||||||
|
}
|
||||||
|
case 'freeze_token_metadata': {
|
||||||
|
return sg721Messages(sg721Contract)?.freezeTokenMetadata()
|
||||||
|
}
|
||||||
case 'shuffle': {
|
case 'shuffle': {
|
||||||
return vendingMinterMessages(minterContract)?.shuffle()
|
return vendingMinterMessages(minterContract)?.shuffle()
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,9 @@ import { FormControl } from 'components/FormControl'
|
|||||||
import { FormGroup } from 'components/FormGroup'
|
import { FormGroup } from 'components/FormGroup'
|
||||||
import { useInputState } from 'components/forms/FormInput.hooks'
|
import { useInputState } from 'components/forms/FormInput.hooks'
|
||||||
import { InputDateTime } from 'components/InputDateTime'
|
import { InputDateTime } from 'components/InputDateTime'
|
||||||
|
import { Tooltip } from 'components/Tooltip'
|
||||||
import type { ChangeEvent } from 'react'
|
import type { ChangeEvent } from 'react'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { toast } from 'react-hot-toast'
|
import { toast } from 'react-hot-toast'
|
||||||
|
|
||||||
import { TextInput } from '../../forms/FormInput'
|
import { TextInput } from '../../forms/FormInput'
|
||||||
@ -31,12 +32,16 @@ export interface CollectionDetailsDataProps {
|
|||||||
externalLink?: string
|
externalLink?: string
|
||||||
startTradingTime?: string
|
startTradingTime?: string
|
||||||
explicit: boolean
|
explicit: boolean
|
||||||
|
updatable: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CollectionDetails = ({ onChange, uploadMethod, coverImageUrl, minterType }: CollectionDetailsProps) => {
|
export const CollectionDetails = ({ onChange, uploadMethod, coverImageUrl, minterType }: CollectionDetailsProps) => {
|
||||||
const [coverImage, setCoverImage] = useState<File | null>(null)
|
const [coverImage, setCoverImage] = useState<File | null>(null)
|
||||||
const [timestamp, setTimestamp] = useState<Date | undefined>()
|
const [timestamp, setTimestamp] = useState<Date | undefined>()
|
||||||
const [explicit, setExplicit] = useState<boolean>(false)
|
const [explicit, setExplicit] = useState<boolean>(false)
|
||||||
|
const [updatable, setUpdatable] = useState<boolean>(false)
|
||||||
|
|
||||||
|
const initialRender = useRef(true)
|
||||||
|
|
||||||
const nameState = useInputState({
|
const nameState = useInputState({
|
||||||
id: 'name',
|
id: 'name',
|
||||||
@ -76,6 +81,7 @@ export const CollectionDetails = ({ onChange, uploadMethod, coverImageUrl, minte
|
|||||||
externalLink: externalLinkState.value || undefined,
|
externalLink: externalLinkState.value || undefined,
|
||||||
startTradingTime: timestamp ? (timestamp.getTime() * 1_000_000).toString() : '',
|
startTradingTime: timestamp ? (timestamp.getTime() * 1_000_000).toString() : '',
|
||||||
explicit,
|
explicit,
|
||||||
|
updatable,
|
||||||
}
|
}
|
||||||
onChange(data)
|
onChange(data)
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
@ -91,6 +97,7 @@ export const CollectionDetails = ({ onChange, uploadMethod, coverImageUrl, minte
|
|||||||
coverImage,
|
coverImage,
|
||||||
timestamp,
|
timestamp,
|
||||||
explicit,
|
explicit,
|
||||||
|
updatable,
|
||||||
])
|
])
|
||||||
|
|
||||||
const selectCoverImage = (event: ChangeEvent<HTMLInputElement>) => {
|
const selectCoverImage = (event: ChangeEvent<HTMLInputElement>) => {
|
||||||
@ -109,6 +116,22 @@ export const CollectionDetails = ({ onChange, uploadMethod, coverImageUrl, minte
|
|||||||
reader.readAsArrayBuffer(event.target.files[0])
|
reader.readAsArrayBuffer(event.target.files[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (initialRender.current) {
|
||||||
|
initialRender.current = false
|
||||||
|
} else if (updatable) {
|
||||||
|
toast.success('Token metadata will be updatable upon collection creation.', {
|
||||||
|
style: { maxWidth: 'none' },
|
||||||
|
icon: '✅📝',
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
toast.error('Token metadata will not be updatable upon collection creation.', {
|
||||||
|
style: { maxWidth: 'none' },
|
||||||
|
icon: '⛔🔏',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [updatable])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<FormGroup subtitle="Information about your collection" title="Collection Details">
|
<FormGroup subtitle="Information about your collection" title="Collection Details">
|
||||||
@ -174,7 +197,7 @@ export const CollectionDetails = ({ onChange, uploadMethod, coverImageUrl, minte
|
|||||||
<div className={clsx(minterType === 'base' ? 'flex flex-col -ml-16 space-y-2' : 'flex flex-col space-y-2')}>
|
<div className={clsx(minterType === 'base' ? 'flex flex-col -ml-16 space-y-2' : 'flex flex-col space-y-2')}>
|
||||||
<div>
|
<div>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<span className="mt-1 text-sm first-letter:capitalize">
|
<span className="mt-1 ml-[2px] text-sm first-letter:capitalize">
|
||||||
Does the collection contain explicit content?
|
Does the collection contain explicit content?
|
||||||
</span>
|
</span>
|
||||||
<div className="ml-2 font-bold form-check form-check-inline">
|
<div className="ml-2 font-bold form-check form-check-inline">
|
||||||
@ -216,6 +239,35 @@ export const CollectionDetails = ({ onChange, uploadMethod, coverImageUrl, minte
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Tooltip
|
||||||
|
label={
|
||||||
|
<div className="grid grid-flow-row">
|
||||||
|
<span>
|
||||||
|
ℹ️ When enabled, the metadata for tokens can be updated after the collection is created until the
|
||||||
|
metadata is frozen by the creator.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
placement="bottom"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={clsx(
|
||||||
|
minterType === 'base'
|
||||||
|
? 'flex flex-col -ml-16 space-y-2 w-1/2 form-control'
|
||||||
|
: 'flex flex-col space-y-2 w-3/4 form-control',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<label className="justify-start cursor-pointer label">
|
||||||
|
<span className="mr-4 font-bold">Updatable Token Metadata</span>
|
||||||
|
<input
|
||||||
|
checked={updatable}
|
||||||
|
className={`toggle ${updatable ? `bg-stargaze` : `bg-gray-600`}`}
|
||||||
|
onClick={() => setUpdatable(!updatable)}
|
||||||
|
type="checkbox"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -4,6 +4,8 @@ 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'
|
||||||
|
|
||||||
|
import { BASE_FACTORY_UPDATABLE_ADDRESS } from '../../utils/constants'
|
||||||
|
|
||||||
export interface CreateBaseMinterResponse {
|
export interface CreateBaseMinterResponse {
|
||||||
readonly baseMinterAddress: string
|
readonly baseMinterAddress: string
|
||||||
readonly sg721Address: string
|
readonly sg721Address: string
|
||||||
@ -21,11 +23,12 @@ export interface BaseFactoryInstance {
|
|||||||
senderAddress: string,
|
senderAddress: string,
|
||||||
msg: Record<string, unknown>,
|
msg: Record<string, unknown>,
|
||||||
funds: Coin[],
|
funds: Coin[],
|
||||||
|
updatable?: boolean,
|
||||||
) => Promise<CreateBaseMinterResponse>
|
) => Promise<CreateBaseMinterResponse>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BaseFactoryMessages {
|
export interface BaseFactoryMessages {
|
||||||
createBaseMinter: (msg: Record<string, unknown>) => CreateBaseMinterMessage
|
createBaseMinter: (msg: Record<string, unknown>, updatable?: boolean) => CreateBaseMinterMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateBaseMinterMessage {
|
export interface CreateBaseMinterMessage {
|
||||||
@ -56,8 +59,16 @@ export const baseFactory = (client: SigningCosmWasmClient, txSigner: string): Ba
|
|||||||
senderAddress: string,
|
senderAddress: string,
|
||||||
msg: Record<string, unknown>,
|
msg: Record<string, unknown>,
|
||||||
funds: Coin[],
|
funds: Coin[],
|
||||||
|
updatable?: boolean,
|
||||||
): Promise<CreateBaseMinterResponse> => {
|
): Promise<CreateBaseMinterResponse> => {
|
||||||
const result = await client.execute(senderAddress, BASE_FACTORY_ADDRESS, msg, 'auto', '', funds)
|
const result = await client.execute(
|
||||||
|
senderAddress,
|
||||||
|
updatable ? BASE_FACTORY_UPDATABLE_ADDRESS : BASE_FACTORY_ADDRESS,
|
||||||
|
msg,
|
||||||
|
'auto',
|
||||||
|
'',
|
||||||
|
funds,
|
||||||
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
baseMinterAddress: result.logs[0].events[5].attributes[0].value,
|
baseMinterAddress: result.logs[0].events[5].attributes[0].value,
|
||||||
@ -75,12 +86,12 @@ export const baseFactory = (client: SigningCosmWasmClient, txSigner: string): Ba
|
|||||||
}
|
}
|
||||||
|
|
||||||
const messages = (contractAddress: string) => {
|
const messages = (contractAddress: string) => {
|
||||||
const createBaseMinter = (msg: Record<string, unknown>): CreateBaseMinterMessage => {
|
const createBaseMinter = (msg: Record<string, unknown>, updatable?: boolean): CreateBaseMinterMessage => {
|
||||||
return {
|
return {
|
||||||
sender: txSigner,
|
sender: txSigner,
|
||||||
contract: contractAddress,
|
contract: contractAddress,
|
||||||
msg,
|
msg,
|
||||||
funds: [coin('1000000000', 'ustars')],
|
funds: [coin(updatable ? '3000000000' : '1000000000', 'ustars')],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ export interface DispatchExecuteArgs {
|
|||||||
txSigner: string
|
txSigner: string
|
||||||
msg: Record<string, unknown>
|
msg: Record<string, unknown>
|
||||||
funds: Coin[]
|
funds: Coin[]
|
||||||
|
updatable?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const dispatchExecute = async (args: DispatchExecuteArgs) => {
|
export const dispatchExecute = async (args: DispatchExecuteArgs) => {
|
||||||
@ -17,12 +18,12 @@ export const dispatchExecute = async (args: DispatchExecuteArgs) => {
|
|||||||
if (!messages) {
|
if (!messages) {
|
||||||
throw new Error('cannot dispatch execute, messages is not defined')
|
throw new Error('cannot dispatch execute, messages is not defined')
|
||||||
}
|
}
|
||||||
return messages.createBaseMinter(txSigner, args.msg, args.funds)
|
return messages.createBaseMinter(txSigner, args.msg, args.funds, args.updatable)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const previewExecutePayload = (args: DispatchExecuteArgs) => {
|
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)
|
return messages(contract)?.createBaseMinter(args.msg, args.updatable)
|
||||||
}
|
}
|
||||||
|
@ -86,6 +86,9 @@ export interface SG721Instance {
|
|||||||
burn: (tokenId: string) => Promise<string>
|
burn: (tokenId: string) => Promise<string>
|
||||||
batchBurn: (tokenIds: string) => Promise<string>
|
batchBurn: (tokenIds: string) => Promise<string>
|
||||||
batchTransfer: (recipient: string, tokenIds: string) => Promise<string>
|
batchTransfer: (recipient: string, tokenIds: string) => Promise<string>
|
||||||
|
updateTokenMetadata: (tokenId: string, tokenURI: string) => Promise<string>
|
||||||
|
batchUpdateTokenMetadata: (tokenIds: string, tokenURI: string) => Promise<string>
|
||||||
|
freezeTokenMetadata: () => Promise<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Sg721Messages {
|
export interface Sg721Messages {
|
||||||
@ -101,6 +104,9 @@ export interface Sg721Messages {
|
|||||||
batchTransfer: (recipient: string, tokenIds: string) => BatchTransferMessage
|
batchTransfer: (recipient: string, tokenIds: string) => BatchTransferMessage
|
||||||
updateCollectionInfo: (collectionInfo: CollectionInfo) => UpdateCollectionInfoMessage
|
updateCollectionInfo: (collectionInfo: CollectionInfo) => UpdateCollectionInfoMessage
|
||||||
freezeCollectionInfo: () => FreezeCollectionInfoMessage
|
freezeCollectionInfo: () => FreezeCollectionInfoMessage
|
||||||
|
updateTokenMetadata: (tokenId: string, tokenURI: string) => UpdateTokenMetadataMessage
|
||||||
|
batchUpdateTokenMetadata: (tokenIds: string, tokenURI: string) => BatchUpdateTokenMetadataMessage
|
||||||
|
freezeTokenMetadata: () => FreezeTokenMetadataMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TransferNFTMessage {
|
export interface TransferNFTMessage {
|
||||||
@ -215,6 +221,32 @@ export interface BatchTransferMessage {
|
|||||||
funds: Coin[]
|
funds: Coin[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UpdateTokenMetadataMessage {
|
||||||
|
sender: string
|
||||||
|
contract: string
|
||||||
|
msg: {
|
||||||
|
update_token_metadata: {
|
||||||
|
token_id: string
|
||||||
|
token_uri: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
funds: Coin[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BatchUpdateTokenMetadataMessage {
|
||||||
|
sender: string
|
||||||
|
contract: string
|
||||||
|
msg: Record<string, unknown>[]
|
||||||
|
funds: Coin[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FreezeTokenMetadataMessage {
|
||||||
|
sender: string
|
||||||
|
contract: string
|
||||||
|
msg: { freeze_token_metadata: Record<string, never> }
|
||||||
|
funds: Coin[]
|
||||||
|
}
|
||||||
|
|
||||||
export interface UpdateCollectionInfoMessage {
|
export interface UpdateCollectionInfoMessage {
|
||||||
sender: string
|
sender: string
|
||||||
contract: string
|
contract: string
|
||||||
@ -570,6 +602,65 @@ export const SG721 = (client: SigningCosmWasmClient, txSigner: string): SG721Con
|
|||||||
return res.transactionHash
|
return res.transactionHash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const batchUpdateTokenMetadata = async (tokenIds: string, baseURI: string): Promise<string> => {
|
||||||
|
const executeContractMsgs: MsgExecuteContractEncodeObject[] = []
|
||||||
|
if (tokenIds.includes(':')) {
|
||||||
|
const [start, end] = tokenIds.split(':').map(Number)
|
||||||
|
for (let i = start; i <= end; i++) {
|
||||||
|
const msg = {
|
||||||
|
update_token_metadata: { token_id: i.toString(), token_uri: `${baseURI}/${i}` },
|
||||||
|
}
|
||||||
|
const executeContractMsg: MsgExecuteContractEncodeObject = {
|
||||||
|
typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract',
|
||||||
|
value: MsgExecuteContract.fromPartial({
|
||||||
|
sender: txSigner,
|
||||||
|
contract: contractAddress,
|
||||||
|
msg: toUtf8(JSON.stringify(msg)),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
executeContractMsgs.push(executeContractMsg)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const tokenNumbers = tokenIds.split(',').map(Number)
|
||||||
|
for (let i = 0; i < tokenNumbers.length; i++) {
|
||||||
|
const msg = {
|
||||||
|
update_token_metadata: { token_id: tokenNumbers[i].toString(), token_uri: `${baseURI}/${tokenNumbers[i]}` },
|
||||||
|
}
|
||||||
|
const executeContractMsg: MsgExecuteContractEncodeObject = {
|
||||||
|
typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract',
|
||||||
|
value: MsgExecuteContract.fromPartial({
|
||||||
|
sender: txSigner,
|
||||||
|
contract: contractAddress,
|
||||||
|
msg: toUtf8(JSON.stringify(msg)),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
executeContractMsgs.push(executeContractMsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await client.signAndBroadcast(txSigner, executeContractMsgs, 'auto', 'batch update metadata')
|
||||||
|
|
||||||
|
return res.transactionHash
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateTokenMetadata = async (tokenId: string, tokenURI: string): Promise<string> => {
|
||||||
|
const res = await client.execute(
|
||||||
|
txSigner,
|
||||||
|
contractAddress,
|
||||||
|
{
|
||||||
|
update_token_metadata: {
|
||||||
|
token_id: tokenId,
|
||||||
|
token_uri: tokenURI,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'auto',
|
||||||
|
'',
|
||||||
|
)
|
||||||
|
return res.transactionHash
|
||||||
|
}
|
||||||
|
|
||||||
const freezeCollectionInfo = async (): Promise<string> => {
|
const freezeCollectionInfo = async (): Promise<string> => {
|
||||||
const res = await client.execute(
|
const res = await client.execute(
|
||||||
txSigner,
|
txSigner,
|
||||||
@ -583,6 +674,19 @@ export const SG721 = (client: SigningCosmWasmClient, txSigner: string): SG721Con
|
|||||||
return res.transactionHash
|
return res.transactionHash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const freezeTokenMetadata = async (): Promise<string> => {
|
||||||
|
const res = await client.execute(
|
||||||
|
txSigner,
|
||||||
|
contractAddress,
|
||||||
|
{
|
||||||
|
freeze_token_metadata: {},
|
||||||
|
},
|
||||||
|
'auto',
|
||||||
|
'',
|
||||||
|
)
|
||||||
|
return res.transactionHash
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
contractAddress,
|
contractAddress,
|
||||||
ownerOf,
|
ownerOf,
|
||||||
@ -609,6 +713,9 @@ export const SG721 = (client: SigningCosmWasmClient, txSigner: string): SG721Con
|
|||||||
batchTransfer,
|
batchTransfer,
|
||||||
updateCollectionInfo,
|
updateCollectionInfo,
|
||||||
freezeCollectionInfo,
|
freezeCollectionInfo,
|
||||||
|
updateTokenMetadata,
|
||||||
|
batchUpdateTokenMetadata,
|
||||||
|
freezeTokenMetadata,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -804,6 +911,58 @@ export const SG721 = (client: SigningCosmWasmClient, txSigner: string): SG721Con
|
|||||||
funds: [],
|
funds: [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const batchUpdateTokenMetadata = (tokenIds: string, baseURI: string): BatchUpdateTokenMetadataMessage => {
|
||||||
|
const msg: Record<string, unknown>[] = []
|
||||||
|
if (tokenIds.includes(':')) {
|
||||||
|
const [start, end] = tokenIds.split(':').map(Number)
|
||||||
|
for (let i = start; i <= end; i++) {
|
||||||
|
msg.push({
|
||||||
|
update_token_metadata: { token_id: i.toString(), token_uri: `${baseURI}/${i}` },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const tokenNumbers = tokenIds.split(',').map(Number)
|
||||||
|
for (let i = 0; i < tokenNumbers.length; i++) {
|
||||||
|
msg.push({
|
||||||
|
update_token_metadata: { token_id: tokenNumbers[i].toString(), token_uri: `${baseURI}/${tokenNumbers[i]}` },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
sender: txSigner,
|
||||||
|
contract: contractAddress,
|
||||||
|
msg,
|
||||||
|
funds: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateTokenMetadata = (tokenId: string, tokenURI: string) => {
|
||||||
|
return {
|
||||||
|
sender: txSigner,
|
||||||
|
contract: contractAddress,
|
||||||
|
msg: {
|
||||||
|
update_token_metadata: {
|
||||||
|
token_id: tokenId,
|
||||||
|
token_uri: tokenURI,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
funds: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const freezeTokenMetadata = () => {
|
||||||
|
return {
|
||||||
|
sender: txSigner,
|
||||||
|
contract: contractAddress,
|
||||||
|
msg: {
|
||||||
|
freeze_token_metadata: {},
|
||||||
|
},
|
||||||
|
funds: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const updateCollectionInfo = (collectionInfo: CollectionInfo) => {
|
const updateCollectionInfo = (collectionInfo: CollectionInfo) => {
|
||||||
return {
|
return {
|
||||||
sender: txSigner,
|
sender: txSigner,
|
||||||
@ -814,6 +973,7 @@ export const SG721 = (client: SigningCosmWasmClient, txSigner: string): SG721Con
|
|||||||
funds: [],
|
funds: [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const freezeCollectionInfo = () => {
|
const freezeCollectionInfo = () => {
|
||||||
return {
|
return {
|
||||||
sender: txSigner,
|
sender: txSigner,
|
||||||
@ -838,6 +998,9 @@ export const SG721 = (client: SigningCosmWasmClient, txSigner: string): SG721Con
|
|||||||
batchTransfer,
|
batchTransfer,
|
||||||
updateCollectionInfo,
|
updateCollectionInfo,
|
||||||
freezeCollectionInfo,
|
freezeCollectionInfo,
|
||||||
|
updateTokenMetadata,
|
||||||
|
batchUpdateTokenMetadata,
|
||||||
|
freezeTokenMetadata,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@ export const EXECUTE_TYPES = [
|
|||||||
'revoke_all',
|
'revoke_all',
|
||||||
'mint',
|
'mint',
|
||||||
'burn',
|
'burn',
|
||||||
|
'update_token_metadata',
|
||||||
|
'freeze_token_metadata',
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
export interface ExecuteListItem {
|
export interface ExecuteListItem {
|
||||||
@ -61,6 +63,16 @@ export const EXECUTE_LIST: ExecuteListItem[] = [
|
|||||||
name: 'Burn',
|
name: 'Burn',
|
||||||
description: `Burn a token transaction sender has access to`,
|
description: `Burn a token transaction sender has access to`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'update_token_metadata',
|
||||||
|
name: 'Update Token Metadata',
|
||||||
|
description: `Update the metadata URI for a token`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'freeze_token_metadata',
|
||||||
|
name: 'Freeze Token Metadata',
|
||||||
|
description: `Render the metadata for tokens no longer updatable`,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export interface DispatchExecuteProps {
|
export interface DispatchExecuteProps {
|
||||||
@ -84,6 +96,8 @@ export type DispatchExecuteArgs = {
|
|||||||
| { type: Select<'revoke_all'>; operator: string }
|
| { type: Select<'revoke_all'>; operator: string }
|
||||||
| { type: Select<'mint'>; recipient: string; tokenId: string; tokenURI?: string }
|
| { type: Select<'mint'>; recipient: string; tokenId: string; tokenURI?: string }
|
||||||
| { type: Select<'burn'>; tokenId: string }
|
| { type: Select<'burn'>; tokenId: string }
|
||||||
|
| { type: Select<'update_token_metadata'>; tokenId: string; tokenURI: string }
|
||||||
|
| { type: Select<'freeze_token_metadata'> }
|
||||||
)
|
)
|
||||||
|
|
||||||
export const dispatchExecute = async (args: DispatchExecuteArgs) => {
|
export const dispatchExecute = async (args: DispatchExecuteArgs) => {
|
||||||
@ -116,6 +130,12 @@ export const dispatchExecute = async (args: DispatchExecuteArgs) => {
|
|||||||
case 'burn': {
|
case 'burn': {
|
||||||
return messages.burn(args.tokenId)
|
return messages.burn(args.tokenId)
|
||||||
}
|
}
|
||||||
|
case 'update_token_metadata': {
|
||||||
|
return messages.updateTokenMetadata(args.tokenId, args.tokenURI)
|
||||||
|
}
|
||||||
|
case 'freeze_token_metadata': {
|
||||||
|
return messages.freezeTokenMetadata()
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
throw new Error('unknown execute type')
|
throw new Error('unknown execute type')
|
||||||
}
|
}
|
||||||
@ -151,6 +171,12 @@ export const previewExecutePayload = (args: DispatchExecuteArgs) => {
|
|||||||
case 'burn': {
|
case 'burn': {
|
||||||
return messages(contract)?.burn(args.tokenId)
|
return messages(contract)?.burn(args.tokenId)
|
||||||
}
|
}
|
||||||
|
case 'update_token_metadata': {
|
||||||
|
return messages(contract)?.updateTokenMetadata(args.tokenId, args.tokenURI)
|
||||||
|
}
|
||||||
|
case 'freeze_token_metadata': {
|
||||||
|
return messages(contract)?.freezeTokenMetadata()
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ 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'
|
||||||
|
|
||||||
|
import { VENDING_FACTORY_UPDATABLE_ADDRESS } from '../../utils/constants'
|
||||||
|
|
||||||
export interface CreateVendingMinterResponse {
|
export interface CreateVendingMinterResponse {
|
||||||
readonly vendingMinterAddress: string
|
readonly vendingMinterAddress: string
|
||||||
readonly sg721Address: string
|
readonly sg721Address: string
|
||||||
@ -21,11 +23,12 @@ export interface VendingFactoryInstance {
|
|||||||
senderAddress: string,
|
senderAddress: string,
|
||||||
msg: Record<string, unknown>,
|
msg: Record<string, unknown>,
|
||||||
funds: Coin[],
|
funds: Coin[],
|
||||||
|
updatable?: boolean,
|
||||||
) => Promise<CreateVendingMinterResponse>
|
) => Promise<CreateVendingMinterResponse>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VendingFactoryMessages {
|
export interface VendingFactoryMessages {
|
||||||
createVendingMinter: (msg: Record<string, unknown>) => CreateVendingMinterMessage
|
createVendingMinter: (msg: Record<string, unknown>, updatable?: boolean) => CreateVendingMinterMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateVendingMinterMessage {
|
export interface CreateVendingMinterMessage {
|
||||||
@ -50,8 +53,16 @@ export const vendingFactory = (client: SigningCosmWasmClient, txSigner: string):
|
|||||||
senderAddress: string,
|
senderAddress: string,
|
||||||
msg: Record<string, unknown>,
|
msg: Record<string, unknown>,
|
||||||
funds: Coin[],
|
funds: Coin[],
|
||||||
|
updatable?: boolean,
|
||||||
): Promise<CreateVendingMinterResponse> => {
|
): Promise<CreateVendingMinterResponse> => {
|
||||||
const result = await client.execute(senderAddress, VENDING_FACTORY_ADDRESS, msg, 'auto', '', funds)
|
const result = await client.execute(
|
||||||
|
senderAddress,
|
||||||
|
updatable ? VENDING_FACTORY_UPDATABLE_ADDRESS : VENDING_FACTORY_ADDRESS,
|
||||||
|
msg,
|
||||||
|
'auto',
|
||||||
|
'',
|
||||||
|
funds,
|
||||||
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
vendingMinterAddress: result.logs[0].events[5].attributes[0].value,
|
vendingMinterAddress: result.logs[0].events[5].attributes[0].value,
|
||||||
@ -68,12 +79,12 @@ export const vendingFactory = (client: SigningCosmWasmClient, txSigner: string):
|
|||||||
}
|
}
|
||||||
|
|
||||||
const messages = (contractAddress: string) => {
|
const messages = (contractAddress: string) => {
|
||||||
const createVendingMinter = (msg: Record<string, unknown>): CreateVendingMinterMessage => {
|
const createVendingMinter = (msg: Record<string, unknown>, updatable?: boolean): CreateVendingMinterMessage => {
|
||||||
return {
|
return {
|
||||||
sender: txSigner,
|
sender: txSigner,
|
||||||
contract: contractAddress,
|
contract: contractAddress,
|
||||||
msg,
|
msg,
|
||||||
funds: [coin('3000000000', 'ustars')],
|
funds: [coin(updatable ? '5000000000' : '3000000000', 'ustars')],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ export interface DispatchExecuteArgs {
|
|||||||
txSigner: string
|
txSigner: string
|
||||||
msg: Record<string, unknown>
|
msg: Record<string, unknown>
|
||||||
funds: Coin[]
|
funds: Coin[]
|
||||||
|
updatable?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const dispatchExecute = async (args: DispatchExecuteArgs) => {
|
export const dispatchExecute = async (args: DispatchExecuteArgs) => {
|
||||||
@ -17,12 +18,12 @@ export const dispatchExecute = async (args: DispatchExecuteArgs) => {
|
|||||||
if (!messages) {
|
if (!messages) {
|
||||||
throw new Error('cannot dispatch execute, messages is not defined')
|
throw new Error('cannot dispatch execute, messages is not defined')
|
||||||
}
|
}
|
||||||
return messages.createVendingMinter(txSigner, args.msg, args.funds)
|
return messages.createVendingMinter(txSigner, args.msg, args.funds, args.updatable)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const previewExecutePayload = (args: DispatchExecuteArgs) => {
|
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)
|
return messages(contract)?.createVendingMinter(args.msg, args.updatable)
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ export const EXECUTE_LIST: ExecuteListItem[] = [
|
|||||||
{
|
{
|
||||||
id: 'mint',
|
id: 'mint',
|
||||||
name: 'Mint',
|
name: 'Mint',
|
||||||
description: `Mint new tokens for a given address`,
|
description: `Mint a new token`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'purge',
|
id: 'purge',
|
||||||
|
3
env.d.ts
vendored
3
env.d.ts
vendored
@ -15,10 +15,13 @@ declare namespace NodeJS {
|
|||||||
readonly APP_VERSION: string
|
readonly APP_VERSION: string
|
||||||
|
|
||||||
readonly NEXT_PUBLIC_SG721_CODE_ID: string
|
readonly NEXT_PUBLIC_SG721_CODE_ID: string
|
||||||
|
readonly NEXT_PUBLIC_SG721_UPDATABLE_CODE_ID: string
|
||||||
readonly NEXT_PUBLIC_WHITELIST_CODE_ID: string
|
readonly NEXT_PUBLIC_WHITELIST_CODE_ID: string
|
||||||
readonly NEXT_PUBLIC_VENDING_MINTER_CODE_ID: string
|
readonly NEXT_PUBLIC_VENDING_MINTER_CODE_ID: string
|
||||||
readonly NEXT_PUBLIC_VENDING_FACTORY_ADDRESS: string
|
readonly NEXT_PUBLIC_VENDING_FACTORY_ADDRESS: string
|
||||||
|
readonly NEXT_PUBLIC_VENDING_FACTORY_UPDATABLE_ADDRESS: string
|
||||||
readonly NEXT_PUBLIC_BASE_FACTORY_ADDRESS: string
|
readonly NEXT_PUBLIC_BASE_FACTORY_ADDRESS: string
|
||||||
|
readonly NEXT_PUBLIC_BASE_FACTORY_UPDATABLE_ADDRESS: string
|
||||||
readonly NEXT_PUBLIC_SG721_NAME_ADDRESS: string
|
readonly NEXT_PUBLIC_SG721_NAME_ADDRESS: string
|
||||||
readonly NEXT_PUBLIC_BASE_MINTER_CODE_ID: string
|
readonly NEXT_PUBLIC_BASE_MINTER_CODE_ID: string
|
||||||
readonly NEXT_PUBLIC_BADGE_HUB_CODE_ID: string
|
readonly NEXT_PUBLIC_BADGE_HUB_CODE_ID: string
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "stargaze-studio",
|
"name": "stargaze-studio",
|
||||||
"version": "0.4.8",
|
"version": "0.4.9",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
],
|
],
|
||||||
|
@ -15,7 +15,7 @@ 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'
|
||||||
|
|
||||||
import type { MinterType } from '../../components/collections/actions/Combobox'
|
import type { MinterType, Sg721Type } from '../../components/collections/actions/Combobox'
|
||||||
|
|
||||||
const CollectionActionsPage: NextPage = () => {
|
const CollectionActionsPage: NextPage = () => {
|
||||||
const { baseMinter: baseMinterContract, vendingMinter: vendingMinterContract, sg721: sg721Contract } = useContracts()
|
const { baseMinter: baseMinterContract, vendingMinter: vendingMinterContract, sg721: sg721Contract } = useContracts()
|
||||||
@ -23,6 +23,7 @@ const CollectionActionsPage: NextPage = () => {
|
|||||||
|
|
||||||
const [action, setAction] = useState<boolean>(false)
|
const [action, setAction] = useState<boolean>(false)
|
||||||
const [minterType, setMinterType] = useState<MinterType>('vending')
|
const [minterType, setMinterType] = useState<MinterType>('vending')
|
||||||
|
const [sg721Type, setSg721Type] = useState<Sg721Type>('updatable')
|
||||||
|
|
||||||
const sg721ContractState = useInputState({
|
const sg721ContractState = useInputState({
|
||||||
id: 'sg721-contract-address',
|
id: 'sg721-contract-address',
|
||||||
@ -39,6 +40,7 @@ const CollectionActionsPage: NextPage = () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const debouncedMinterContractState = useDebounce(minterContractState.value, 300)
|
const debouncedMinterContractState = useDebounce(minterContractState.value, 300)
|
||||||
|
const debouncedSg721ContractState = useDebounce(sg721ContractState.value, 300)
|
||||||
|
|
||||||
const vendingMinterMessages = useMemo(
|
const vendingMinterMessages = useMemo(
|
||||||
() => vendingMinterContract?.use(minterContractState.value),
|
() => vendingMinterContract?.use(minterContractState.value),
|
||||||
@ -109,10 +111,45 @@ const CollectionActionsPage: NextPage = () => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
setMinterType('vending')
|
setMinterType('vending')
|
||||||
console.log('Unable to retrieve contract version')
|
console.log('Unable to retrieve contract type. Defaulting to "vending".')
|
||||||
})
|
})
|
||||||
}, [debouncedMinterContractState, wallet.client])
|
}, [debouncedMinterContractState, wallet.client])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function getSg721ContractType() {
|
||||||
|
if (wallet.client && debouncedSg721ContractState.length > 0) {
|
||||||
|
const client = wallet.client
|
||||||
|
const data = await toast.promise(
|
||||||
|
client.queryContractRaw(
|
||||||
|
debouncedSg721ContractState,
|
||||||
|
toUtf8(Buffer.from(Buffer.from('contract_info').toString('hex'), 'hex').toString()),
|
||||||
|
),
|
||||||
|
{
|
||||||
|
loading: 'Retrieving SG721 type...',
|
||||||
|
error: 'SG721 type retrieval failed.',
|
||||||
|
success: 'SG721 type retrieved.',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
const contract: string = JSON.parse(new TextDecoder().decode(data as Uint8Array)).contract
|
||||||
|
console.log(contract)
|
||||||
|
return contract
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void getSg721ContractType()
|
||||||
|
.then((contract) => {
|
||||||
|
if (contract?.includes('sg721-updatable')) {
|
||||||
|
setSg721Type('updatable')
|
||||||
|
} else {
|
||||||
|
setSg721Type('base')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
setMinterType('base')
|
||||||
|
console.log('Unable to retrieve contract type. Defaulting to "base".')
|
||||||
|
})
|
||||||
|
}, [debouncedSg721ContractState, wallet.client])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="py-6 px-12 space-y-4">
|
<section className="py-6 px-12 space-y-4">
|
||||||
<NextSeo title="Collection Actions" />
|
<NextSeo title="Collection Actions" />
|
||||||
@ -178,6 +215,7 @@ const CollectionActionsPage: NextPage = () => {
|
|||||||
minterType={minterType}
|
minterType={minterType}
|
||||||
sg721ContractAddress={sg721ContractState.value}
|
sg721ContractAddress={sg721ContractState.value}
|
||||||
sg721Messages={sg721Messages}
|
sg721Messages={sg721Messages}
|
||||||
|
sg721Type={sg721Type}
|
||||||
vendingMinterMessages={vendingMinterMessages}
|
vendingMinterMessages={vendingMinterMessages}
|
||||||
/>
|
/>
|
||||||
)) || (
|
)) || (
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
/* eslint-disable eslint-comments/disable-enable-pair */
|
/* eslint-disable eslint-comments/disable-enable-pair */
|
||||||
|
/* eslint-disable no-nested-ternary */
|
||||||
|
|
||||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||||
@ -39,11 +40,15 @@ import { upload } from 'services/upload'
|
|||||||
import { compareFileArrays } from 'utils/compareFileArrays'
|
import { compareFileArrays } from 'utils/compareFileArrays'
|
||||||
import {
|
import {
|
||||||
BASE_FACTORY_ADDRESS,
|
BASE_FACTORY_ADDRESS,
|
||||||
|
BASE_FACTORY_UPDATABLE_ADDRESS,
|
||||||
BLOCK_EXPLORER_URL,
|
BLOCK_EXPLORER_URL,
|
||||||
NETWORK,
|
NETWORK,
|
||||||
SG721_CODE_ID,
|
SG721_CODE_ID,
|
||||||
|
SG721_UPDATABLE_CODE_ID,
|
||||||
STARGAZE_URL,
|
STARGAZE_URL,
|
||||||
VENDING_FACTORY_ADDRESS,
|
VENDING_FACTORY_ADDRESS,
|
||||||
|
VENDING_FACTORY_UPDATABLE_ADDRESS,
|
||||||
|
WHITELIST_CODE_ID,
|
||||||
} from 'utils/constants'
|
} from 'utils/constants'
|
||||||
import { withMetadata } from 'utils/layout'
|
import { withMetadata } from 'utils/layout'
|
||||||
import { links } from 'utils/links'
|
import { links } from 'utils/links'
|
||||||
@ -412,7 +417,7 @@ const CollectionCreationPage: NextPage = () => {
|
|||||||
whitelist,
|
whitelist,
|
||||||
},
|
},
|
||||||
collection_params: {
|
collection_params: {
|
||||||
code_id: SG721_CODE_ID,
|
code_id: collectionDetails?.updatable ? SG721_UPDATABLE_CODE_ID : SG721_CODE_ID,
|
||||||
name: collectionDetails?.name,
|
name: collectionDetails?.name,
|
||||||
symbol: collectionDetails?.symbol,
|
symbol: collectionDetails?.symbol,
|
||||||
info: {
|
info: {
|
||||||
@ -433,11 +438,12 @@ const CollectionCreationPage: NextPage = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const payload: VendingFactoryDispatchExecuteArgs = {
|
const payload: VendingFactoryDispatchExecuteArgs = {
|
||||||
contract: VENDING_FACTORY_ADDRESS,
|
contract: collectionDetails?.updatable ? VENDING_FACTORY_UPDATABLE_ADDRESS : VENDING_FACTORY_ADDRESS,
|
||||||
messages: vendingFactoryMessages,
|
messages: vendingFactoryMessages,
|
||||||
txSigner: wallet.address,
|
txSigner: wallet.address,
|
||||||
msg,
|
msg,
|
||||||
funds: [coin('3000000000', 'ustars')],
|
funds: [coin(collectionDetails?.updatable ? '5000000000' : '3000000000', 'ustars')],
|
||||||
|
updatable: collectionDetails?.updatable,
|
||||||
}
|
}
|
||||||
const data = await vendingFactoryDispatchExecute(payload)
|
const data = await vendingFactoryDispatchExecute(payload)
|
||||||
setTransactionHash(data.transactionHash)
|
setTransactionHash(data.transactionHash)
|
||||||
@ -462,7 +468,7 @@ const CollectionCreationPage: NextPage = () => {
|
|||||||
create_minter: {
|
create_minter: {
|
||||||
init_msg: null,
|
init_msg: null,
|
||||||
collection_params: {
|
collection_params: {
|
||||||
code_id: SG721_CODE_ID,
|
code_id: collectionDetails?.updatable ? SG721_UPDATABLE_CODE_ID : SG721_CODE_ID,
|
||||||
name: collectionDetails?.name,
|
name: collectionDetails?.name,
|
||||||
symbol: collectionDetails?.symbol,
|
symbol: collectionDetails?.symbol,
|
||||||
info: {
|
info: {
|
||||||
@ -483,11 +489,12 @@ const CollectionCreationPage: NextPage = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const payload: BaseFactoryDispatchExecuteArgs = {
|
const payload: BaseFactoryDispatchExecuteArgs = {
|
||||||
contract: BASE_FACTORY_ADDRESS,
|
contract: collectionDetails?.updatable ? BASE_FACTORY_UPDATABLE_ADDRESS : BASE_FACTORY_ADDRESS,
|
||||||
messages: baseFactoryMessages,
|
messages: baseFactoryMessages,
|
||||||
txSigner: wallet.address,
|
txSigner: wallet.address,
|
||||||
msg,
|
msg,
|
||||||
funds: [coin('1000000000', 'ustars')],
|
funds: [coin(collectionDetails?.updatable ? '3000000000' : '1000000000', 'ustars')],
|
||||||
|
updatable: collectionDetails?.updatable,
|
||||||
}
|
}
|
||||||
await baseFactoryDispatchExecute(payload)
|
await baseFactoryDispatchExecute(payload)
|
||||||
.then(async (data) => {
|
.then(async (data) => {
|
||||||
@ -845,11 +852,20 @@ const CollectionCreationPage: NextPage = () => {
|
|||||||
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 = Math.ceil(Number(whitelistDetails.memberLimit) / 1000) * 100000000 + 3000000000
|
const amountNeeded =
|
||||||
|
Math.ceil(Number(whitelistDetails.memberLimit) / 1000) * 100000000 +
|
||||||
|
(collectionDetails?.updatable ? 5000000000 : 3000000000)
|
||||||
if (amountNeeded >= Number(wallet.balance[0].amount))
|
if (amountNeeded >= Number(wallet.balance[0].amount))
|
||||||
throw new Error('Insufficient wallet balance to instantiate the required contracts.')
|
throw new Error('Insufficient wallet balance to instantiate the required contracts.')
|
||||||
} else {
|
} else {
|
||||||
const amountNeeded = minterType === 'vending' ? 3000000000 : 1000000000
|
const amountNeeded =
|
||||||
|
minterType === 'vending'
|
||||||
|
? collectionDetails?.updatable
|
||||||
|
? 5000000000
|
||||||
|
: 3000000000
|
||||||
|
: collectionDetails?.updatable
|
||||||
|
? 3000000000
|
||||||
|
: 1000000000
|
||||||
if (amountNeeded >= Number(wallet.balance[0].amount))
|
if (amountNeeded >= Number(wallet.balance[0].amount))
|
||||||
throw new Error('Insufficient wallet balance to instantiate the required contracts.')
|
throw new Error('Insufficient wallet balance to instantiate the required contracts.')
|
||||||
}
|
}
|
||||||
|
@ -85,11 +85,19 @@ const Sg721ExecutePage: NextPage = () => {
|
|||||||
placeholder: 'ipfs://xyz...',
|
placeholder: 'ipfs://xyz...',
|
||||||
})
|
})
|
||||||
|
|
||||||
const showTokenIdField = isEitherType(type, ['transfer_nft', 'send_nft', 'approve', 'revoke', 'mint', 'burn'])
|
const showTokenIdField = isEitherType(type, [
|
||||||
|
'transfer_nft',
|
||||||
|
'send_nft',
|
||||||
|
'approve',
|
||||||
|
'revoke',
|
||||||
|
'mint',
|
||||||
|
'burn',
|
||||||
|
'update_token_metadata',
|
||||||
|
])
|
||||||
const showRecipientField = isEitherType(type, ['transfer_nft', 'send_nft', 'approve', 'revoke', 'mint'])
|
const showRecipientField = isEitherType(type, ['transfer_nft', 'send_nft', 'approve', 'revoke', 'mint'])
|
||||||
const showOperatorField = isEitherType(type, ['approve_all', 'revoke_all'])
|
const showOperatorField = isEitherType(type, ['approve_all', 'revoke_all'])
|
||||||
const showMessageField = type === 'send_nft'
|
const showMessageField = type === 'send_nft'
|
||||||
const showTokenURIField = type === 'mint'
|
const showTokenURIField = isEitherType(type, ['mint', 'update_token_metadata'])
|
||||||
|
|
||||||
const messages = useMemo(() => contract?.use(contractState.value), [contract, contractState.value])
|
const messages = useMemo(() => contract?.use(contractState.value), [contract, contractState.value])
|
||||||
const payload: DispatchExecuteArgs = {
|
const payload: DispatchExecuteArgs = {
|
||||||
@ -99,7 +107,7 @@ const Sg721ExecutePage: NextPage = () => {
|
|||||||
recipient: resolvedRecipientAddress,
|
recipient: resolvedRecipientAddress,
|
||||||
operator: resolvedOperatorAddress,
|
operator: resolvedOperatorAddress,
|
||||||
type,
|
type,
|
||||||
tokenURI: tokenURIState.value,
|
tokenURI: tokenURIState.value.trim(),
|
||||||
msg: parseJson(messageState.value) || {},
|
msg: parseJson(messageState.value) || {},
|
||||||
}
|
}
|
||||||
const { isLoading, mutate } = useMutation(
|
const { isLoading, mutate } = useMutation(
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
export const SG721_CODE_ID = parseInt(process.env.NEXT_PUBLIC_SG721_CODE_ID, 10)
|
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 WHITELIST_CODE_ID = parseInt(process.env.NEXT_PUBLIC_WHITELIST_CODE_ID, 10)
|
export const WHITELIST_CODE_ID = parseInt(process.env.NEXT_PUBLIC_WHITELIST_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_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_VENDING_FACTORY_ADDRESS
|
export const VENDING_FACTORY_ADDRESS = process.env.NEXT_PUBLIC_VENDING_FACTORY_ADDRESS
|
||||||
|
export const VENDING_FACTORY_UPDATABLE_ADDRESS = process.env.NEXT_PUBLIC_VENDING_FACTORY_UPDATABLE_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 SG721_NAME_ADDRESS = process.env.NEXT_PUBLIC_SG721_NAME_ADDRESS
|
export const SG721_NAME_ADDRESS = process.env.NEXT_PUBLIC_SG721_NAME_ADDRESS
|
||||||
export const BASE_MINTER_CODE_ID = parseInt(process.env.NEXT_PUBLIC_VENDING_MINTER_CODE_ID, 10)
|
export const BASE_MINTER_CODE_ID = parseInt(process.env.NEXT_PUBLIC_VENDING_MINTER_CODE_ID, 10)
|
||||||
export const BADGE_HUB_CODE_ID = parseInt(process.env.NEXT_PUBLIC_BADGE_HUB_CODE_ID, 10)
|
export const BADGE_HUB_CODE_ID = parseInt(process.env.NEXT_PUBLIC_BADGE_HUB_CODE_ID, 10)
|
||||||
|
Loading…
Reference in New Issue
Block a user