From 76ba766b28aad9acdacb0e4bddcaad83e887c82f Mon Sep 17 00:00:00 2001 From: Serkan Reis Date: Mon, 17 Apr 2023 19:20:37 +0300 Subject: [PATCH] Update WL dashboard > Execute --- contracts/whitelist/messages/execute.ts | 26 ++--- pages/collections/actions.tsx | 2 +- pages/contracts/whitelist/execute.tsx | 129 ++++++++++++++++++++++-- 3 files changed, 129 insertions(+), 28 deletions(-) diff --git a/contracts/whitelist/messages/execute.ts b/contracts/whitelist/messages/execute.ts index a0fbdec..2e528bd 100644 --- a/contracts/whitelist/messages/execute.ts +++ b/contracts/whitelist/messages/execute.ts @@ -1,3 +1,4 @@ +import type { WhitelistFlexMember } from '../../../components/WhitelistFlexUpload' import type { WhiteListInstance } from '../index' import { useWhiteListContract } from '../index' @@ -68,23 +69,16 @@ export interface DispatchExecuteProps { [k: string]: unknown } -type Select = T - /** @see {@link WhiteListInstance} */ -export type DispatchExecuteArgs = { +export interface DispatchExecuteArgs { contract: string messages?: WhiteListInstance -} & ( - | { type: undefined } - | { type: Select<'update_start_time'>; timestamp: string } - | { type: Select<'update_end_time'>; timestamp: string } - | { type: Select<'add_members'>; members: string[] } - | { type: Select<'remove_members'>; members: string[] } - | { type: Select<'update_per_address_limit'>; limit: number } - | { type: Select<'increase_member_limit'>; limit: number } - | { type: Select<'update_admins'>; admins: string[] } - | { type: Select<'freeze'> } -) + type: string | undefined + timestamp: string + members: string[] | WhitelistFlexMember[] + limit: number + admins: string[] +} export const dispatchExecute = async (args: DispatchExecuteArgs) => { const { messages } = args @@ -105,7 +99,7 @@ export const dispatchExecute = async (args: DispatchExecuteArgs) => { return messages.addMembers(args.members) } case 'remove_members': { - return messages.removeMembers(args.members) + return messages.removeMembers(args.members as string[]) } case 'update_per_address_limit': { return messages.updatePerAddressLimit(args.limit) @@ -140,7 +134,7 @@ export const previewExecutePayload = (args: DispatchExecuteArgs) => { return messages(contract)?.addMembers(args.members) } case 'remove_members': { - return messages(contract)?.removeMembers(args.members) + return messages(contract)?.removeMembers(args.members as string[]) } case 'update_per_address_limit': { return messages(contract)?.updatePerAddressLimit(args.limit) diff --git a/pages/collections/actions.tsx b/pages/collections/actions.tsx index 445a199..c56a059 100644 --- a/pages/collections/actions.tsx +++ b/pages/collections/actions.tsx @@ -145,7 +145,7 @@ const CollectionActionsPage: NextPage = () => { }) .catch((err) => { console.log(err) - setMinterType('base') + setSg721Type('base') console.log('Unable to retrieve contract type. Defaulting to "base".') }) }, [debouncedSg721ContractState, wallet.client]) diff --git a/pages/contracts/whitelist/execute.tsx b/pages/contracts/whitelist/execute.tsx index d38339b..b085b05 100644 --- a/pages/contracts/whitelist/execute.tsx +++ b/pages/contracts/whitelist/execute.tsx @@ -1,3 +1,6 @@ +/* eslint-disable eslint-comments/disable-enable-pair */ +/* eslint-disable no-nested-ternary */ +import { toUtf8 } from '@cosmjs/encoding' import { Alert } from 'components/Alert' import { Button } from 'components/Button' import { Conditional } from 'components/Conditional' @@ -7,6 +10,8 @@ import { useExecuteComboboxState } from 'components/contracts/whitelist/ExecuteC import { FormControl } from 'components/FormControl' import { AddressList } from 'components/forms/AddressList' import { useAddressListState } from 'components/forms/AddressList.hooks' +import { FlexMemberAttributes } from 'components/forms/FlexMemberAttributes' +import { useFlexMemberAttributesState } from 'components/forms/FlexMemberAttributes.hooks' import { AddressInput, NumberInput } from 'components/forms/FormInput' import { useInputState, useNumberInputState } from 'components/forms/FormInput.hooks' import { InputDateTime } from 'components/InputDateTime' @@ -14,6 +19,8 @@ import { JsonPreview } from 'components/JsonPreview' import { LinkTabs } from 'components/LinkTabs' import { whitelistLinkTabs } from 'components/LinkTabs.data' import { TransactionHash } from 'components/TransactionHash' +import type { WhitelistFlexMember } from 'components/WhitelistFlexUpload' +import { WhitelistFlexUpload } from 'components/WhitelistFlexUpload' import { WhitelistUpload } from 'components/WhitelistUpload' import { useContracts } from 'contexts/contracts' import { useWallet } from 'contexts/wallet' @@ -27,6 +34,7 @@ import { useEffect, useMemo, useState } from 'react' import { toast } from 'react-hot-toast' import { FaArrowRight } from 'react-icons/fa' import { useMutation } from 'react-query' +import { useDebounce } from 'utils/debounce' import { isValidAddress } from 'utils/isValidAddress' import { withMetadata } from 'utils/layout' import { links } from 'utils/links' @@ -37,6 +45,8 @@ const WhitelistExecutePage: NextPage = () => { const [lastTx, setLastTx] = useState('') const [memberList, setMemberList] = useState([]) + const [flexMemberList, setFlexMemberList] = useState([]) + const [whitelistType, setWhitelistType] = useState<'standard' | 'flex'>('standard') const comboboxState = useExecuteComboboxState() const type = comboboxState.value?.id @@ -45,6 +55,8 @@ const WhitelistExecutePage: NextPage = () => { const addressListState = useAddressListState() + const flexAddressListState = useFlexMemberAttributesState() + const contractState = useInputState({ id: 'contract-address', name: 'contract-address', @@ -53,6 +65,8 @@ const WhitelistExecutePage: NextPage = () => { }) const contractAddress = contractState.value + const debouncedWhitelistContractState = useDebounce(contractState.value, 300) + const limitState = useNumberInputState({ id: 'limit', name: 'limit', @@ -63,7 +77,9 @@ const WhitelistExecutePage: NextPage = () => { const showLimitState = isEitherType(type, ['update_per_address_limit', 'increase_member_limit']) const showTimestamp = isEitherType(type, ['update_start_time', 'update_end_time']) - const showMemberList = isEitherType(type, ['add_members', 'remove_members']) + const showMemberList = isEitherType(type, ['add_members']) + const showFlexMemberList = isEitherType(type, ['add_members']) + const showRemoveMemberList = isEitherType(type, ['remove_members']) const showAdminList = isEitherType(type, ['update_admins']) const messages = useMemo(() => contract?.use(contractState.value), [contract, contractState.value]) @@ -73,14 +89,44 @@ const WhitelistExecutePage: NextPage = () => { type, limit: limitState.value, timestamp: timestamp ? (timestamp.getTime() * 1_000_000).toString() : '', - members: [ - ...new Set( - addressListState.values - .map((a) => a.address.trim()) - .filter((address) => address !== '' && isValidAddress(address.trim()) && address.startsWith('stars')) - .concat(memberList), - ), - ], + members: + whitelistType === 'standard' + ? [ + ...new Set( + addressListState.values + .map((a) => a.address.trim()) + .filter((address) => address !== '' && isValidAddress(address.trim()) && address.startsWith('stars')) + .concat(memberList), + ), + ] + : type === 'add_members' + ? [ + ...new Set( + flexAddressListState.values + .concat(flexMemberList) + .filter((obj, index, self) => index === self.findIndex((t) => t.address.trim() === obj.address.trim())) + .filter( + (member) => + member.address !== '' && + isValidAddress(member.address.trim()) && + member.address.startsWith('stars'), + ) + .map((member) => { + return { + address: member.address.trim(), + mint_count: Math.round(member.mint_count), + } + }), + ), + ] + : [ + ...new Set( + addressListState.values + .map((a) => a.address.trim()) + .filter((address) => address !== '' && isValidAddress(address.trim()) && address.startsWith('stars')) + .concat(memberList), + ), + ], admins: [ ...new Set( addressListState.values @@ -122,11 +168,55 @@ const WhitelistExecutePage: NextPage = () => { } // eslint-disable-next-line react-hooks/exhaustive-deps }, [contractAddress]) + useEffect(() => { const initial = new URL(document.URL).searchParams.get('contractAddress') if (initial && initial.length > 0) contractState.onChange(initial) }, []) + useEffect(() => { + flexAddressListState.reset() + flexAddressListState.add({ + address: '', + mint_count: 0, + }) + }, []) + + useEffect(() => { + async function getWhitelistContractType() { + if (wallet.client && debouncedWhitelistContractState.length > 0) { + const client = wallet.client + const data = await toast.promise( + client.queryContractRaw( + debouncedWhitelistContractState, + toUtf8(Buffer.from(Buffer.from('contract_info').toString('hex'), 'hex').toString()), + ), + { + loading: 'Retrieving Whitelist type...', + error: 'Whitelist type retrieval failed.', + success: 'Whitelist type retrieved.', + }, + ) + const contractType: string = JSON.parse(new TextDecoder().decode(data as Uint8Array)).contract + console.log(contractType) + return contractType + } + } + void getWhitelistContractType() + .then((contractType) => { + if (contractType?.includes('flex')) { + setWhitelistType('flex') + } else { + setWhitelistType('standard') + } + }) + .catch((err) => { + console.log(err) + setWhitelistType('standard') + console.log('Unable to retrieve contract type. Defaulting to "standard".') + }) + }, [debouncedWhitelistContractState, wallet.client]) + return (
@@ -154,7 +244,7 @@ const WhitelistExecutePage: NextPage = () => { setTimestamp(date)} value={timestamp} /> - + { subtitle={type === 'update_admins' ? 'Enter the admin addresses' : 'Enter the member addresses'} title="Addresses" /> - + You may optionally choose a text file of additional member addresses. + + + + + + You may optionally choose a .csv file of additional member addresses and mint counts. + + + +