Skip to content

Commit

Permalink
deepTxs hooks compatibilityToken
Browse files Browse the repository at this point in the history
  • Loading branch information
Tbaut committed Sep 17, 2024
1 parent 48366a9 commit 3bcf704
Show file tree
Hide file tree
Showing 11 changed files with 152 additions and 158 deletions.
122 changes: 50 additions & 72 deletions packages/ui/src/components/modals/ChangeMultisig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import Summary from '../../pages/Creation/Summary'
import { useApi } from '../../contexts/ApiContext'
import { useAccounts } from '../../contexts/AccountsContext'
import { useSigningCallback } from '../../hooks/useSigningCallback'
import { useToasts } from '../../contexts/ToastContext'
import { AccountBadge } from '../../types'
import { getIntersection } from '../../utils'
import GenericAccountSelection, { AccountBaseInfo } from '../select/GenericAccountSelection'
Expand All @@ -26,12 +25,13 @@ import { useCheckBalance } from '../../hooks/useCheckBalance'
import { formatBnBalance } from '../../utils/formatBnBalance'
import { useMultisigProposalNeededFunds } from '../../hooks/useMultisigProposalNeededFunds'
import { MdErrorOutline as ErrorOutlineIcon } from 'react-icons/md'
import { useGetSubscanLinks } from '../../hooks/useSubscanLink'
import { Button } from '../library'
import { ModalCloseButton } from '../library/ModalCloseButton'
import { useGetSortAddress } from '../../hooks/useGetSortAddress'
import { useGetMultisigAddress } from '../../contexts/useGetMultisigAddress'
import { getAsMultiTx } from '../../utils/getAsMultiTx'
import { TypedApi } from 'polkadot-api'
import { dot, MultiAddress, ProxyType } from '@polkadot-api/descriptors'

