Merge pull request #128 from public-awesome/wl-related-changes

WL related changes
This commit is contained in:
Serkan Reis 2023-03-27 07:06:31 +03:00 committed by GitHub
commit 2e0d8e8ed9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 223 additions and 14 deletions

View File

@ -1,4 +1,4 @@
APP_VERSION=0.4.9 APP_VERSION=0.5.0
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=1702

View File

@ -1,8 +1,11 @@
import { FormControl } from 'components/FormControl' import { FormControl } from 'components/FormControl'
import { FormGroup } from 'components/FormGroup' import { FormGroup } from 'components/FormGroup'
import { AddressList } from 'components/forms/AddressList'
import { useAddressListState } from 'components/forms/AddressList.hooks'
import { useInputState, useNumberInputState } from 'components/forms/FormInput.hooks' import { useInputState, useNumberInputState } from 'components/forms/FormInput.hooks'
import { InputDateTime } from 'components/InputDateTime' import { InputDateTime } from 'components/InputDateTime'
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { isValidAddress } from 'utils/isValidAddress'
import { Conditional } from '../../Conditional' import { Conditional } from '../../Conditional'
import { AddressInput, NumberInput } from '../../forms/FormInput' import { AddressInput, NumberInput } from '../../forms/FormInput'
@ -22,6 +25,8 @@ export interface WhitelistDetailsDataProps {
endTime?: string endTime?: string
perAddressLimit?: number perAddressLimit?: number
memberLimit?: number memberLimit?: number
admins?: string[]
adminsMutable?: boolean
} }
type WhitelistState = 'none' | 'existing' | 'new' type WhitelistState = 'none' | 'existing' | 'new'
@ -31,6 +36,7 @@ export const WhitelistDetails = ({ onChange }: WhitelistDetailsProps) => {
const [startDate, setStartDate] = useState<Date | undefined>(undefined) const [startDate, setStartDate] = useState<Date | undefined>(undefined)
const [endDate, setEndDate] = useState<Date | undefined>(undefined) const [endDate, setEndDate] = useState<Date | undefined>(undefined)
const [whitelistArray, setWhitelistArray] = useState<string[]>([]) const [whitelistArray, setWhitelistArray] = useState<string[]>([])
const [adminsMutable, setAdminsMutable] = useState<boolean>(true)
const whitelistAddressState = useInputState({ const whitelistAddressState = useInputState({
id: 'whitelist-address', id: 'whitelist-address',
@ -67,6 +73,8 @@ export const WhitelistDetails = ({ onChange }: WhitelistDetailsProps) => {
setWhitelistArray(data) setWhitelistArray(data)
} }
const addressListState = useAddressListState()
useEffect(() => { useEffect(() => {
const data: WhitelistDetailsDataProps = { const data: WhitelistDetailsDataProps = {
whitelistType: whitelistState, whitelistType: whitelistState,
@ -82,6 +90,14 @@ export const WhitelistDetails = ({ onChange }: WhitelistDetailsProps) => {
endTime: endDate ? (endDate.getTime() * 1_000_000).toString() : '', endTime: endDate ? (endDate.getTime() * 1_000_000).toString() : '',
perAddressLimit: perAddressLimitState.value, perAddressLimit: perAddressLimitState.value,
memberLimit: memberLimitState.value, memberLimit: memberLimitState.value,
admins: [
...new Set(
addressListState.values
.map((a) => a.address.trim())
.filter((address) => address !== '' && isValidAddress(address.trim()) && address.startsWith('stars')),
),
],
adminsMutable,
} }
onChange(data) onChange(data)
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
@ -94,6 +110,8 @@ export const WhitelistDetails = ({ onChange }: WhitelistDetailsProps) => {
endDate, endDate,
whitelistArray, whitelistArray,
whitelistState, whitelistState,
addressListState.values,
adminsMutable,
]) ])
return ( return (
@ -186,6 +204,28 @@ export const WhitelistDetails = ({ onChange }: WhitelistDetailsProps) => {
</FormControl> </FormControl>
</FormGroup> </FormGroup>
<div> <div>
<div className="mt-2 ml-3 w-[65%] form-control">
<label className="justify-start cursor-pointer label">
<span className="mr-4 font-bold">Mutable Administrator Addresses</span>
<input
checked={adminsMutable}
className={`toggle ${adminsMutable ? `bg-stargaze` : `bg-gray-600`}`}
onClick={() => setAdminsMutable(!adminsMutable)}
type="checkbox"
/>
</label>
</div>
<div className="my-4 ml-4">
<AddressList
entries={addressListState.entries}
isRequired
onAdd={addressListState.add}
onChange={addressListState.update}
onRemove={addressListState.remove}
subtitle="The list of administrator addresses"
title="Administrator Addresses"
/>
</div>
<FormGroup subtitle="TXT file that contains the whitelisted addresses" title="Whitelist File"> <FormGroup subtitle="TXT file that contains the whitelisted addresses" title="Whitelist File">
<WhitelistUpload onChange={whitelistFileOnChange} /> <WhitelistUpload onChange={whitelistFileOnChange} />
</FormGroup> </FormGroup>

View File

@ -27,5 +27,9 @@ export function useAddressListState() {
}) })
} }
return { entries, values, add, update, remove } function reset() {
setRecord({})
}
return { entries, values, add, update, remove, reset }
} }

View File

@ -24,6 +24,7 @@ export interface WhiteListInstance {
isActive: () => Promise<boolean> isActive: () => Promise<boolean>
members: (startAfter?: string, limit?: number) => Promise<string[]> members: (startAfter?: string, limit?: number) => Promise<string[]>
hasMember: (member: string) => Promise<boolean> hasMember: (member: string) => Promise<boolean>
adminList: () => Promise<string[]>
config: () => Promise<ConfigResponse> config: () => Promise<ConfigResponse>
//Execute //Execute
@ -33,6 +34,8 @@ export interface WhiteListInstance {
removeMembers: (memberList: string[]) => Promise<string> removeMembers: (memberList: string[]) => Promise<string>
updatePerAddressLimit: (limit: number) => Promise<string> updatePerAddressLimit: (limit: number) => Promise<string>
increaseMemberLimit: (limit: number) => Promise<string> increaseMemberLimit: (limit: number) => Promise<string>
updateAdmins: (admins: string[]) => Promise<string>
freeze: () => Promise<string>
} }
export interface WhitelistMessages { export interface WhitelistMessages {
@ -42,6 +45,8 @@ export interface WhitelistMessages {
removeMembers: (memberList: string[]) => RemoveMembersMessage removeMembers: (memberList: string[]) => RemoveMembersMessage
updatePerAddressLimit: (limit: number) => UpdatePerAddressLimitMessage updatePerAddressLimit: (limit: number) => UpdatePerAddressLimitMessage
increaseMemberLimit: (limit: number) => IncreaseMemberLimitMessage increaseMemberLimit: (limit: number) => IncreaseMemberLimitMessage
updateAdmins: (admins: string[]) => UpdateAdminsMessage
freeze: () => FreezeMessage
} }
export interface UpdateStartTimeMessage { export interface UpdateStartTimeMessage {
@ -62,6 +67,22 @@ export interface UpdateEndTimeMessage {
funds: Coin[] funds: Coin[]
} }
export interface UpdateAdminsMessage {
sender: string
contract: string
msg: {
update_admins: { admins: string[] }
}
funds: Coin[]
}
export interface FreezeMessage {
sender: string
contract: string
msg: { freeze: Record<string, never> }
funds: Coin[]
}
export interface AddMembersMessage { export interface AddMembersMessage {
sender: string sender: string
contract: string contract: string
@ -139,6 +160,12 @@ export const WhiteList = (client: SigningCosmWasmClient, txSigner: string): Whit
}) })
} }
const adminList = async (): Promise<string[]> => {
return client.queryContractSmart(contractAddress, {
admin_list: {},
})
}
const config = async (): Promise<ConfigResponse> => { const config = async (): Promise<ConfigResponse> => {
return client.queryContractSmart(contractAddress, { return client.queryContractSmart(contractAddress, {
config: {}, config: {},
@ -170,6 +197,32 @@ export const WhiteList = (client: SigningCosmWasmClient, txSigner: string): Whit
return res.transactionHash return res.transactionHash
} }
const updateAdmins = async (admins: string[]): Promise<string> => {
const res = await client.execute(
txSigner,
contractAddress,
{
update_admins: {
admins,
},
},
'auto',
)
return res.transactionHash
}
const freeze = async (): Promise<string> => {
const res = await client.execute(
txSigner,
contractAddress,
{
freeze: {},
},
'auto',
)
return res.transactionHash
}
const removeMembers = async (memberList: string[]): Promise<string> => { const removeMembers = async (memberList: string[]): Promise<string> => {
const res = await client.execute( const res = await client.execute(
txSigner, txSigner,
@ -199,6 +252,8 @@ export const WhiteList = (client: SigningCosmWasmClient, txSigner: string): Whit
contractAddress, contractAddress,
updateStartTime, updateStartTime,
updateEndTime, updateEndTime,
updateAdmins,
freeze,
addMembers, addMembers,
removeMembers, removeMembers,
updatePerAddressLimit, updatePerAddressLimit,
@ -208,6 +263,7 @@ export const WhiteList = (client: SigningCosmWasmClient, txSigner: string): Whit
isActive, isActive,
members, members,
hasMember, hasMember,
adminList,
config, config,
} }
} }
@ -263,6 +319,28 @@ export const WhiteList = (client: SigningCosmWasmClient, txSigner: string): Whit
} }
} }
const updateAdmins = (admins: string[]) => {
return {
sender: txSigner,
contract: contractAddress,
msg: {
update_admins: { admins },
},
funds: [],
}
}
const freeze = () => {
return {
sender: txSigner,
contract: contractAddress,
msg: {
freeze: {},
},
funds: [],
}
}
const removeMembers = (memberList: string[]) => { const removeMembers = (memberList: string[]) => {
return { return {
sender: txSigner, sender: txSigner,
@ -299,10 +377,12 @@ export const WhiteList = (client: SigningCosmWasmClient, txSigner: string): Whit
return { return {
updateStartTime, updateStartTime,
updateEndTime, updateEndTime,
updateAdmins,
addMembers, addMembers,
removeMembers, removeMembers,
updatePerAddressLimit, updatePerAddressLimit,
increaseMemberLimit, increaseMemberLimit,
freeze,
} }
} }

View File

@ -6,10 +6,12 @@ export type ExecuteType = typeof EXECUTE_TYPES[number]
export const EXECUTE_TYPES = [ export const EXECUTE_TYPES = [
'update_start_time', 'update_start_time',
'update_end_time', 'update_end_time',
'update_admins',
'add_members', 'add_members',
'remove_members', 'remove_members',
'update_per_address_limit', 'update_per_address_limit',
'increase_member_limit', 'increase_member_limit',
'freeze',
] as const ] as const
export interface ExecuteListItem { export interface ExecuteListItem {
@ -29,6 +31,11 @@ export const EXECUTE_LIST: ExecuteListItem[] = [
name: 'Update End Time', name: 'Update End Time',
description: `Update the end time of the whitelist`, description: `Update the end time of the whitelist`,
}, },
{
id: 'update_admins',
name: 'Update Admins',
description: `Update the list of administrators for the whitelist`,
},
{ {
id: 'add_members', id: 'add_members',
name: 'Add Members', name: 'Add Members',
@ -49,6 +56,11 @@ export const EXECUTE_LIST: ExecuteListItem[] = [
name: 'Increase Member Limit', name: 'Increase Member Limit',
description: `Increase the member limit of the whitelist`, description: `Increase the member limit of the whitelist`,
}, },
{
id: 'freeze',
name: 'Freeze',
description: `Freeze the current state of the contract admin list`,
},
] ]
export interface DispatchExecuteProps { export interface DispatchExecuteProps {
@ -70,6 +82,8 @@ export type DispatchExecuteArgs = {
| { type: Select<'remove_members'>; members: string[] } | { type: Select<'remove_members'>; members: string[] }
| { type: Select<'update_per_address_limit'>; limit: number } | { type: Select<'update_per_address_limit'>; limit: number }
| { type: Select<'increase_member_limit'>; limit: number } | { type: Select<'increase_member_limit'>; limit: number }
| { type: Select<'update_admins'>; admins: string[] }
| { type: Select<'freeze'> }
) )
export const dispatchExecute = async (args: DispatchExecuteArgs) => { export const dispatchExecute = async (args: DispatchExecuteArgs) => {
@ -84,6 +98,9 @@ export const dispatchExecute = async (args: DispatchExecuteArgs) => {
case 'update_end_time': { case 'update_end_time': {
return messages.updateEndTime(args.timestamp) return messages.updateEndTime(args.timestamp)
} }
case 'update_admins': {
return messages.updateAdmins(args.admins)
}
case 'add_members': { case 'add_members': {
return messages.addMembers(args.members) return messages.addMembers(args.members)
} }
@ -96,6 +113,9 @@ export const dispatchExecute = async (args: DispatchExecuteArgs) => {
case 'increase_member_limit': { case 'increase_member_limit': {
return messages.increaseMemberLimit(args.limit) return messages.increaseMemberLimit(args.limit)
} }
case 'freeze': {
return messages.freeze()
}
default: { default: {
throw new Error('unknown execute type') throw new Error('unknown execute type')
} }
@ -113,6 +133,9 @@ export const previewExecutePayload = (args: DispatchExecuteArgs) => {
case 'update_end_time': { case 'update_end_time': {
return messages(contract)?.updateEndTime(args.timestamp) return messages(contract)?.updateEndTime(args.timestamp)
} }
case 'update_admins': {
return messages(contract)?.updateAdmins(args.admins)
}
case 'add_members': { case 'add_members': {
return messages(contract)?.addMembers(args.members) return messages(contract)?.addMembers(args.members)
} }
@ -125,6 +148,9 @@ export const previewExecutePayload = (args: DispatchExecuteArgs) => {
case 'increase_member_limit': { case 'increase_member_limit': {
return messages(contract)?.increaseMemberLimit(args.limit) return messages(contract)?.increaseMemberLimit(args.limit)
} }
case 'freeze': {
return messages(contract)?.freeze()
}
default: { default: {
return {} return {}
} }

View File

@ -2,8 +2,15 @@ import type { WhiteListInstance } from '../contract'
export type QueryType = typeof QUERY_TYPES[number] export type QueryType = typeof QUERY_TYPES[number]
export const QUERY_TYPES = ['has_started', 'has_ended', 'is_active', 'members', 'has_member', 'config'] as const export const QUERY_TYPES = [
'has_started',
'has_ended',
'is_active',
'members',
'admin_list',
'has_member',
'config',
] as const
export interface QueryListItem { export interface QueryListItem {
id: QueryType id: QueryType
name: string name: string
@ -15,6 +22,7 @@ export const QUERY_LIST: QueryListItem[] = [
{ id: 'has_ended', name: 'Has Ended', description: 'Check if the whitelist minting has ended' }, { id: 'has_ended', name: 'Has Ended', description: 'Check if the whitelist minting has ended' },
{ id: 'is_active', name: 'Is Active', description: 'Check if the whitelist minting is active' }, { id: 'is_active', name: 'Is Active', description: 'Check if the whitelist minting is active' },
{ id: 'members', name: 'Members', description: 'View the whitelist members' }, { id: 'members', name: 'Members', description: 'View the whitelist members' },
{ id: 'admin_list', name: 'Admin List', description: 'View the whitelist admin list' },
{ id: 'has_member', name: 'Has Member', description: 'Check if a member is in the whitelist' }, { id: 'has_member', name: 'Has Member', description: 'Check if a member is in the whitelist' },
{ id: 'config', name: 'Config', description: 'View the whitelist configuration' }, { id: 'config', name: 'Config', description: 'View the whitelist configuration' },
] ]
@ -36,6 +44,8 @@ export const dispatchQuery = (props: DispatchQueryProps) => {
return messages?.isActive() return messages?.isActive()
case 'members': case 'members':
return messages?.members() return messages?.members()
case 'admin_list':
return messages?.adminList()
case 'has_member': case 'has_member':
return messages?.hasMember(address) return messages?.hasMember(address)
case 'config': case 'config':

View File

@ -1,6 +1,6 @@
{ {
"name": "stargaze-studio", "name": "stargaze-studio",
"version": "0.4.9", "version": "0.5.0",
"workspaces": [ "workspaces": [
"packages/*" "packages/*"
], ],

View File

@ -378,6 +378,8 @@ const CollectionCreationPage: NextPage = () => {
mint_price: coin(String(Number(whitelistDetails?.unitPrice)), 'ustars'), mint_price: coin(String(Number(whitelistDetails?.unitPrice)), 'ustars'),
per_address_limit: whitelistDetails?.perAddressLimit, per_address_limit: whitelistDetails?.perAddressLimit,
member_limit: whitelistDetails?.memberLimit, member_limit: whitelistDetails?.memberLimit,
admins: whitelistDetails?.admins || [wallet.address],
admins_mutable: whitelistDetails?.adminsMutable,
} }
const data = await whitelistContract.instantiate( const data = await whitelistContract.instantiate(
@ -813,8 +815,8 @@ const CollectionCreationPage: NextPage = () => {
throw new Error('Per address limit is required') throw new Error('Per address limit is required')
if (!whitelistDetails.memberLimit || whitelistDetails.memberLimit === 0) if (!whitelistDetails.memberLimit || whitelistDetails.memberLimit === 0)
throw new Error('Member limit is required') throw new Error('Member limit is required')
if (Number(whitelistDetails.startTime) > Number(whitelistDetails.endTime)) if (Number(whitelistDetails.startTime) >= Number(whitelistDetails.endTime))
throw new Error('Whitelist start time cannot be later than whitelist end time') throw new Error('Whitelist start time cannot be equal to or later than the whitelist end time')
if (Number(whitelistDetails.startTime) !== Number(mintingDetails?.startTime)) if (Number(whitelistDetails.startTime) !== Number(mintingDetails?.startTime))
throw new Error('Whitelist start time must be the same as the minting start time') throw new Error('Whitelist start time must be the same as the minting start time')
if (whitelistDetails.perAddressLimit && mintingDetails?.numTokens) { if (whitelistDetails.perAddressLimit && mintingDetails?.numTokens) {

View File

@ -64,6 +64,7 @@ const WhitelistExecutePage: NextPage = () => {
const showLimitState = isEitherType(type, ['update_per_address_limit', 'increase_member_limit']) const showLimitState = isEitherType(type, ['update_per_address_limit', 'increase_member_limit'])
const showTimestamp = isEitherType(type, ['update_start_time', 'update_end_time']) const showTimestamp = isEitherType(type, ['update_start_time', 'update_end_time'])
const showMemberList = isEitherType(type, ['add_members', 'remove_members']) const showMemberList = isEitherType(type, ['add_members', 'remove_members'])
const showAdminList = isEitherType(type, ['update_admins'])
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 = {
@ -80,6 +81,13 @@ const WhitelistExecutePage: NextPage = () => {
.concat(memberList), .concat(memberList),
), ),
], ],
admins: [
...new Set(
addressListState.values
.map((a) => a.address.trim())
.filter((address) => address !== '' && isValidAddress(address.trim()) && address.startsWith('stars')),
),
] || [wallet.address],
} }
const { isLoading, mutate } = useMutation( const { isLoading, mutate } = useMutation(
async (event: FormEvent) => { async (event: FormEvent) => {
@ -146,20 +154,22 @@ const WhitelistExecutePage: NextPage = () => {
<InputDateTime minDate={new Date()} onChange={(date) => setTimestamp(date)} value={timestamp} /> <InputDateTime minDate={new Date()} onChange={(date) => setTimestamp(date)} value={timestamp} />
</FormControl> </FormControl>
</Conditional> </Conditional>
<Conditional test={showMemberList}> <Conditional test={showMemberList || showAdminList}>
<AddressList <AddressList
entries={addressListState.entries} entries={addressListState.entries}
isRequired isRequired
onAdd={addressListState.add} onAdd={addressListState.add}
onChange={addressListState.update} onChange={addressListState.update}
onRemove={addressListState.remove} onRemove={addressListState.remove}
subtitle="Enter the member addresses" subtitle={type === 'update_admins' ? 'Enter the admin addresses' : 'Enter the member addresses'}
title="Addresses" title="Addresses"
/> />
<Alert className="mt-8" type="info"> <Conditional test={showMemberList}>
You may optionally choose a text file of additional member addresses. <Alert className="mt-8" type="info">
</Alert> You may optionally choose a text file of additional member addresses.
<WhitelistUpload onChange={setMemberList} /> </Alert>
<WhitelistUpload onChange={setMemberList} />
</Conditional>
</Conditional> </Conditional>
</div> </div>
<div className="space-y-8"> <div className="space-y-8">

View File

@ -5,6 +5,8 @@ import { Conditional } from 'components/Conditional'
import { ContractPageHeader } from 'components/ContractPageHeader' import { ContractPageHeader } from 'components/ContractPageHeader'
import { FormControl } from 'components/FormControl' import { FormControl } from 'components/FormControl'
import { FormGroup } from 'components/FormGroup' import { FormGroup } from 'components/FormGroup'
import { AddressList } from 'components/forms/AddressList'
import { useAddressListState } from 'components/forms/AddressList.hooks'
import { NumberInput } from 'components/forms/FormInput' import { NumberInput } from 'components/forms/FormInput'
import { useNumberInputState } from 'components/forms/FormInput.hooks' import { useNumberInputState } from 'components/forms/FormInput.hooks'
import { InputDateTime } from 'components/InputDateTime' import { InputDateTime } from 'components/InputDateTime'
@ -22,6 +24,7 @@ import { toast } from 'react-hot-toast'
import { FaAsterisk } from 'react-icons/fa' import { FaAsterisk } from 'react-icons/fa'
import { useMutation } from 'react-query' import { useMutation } from 'react-query'
import { WHITELIST_CODE_ID } from 'utils/constants' import { WHITELIST_CODE_ID } from 'utils/constants'
import { isValidAddress } from 'utils/isValidAddress'
import { withMetadata } from 'utils/layout' import { withMetadata } from 'utils/layout'
import { links } from 'utils/links' import { links } from 'utils/links'
@ -31,6 +34,7 @@ const WhitelistInstantiatePage: NextPage = () => {
const [startDate, setStartDate] = useState<Date | undefined>(undefined) const [startDate, setStartDate] = useState<Date | undefined>(undefined)
const [endDate, setEndDate] = useState<Date | undefined>(undefined) const [endDate, setEndDate] = useState<Date | undefined>(undefined)
const [adminsMutable, setAdminsMutable] = useState<boolean>(true)
const [whitelistArray, setWhitelistArray] = useState<string[]>([]) const [whitelistArray, setWhitelistArray] = useState<string[]>([])
@ -58,6 +62,8 @@ const WhitelistInstantiatePage: NextPage = () => {
placeholder: '5', placeholder: '5',
}) })
const addressListState = useAddressListState()
const { data, isLoading, mutate } = useMutation( const { data, isLoading, mutate } = useMutation(
async (event: FormEvent): Promise<InstantiateResponse | null> => { async (event: FormEvent): Promise<InstantiateResponse | null> => {
event.preventDefault() event.preventDefault()
@ -79,6 +85,14 @@ const WhitelistInstantiatePage: NextPage = () => {
mint_price: coin(String(Number(unitPriceState.value) * 1000000), 'ustars'), mint_price: coin(String(Number(unitPriceState.value) * 1000000), 'ustars'),
per_address_limit: perAddressLimitState.value, per_address_limit: perAddressLimitState.value,
member_limit: memberLimitState.value, member_limit: memberLimitState.value,
admins: [
...new Set(
addressListState.values
.map((a) => a.address.trim())
.filter((address) => address !== '' && isValidAddress(address.trim()) && address.startsWith('stars')),
),
] || [wallet.address],
admins_mutable: adminsMutable,
} }
return toast.promise( return toast.promise(
contract.instantiate(WHITELIST_CODE_ID, msg, 'Stargaze Whitelist Contract', wallet.address), contract.instantiate(WHITELIST_CODE_ID, msg, 'Stargaze Whitelist Contract', wallet.address),
@ -119,6 +133,29 @@ const WhitelistInstantiatePage: NextPage = () => {
<br /> <br />
</Conditional> </Conditional>
<div className="mt-2 ml-3 w-full form-control">
<label className="justify-start cursor-pointer label">
<span className="mr-4 font-bold">Mutable Administrator Addresses</span>
<input
checked={adminsMutable}
className={`toggle ${adminsMutable ? `bg-stargaze` : `bg-gray-600`}`}
onClick={() => setAdminsMutable(!adminsMutable)}
type="checkbox"
/>
</label>
</div>
<div className="my-4 ml-4 w-1/2">
<AddressList
entries={addressListState.entries}
isRequired
onAdd={addressListState.add}
onChange={addressListState.update}
onRemove={addressListState.remove}
subtitle="The list of administrator addresses"
title="Administrator Addresses"
/>
</div>
<FormGroup subtitle="Your whitelisted addresses" title="Whitelist File"> <FormGroup subtitle="Your whitelisted addresses" title="Whitelist File">
<WhitelistUpload onChange={whitelistFileOnChange} /> <WhitelistUpload onChange={whitelistFileOnChange} />
<Conditional test={whitelistArray.length > 0}> <Conditional test={whitelistArray.length > 0}>

View File

@ -108,7 +108,7 @@ const WhitelistQueryPage: NextPage = () => {
onChange={(e) => setType(e.target.value as QueryType)} onChange={(e) => setType(e.target.value as QueryType)}
> >
{QUERY_LIST.map(({ id, name }) => ( {QUERY_LIST.map(({ id, name }) => (
<option key={`query-${id}`} value={id}> <option key={`query-${id}`} className="mt-2 text-lg bg-[#1A1A1A]" value={id}>
{name} {name}
</option> </option>
))} ))}