diff --git a/packages/ui/cypress/tests/multisig-creation.cy.ts b/packages/ui/cypress/tests/multisig-creation.cy.ts index 345e7fa6..720a5822 100644 --- a/packages/ui/cypress/tests/multisig-creation.cy.ts +++ b/packages/ui/cypress/tests/multisig-creation.cy.ts @@ -99,6 +99,8 @@ describe('Multisig creation', () => { // Step 2 newMultisigPage.step2.thresholdInput().type('2') newMultisigPage.step2.nameInput().type(multisigName) + newMultisigPage.step2.checkboxUsePureProxy().click() + newMultisigPage.step2.checkboxUsePureProxy().should('be.checked') newMultisigPage.nextButton().should('contain', 'Next').click() // Step 3 @@ -136,7 +138,6 @@ describe('Multisig creation', () => { // Step 2 newMultisigPage.step2.thresholdInput().type('3') newMultisigPage.step2.nameInput().type(multisigName) - newMultisigPage.step2.checkboxUsePureProxy().click() newMultisigPage.step2.checkboxUsePureProxy().should('not.be.checked') newMultisigPage.nextButton().should('contain', 'Next').click() diff --git a/packages/ui/package.json b/packages/ui/package.json index 63b7f4fb..3aed2285 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -16,7 +16,7 @@ "@polkadot/react-identicon": "^3.11.3", "@polkadot/util-crypto": "^13.2.3", "@reactive-dot/core": "^0.27.1", - "@reactive-dot/react": "^0.27.1", + "@reactive-dot/react": "^0.28.0", "@tanstack/react-query": "^5.62.2", "@walletconnect/web3wallet": "^1.16.1", "dayjs": "^1.11.13", diff --git a/packages/ui/src/components/CallInfo.tsx b/packages/ui/src/components/CallInfo.tsx index 48397a2c..ff45a0e2 100644 --- a/packages/ui/src/components/CallInfo.tsx +++ b/packages/ui/src/components/CallInfo.tsx @@ -33,7 +33,7 @@ interface CreateTreeParams { chainInfo?: ChainInfoHuman } -const isWhiteListedCall = (type: string, value: string) => { +const isWhiteListedCall = (extrinsicName: string) => { return [ 'Balances.transfer', 'Balances.transfer_keep_alive', @@ -57,12 +57,18 @@ const isWhiteListedCall = (type: string, value: string) => { 'ConvictionVoting.vote', 'ConvictionVoting.remove_vote', 'ConvictionVoting.undelegate', - 'ConvictionVoting.unlock' - ].includes(`${type}.${value}`) + 'ConvictionVoting.unlock', + // Hydration + 'Tokens.transfer' + ].includes(extrinsicName) } -const isBatchedCall = (type: string, value: string) => { - return ['Utility.batch', 'Utility.batch_all', 'Utility.force_batch'].includes(`${type}.${value}`) +const isPreventBalanceFormat = (extrinsicName: string) => { + return ['Tokens.transfer'].includes(extrinsicName) +} + +const isBatchedCall = (extrinsicName: string) => { + return ['Utility.batch', 'Utility.batch_all', 'Utility.force_batch'].includes(extrinsicName) } const formatBalance = (amount: bigint, label: string, chainInfo: ChainInfoHuman, id: string) => ( @@ -74,11 +80,23 @@ const formatBalance = (amount: bigint, label: string, chainInfo: ChainInfoHuman, ) -const eachFieldRendered = (value: Record, chainInfo: ChainInfoHuman, id: string) => { +interface EachFieldRenderedParams { + value: Record + chainInfo: ChainInfoHuman + id: string + preventBalanceFormating?: boolean +} +const eachFieldRendered = ({ + value, + chainInfo, + id, + preventBalanceFormating = false +}: EachFieldRenderedParams) => { // for transfer, nomination, staking, bounties - const bigIntKey = ['value', 'fee', 'max_additional', 'balance'].find( - (key) => typeof value[key] === 'bigint' - ) + // We should make sure this is not done for hydration + const bigIntKey = + !preventBalanceFormating && + ['value', 'fee', 'max_additional', 'balance'].find((key) => typeof value[key] === 'bigint') if (bigIntKey) { return formatBalance(value[bigIntKey], bigIntKey, chainInfo, id) @@ -162,7 +180,10 @@ const preparedCall = ({ }: PreparedCallParams) => { if (!decodedCall) return - if (isBatchedCall(decodedCall.type, decodedCall.value.type)) { + const extrinsicName = getExtrinsicName(decodedCall.type, decodedCall.value.type) + const preventBalanceFormating = isPreventBalanceFormat(extrinsicName) + + if (isBatchedCall(extrinsicName)) { const lowerLevelCalls = decodedCall.value.value.calls as Array> return lowerLevelCalls.map((call, index) => { @@ -178,19 +199,20 @@ const preparedCall = ({ }) } - if (isWhiteListedCall(decodedCall.type, decodedCall.value.type)) { + if (isWhiteListedCall(extrinsicName)) { const lowerLevelCall = decodedCall.value.value if (typeof lowerLevelCall === 'object') { return ( <> - {isBatch && ( - - {getExtrinsicName(decodedCall.type, decodedCall.value.type)} - - )} + {isBatch && {extrinsicName}}
    {Object.entries(lowerLevelCall).map(([key, value], index) => - eachFieldRendered({ [key]: value }, chainInfo, `${decodedCall.type}-${index}`) + eachFieldRendered({ + value: { [key]: value }, + chainInfo, + id: `${decodedCall.type}-${index}`, + preventBalanceFormating + }) )}
diff --git a/packages/ui/src/components/EasySetup/FromCallData.tsx b/packages/ui/src/components/EasySetup/FromCallData.tsx index 13ea3d8b..fba3b3a6 100644 --- a/packages/ui/src/components/EasySetup/FromCallData.tsx +++ b/packages/ui/src/components/EasySetup/FromCallData.tsx @@ -8,6 +8,7 @@ import { useCallInfoFromCallData } from '../../hooks/useCallInfoFromCallData' import { getExtrinsicName } from '../../utils/getExtrinsicName' import { usePjsLinks } from '../../hooks/usePjsLinks' import { Binary, HexString, Transaction } from 'polkadot-api' +import { getPapiHowLink } from '../../utils/getPapiHowLink' interface Props { className?: string @@ -40,7 +41,8 @@ const FromCallData = ({ className, onSetExtrinsic }: Props) => { } return call - } catch { + } catch (e: unknown) { + !!e && setCallDataError(String(e)) return } }, @@ -82,13 +84,21 @@ const FromCallData = ({ className, onSetExtrinsic }: Props) => { return ( - Paste below the "encoded call data" from a{' '} + Paste below the "encoded call data" from{' '} + + papi console + {' '} + or{' '} - manual extrinsic + pjs manual extrinsic .
Multix will take care of wrapping it in a multisig/proxy call
diff --git a/packages/ui/src/components/library/TextFieldStyled.tsx b/packages/ui/src/components/library/TextFieldStyled.tsx index ac3cc220..188ad21a 100644 --- a/packages/ui/src/components/library/TextFieldStyled.tsx +++ b/packages/ui/src/components/library/TextFieldStyled.tsx @@ -50,13 +50,14 @@ const TextFieldStyled = styled(TextField)` &.Mui-error { outline: 3px solid ${({ theme }) => theme.custom.error}; + margin-bottom: 1rem; } } .MuiFormHelperText-root { &.Mui-error { position: absolute; - bottom: -24px; + bottom: -1rem; } } ` diff --git a/packages/ui/src/hooks/useGetMultisigTx.tsx b/packages/ui/src/hooks/useGetMultisigTx.tsx index da9c3619..58aa7d20 100644 --- a/packages/ui/src/hooks/useGetMultisigTx.tsx +++ b/packages/ui/src/hooks/useGetMultisigTx.tsx @@ -61,10 +61,10 @@ export const useGetMultisigTx = ({ } if (forceAsMulti && !extrinsicToCall) { - console.warn( - 'The extrinsic call is required when multisig.asMulti is called', - extrinsicToCall - ) + // console.warn( + // 'The extrinsic call is required when multisig.asMulti is called', + // extrinsicToCall + // ) return } diff --git a/packages/ui/src/pages/Creation/WithProxySelection.tsx b/packages/ui/src/pages/Creation/WithProxySelection.tsx index b9f047c5..4fc74b74 100644 --- a/packages/ui/src/pages/Creation/WithProxySelection.tsx +++ b/packages/ui/src/pages/Creation/WithProxySelection.tsx @@ -13,7 +13,19 @@ const WithProxySelection = ({ setWithProxy, withProxy, className }: Props) => { Pure proxy + Use a pure proxy (not cross-chain{' '} + + see here + + ) + + } control={ ( className={className} title={ - Using a proxy makes the multisig more flexible. You can then change the signatories without - changing the proxy address. More info{' '} + Using a pure proxy has advantages and drawbacks see when it makes sense to use it{' '} - in this video + in the docs . diff --git a/packages/ui/src/pages/Creation/index.tsx b/packages/ui/src/pages/Creation/index.tsx index e1207cc2..1aa048eb 100644 --- a/packages/ui/src/pages/Creation/index.tsx +++ b/packages/ui/src/pages/Creation/index.tsx @@ -276,12 +276,6 @@ const MultisigCreation = ({ className }: Props) => { threshold ]) - useEffect(() => { - // default to using a proxy - if (supportsProxy) { - setWithProxy(true) - } - }, [supportsProxy]) useEffect(() => { setErrorMessage('') diff --git a/packages/ui/src/utils/getPapiHowLink.ts b/packages/ui/src/utils/getPapiHowLink.ts new file mode 100644 index 00000000..14cd9bd8 --- /dev/null +++ b/packages/ui/src/utils/getPapiHowLink.ts @@ -0,0 +1 @@ +export const getPapiHowLink = () => 'https://dev.papi.how' diff --git a/yarn.lock b/yarn.lock index c1e7ffa4..c1ac0b08 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3689,15 +3689,15 @@ __metadata: languageName: node linkType: hard -"@reactive-dot/react@npm:^0.27.1": - version: 0.27.1 - resolution: "@reactive-dot/react@npm:0.27.1" +"@reactive-dot/react@npm:^0.28.0": + version: 0.28.0 + resolution: "@reactive-dot/react@npm:0.28.0" dependencies: "@reactive-dot/core": ^0.27.1 jotai: ^2.10.3 peerDependencies: - react: 18.x - checksum: 5e932f259c0c9ec99e0481f05cbba2f1920805e8df11f13722cd6ba999d588b1552ecf479b6cfe1c2aded27fa7876217b066731355dad4233bf8bb325d6b96e8 + react: 18.x || 19.x + checksum: c23a4f2a400864773c1408770d1bb38454fb02ffb9cb94372e8c2d6cc8d1a0aeb8490816454a6b51bc55a2e9f303bfbfaade76fa16d9e86459f22fe9aee1298f languageName: node linkType: hard @@ -10166,7 +10166,7 @@ __metadata: "@polkadot/react-identicon": ^3.11.3 "@polkadot/util-crypto": ^13.2.3 "@reactive-dot/core": ^0.27.1 - "@reactive-dot/react": ^0.27.1 + "@reactive-dot/react": ^0.28.0 "@tanstack/react-query": ^5.62.2 "@types/node": ^22.10.1 "@types/react-dom": ^18.3.1