/* eslint-disable eslint-comments/disable-enable-pair */ /* eslint-disable @typescript-eslint/no-unnecessary-condition */ /* eslint-disable no-nested-ternary */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable tailwindcss/classnames-order */ import { coins, GasPrice, SigningStargateClient } from '@cosmjs/stargate' import { Alert } from 'components/Alert' import { Button } from 'components/Button' import { Conditional } from 'components/Conditional' import { ContractPageHeader } from 'components/ContractPageHeader' import { FormControl } from 'components/FormControl' import { AddressInput, NumberInput, TextInput } from 'components/forms/FormInput' import { useInputState, useNumberInputState } from 'components/forms/FormInput.hooks' import { InputDateTime } from 'components/InputDateTime' import { LinkTabs } from 'components/LinkTabs' import { authzLinkTabs } from 'components/LinkTabs.data' import { getConfig } from 'config' import type { Msg } from 'config/authz' import { AuthzExecuteContractGrantMsg, AuthzGenericGrantMsg, AuthzMigrateContractGrantMsg, AuthzSendGrantMsg, } from 'config/authz' import { useGlobalSettings } from 'contexts/globalSettings' import type { NextPage } from 'next' import { NextSeo } from 'next-seo' import { useState } from 'react' import toast from 'react-hot-toast' import { NETWORK } from 'utils/constants' import { withMetadata } from 'utils/layout' import { useWallet } from 'utils/wallet' export type AuthorizationMode = 'Grant' | 'Revoke' export type GrantAuthorizationType = 'Generic' | 'Send' | 'Execute Smart Contract' | 'Migrate Smart Contract' export type GenericAuthorizationType = | 'MsgDelegate' | 'MsgUndelegate' | 'MsgBeginRedelegate' | 'MsgWithdrawDelegatorReward' | 'MsgVote' | 'MsgSend' | 'MsgExecuteContract' | 'MsgMigrateContract' | 'MsgStoreCode' const Grant: NextPage = () => { const wallet = useWallet() const { timezone } = useGlobalSettings() const [authMode, setAuthMode] = useState('Grant') const [authType, setAuthType] = useState('Generic') const [genericAuthType, setGenericAuthType] = useState('MsgSend') const [expiration, setExpiration] = useState() const [transactionHash, setTransactionHash] = useState(undefined) const [isLoading, setIsLoading] = useState(false) const granteeAddressState = useInputState({ id: 'grantee-address', name: 'granteeAddress', title: 'Grantee Address', placeholder: 'stars1...', subtitle: 'The address to grant authorization to', }) const spendLimitDenomState = useInputState({ id: 'spend-limit-denom', name: 'spendLimitDenom', title: 'Spend Limit Denom', placeholder: `ustars`, subtitle: 'The spend limit denom', }) const spendLimitState = useNumberInputState({ id: 'spend-limit', name: 'spendLimit', title: 'Spend Limit', placeholder: `1000000`, subtitle: 'The spend limit', }) const maxFundsLimitDenomState = useInputState({ id: 'max-funds-limit-denom', name: 'maxFundsLimitDenom', title: 'Max Funds Limit Denom', placeholder: `ustars`, subtitle: 'The denom for max funds limit', }) const maxFundsLimitState = useNumberInputState({ id: 'max-funds-limit', name: 'maxFundsLimit', title: 'Max Funds Limit', placeholder: `1000000`, subtitle: 'The max funds limit for contract execution (leave blank for no limit)', }) const allowListState = useInputState({ id: 'allow-list', name: 'allowList', title: 'Allow List', placeholder: `stars1..., stars1...`, subtitle: 'Comma separated list of addresses to allow transactions to', }) const contractAddressState = useInputState({ id: 'contract-address', name: 'contractAddress', title: 'Contract Address', placeholder: `stars1...`, subtitle: 'The contract address to authorize execution on', }) const allowedMessageKeysState = useInputState({ id: 'allowed-message-keys', name: 'allowedMessageKeys', title: 'Allowed Message Keys', placeholder: `mint_to, burn, transfer`, subtitle: 'Comma separated list of allowed message keys (leave blank to allow all)', }) const callsRemainingState = useNumberInputState({ id: 'calls-remaining', name: 'callsRemaining', title: 'Calls Remaining', placeholder: `10`, subtitle: 'The allowed number of contract execution calls (leave blank for no limit)', }) const messageToSign = () => { if (authType === 'Generic') { if (genericAuthType === 'MsgSend') { return AuthzGenericGrantMsg( wallet.address || '', granteeAddressState.value, '/cosmos.bank.v1beta1.MsgSend', (expiration?.getTime() as number) / 1000 || 0, ) } if (genericAuthType === 'MsgDelegate') { return AuthzGenericGrantMsg( wallet.address || '', granteeAddressState.value, '/cosmos.staking.v1beta1.MsgDelegate', (expiration?.getTime() as number) / 1000 || 0, ) } if (genericAuthType === 'MsgUndelegate') { return AuthzGenericGrantMsg( wallet.address || '', granteeAddressState.value, '/cosmos.staking.v1beta1.MsgUndelegate', (expiration?.getTime() as number) / 1000 || 0, ) } if (genericAuthType === 'MsgBeginRedelegate') { return AuthzGenericGrantMsg( wallet.address || '', granteeAddressState.value, '/cosmos.staking.v1beta1.MsgBeginRedelegate', (expiration?.getTime() as number) / 1000 || 0, ) } if (genericAuthType === 'MsgWithdrawDelegatorReward') { return AuthzGenericGrantMsg( wallet.address || '', granteeAddressState.value, '/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward', (expiration?.getTime() as number) / 1000 || 0, ) } if (genericAuthType === 'MsgVote') { return AuthzGenericGrantMsg( wallet.address || '', granteeAddressState.value, '/cosmos.gov.v1beta1.MsgVote', (expiration?.getTime() as number) / 1000 || 0, ) } if (genericAuthType === 'MsgExecuteContract') { return AuthzGenericGrantMsg( wallet.address || '', granteeAddressState.value, '/cosmwasm.wasm.v1.MsgExecuteContract', (expiration?.getTime() as number) / 1000 || 0, ) } if (genericAuthType === 'MsgMigrateContract') { return AuthzGenericGrantMsg( wallet.address || '', granteeAddressState.value, '/cosmwasm.wasm.v1.MsgMigrateContract', (expiration?.getTime() as number) / 1000 || 0, ) } if (genericAuthType === 'MsgStoreCode') { return AuthzGenericGrantMsg( wallet.address || '', granteeAddressState.value, '/cosmwasm.wasm.v1.MsgStoreCode', (expiration?.getTime() as number) / 1000 || 0, ) } } else if (authType === 'Send') { return AuthzSendGrantMsg( wallet.address || '', granteeAddressState.value, spendLimitDenomState.value, spendLimitState.value, (expiration?.getTime() as number) / 1000 || 0, allowListState.value ? allowListState.value.split(',').map((address) => address.trim()) : [], ) } else if (authType === 'Execute Smart Contract') { return AuthzExecuteContractGrantMsg( wallet.address || '', granteeAddressState.value, contractAddressState.value, (expiration?.getTime() as number) / 1000 || 0, callsRemainingState.value ? callsRemainingState.value : undefined, maxFundsLimitState.value > 0 ? coins(maxFundsLimitState.value, maxFundsLimitDenomState.value) : undefined, allowedMessageKeysState.value ? allowedMessageKeysState.value.split(',').map((key) => key.trim()) : undefined, ) } else if (authType === 'Migrate Smart Contract') { return AuthzMigrateContractGrantMsg( wallet.address || '', granteeAddressState.value, contractAddressState.value, (expiration?.getTime() as number) / 1000 || 0, callsRemainingState.value ? callsRemainingState.value : undefined, maxFundsLimitState.value > 0 ? coins(maxFundsLimitState.value, maxFundsLimitDenomState.value) : undefined, allowedMessageKeysState.value ? allowedMessageKeysState.value.split(',').map((key) => key.trim()) : undefined, ) } } const handleSendMessage = async () => { try { if (!wallet.isWalletConnected) return toast.error('Please connect your wallet.') setTransactionHash(undefined) setIsLoading(true) const offlineSigner = wallet.getOfflineSignerDirect() const stargateClient = await SigningStargateClient.connectWithSigner(getConfig(NETWORK).rpcUrl, offlineSigner, { gasPrice: GasPrice.fromString('0.025ustars'), }) const response = await stargateClient.signAndBroadcast(wallet.address || '', [messageToSign() as Msg], 'auto') setTransactionHash(response.transactionHash) toast.success(`${authType} authorization success.`, { style: { maxWidth: 'none' } }) setIsLoading(false) } catch (error: any) { toast.error(error.message, { style: { maxWidth: 'none' } }) setIsLoading(false) setTransactionHash(undefined) console.error('Error: ', error) } } return (
Authorization Type
Generic Authorization Type
{/* Needs cosmos-sdk v0.47 */} {/* */}
date ? setExpiration( timezone === 'Local' ? date : new Date(date?.getTime() - new Date().getTimezoneOffset() * 60 * 1000), ) : setExpiration(undefined) } value={ timezone === 'Local' ? expiration : expiration ? new Date(expiration.getTime() + new Date().getTimezoneOffset() * 60 * 1000) : undefined } /> {transactionHash && ( {`Transaction Hash: ${transactionHash}`} )}
) } export default withMetadata(Grant, { center: false })