Skip to content

Commit

Permalink
Merge branch 'main' of github.com:ChainSafe/Multix
Browse files Browse the repository at this point in the history
  • Loading branch information
Tbaut committed Oct 18, 2023
2 parents 548412c + 8131f4a commit a6b95b0
Show file tree
Hide file tree
Showing 17 changed files with 364 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { watchSignatories } from './watchSignatories'
export const watchMultisigs = {
'multisig-with-pure': {
name: 'Multisig With Pure',
address: '5Fa3UUF3S6SVdXZtPrCw2tGUqxJiRJLxEGfujozfZ4xFeAKn',
address: '5EwAYK9noidJUqDXT7RmDABzh8Ag1PEd4HWy9DW82KU3H6tq',
pureAddress: '5EfdqwwuyjjtEa4UhdjbZJu3UxHEHbzh8LMRvE13xTD7z6Wd',
threshold: 2,
signatories: [watchSignatories[0].address, watchSignatories[1].address]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const watchSignatories = [
mnemonic: 'citizen heavy warrior cattle enter chef label split differ seek turtle gorilla'
},
{
address: '5EkbU3anZKYP98aXF5MvmCUxvwvM4kxp7osc2Xhj1wHYL6ym',
address: '5E9XHcUfeDCL2HEvH8c8rcfroNDSzbLwhV5A1fq7J7RUwAkd',
name: 'Pure Signatory 2',
type: 'sr25519',
mnemonic: 'script spoon elder spawn kite burst theme property hip fatal flight amount'
Expand Down
45 changes: 14 additions & 31 deletions packages/ui/src/components/AccountDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import { AccountBadge, IconSizeVariant } from '../types'
import { getDisplayAddress } from '../utils'
import IdenticonBadge from './IdenticonBadge'
import { useApi } from '../contexts/ApiContext'
import { DeriveAccountInfo, DeriveAccountRegistration } from '@polkadot/api-derive/types'
import IdentityIcon from './IdentityIcon'
import Balance from './library/Balance'
import { useGetEncodedAddress } from '../hooks/useGetEncodedAddress'
import { useIdentity } from '../hooks/useIdentity'

interface Props {
address: string
Expand All @@ -30,44 +30,27 @@ const AccountDisplay = ({
}: Props) => {
const { getNamesWithExtension } = useAccountNames()
const localName = useMemo(() => getNamesWithExtension(address), [address, getNamesWithExtension])
const [identity, setIdentity] = useState<DeriveAccountRegistration | null>(null)
const { api } = useApi()
const [mainDisplay, setMainDisplay] = useState<string>('')
const [sub, setSub] = useState<string | null>(null)
const getEncodedAddress = useGetEncodedAddress()
const encodedAddress = useMemo(() => getEncodedAddress(address), [address, getEncodedAddress])
const identity = useIdentity(address)

useEffect(() => {
if (!api) {
return
}

let unsubscribe: () => void

api.derive.accounts
.info(address, (info: DeriveAccountInfo) => {
setIdentity(info.identity)
if (!identity) return

if (info.identity.displayParent && info.identity.display) {
// when an identity is a sub identity `displayParent` is set
// and `display` get the sub identity
setMainDisplay(info.identity.displayParent)
setSub(info.identity.display)
} else {
// There should not be a `displayParent` without a `display`
// but we can't be too sure.
setMainDisplay(
info.identity.displayParent || info.identity.display || info.nickname || ''
)
}
})
.then((unsub) => {
unsubscribe = unsub
})
.catch((e) => console.error(e))

return () => unsubscribe && unsubscribe()
}, [address, api])
if (identity.displayParent && identity.display) {
// when an identity is a sub identity `displayParent` is set
// and `display` get the sub identity
setMainDisplay(identity.displayParent)
setSub(identity.display)
} else {
// There should not be a `displayParent` without a `display`
// but we can't be too sure.
setMainDisplay(identity.displayParent || identity.display || '')
}
}, [address, api, identity])

return (
<div className={className}>
Expand Down
6 changes: 3 additions & 3 deletions packages/ui/src/components/EasySetup/BalancesTransfer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { styled } from '@mui/material/styles'
import { SubmittableExtrinsic } from '@polkadot/api/types'
import { ISubmittableResult } from '@polkadot/types/types'
import GenericAccountSelection, { AccountBaseInfo } from '../select/GenericAccountSelection'
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { useApi } from '../../contexts/ApiContext'
import { useCheckBalance } from '../../hooks/useCheckBalance'
import BN from 'bn.js'
import { getGlobalMaxValue, inputToBn } from '../../utils'
import { TextFieldStyled } from '../library'
import { TextField } from '../library'
import { getOptionLabel } from '../../utils/getOptionLabel'
import { useAccountBaseFromAccountList } from '../../hooks/useAccountBaseFromAccountList'

Expand Down Expand Up @@ -123,7 +123,7 @@ const BalancesTransfer = ({ className, onSetExtrinsic, onSetErrorMessage, from }
accountList={accountBase}
testId="field-to"
/>
<TextFieldStyled
<TextField
data-cy="field-amount"
label={`Amount`}
onChange={onAmountChange}
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/src/components/EasySetup/FromCallData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { SubmittableExtrinsic } from '@polkadot/api/types'
import { ISubmittableResult } from '@polkadot/types/types'
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { useApi } from '../../contexts/ApiContext'
import { TextFieldStyled } from '../library'
import { TextField } from '../library'
import CallInfo from '../CallInfo'
import { useCallInfoFromCallData } from '../../hooks/useCallInfoFromCallData'
import { HexString } from '../../types'
Expand Down Expand Up @@ -96,7 +96,7 @@ const FromCallData = ({ className, onSetExtrinsic, isProxySelected, onSetErrorMe
Multix will override the proxy.proxy call with the proxy you have selected
</AlertStyled>
)}
<TextFieldStyled
<TextField
label={`Call data`}
onChange={onCallDataChange}
value={pastedCallData || ''}
Expand Down
1 change: 0 additions & 1 deletion packages/ui/src/components/EasySetup/ManualExtrinsic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ const ManualExtrinsic = ({
const isValidAmountString = useCallback(
(value: any) => {
if (!value.match(/^[0-9]+([.][0-9]+)?$/)) {
console.log('wrong boom')
onSetErrorMessage('Only numbers and "." are accepted.')
return false
}
Expand Down
228 changes: 228 additions & 0 deletions packages/ui/src/components/EasySetup/SetIdentity.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
import { Grid } from '@mui/material'
import { styled } from '@mui/material/styles'
import { SubmittableExtrinsic } from '@polkadot/api/types'
import { ISubmittableResult } from '@polkadot/types/types'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { useApi } from '../../contexts/ApiContext'
import { TextField } from '../library'
import { useIdentity } from '../../hooks/useIdentity'

interface Props {
className?: string
from: string
onSetExtrinsic: (ext?: SubmittableExtrinsic<'promise', ISubmittableResult>) => void
onSetErrorMessage: React.Dispatch<React.SetStateAction<string>>
}

type IdentityFields = {
display: string | undefined
legal: string | undefined
web: string | undefined
riot: string | undefined
email: string | undefined
twitter: string | undefined
}

const getRawOrNone = (val: string | undefined) => {
return val
? {
Raw: val
}
: { none: null }
}
const getExtrinsicsArgs = ({ legal, display, email, riot, twitter, web }: IdentityFields) => {
return {
additional: [],
display: getRawOrNone(display),
legal: getRawOrNone(legal),
web: getRawOrNone(web),
riot: getRawOrNone(riot),
email: getRawOrNone(email),
pgpFingerprint: null,
twitter: getRawOrNone(twitter)
}
}

const fieldNameAndPlaceholder = (fieldName: keyof IdentityFields) => {
switch (fieldName) {
case 'display':
return {
field: 'Display name',
placeholder: 'Luke',
required: true
}

case 'legal':
return {
field: 'Legal name',
placeholder: 'Luke Skylwalker',
required: false
}

case 'riot':
return {
field: 'Element handle',
placeholder: '@luke:matrix.org',
required: false
}

case 'web':
return {
field: 'Website',
placeholder: 'https://luke.sky',
required: false
}

case 'twitter':
return {
field: 'Twitter/X handle',
placeholder: '@luke',
required: false
}

case 'email':
return {
field: 'Email',
placeholder: '[email protected]',
required: false
}

default:
return {
field: fieldName,
placeholder: '',
required: false
}
}
}

const MAX_ALLOWED_VAL_LENGTH = 32

const SetIdentity = ({ className, onSetExtrinsic, from, onSetErrorMessage }: Props) => {
const { api, chainInfo } = useApi()
const [identityFields, setIdentityFields] = useState<IdentityFields | undefined>()
const chainIdentity = useIdentity(from)
const [hasChangedAtLeastAField, setHasChangedAtLeastAField] = useState(false)
const fieldtooLongError = useMemo(() => {
const res: (keyof IdentityFields)[] = []
identityFields &&
Object.entries(identityFields).forEach(([field, value]) => {
if (typeof value === 'string' && value.length >= MAX_ALLOWED_VAL_LENGTH) {
res.push(field as keyof IdentityFields)
}
})

return res
}, [identityFields])

useEffect(() => {
if (fieldtooLongError.length > 0) {
onSetErrorMessage(`A field exceeds the ${MAX_ALLOWED_VAL_LENGTH} character limit`)
return
}

if (!identityFields?.display && hasChangedAtLeastAField) {
onSetErrorMessage('Display name is required')
return
}

onSetErrorMessage('')
}, [fieldtooLongError, hasChangedAtLeastAField, identityFields, onSetErrorMessage])

useEffect(() => {
if (chainIdentity) {
const { display, email, legal, web, riot, twitter } = chainIdentity
setIdentityFields({
display,
legal,
web,
riot,
email,
twitter
})
} else {
setIdentityFields({
display: undefined,
legal: undefined,
web: undefined,
riot: undefined,
email: undefined,
twitter: undefined
})
}
}, [chainIdentity])

useEffect(() => {
if (!api) {
onSetExtrinsic(undefined)
return
}

if (!identityFields) {
onSetExtrinsic(undefined)
return
}

if (fieldtooLongError.length > 0) {
onSetExtrinsic(undefined)
return
}

const extrinsicsArgs = getExtrinsicsArgs(identityFields)
onSetExtrinsic(api.tx.identity.setIdentity(extrinsicsArgs))
}, [api, chainInfo, fieldtooLongError, identityFields, onSetErrorMessage, onSetExtrinsic])

const onChangeField = useCallback((field: keyof IdentityFields, value: string) => {
setHasChangedAtLeastAField(true)
setIdentityFields((prev) => (prev ? { ...prev, [field]: value } : undefined))
}, [])

return (
<Grid
className={className}
container
spacing={1}
>
{identityFields &&
Object.entries(identityFields).map(([fieldName, value]) => {
const { field, placeholder, required } = fieldNameAndPlaceholder(
fieldName as keyof IdentityFields
)
const isFieldError = fieldtooLongError.includes(fieldName as keyof IdentityFields)
const isDiplayNameError = fieldName === 'display' && !value && hasChangedAtLeastAField
return (
<Grid
item
xs={12}
sm={6}
md={6}
alignItems="center"
>
<TextFieldStyled
data-cy={`${fieldName}-identity`}
label={field}
placeholder={placeholder}
onChange={(val) =>
onChangeField(fieldName as keyof IdentityFields, val.target.value)
}
value={value || ''}
required={required}
helperText={isFieldError && `Field has more than ${MAX_ALLOWED_VAL_LENGTH} chars`}
error={isFieldError || isDiplayNameError}
/>
</Grid>
)
})}
</Grid>
)
}

const TextFieldStyled = styled(TextField)`
.MuiFormHelperText-root.Mui-error {
position: initial;
}
`

export default styled(SetIdentity)`
margin-top: 0.5rem;
`
4 changes: 2 additions & 2 deletions packages/ui/src/components/library/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Button, ButtonWithIcon } from './Button'
import { Link, RouterLink, NavLink } from './Link'
import { InputField } from './InputField'
import TextFieldStyled from './TextFieldStyled'
import TextField from './TextFieldStyled'
import TextFieldLargeStyled from './TextFieldLargeStyled'
import Select from './Select'
import Autocomplete from './Autocomplete'
Expand All @@ -16,7 +16,7 @@ export {
NavLink,
RouterLink,
InputField,
TextFieldStyled,
TextField,
TextFieldLargeStyled,
Select
}
Loading

0 comments on commit a6b95b0

Please sign in to comment.