Calculate editBadge() fee on the go

This commit is contained in:
Serkan Reis 2023-02-21 00:00:11 +03:00
parent e1adf87dac
commit 080c74a110
5 changed files with 107 additions and 63 deletions

View File

@ -1,4 +1,5 @@
// import { AirdropUpload } from 'components/AirdropUpload' // import { AirdropUpload } from 'components/AirdropUpload'
import { toUtf8 } from '@cosmjs/encoding'
import type { DispatchExecuteArgs } from 'components/badges/actions/actions' import type { DispatchExecuteArgs } from 'components/badges/actions/actions'
import { dispatchExecute, isEitherType, previewExecutePayload } from 'components/badges/actions/actions' import { dispatchExecute, isEitherType, previewExecutePayload } from 'components/badges/actions/actions'
import { ActionsCombobox } from 'components/badges/actions/Combobox' import { ActionsCombobox } from 'components/badges/actions/Combobox'
@ -18,6 +19,7 @@ import { useWallet } from 'contexts/wallet'
import type { Badge, BadgeHubInstance } from 'contracts/badgeHub' import type { Badge, BadgeHubInstance } from 'contracts/badgeHub'
import * as crypto from 'crypto' import * as crypto from 'crypto'
import { toPng } from 'html-to-image' import { toPng } from 'html-to-image'
import sizeof from 'object-sizeof'
import { QRCodeCanvas } from 'qrcode.react' import { QRCodeCanvas } from 'qrcode.react'
import type { FormEvent } from 'react' import type { FormEvent } from 'react'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
@ -51,6 +53,8 @@ export const BadgeActions = ({ badgeHubContractAddress, badgeId, badgeHubMessage
const [badge, setBadge] = useState<Badge>() const [badge, setBadge] = useState<Badge>()
const [transferrable, setTransferrable] = useState<TransferrableType>(undefined) const [transferrable, setTransferrable] = useState<TransferrableType>(undefined)
const [resolvedOwnerAddress, setResolvedOwnerAddress] = useState<string>('') const [resolvedOwnerAddress, setResolvedOwnerAddress] = useState<string>('')
const [editFee, setEditFee] = useState<number | undefined>(undefined)
const [dispatch, setDispatch] = useState<boolean>(false)
const [createdBadgeId, setCreatedBadgeId] = useState<string | undefined>(undefined) const [createdBadgeId, setCreatedBadgeId] = useState<string | undefined>(undefined)
const [createdBadgeKey, setCreatedBadgeKey] = useState<string | undefined>(undefined) const [createdBadgeKey, setCreatedBadgeKey] = useState<string | undefined>(undefined)
@ -229,6 +233,7 @@ export const BadgeActions = ({ badgeHubContractAddress, badgeId, badgeHubMessage
youtube_url: youtubeUrlState.value || undefined, youtube_url: youtubeUrlState.value || undefined,
}, },
id: badgeId, id: badgeId,
editFee,
owner: resolvedOwnerAddress, owner: resolvedOwnerAddress,
pubkey: pubkeyState.value, pubkey: pubkeyState.value,
signature: signatureState.value, signature: signatureState.value,
@ -241,6 +246,7 @@ export const BadgeActions = ({ badgeHubContractAddress, badgeId, badgeHubMessage
txSigner: wallet.address, txSigner: wallet.address,
type, type,
} }
const resolveOwnerAddress = async () => { const resolveOwnerAddress = async () => {
await resolveAddress(ownerState.value.trim(), wallet).then((resolvedAddress) => { await resolveAddress(ownerState.value.trim(), wallet).then((resolvedAddress) => {
setResolvedOwnerAddress(resolvedAddress) setResolvedOwnerAddress(resolvedAddress)
@ -333,6 +339,20 @@ export const BadgeActions = ({ badgeHubContractAddress, badgeId, badgeHubMessage
maxSupplyState.value, maxSupplyState.value,
]) ])
useEffect(() => {
if (attributesState.values.length === 0)
attributesState.add({
trait_type: '',
value: '',
})
}, [])
useEffect(() => {
void dispatchEditBadge().catch((err) => {
toast.error(String(err), { style: { maxWidth: 'none' } })
})
}, [dispatch])
useEffect(() => { useEffect(() => {
const addresses: string[] = [] const addresses: string[] = []
airdropAllocationArray.forEach((allocation) => { airdropAllocationArray.forEach((allocation) => {
@ -358,53 +378,56 @@ export const BadgeActions = ({ badgeHubContractAddress, badgeId, badgeHubMessage
throw new Error('Please enter the Badge Hub contract addresses.') throw new Error('Please enter the Badge Hub contract addresses.')
} }
// if (wallet.client && type === 'update_mint_price') { if (wallet.client && type === 'edit_badge') {
// const contractConfig = wallet.client.queryContractSmart(minterContractAddress, { const feeRateRaw = await wallet.client.queryContractRaw(
// config: {}, badgeHubContractAddress,
// }) toUtf8(Buffer.from(Buffer.from('fee_rate').toString('hex'), 'hex').toString()),
// await toast )
// .promise( const feeRate = JSON.parse(new TextDecoder().decode(feeRateRaw as Uint8Array))
// wallet.client.queryContractSmart(minterContractAddress, {
// mint_price: {},
// }),
// {
// error: `Querying mint price failed!`,
// loading: 'Querying current mint price...',
// success: (price) => {
// console.log('Current mint price: ', price)
// return `Current mint price is ${Number(price.public_price.amount) / 1000000} STARS`
// },
// },
// )
// .then(async (price) => {
// if (Number(price.public_price.amount) / 1000000 <= priceState.value) {
// await contractConfig
// .then((config) => {
// console.log(config.start_time, Date.now() * 1000000)
// if (Number(config.start_time) < Date.now() * 1000000) {
// throw new Error(
// `Minting has already started on ${new Date(
// Number(config.start_time) / 1000000,
// ).toLocaleString()}. Updated mint price cannot be higher than the current price of ${
// Number(price.public_price.amount) / 1000000
// } STARS`,
// )
// }
// })
// .catch((error) => {
// throw new Error(String(error).substring(String(error).lastIndexOf('Error:') + 7))
// })
// }
// })
// }
const txHash = await toast.promise(dispatchExecute(payload), { await toast
error: `${type.charAt(0).toUpperCase() + type.slice(1)} execute failed!`, .promise(
loading: 'Executing message...', wallet.client.queryContractSmart(badgeHubContractAddress, {
success: (tx) => `Transaction ${tx} success!`, badge: { id: badgeId },
}) }),
if (txHash) { {
setLastTx(txHash) 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) => {
const currentBadgeMetadataSize =
Number(sizeof(currentBadge.metadata)) + Number(sizeof(currentBadge.metadata.attributes))
console.log('Current badge metadata size: ', currentBadgeMetadataSize)
const newBadgeMetadataSize = Number(sizeof(badge?.metadata)) + Number(sizeof(badge?.metadata.attributes))
console.log('New badge metadata size: ', newBadgeMetadataSize)
if (newBadgeMetadataSize > currentBadgeMetadataSize) {
const calculatedFee = ((newBadgeMetadataSize - currentBadgeMetadataSize) * Number(feeRate.metadata)) / 2
setEditFee(calculatedFee)
setDispatch(!dispatch)
} else {
setEditFee(undefined)
setDispatch(!dispatch)
}
})
.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} success!`,
})
if (txHash) {
setLastTx(txHash)
}
} }
}, },
{ {
@ -414,6 +437,19 @@ export const BadgeActions = ({ badgeHubContractAddress, badgeId, badgeHubMessage
}, },
) )
const dispatchEditBadge = 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 airdropFileOnChange = (data: AirdropAllocation[]) => { const airdropFileOnChange = (data: AirdropAllocation[]) => {
setAirdropAllocationArray(data) setAirdropAllocationArray(data)
} }

View File

@ -100,7 +100,7 @@ export type DispatchExecuteArgs = {
} & ( } & (
| { type: undefined } | { type: undefined }
| { type: Select<'create_badge'>; badge: Badge } | { 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<'add_keys'>; id: number; keys: string[] }
| { type: Select<'purge_keys'>; id: number; limit?: number } | { type: Select<'purge_keys'>; id: number; limit?: number }
| { type: Select<'purge_owners'>; id: number; limit?: number } | { type: Select<'purge_owners'>; id: number; limit?: number }
@ -120,7 +120,7 @@ export const dispatchExecute = async (args: DispatchExecuteArgs) => {
return badgeHubMessages.createBadge(txSigner, args.badge) return badgeHubMessages.createBadge(txSigner, args.badge)
} }
case 'edit_badge': { case 'edit_badge': {
return badgeHubMessages.editBadge(txSigner, args.id, args.metadata) return badgeHubMessages.editBadge(txSigner, args.id, args.metadata, args.editFee)
} }
case 'add_keys': { case 'add_keys': {
return badgeHubMessages.addKeys(txSigner, args.id, args.keys) return badgeHubMessages.addKeys(txSigner, args.id, args.keys)

View File

@ -15,7 +15,7 @@ import { toast } from 'react-hot-toast'
import type { UploadServiceType } from 'services/upload' import type { UploadServiceType } from 'services/upload'
export type UploadMethod = 'new' | 'existing' export type UploadMethod = 'new' | 'existing'
export type MintRule = 'by_key' | 'by_minter' | 'by_keys' export type MintRule = 'by_key' | 'by_minter' | 'by_keys' | 'not_resolved'
interface ImageUploadDetailsProps { interface ImageUploadDetailsProps {
onChange: (value: ImageUploadDetailsDataProps) => void onChange: (value: ImageUploadDetailsDataProps) => void

View File

@ -67,7 +67,7 @@ export interface BadgeHubInstance {
//Execute //Execute
createBadge: (senderAddress: string, badge: Badge) => Promise<string> createBadge: (senderAddress: string, badge: Badge) => Promise<string>
editBadge: (senderAddress: string, id: number, metadata: Metadata) => Promise<string> editBadge: (senderAddress: string, id: number, metadata: Metadata, editFee?: number) => Promise<string>
addKeys: (senderAddress: string, id: number, keys: string[]) => Promise<string> addKeys: (senderAddress: string, id: number, keys: string[]) => Promise<string>
purgeKeys: (senderAddress: string, id: number, limit?: number) => Promise<string> purgeKeys: (senderAddress: string, id: number, limit?: number) => Promise<string>
purgeOwners: (senderAddress: string, id: number, limit?: number) => Promise<string> purgeOwners: (senderAddress: string, id: number, limit?: number) => Promise<string>
@ -79,7 +79,7 @@ export interface BadgeHubInstance {
export interface BadgeHubMessages { export interface BadgeHubMessages {
createBadge: (badge: Badge) => CreateBadgeMessage createBadge: (badge: Badge) => CreateBadgeMessage
editBadge: (id: number, metadata: Metadata) => EditBadgeMessage editBadge: (id: number, metadata: Metadata, editFee?: number) => EditBadgeMessage
addKeys: (id: number, keys: string[]) => AddKeysMessage addKeys: (id: number, keys: string[]) => AddKeysMessage
purgeKeys: (id: number, limit?: number) => PurgeKeysMessage purgeKeys: (id: number, limit?: number) => PurgeKeysMessage
purgeOwners: (id: number, limit?: number) => PurgeOwnersMessage purgeOwners: (id: number, limit?: number) => PurgeOwnersMessage
@ -314,7 +314,12 @@ export const badgeHub = (client: SigningCosmWasmClient, txSigner: string): Badge
return res.transactionHash.concat(`:${id}`) return res.transactionHash.concat(`:${id}`)
} }
const editBadge = async (senderAddress: string, id: number, metadata: Metadata): Promise<string> => { const editBadge = async (
senderAddress: string,
id: number,
metadata: Metadata,
editFee?: number,
): Promise<string> => {
const res = await client.execute( const res = await client.execute(
senderAddress, senderAddress,
contractAddress, contractAddress,
@ -326,6 +331,7 @@ export const badgeHub = (client: SigningCosmWasmClient, txSigner: string): Badge
}, },
'auto', 'auto',
'', '',
editFee ? [coin(editFee, 'ustars')] : [],
) )
return res.transactionHash return res.transactionHash
@ -524,7 +530,7 @@ export const badgeHub = (client: SigningCosmWasmClient, txSigner: string): Badge
} }
} }
const editBadge = (id: number, metadata: Metadata): EditBadgeMessage => { const editBadge = (id: number, metadata: Metadata, editFee?: number): EditBadgeMessage => {
return { return {
sender: txSigner, sender: txSigner,
contract: contractAddress, contract: contractAddress,
@ -534,7 +540,7 @@ export const badgeHub = (client: SigningCosmWasmClient, txSigner: string): Badge
metadata, metadata,
}, },
}, },
funds: [], funds: editFee ? [coin(editFee, 'ustars')] : [],
} }
} }

View File

@ -113,7 +113,7 @@ const BadgeActionsPage: NextPage = () => {
}) })
.catch((err) => { .catch((err) => {
console.log(err) console.log(err)
setMintRule('by_key') setMintRule('not_resolved')
console.log('Unable to retrieve Mint Rule. Defaulting to "by_key".') console.log('Unable to retrieve Mint Rule. Defaulting to "by_key".')
}) })
}, [debouncedBadgeHubContractState, debouncedBadgeIdState, wallet.client]) }, [debouncedBadgeHubContractState, debouncedBadgeIdState, wallet.client])
@ -132,14 +132,16 @@ const BadgeActionsPage: NextPage = () => {
<AddressInput {...badgeHubContractState} className="mr-2" /> <AddressInput {...badgeHubContractState} className="mr-2" />
<div className="flex-row"> <div className="flex-row">
<NumberInput className="w-1/2" {...badgeIdState} /> <NumberInput className="w-1/2" {...badgeIdState} />
<span className="mt-1 font-bold">Mint Rule: </span> <div className="mt-2">
<span> <span className="font-bold">Mint Rule: </span>
{mintRule <span>
.toString() {mintRule
.split('_') .toString()
.map((s) => s.charAt(0).toUpperCase() + s.substring(1)) .split('_')
.join(' ')} .map((s) => s.charAt(0).toUpperCase() + s.substring(1))
</span> .join(' ')}
</span>
</div>
</div> </div>
</div> </div>
<div className="mt-4"> <div className="mt-4">