Skip to content

Commit

Permalink
proposal signing
Browse files Browse the repository at this point in the history
  • Loading branch information
Tbaut committed Sep 6, 2024
1 parent 4af4934 commit 0d8fa28
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 195 deletions.
6 changes: 3 additions & 3 deletions packages/ui/.papi/descriptors/package.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"version": "0.1.0-autogenerated.6583868000815430009",
"version": "0.1.0-autogenerated.4649279494484163350",
"name": "@polkadot-api/descriptors",
"files": [
"dist"
],
"exports": {
".": {
"types": "./dist/index.d.ts",
"module": "./dist/index.mjs",
"import": "./dist/index.mjs",
"require": "./dist/index.js",
"default": "./dist/index.js"
"require": "./dist/index.js"
},
"./package.json": "./package.json"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"graphql": "^16.8.1",
"graphql-request": "^6.1.0",
"graphql-ws": "^5.16.0",
"polkadot-api": "^1.0.1",
"polkadot-api": "^1.2.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-icons": "^5.1.0",
Expand Down
59 changes: 18 additions & 41 deletions packages/ui/src/components/modals/ProposalSigning.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ import { useApi } from '../../contexts/ApiContext'
import { useMultiProxy } from '../../contexts/MultiProxyContext'
import CallInfo from '../CallInfo'
import SignerSelection from '../select/SignerSelection'
import { useToasts } from '../../contexts/ToastContext'
import { useSigningCallback } from '../../hooks/useSigningCallback'
import { HexString, MultisigStorageInfo } from '../../types'
import { useGetSubscanLinks } from '../../hooks/useSubscanLink'
import { getDisplayArgs, getExtrinsicName } from '../../utils'
import { useCallInfoFromCallData } from '../../hooks/useCallInfoFromCallData'
import { ModalCloseButton } from '../library/ModalCloseButton'
Expand All @@ -21,8 +19,6 @@ import { getAsMultiTx } from '../../utils/getAsMultiTx'
import { CallDataInfoFromChain } from '../../hooks/usePendingTx'
import { debounce } from '../../utils/debounce'
import { FixedSizeBinary, Transaction } from 'polkadot-api'
import { DotCalls, DotQueries } from '@polkadot-api/descriptors'
import { Multisig } from '@polkadot/types/interfaces'

export interface SigningModalProps {
onClose: () => void
Expand All @@ -39,15 +35,13 @@ const ProposalSigning = ({
proposalData,
onSuccess
}: SigningModalProps) => {
const { getSubscanExtrinsicLink } = useGetSubscanLinks()
const { api } = useApi()
const [isSubmitting, setIsSubmitting] = useState(false)
const { getMultisigByAddress, setRefetchMultisigTimeoutMinutes } = useMultiProxy()
const { selectedAccount, selectedSigner } = useAccounts()
const [addedCallData, setAddedCallData] = useState<HexString | undefined>()
const [debouncedAddedCallData, setDebouncedAddedCallData] = useState<HexString | undefined>()
const [errorMessage, setErrorMessage] = useState('')
const { addToast } = useToasts()
const multisig = useMemo(
() => getMultisigByAddress(proposalData.from),
[getMultisigByAddress, proposalData]
Expand Down Expand Up @@ -88,8 +82,13 @@ const ProposalSigning = ({

const onSubmitting = useCallback(() => {
setIsSubmitting(false)
// poll for 1min if the tx may make changes
// such as creating a proxy, adding/removing a multisig
if (mustProvideCallData) {
setRefetchMultisigTimeoutMinutes(1)
}
onClose()
}, [onClose])
}, [mustProvideCallData, onClose, setRefetchMultisigTimeoutMinutes])

const signCallback = useSigningCallback({ onSuccess, onSubmitting })
const { getSortAddress } = useGetSortAddress()
Expand Down Expand Up @@ -158,8 +157,8 @@ const ProposalSigning = ({
return
}

if (!selectedAccount) {
const error = 'No selected address'
if (!selectedAccount || !selectedSigner) {
const error = 'No selected address or selectedSigner'
console.error(error)
setErrorMessage(error)
return
Expand Down Expand Up @@ -218,24 +217,24 @@ const ProposalSigning = ({

// If we can submit the proposal and have the call data
} else if (shouldExecute && callInfo?.call && callInfo?.weight) {
tx = getAsMultiTx({
tx = await getAsMultiTx({
api,
threshold,
otherSignatories: otherSigners,
weight: callInfo.weight,
when: proposalData.info.when,
tx: proposalData.callData || addedCallData
callData: proposalData.callData || addedCallData
})

// if we can't submit yet (more signatures required), all we need is the call hash
} else if (!shouldExecute && proposalData.hash) {
tx = api.tx.multisig.approveAsMulti(
tx = api.tx.Multisig.approve_as_multi({
threshold,
otherSigners,
proposalData.info.when,
proposalData.hash,
{ refTime: 0, proofSize: 0 }
)
other_signatories: otherSigners,
maybe_timepoint: proposalData.info.when,
call_hash: FixedSizeBinary.fromText(proposalData.hash),
max_weight: { ref_time: 0n, proof_size: 0n }
})
} else {
console.error("We don't have the required data to submit the call")
return
Expand All @@ -246,26 +245,7 @@ const ProposalSigning = ({
return
}

tx.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 (mustProvideCallData) {
setRefetchMultisigTimeoutMinutes(1)
}
})
.catch((error: Error) => {
setIsSubmitting(false)
addToast({
title: error.message,
type: 'error',
link: getSubscanExtrinsicLink(tx.hash.toHex())
})
})
tx.signSubmitAndWatch(selectedSigner, { at: 'best' }).subscribe(signCallback)
},
[
getSortAddress,
Expand All @@ -280,10 +260,7 @@ const ProposalSigning = ({
hasReachedThreshold,
selectedSigner,
signCallback,
addedCallData,
setRefetchMultisigTimeoutMinutes,
addToast,
getSubscanExtrinsicLink
addedCallData
]
)

Expand Down
7 changes: 4 additions & 3 deletions packages/ui/src/contexts/AccountsContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { DAPP_NAME } from '../constants'
import { Signer } from '@polkadot/api/types'
import { useApi } from './ApiContext'
import { encodeAccounts } from '../utils/encodeAccounts'
import { PolkadotSigner } from 'polkadot-api'

const LOCALSTORAGE_SELECTED_ACCOUNT_KEY = 'multix.selectedAccount'
const LOCALSTORAGE_ALLOWED_CONNECTION_KEY = 'multix.canConnectToExtension'
Expand All @@ -21,7 +22,7 @@ export interface IAccountContext {
getAccountByAddress: (address: string) => InjectedAccountWithMeta | undefined
isAccountLoading: boolean
isExtensionError: boolean
selectedSigner?: Signer
selectedSigner?: PolkadotSigner
allowConnectionToExtension: () => void
isAllowedToConnectToExtension: boolean
isLocalStorageSetupDone: boolean
Expand All @@ -34,7 +35,7 @@ const AccountContextProvider = ({ children }: AccountContextProps) => {
const [selectedAccount, setSelected] = useState<InjectedAccountWithMeta>(ownAccountList[0])
const [isAccountLoading, setIsAccountLoading] = useState(false)
const [isExtensionError, setIsExtensionError] = useState(false)
const [selectedSigner, setSelectedSigner] = useState<Signer | undefined>()
const [selectedSigner, setSelectedSigner] = useState<PolkadotSigner | undefined>()
const [isAllowedToConnectToExtension, setIsAllowedToConnectToExtension] = useState(false)
const ownAddressList = useMemo(() => ownAccountList.map((a) => a.address), [ownAccountList])
const [accountGotRequested, setAccountGotRequested] = useState(false)
Expand Down Expand Up @@ -161,7 +162,7 @@ const AccountContextProvider = ({ children }: AccountContextProps) => {

web3FromSource(selectedAccount.meta.source)
.then((injector) => {
setSelectedSigner(injector.signer)
setSelectedSigner(injector.signer as PolkadotSigner)
})
.catch(console.error)
})
Expand Down
1 change: 0 additions & 1 deletion packages/ui/src/contexts/ApiContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ const ApiContextProvider = ({ children }: ApiContextProps) => {

const isEthereum = ethereumChains.includes(name)

console.log('Chain properties', properties)
setChainInfo({
// some parachains such as interlay have a comma in the format, e.g: "2,042"
ss58Format: Number(properties?.ss58Format.replace(',', '')) || 0,
Expand Down
115 changes: 68 additions & 47 deletions packages/ui/src/hooks/useSigningCallback.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { ISubmittableResult } from '@polkadot/types/types'
// import { ISubmittableResult } from '@polkadot/types/types'
import { useApi } from '../contexts/ApiContext'
import { useGetSubscanLinks } from './useSubscanLink'
import { useToasts } from '../contexts/ToastContext'
import { getIncompleteMessage } from '../utils/extinsicErrorChecks'
import { EventRecord } from '@polkadot/types/interfaces'
// import { getIncompleteMessage } from '../utils/extinsicErrorChecks'
// import { EventRecord } from '@polkadot/types/interfaces'
import { TxEvent } from 'polkadot-api'

interface Args {
onSubmitting?: () => void
Expand All @@ -17,12 +18,12 @@ export const useSigningCallback = ({ onSubmitting, onSuccess, onFinalized, onErr
const { api } = useApi()
const { getSubscanExtrinsicLink } = useGetSubscanLinks()

return ({ events = [], status, txHash }: ISubmittableResult) => {
return (event: TxEvent) => {
onSubmitting && onSubmitting()
console.log('Transaction status:', status.type)
const link = getSubscanExtrinsicLink(txHash.toHex())
console.log('Transaction hash:', event.txHash)
const link = getSubscanExtrinsicLink(event.txHash)

if (status.isBroadcast) {
if (event.type === 'broadcasted') {
addToast({ title: `Tx broadcasted`, type: 'loading', link })
}

Expand All @@ -33,58 +34,78 @@ export const useSigningCallback = ({ onSubmitting, onSuccess, onFinalized, onErr
return
}

if (status.isInBlock) {
console.log('Included at block hash', status.asInBlock.toHex())
console.log('Events:')
if (event.type === 'txBestBlocksState' && event.found) {
if (event.dispatchError) {
console.log('DispatchError', event.dispatchError)

events.forEach(({ event, phase }) => {
const { data, method, section } = event
console.log('\t', phase.toString(), `: ${section}.${method}`, data.toString())

const incomplete = getIncompleteMessage({ event } as EventRecord)

// check if multisig or proxy or batch has an error
if (incomplete) {
errorInfo = incomplete
if (
event.dispatchError.type === 'Module' &&
!!(event.dispatchError.value as any)?.value?.type
) {
errorInfo = (event.dispatchError.value as any)?.value?.type
}
}

// if the extrinsic fails alltogether
if (!errorInfo && api.events.system.ExtrinsicFailed.is(event)) {
// extract the data for this event
const dispatchError = data[0]

// decode the error
if ((dispatchError as any).isModule) {
// for module errors, we have the section indexed, lookup
// (For specific known errors, we can also do a check against the
// api.errors.<module>.<ErrorName>.is(dispatchError.asModule) guard)
const decoded = api.registry.findMetaError((dispatchError as any).asModule)

errorInfo = `${decoded.docs} - ${decoded.section}.${decoded.name}`
} else {
// Other, CannotLookup, BadOrigin, no extra info
errorInfo = dispatchError.toString()
}
event.events.forEach((event) => {
console.log(JSON.stringify(event, (_, v) => (typeof v === 'bigint' ? v.toString() : v)))

// interrupted batch
if (event.type === 'Utility' && event.value.type === 'BatchInterrupted') {
errorInfo = event.value.value.error.type
}

if (api.events.system.ExtrinsicSuccess.is(event)) {
// if it's a success and there's been no error nested in
if (event.type === 'System' && event.value.type === 'ExtrinsicSuccess') {
!errorInfo &&
!toastErrorShown &&
addToast({ title: 'Tx in block', type: 'success', link })
onSuccess && onSuccess()
}

if (!!errorInfo && !toastErrorShown) {
addToast({ title: errorInfo, type: 'error', link })
onError && onError(errorInfo)
// prevent showing several errors
toastErrorShown = true
}
})
} else if (status.isFinalized) {

if (!!errorInfo && !toastErrorShown) {
addToast({ title: errorInfo, type: 'error', link })
onError && onError(errorInfo)
// prevent showing several errors
toastErrorShown = true
}
}

if (event.type === 'finalized') {
console.log('finalized:', event)
onFinalized && onFinalized()
// !errorInfo && addToast({ title: "Tx finalized", type: "success", link })
console.log('Finalized block hash', status.asFinalized.toHex())

// event.events.forEach(({type, value}) => {
// const { data, method, section } = event

// console.log('\t', phase.toString(), `: ${section}.${method}`, data.toString())

// const incomplete = getIncompleteMessage({ event } as EventRecord)

// // check if multisig or proxy or batch has an error
// if (incomplete) {
// errorInfo = incomplete
// }

// if the extrinsic fails alltogether
// if (!errorInfo && api.events.system.ExtrinsicFailed.is(event)) {
// // extract the data for this event
// const dispatchError = data[0]

// // decode the error
// if ((dispatchError as any).isModule) {
// // for module errors, we have the section indexed, lookup
// // (For specific known errors, we can also do a check against the
// // api.errors.<module>.<ErrorName>.is(dispatchError.asModule) guard)
// const decoded = api.registry.findMetaError((dispatchError as any).asModule)

// errorInfo = `${decoded.docs} - ${decoded.section}.${decoded.name}`
// } else {
// // Other, CannotLookup, BadOrigin, no extra info
// errorInfo = dispatchError.toString()
// }
// }
// })
}
}
}
2 changes: 1 addition & 1 deletion packages/ui/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ export interface SubmittingCall {
call?: GenericCall
method?: string
section?: string
weight?: Weight
weight?: { ref_time: bigint; proof_size: bigint }
}
Loading

0 comments on commit 0d8fa28

Please sign in to comment.