interface Props {
onClose: () => void
Expand All @@ -41,14 +41,15 @@ interface Props {
type Step = 'selection' | 'summary' | 'call1' | 'call2'

const ChangeMultisig = ({ onClose, className }: Props) => {
const { getSubscanExtrinsicLink } = useGetSubscanLinks()
const modalRef = useRef<HTMLDivElement | null>(null)
const { api, chainInfo } = useApi()
const { api, chainInfo, compatibilityToken } = useApi()
const { selectedMultiProxy, getMultisigAsAccountBaseInfo, getMultisigByAddress } = useMultiProxy()
const { addToast } = useToasts()
const signCallBack2 = useSigningCallback({
onSuccess: onClose,
onError: onClose
onError: (e) => {
onClose()
onErrorCallback(e)
}
})
const { getSortAddress } = useGetSortAddress()
const { selectedAccount, selectedSigner, ownAddressList } = useAccounts()
Expand Down Expand Up @@ -85,8 +86,8 @@ const ChangeMultisig = ({ onClose, className }: Props) => {
const multisigList = useMemo(() => getMultisigAsAccountBaseInfo(), [getMultisigAsAccountBaseInfo])
const [callError, setCallError] = useState('')

const firstCall = useMemo(() => {
if (!api) {
const secondCall = useMemo(() => {
if (!api || !compatibilityToken) {
// console.error('api is not ready')
return
}
Expand Down Expand Up @@ -119,29 +120,40 @@ const ChangeMultisig = ({ onClose, className }: Props) => {
selectedMultisig.signatories.filter((sig) => sig !== selectedAccount.address)
)

const addProxyTx = api.tx.proxy.addProxy(newMultisigAddress, 'Any', 0)
const proxyTx = api.tx.proxy.proxy(selectedMultiProxy?.proxy, null, addProxyTx)
// call with the old multisig
const addProxyTx = (api as TypedApi<typeof dot>).tx.Proxy.add_proxy({
delegate: MultiAddress.Id(newMultisigAddress),
proxy_type: ProxyType.Any(),
delay: 0
})

const proxyTx = (api as TypedApi<typeof dot>).tx.Proxy.proxy({
real: MultiAddress.Id(selectedMultiProxy?.proxy),
force_proxy_type: undefined,
call: addProxyTx.decodedCall
})
// call with the old multisig to delete the new one
return getAsMultiTx({
api,
threshold: oldThreshold,
otherSignatories: otherOldSignatories,
tx: proxyTx
tx: proxyTx,
compatibilityToken
})
}, [
api,
chainInfo,
compatibilityToken,
getSortAddress,
newMultisigAddress,
newThreshold,
oldThreshold,
selectedAccount,
selectedMultiProxy,
selectedMultiProxy?.proxy,
selectedMultisig
])

const secondCall = useMemo(() => {
if (!api) {
const firstCall = useMemo(() => {
if (!api || !compatibilityToken) {
// console.error('api is not ready')
return
}
Expand Down Expand Up @@ -169,13 +181,23 @@ const ChangeMultisig = ({ onClose, className }: Props) => {
const otherNewSignatories = getSortAddress(
newSignatories.filter((sig) => sig !== selectedAccount.address)
)
const removeProxyTx = api.tx.proxy.removeProxy(selectedMultisig?.address, 'Any', 0)
const proxyTx = api.tx.proxy.proxy(selectedMultiProxy?.proxy, null, removeProxyTx)
const removeProxyTx = (api as TypedApi<typeof dot>).tx.Proxy.remove_proxy({
delegate: MultiAddress.Id(selectedMultisig?.address),
proxy_type: ProxyType.Any(),
delay: 0
})
const proxyTx = (api as TypedApi<typeof dot>).tx.Proxy.proxy({
real: MultiAddress.Id(selectedMultiProxy?.proxy),
force_proxy_type: undefined,
call: removeProxyTx.decodedCall
})

return getAsMultiTx({
api,
otherSignatories: otherNewSignatories,
threshold: newThreshold,
tx: proxyTx
tx: proxyTx,
compatibilityToken
})
}, [
api,
Expand All @@ -185,7 +207,8 @@ const ChangeMultisig = ({ onClose, className }: Props) => {
newThreshold,
selectedAccount,
selectedMultiProxy,
selectedMultisig
selectedMultisig,
compatibilityToken
])

const { multisigProposalNeededFunds: firstCallNeededFunds, reserved: firstCallReserved } =
Expand All @@ -201,7 +224,7 @@ const ChangeMultisig = ({ onClose, className }: Props) => {
threshold: newThreshold
})
const neededBalance = useMemo(
() => firstCallNeededFunds.add(secondCallNeededFunds),
() => firstCallNeededFunds + secondCallNeededFunds,
[firstCallNeededFunds, secondCallNeededFunds]
)
const { hasEnoughFreeBalance: hasSignerEnoughFunds } = useCheckBalance({
Expand Down Expand Up @@ -260,37 +283,14 @@ const ChangeMultisig = ({ onClose, className }: Props) => {
return
}

if (!secondCall) {
if (!secondCall || !selectedSigner) {
return
}

setCurrentStep('call2')

secondCall
.signAndSend(
selectedAccount.address,
{ signer: selectedSigner, withSignedTransaction: true },
signCallBack2
)
.catch((error: Error) => {
addToast({
title: error.message,
type: 'error',
link: getSubscanExtrinsicLink(secondCall.hash.toHex())
})
onErrorCallback(error.message)
})
}, [
callError,
api,
selectedAccount,
secondCall,
selectedSigner,
signCallBack2,
addToast,
getSubscanExtrinsicLink,
onErrorCallback
])
secondCall.signSubmitAndWatch(selectedSigner, { at: 'best' }).subscribe(signCallBack2)
}, [callError, api, selectedAccount, secondCall, selectedSigner, signCallBack2])

const signCallBack1 = useSigningCallback({
onSuccess: onMakeSecondCall,
Expand All @@ -309,36 +309,14 @@ const ChangeMultisig = ({ onClose, className }: Props) => {
return
}

if (!firstCall) {
if (!firstCall || !selectedSigner) {
return
}

setCurrentStep('call1')

firstCall
.signAndSend(
selectedAccount.address,
{ signer: selectedSigner, withSignedTransaction: true },
signCallBack1
)
.catch((error: Error) => {
addToast({
title: error.message,
type: 'error',
link: getSubscanExtrinsicLink(firstCall.hash.toHex())
})
onErrorCallback(error.message)
})
}, [
api,
selectedAccount,
firstCall,
selectedSigner,
signCallBack1,
addToast,
getSubscanExtrinsicLink,
onErrorCallback
])
firstCall.signSubmitAndWatch(selectedSigner, { at: 'best' }).subscribe(signCallBack1)
}, [api, selectedAccount, firstCall, selectedSigner, signCallBack1])

const onClickNext = useCallback(() => {
if (currentStep === 'summary') {
Expand Down Expand Up @@ -437,7 +415,7 @@ const ChangeMultisig = ({ onClose, className }: Props) => {
balanceMin={neededBalance}
isBalanceError={!hasSignerEnoughFunds}
selectedMultisig={selectedMultisig}
reservedBalance={firstCallReserved.add(secondCallReserved)}
reservedBalance={firstCallReserved + secondCallReserved}
/>
)}
{(currentStep === 'call1' || currentStep === 'call2') && (
Expand Down
73 changes: 27 additions & 46 deletions packages/ui/src/components/modals/DeepTxCreation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ import { useApi } from '../../contexts/ApiContext'
import { MultisigAggregated, useMultiProxy } from '../../contexts/MultiProxyContext'
import CallInfo from '../CallInfo'
import SignerSelection from '../select/SignerSelection'
import { useToasts } from '../../contexts/ToastContext'
import { useSigningCallback } from '../../hooks/useSigningCallback'
import { useGetSubscanLinks } from '../../hooks/useSubscanLink'
import { useCallInfoFromCallData } from '../../hooks/useCallInfoFromCallData'
import { ModalCloseButton } from '../library/ModalCloseButton'
import { useCheckBalance } from '../../hooks/useCheckBalance'
Expand All @@ -21,6 +19,7 @@ import { HexString } from '../../types'
import { getDisplayArgs, getErrorMessageReservedFunds, getExtrinsicName } from '../../utils'
import { useMultisigProposalNeededFunds } from '../../hooks/useMultisigProposalNeededFunds'
import { formatBnBalance } from '../../utils/formatBnBalance'
import { hashFromTx } from '../../utils/txHash'

export interface DeepTxCreationProps {
onClose: () => void
Expand All @@ -41,12 +40,10 @@ const DeepTxCreationModal = ({
parentMultisigInfo,
currentMultisigInvolved
}: DeepTxCreationProps) => {
const { getSubscanExtrinsicLink } = useGetSubscanLinks()
const { api, chainInfo } = useApi()
const { api, chainInfo, compatibilityToken } = useApi()
const [isSubmitting, setIsSubmitting] = useState(false)
const { selectedAccount, selectedSigner } = useAccounts()
const [errorMessage, setErrorMessage] = useState<ReactNode | string>('')
const { addToast } = useToasts()
const { selectedMultiProxy, getMultisigByAddress, setRefetchMultisigTimeoutMinutes } =
useMultiProxy()
const [addedCallData, setAddedCallData] = useState<HexString | undefined>()
Expand All @@ -64,7 +61,7 @@ const DeepTxCreationModal = ({
// this will never be a proxy, if there's a proxy, it's already in the call
const parentMultisigTx = useGetMultisigTx({
fromAddress: parentMultisigInfo.parentSignatoryAddress,
extrinsicToCall: (api && parentCallInfo?.call && api.tx(parentCallInfo?.call)) || undefined,
extrinsicToCall: (api && parentCallInfo?.call && parentCallInfo?.call) || undefined,
senderAddress: parentMultisigInfo.parentSignatoryAddress,
isProxy: false,
threshold: parentMultisigInfo.threshold,
Expand All @@ -86,7 +83,7 @@ const DeepTxCreationModal = ({
// and calls a asMulti because it's a creation
const fullTx = useGetMultisigTx({
fromAddress: parentMultisigInfo.parentSignatoryAddress,
extrinsicToCall: (api && parentMultisigTx && api.tx(parentMultisigTx)) || undefined,
extrinsicToCall: (api && parentMultisigTx && parentMultisigTx) || undefined,
senderAddress: selectedAccount?.address,
isProxy: !!parentMultisigInfo.isSignatoryProxy,
threshold: currentMultisigInvolved?.threshold,
Expand All @@ -112,17 +109,32 @@ const DeepTxCreationModal = ({
onClose()
}, [onClose])

const signCallback = useSigningCallback({ onSuccess, onSubmitting })
const signCallback = useSigningCallback({
onSuccess: () => {
onSuccess && onSuccess()
// // poll for 1min if the tx may make changes
// // such as creating a proxy, adding/removing a multisig
if (mustSubmitCallData) {
setRefetchMultisigTimeoutMinutes(1)
}
},
onSubmitting,
onError: () => setIsSubmitting(false)
})

useEffect(() => {
if (!!parentCallInfo?.call && parentCallInfo.call.hash.toHex() !== proposalData.hash) {
const hash =
!!parentCallInfo?.call &&
hashFromTx(parentCallInfo?.call?.getEncodedData(compatibilityToken as any).asHex())

if (hash !== proposalData.hash) {
setErrorMessage("The callData provided doesn't match with the on-chain transaction")
return
}
}, [parentCallInfo, proposalData])
}, [compatibilityToken, parentCallInfo, proposalData])

useEffect(() => {
if (!multisigProposalNeededFunds.isZero() && !hasSignerEnoughFunds) {
if (multisigProposalNeededFunds !== 0n && !hasSignerEnoughFunds) {
const requiredBalanceString = formatBnBalance(
multisigProposalNeededFunds,
chainInfo?.tokenDecimals,
Expand All @@ -149,8 +161,8 @@ const DeepTxCreationModal = ({
return
}

if (!selectedAccount) {
const error = 'No selected address or multisig/proxy'
if (!selectedSigner) {
const error = 'No selected signer or multisig/proxy'
console.error(error)
setErrorMessage(error)
return
Expand All @@ -173,39 +185,8 @@ const DeepTxCreationModal = ({

setIsSubmitting(true)

fullTx
.signAndSend(
selectedAccount.address,
{ signer: selectedSigner, withSignedTransaction: true },
signCallback
)
.then(() => {
// poll for 1min if the tx may make changes
// such as creating a proxy, adding/removing a multisig
if (mustSubmitCallData) {
setRefetchMultisigTimeoutMinutes(1)
}
})
.catch((error: Error) => {
setIsSubmitting(false)
addToast({
title: error.message,
type: 'error',
link: getSubscanExtrinsicLink(fullTx.hash.toHex())
})
})
}, [
api,
selectedAccount,
mustSubmitCallData,
parentCallInfo,
fullTx,
selectedSigner,
signCallback,
setRefetchMultisigTimeoutMinutes,
addToast,
getSubscanExtrinsicLink
])
fullTx.signSubmitAndWatch(selectedSigner, { at: 'best' }).subscribe(signCallback)
}, [api, mustSubmitCallData, parentCallInfo, fullTx, selectedSigner, signCallback])

const onAddedCallDataChange = useCallback(
(event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
Expand Down
Loading

0 comments on commit 3bcf704

Please sign in to comment.