Implement editBadge for Badge Hub Dashboard > Execute
This commit is contained in:
parent
edccae535e
commit
4a11d08ca9
@ -84,7 +84,7 @@ export type DispatchExecuteArgs = {
|
||||
} & (
|
||||
| { type: undefined }
|
||||
| { type: Select<'create_badge'>; badge: Badge }
|
||||
| { type: Select<'edit_badge'>; id: number; metadata: Metadata }
|
||||
| { type: Select<'edit_badge'>; id: number; metadata: Metadata; editFee?: number }
|
||||
| { type: Select<'add_keys'>; id: number; keys: string[] }
|
||||
| { type: Select<'purge_keys'>; id: number; limit?: number }
|
||||
| { type: Select<'purge_owners'>; id: number; limit?: number }
|
||||
@ -104,7 +104,7 @@ export const dispatchExecute = async (args: DispatchExecuteArgs) => {
|
||||
return messages.createBadge(txSigner, args.badge)
|
||||
}
|
||||
case 'edit_badge': {
|
||||
return messages.editBadge(txSigner, args.id, args.metadata)
|
||||
return messages.editBadge(txSigner, args.id, args.metadata, args.editFee)
|
||||
}
|
||||
case 'add_keys': {
|
||||
return messages.addKeys(txSigner, args.id, args.keys)
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { toUtf8 } from '@cosmjs/encoding'
|
||||
import { Button } from 'components/Button'
|
||||
import { Conditional } from 'components/Conditional'
|
||||
import { ContractPageHeader } from 'components/ContractPageHeader'
|
||||
@ -13,6 +14,7 @@ import { badgeHubLinkTabs } from 'components/LinkTabs.data'
|
||||
import { TransactionHash } from 'components/TransactionHash'
|
||||
import { useContracts } from 'contexts/contracts'
|
||||
import { useWallet } from 'contexts/wallet'
|
||||
import type { Badge } from 'contracts/badgeHub'
|
||||
import type { DispatchExecuteArgs } from 'contracts/badgeHub/messages/execute'
|
||||
import { dispatchExecute, isEitherType, previewExecutePayload } from 'contracts/badgeHub/messages/execute'
|
||||
import * as crypto from 'crypto'
|
||||
@ -20,6 +22,7 @@ import { toPng } from 'html-to-image'
|
||||
import type { NextPage } from 'next'
|
||||
import { useRouter } from 'next/router'
|
||||
import { NextSeo } from 'next-seo'
|
||||
import sizeof from 'object-sizeof'
|
||||
import { QRCodeCanvas } from 'qrcode.react'
|
||||
import type { FormEvent } from 'react'
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
@ -30,30 +33,37 @@ import * as secp256k1 from 'secp256k1'
|
||||
import { NETWORK } from 'utils/constants'
|
||||
import { withMetadata } from 'utils/layout'
|
||||
import { links } from 'utils/links'
|
||||
import { resolveAddress } from 'utils/resolveAddress'
|
||||
|
||||
import { TextInput } from '../../../components/forms/FormInput'
|
||||
import { MetadataAttributes } from '../../../components/forms/MetadataAttributes'
|
||||
import { useMetadataAttributesState } from '../../../components/forms/MetadataAttributes.hooks'
|
||||
import { BADGE_HUB_ADDRESS } from '../../../utils/constants'
|
||||
|
||||
const BadgeHubExecutePage: NextPage = () => {
|
||||
const { badgeHub: contract } = useContracts()
|
||||
const wallet = useWallet()
|
||||
const [lastTx, setLastTx] = useState('')
|
||||
const [badge, setBadge] = useState<Badge>()
|
||||
|
||||
const [timestamp, setTimestamp] = useState<Date | undefined>(undefined)
|
||||
const [transferrable, setTransferrable] = useState<boolean>(false)
|
||||
const [createdBadgeId, setCreatedBadgeId] = useState<string | undefined>(undefined)
|
||||
const [createdBadgeKey, setCreatedBadgeKey] = useState<string | undefined>(undefined)
|
||||
const [resolvedOwnerAddress, setResolvedOwnerAddress] = useState<string>('')
|
||||
const [editFee, setEditFee] = useState<number | undefined>(undefined)
|
||||
const [triggerDispatch, setTriggerDispatch] = useState<boolean>(false)
|
||||
const qrRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const comboboxState = useExecuteComboboxState()
|
||||
const type = comboboxState.value?.id
|
||||
|
||||
const tokenIdState = useNumberInputState({
|
||||
id: 'token-id',
|
||||
name: 'tokenId',
|
||||
title: 'Token ID',
|
||||
subtitle: 'Enter the token ID',
|
||||
const badgeIdState = useNumberInputState({
|
||||
id: 'badge-id',
|
||||
name: 'badgeId',
|
||||
title: 'Badge ID',
|
||||
subtitle: 'Enter the badge ID',
|
||||
defaultValue: 1,
|
||||
})
|
||||
|
||||
const maxSupplyState = useNumberInputState({
|
||||
@ -68,6 +78,7 @@ const BadgeHubExecutePage: NextPage = () => {
|
||||
name: 'contract-address',
|
||||
title: 'Badge Hub Address',
|
||||
subtitle: 'Address of the Badge Hub contract',
|
||||
defaultValue: BADGE_HUB_ADDRESS,
|
||||
})
|
||||
const contractAddress = contractState.value
|
||||
|
||||
@ -145,13 +156,6 @@ const BadgeHubExecutePage: NextPage = () => {
|
||||
subtitle: 'The key generated for the badge',
|
||||
})
|
||||
|
||||
const idState = useNumberInputState({
|
||||
id: 'id',
|
||||
name: 'id',
|
||||
title: 'ID',
|
||||
subtitle: 'The ID of the badge',
|
||||
})
|
||||
|
||||
const ownerState = useInputState({
|
||||
id: 'owner-address',
|
||||
name: 'owner',
|
||||
@ -241,7 +245,7 @@ const BadgeHubExecutePage: NextPage = () => {
|
||||
animation_url: animationUrlState.value || undefined,
|
||||
youtube_url: youtubeUrlState.value || undefined,
|
||||
},
|
||||
id: idState.value,
|
||||
id: badgeIdState.value,
|
||||
owner: ownerState.value,
|
||||
pubkey: pubkeyState.value,
|
||||
signature: signatureState.value,
|
||||
@ -249,6 +253,7 @@ const BadgeHubExecutePage: NextPage = () => {
|
||||
limit: limitState.value,
|
||||
owners: [],
|
||||
nft: nftState.value,
|
||||
editFee,
|
||||
contract: contractState.value,
|
||||
messages,
|
||||
txSigner: wallet.address,
|
||||
@ -266,15 +271,58 @@ const BadgeHubExecutePage: NextPage = () => {
|
||||
if (contractState.value === '') {
|
||||
throw new Error('Please enter the contract address.')
|
||||
}
|
||||
if (wallet.client && type === 'edit_badge') {
|
||||
const feeRateRaw = await wallet.client.queryContractRaw(
|
||||
contractAddress,
|
||||
toUtf8(Buffer.from(Buffer.from('fee_rate').toString('hex'), 'hex').toString()),
|
||||
)
|
||||
const feeRate = JSON.parse(new TextDecoder().decode(feeRateRaw as Uint8Array))
|
||||
|
||||
await toast
|
||||
.promise(
|
||||
wallet.client.queryContractSmart(contractAddress, {
|
||||
badge: { id: badgeIdState.value },
|
||||
}),
|
||||
{
|
||||
error: `Edit Fee calculation failed!`,
|
||||
loading: 'Calculating Edit Fee...',
|
||||
success: (currentBadge) => {
|
||||
console.log('Current badge: ', currentBadge)
|
||||
return `Current metadata is ${
|
||||
Number(sizeof(currentBadge.metadata)) + Number(sizeof(currentBadge.metadata.attributes))
|
||||
} bytes in size.`
|
||||
},
|
||||
},
|
||||
)
|
||||
.then((currentBadge) => {
|
||||
// TODO - Go over the calculation
|
||||
const currentBadgeMetadataSize =
|
||||
Number(sizeof(currentBadge.metadata)) + Number(sizeof(currentBadge.metadata.attributes) * 2)
|
||||
console.log('Current badge metadata size: ', currentBadgeMetadataSize)
|
||||
const newBadgeMetadataSize =
|
||||
Number(sizeof(badge?.metadata)) + Number(sizeof(badge?.metadata.attributes)) * 2
|
||||
console.log('New badge metadata size: ', newBadgeMetadataSize)
|
||||
if (newBadgeMetadataSize > currentBadgeMetadataSize) {
|
||||
const calculatedFee = ((newBadgeMetadataSize - currentBadgeMetadataSize) * Number(feeRate.metadata)) / 2
|
||||
setEditFee(calculatedFee)
|
||||
setTriggerDispatch(!triggerDispatch)
|
||||
} else {
|
||||
setEditFee(undefined)
|
||||
setTriggerDispatch(!triggerDispatch)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
throw new Error(String(error).substring(String(error).lastIndexOf('Error:') + 7))
|
||||
})
|
||||
} else {
|
||||
const txHash = await toast.promise(dispatchExecute(payload), {
|
||||
error: `${type.charAt(0).toUpperCase() + type.slice(1)} execute failed!`,
|
||||
loading: 'Executing message...',
|
||||
success: (tx) => `Transaction ${tx.split(':')[0]} success!`,
|
||||
success: (tx) => `Transaction ${tx} success!`,
|
||||
})
|
||||
if (txHash) {
|
||||
setLastTx(txHash.split(':')[0])
|
||||
setCreatedBadgeId(txHash.split(':')[1])
|
||||
console.log(txHash.split(':')[1])
|
||||
setLastTx(txHash)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -316,6 +364,19 @@ const BadgeHubExecutePage: NextPage = () => {
|
||||
toast.success('Copied claim URL to clipboard')
|
||||
}
|
||||
|
||||
const dispatchEditBadgeMessage = async () => {
|
||||
if (type) {
|
||||
const txHash = await toast.promise(dispatchExecute(payload), {
|
||||
error: `${type.charAt(0).toUpperCase() + type.slice(1)} execute failed!`,
|
||||
loading: 'Executing message...',
|
||||
success: (tx) => `Transaction ${tx} success!`,
|
||||
})
|
||||
if (txHash) {
|
||||
setLastTx(txHash)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
@ -335,6 +396,104 @@ const BadgeHubExecutePage: NextPage = () => {
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
void dispatchEditBadgeMessage().catch((err) => {
|
||||
toast.error(String(err), { style: { maxWidth: 'none' } })
|
||||
})
|
||||
}, [triggerDispatch])
|
||||
|
||||
const resolveOwnerAddress = async () => {
|
||||
await resolveAddress(ownerState.value.trim(), wallet).then((resolvedAddress) => {
|
||||
setResolvedOwnerAddress(resolvedAddress)
|
||||
})
|
||||
}
|
||||
useEffect(() => {
|
||||
void resolveOwnerAddress()
|
||||
}, [ownerState.value])
|
||||
|
||||
const resolveManagerAddress = async () => {
|
||||
await resolveAddress(managerState.value.trim(), wallet).then((resolvedAddress) => {
|
||||
setBadge({
|
||||
manager: resolvedAddress,
|
||||
metadata: {
|
||||
name: nameState.value || undefined,
|
||||
description: descriptionState.value || undefined,
|
||||
image: imageState.value || undefined,
|
||||
image_data: imageDataState.value || undefined,
|
||||
external_url: externalUrlState.value || undefined,
|
||||
attributes:
|
||||
attributesState.values[0]?.trait_type && attributesState.values[0]?.value
|
||||
? attributesState.values
|
||||
.map((attr) => ({
|
||||
trait_type: attr.trait_type,
|
||||
value: attr.value,
|
||||
}))
|
||||
.filter((attr) => attr.trait_type && attr.value)
|
||||
: undefined,
|
||||
background_color: backgroundColorState.value || undefined,
|
||||
animation_url: animationUrlState.value || undefined,
|
||||
youtube_url: youtubeUrlState.value || undefined,
|
||||
},
|
||||
transferrable,
|
||||
rule: {
|
||||
by_key: keyState.value,
|
||||
},
|
||||
expiry: timestamp ? timestamp.getTime() * 1000000 : undefined,
|
||||
max_supply: maxSupplyState.value || undefined,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
void resolveManagerAddress()
|
||||
}, [managerState.value])
|
||||
|
||||
useEffect(() => {
|
||||
setBadge({
|
||||
manager: managerState.value,
|
||||
metadata: {
|
||||
name: nameState.value || undefined,
|
||||
description: descriptionState.value || undefined,
|
||||
image: imageState.value || undefined,
|
||||
image_data: imageDataState.value || undefined,
|
||||
external_url: externalUrlState.value || undefined,
|
||||
attributes:
|
||||
attributesState.values[0]?.trait_type && attributesState.values[0]?.value
|
||||
? attributesState.values
|
||||
.map((attr) => ({
|
||||
trait_type: attr.trait_type,
|
||||
value: attr.value,
|
||||
}))
|
||||
.filter((attr) => attr.trait_type && attr.value)
|
||||
: undefined,
|
||||
background_color: backgroundColorState.value || undefined,
|
||||
animation_url: animationUrlState.value || undefined,
|
||||
youtube_url: youtubeUrlState.value || undefined,
|
||||
},
|
||||
transferrable,
|
||||
rule: {
|
||||
by_key: keyState.value,
|
||||
},
|
||||
expiry: timestamp ? timestamp.getTime() * 1000000 : undefined,
|
||||
max_supply: maxSupplyState.value || undefined,
|
||||
})
|
||||
}, [
|
||||
managerState.value,
|
||||
nameState.value,
|
||||
descriptionState.value,
|
||||
imageState.value,
|
||||
imageDataState.value,
|
||||
externalUrlState.value,
|
||||
attributesState.values,
|
||||
backgroundColorState.value,
|
||||
animationUrlState.value,
|
||||
youtubeUrlState.value,
|
||||
transferrable,
|
||||
keyState.value,
|
||||
timestamp,
|
||||
maxSupplyState.value,
|
||||
])
|
||||
|
||||
return (
|
||||
<section className="py-6 px-12 space-y-4">
|
||||
<NextSeo title="Execute Badge Hub Contract" />
|
||||
@ -380,6 +539,7 @@ const BadgeHubExecutePage: NextPage = () => {
|
||||
<div className="space-y-8">
|
||||
<AddressInput {...contractState} />
|
||||
<ExecuteCombobox {...comboboxState} />
|
||||
{showIdField && <NumberInput {...badgeIdState} />}
|
||||
{showBadgeField && <AddressInput {...managerState} />}
|
||||
{showBadgeField && <TextInput {...keyState} />}
|
||||
{showBadgeField && <Button onClick={handleGenerateKey}>Generate Key</Button>}
|
||||
|
Loading…
Reference in New Issue
Block a user