From 8a07a182e595ec5232864072e3020ccc80190e3c Mon Sep 17 00:00:00 2001 From: Serkan Reis Date: Mon, 24 Oct 2022 12:09:43 +0300 Subject: [PATCH] Add update_collection_info() to collection actions --- components/collections/actions/Action.tsx | 125 +++++++++++++++++- components/collections/actions/actions.ts | 15 ++- .../creation/CollectionDetails.tsx | 4 - contracts/minter/contract.ts | 2 +- contracts/sg721/contract.ts | 51 ++++++- pages/contracts/minter/execute.tsx | 2 +- 6 files changed, 190 insertions(+), 9 deletions(-) diff --git a/components/collections/actions/Action.tsx b/components/collections/actions/Action.tsx index 77dcab9..cc8a036 100644 --- a/components/collections/actions/Action.tsx +++ b/components/collections/actions/Action.tsx @@ -22,6 +22,7 @@ import { FaArrowRight } from 'react-icons/fa' import { useMutation } from 'react-query' import type { AirdropAllocation } from 'utils/isValidAccountsFile' +import type { CollectionInfo } from '../../../contracts/sg721/contract' import { TextInput } from '../../forms/FormInput' interface CollectionActionsProps { @@ -43,12 +44,14 @@ export const CollectionActions = ({ const [timestamp, setTimestamp] = useState(undefined) const [airdropAllocationArray, setAirdropAllocationArray] = useState([]) const [airdropArray, setAirdropArray] = useState([]) + const [collectionInfo, setCollectionInfo] = useState() + const [explicitContent, setExplicitContent] = useState(false) const actionComboboxState = useActionsComboboxState() const type = actionComboboxState.value?.id const limitState = useNumberInputState({ - id: 'per-address-limi', + id: 'per-address-limit', name: 'perAddressLimit', title: 'Per Address Limit', subtitle: 'Enter the per address limit', @@ -97,6 +100,41 @@ export const CollectionActions = ({ subtitle: 'New minting price in STARS', }) + const descriptionState = useInputState({ + id: 'collection-description', + name: 'description', + title: 'Collection Description', + }) + + const imageState = useInputState({ + id: 'collection-cover-image', + name: 'cover_image', + title: 'Collection Cover Image', + subtitle: 'URL for collection cover image.', + }) + + const externalLinkState = useInputState({ + id: 'collection-ext-link', + name: 'external_link', + title: 'External Link', + subtitle: 'External URL for the collection.', + }) + + const royaltyPaymentAddressState = useInputState({ + id: 'royalty-payment-address', + name: 'royaltyPaymentAddress', + title: 'Royalty Payment Address', + subtitle: 'Address to receive royalties.', + }) + + const royaltyShareState = useInputState({ + id: 'royalty-share', + name: 'royaltyShare', + title: 'Share Percentage', + subtitle: 'Percentage of royalties to be paid', + placeholder: '8%', + }) + const showWhitelistField = type === 'set_whitelist' const showDateField = isEitherType(type, ['update_start_time', 'update_start_trading_time']) const showLimitField = type === 'update_per_address_limit' @@ -106,6 +144,11 @@ export const CollectionActions = ({ const showRecipientField = isEitherType(type, ['transfer', 'mint_to', 'mint_for', 'batch_mint', 'batch_transfer']) const showAirdropFileField = type === 'airdrop' const showPriceField = type === 'update_mint_price' + const showDescriptionField = type === 'update_collection_info' + const showImageField = type === 'update_collection_info' + const showExternalLinkField = type === 'update_collection_info' + const showRoyaltyRelatedFields = type === 'update_collection_info' + const showExplicitContentField = type === 'update_collection_info' const payload: DispatchExecuteArgs = { whitelist: whitelistState.value, @@ -123,8 +166,32 @@ export const CollectionActions = ({ txSigner: wallet.address, type, price: priceState.value.toString(), + collectionInfo, } + useEffect(() => { + setCollectionInfo({ + description: descriptionState.value || undefined, + image: imageState.value || undefined, + explicit_content: explicitContent, + external_link: externalLinkState.value || undefined, + royalty_info: + royaltyPaymentAddressState.value && royaltyShareState.value + ? { + payment_address: royaltyPaymentAddressState.value, + share: (Number(royaltyShareState.value) / 100).toString(), + } + : undefined, + }) + }, [ + descriptionState.value, + imageState.value, + explicitContent, + externalLinkState.value, + royaltyPaymentAddressState.value, + royaltyShareState.value, + ]) + useEffect(() => { const addresses: string[] = [] airdropAllocationArray.forEach((allocation) => { @@ -187,6 +254,62 @@ export const CollectionActions = ({ {showTokenIdListField && } {showNumberOfTokensField && } {showPriceField && } + {showDescriptionField && } + {showImageField && } + {showExternalLinkField && } + {showRoyaltyRelatedFields && ( + <> + + + + )} + {showExplicitContentField && ( +
+
+
+ + Does the collection contain explicit content? + +
+ { + setExplicitContent(true) + }} + type="radio" + /> + +
+
+ { + setExplicitContent(false) + }} + type="radio" + /> + +
+
+
+
+ )} {showAirdropFileField && ( ; tokenIds: string } | { type: Select<'airdrop'>; recipients: string[] } | { type: Select<'burn_remaining'> } + | { type: Select<'update_collection_info'>; collectionInfo: CollectionInfo | undefined } ) export const dispatchExecute = async (args: DispatchExecuteArgs) => { @@ -197,6 +204,9 @@ export const dispatchExecute = async (args: DispatchExecuteArgs) => { case 'update_per_address_limit': { return minterMessages.updatePerAddressLimit(txSigner, args.limit) } + case 'update_collection_info': { + return sg721Messages.updateCollectionInfo(args.collectionInfo as CollectionInfo) + } case 'shuffle': { return minterMessages.shuffle(txSigner) } @@ -264,6 +274,9 @@ export const previewExecutePayload = (args: DispatchExecuteArgs) => { case 'update_per_address_limit': { return minterMessages(minterContract)?.updatePerAddressLimit(args.limit) } + case 'update_collection_info': { + return sg721Messages(sg721Contract)?.updateCollectionInfo(args.collectionInfo as CollectionInfo) + } case 'shuffle': { return minterMessages(minterContract)?.shuffle() } diff --git a/components/collections/creation/CollectionDetails.tsx b/components/collections/creation/CollectionDetails.tsx index a078689..072177b 100644 --- a/components/collections/creation/CollectionDetails.tsx +++ b/components/collections/creation/CollectionDetails.tsx @@ -107,10 +107,6 @@ export const CollectionDetails = ({ onChange, uploadMethod, coverImageUrl }: Col reader.readAsArrayBuffer(event.target.files[0]) } - useEffect(() => { - console.log(explicit) - }, [explicit]) - return (
diff --git a/contracts/minter/contract.ts b/contracts/minter/contract.ts index db89d9e..3303dc1 100644 --- a/contracts/minter/contract.ts +++ b/contracts/minter/contract.ts @@ -12,7 +12,7 @@ export interface InstantiateResponse { readonly logs: readonly logs.Log[] } -export interface RoyalityInfo { +export interface RoyaltyInfo { payment_address: string share: string } diff --git a/contracts/sg721/contract.ts b/contracts/sg721/contract.ts index ba108f1..8db16fc 100644 --- a/contracts/sg721/contract.ts +++ b/contracts/sg721/contract.ts @@ -4,6 +4,8 @@ import type { Coin } from '@cosmjs/stargate' import { coin } from '@cosmjs/stargate' import { MsgExecuteContract } from 'cosmjs-types/cosmwasm/wasm/v1/tx' +import type { RoyaltyInfo } from '../minter/contract' + export interface InstantiateResponse { readonly contractAddress: string readonly transactionHash: string @@ -11,6 +13,14 @@ export interface InstantiateResponse { export type Expiration = { at_height: number } | { at_time: string } | { never: Record } +export interface CollectionInfo { + description?: string + image?: string + external_link?: string + explicit_content?: boolean + royalty_info?: RoyaltyInfo | undefined +} + export interface SG721Instance { readonly contractAddress: string @@ -65,7 +75,7 @@ export interface SG721Instance { revokeAll: (operator: string) => Promise /// Mint a new NFT, can only be called by the contract minter mint: (tokenId: string, owner: string, tokenURI?: string) => Promise //MintMsg - + updateCollectionInfo: (collectionInfo: CollectionInfo) => Promise /// Burn an NFT the sender has access to burn: (tokenId: string) => Promise batchBurn: (tokenIds: string) => Promise @@ -83,6 +93,7 @@ export interface Sg721Messages { burn: (tokenId: string) => BurnMessage batchBurn: (tokenIds: string) => BatchBurnMessage batchTransfer: (recipient: string, tokenIds: string) => BatchTransferMessage + updateCollectionInfo: (collectionInfo: CollectionInfo) => UpdateCollectionInfoMessage } export interface TransferNFTMessage { @@ -197,6 +208,17 @@ export interface BatchTransferMessage { funds: Coin[] } +export interface UpdateCollectionInfoMessage { + sender: string + contract: string + msg: { + update_collection_info: { + collection_info: CollectionInfo + } + } + funds: Coin[] +} + export interface SG721Contract { instantiate: ( senderAddress: string, @@ -513,6 +535,21 @@ export const SG721 = (client: SigningCosmWasmClient, txSigner: string): SG721Con return res.transactionHash } + // eslint-disable-next-line @typescript-eslint/no-shadow + const updateCollectionInfo = async (collectionInfo: CollectionInfo): Promise => { + console.log(collectionInfo) + const res = await client.execute( + txSigner, + contractAddress, + { + update_collection_info: { collection_info: collectionInfo }, + }, + 'auto', + '', + ) + return res.transactionHash + } + return { contractAddress, ownerOf, @@ -537,6 +574,7 @@ export const SG721 = (client: SigningCosmWasmClient, txSigner: string): SG721Con burn, batchBurn, batchTransfer, + updateCollectionInfo, } } @@ -719,6 +757,16 @@ export const SG721 = (client: SigningCosmWasmClient, txSigner: string): SG721Con funds: [], } } + const updateCollectionInfo = (collectionInfo: CollectionInfo) => { + return { + sender: txSigner, + contract: contractAddress, + msg: { + update_collection_info: { collection_info: collectionInfo }, + }, + funds: [], + } + } return { transferNft, @@ -731,6 +779,7 @@ export const SG721 = (client: SigningCosmWasmClient, txSigner: string): SG721Con burn, batchBurn, batchTransfer, + updateCollectionInfo, } } diff --git a/pages/contracts/minter/execute.tsx b/pages/contracts/minter/execute.tsx index 5cd0b67..f2dce66 100644 --- a/pages/contracts/minter/execute.tsx +++ b/pages/contracts/minter/execute.tsx @@ -37,7 +37,7 @@ const MinterExecutePage: NextPage = () => { const type = comboboxState.value?.id const limitState = useNumberInputState({ - id: 'per-address-limi', + id: 'per-address-limit', name: 'perAddressLimit', title: 'Per Address Limit', subtitle: 'Enter the per address limit',