migrate to v2 (#118)

This commit is contained in:
Carlo Sala
2026-03-01 07:23:44 +01:00
committed by Victor Oliva
parent d9428a8d9c
commit 58640a590d
43 changed files with 2297 additions and 2444 deletions

View File

@@ -19,6 +19,6 @@
"types": "./dist/index.d.ts",
"sideEffects": false,
"peerDependencies": {
"polkadot-api": ">=1.21.0"
"polkadot-api": ">=2.0.0-rc.1"
}
}

View File

@@ -1,9 +1,6 @@
{
"version": 0,
"descriptorPath": ".papi/descriptors",
"options": {
"whitelist": ".papi/whitelist.ts"
},
"entries": {
"polkadot_people": {
"chain": "polkadot_people",

View File

@@ -14,19 +14,18 @@
"semi": false
},
"dependencies": {
"@acala-network/chopsticks-core": "^1.2.5",
"@acala-network/chopsticks-core": "^1.2.7",
"@ledgerhq/hw-transport-webusb": "^6.30.0",
"@monaco-editor/react": "^4.7.0",
"@polkadot-api/descriptors": "file:.papi/descriptors",
"@polkadot-api/json-rpc-provider-proxy": "^0.2.8",
"@polkadot-api/metadata-builders": "^0.13.9",
"@polkadot-api/observable-client": "^0.17.3",
"@polkadot-api/react-builder": "0.3.11",
"@polkadot-api/react-components": "^0.4.1",
"@polkadot-api/substrate-bindings": "^0.17.0",
"@polkadot-api/tx-utils": "^0.2.2",
"@polkadot-api/utils": "^0.2.0",
"@polkahub/ui-components": "0.3.2",
"@polkadot-api/json-rpc-provider-proxy": "^0.3.0",
"@polkadot-api/metadata-builders": "^0.13.11",
"@polkadot-api/observable-client": "^0.18.1",
"@polkadot-api/react-builder": "0.3.13",
"@polkadot-api/react-components": "^0.4.2",
"@polkadot-api/substrate-bindings": "^0.19.0",
"@polkadot-api/tx-utils": "^0.2.4",
"@polkahub/ui-components": "^0.5.0",
"@radix-ui/react-accordion": "^1.2.12",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-label": "^2.1.8",
@@ -44,41 +43,41 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"idb-keyval": "^6.2.2",
"lucide-react": "^0.562.0",
"polkadot-api": "^1.23.3",
"polkahub": "0.4.0",
"react": "^19.2.3",
"react-dom": "^19.2.3",
"lucide-react": "^0.575.0",
"polkadot-api": "^2.0.0-rc.2",
"polkahub": "^0.5.0",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react-portal": "^4.3.0",
"react-router-dom": "^7.12.0",
"react-svg": "^16.3.0",
"react-router-dom": "^7.13.1",
"react-svg": "^17.2.2",
"react-virtuoso": "^4.18.1",
"react18-json-view": "^0.2.9",
"rxjs": "^7.8.2",
"save-as": "^0.1.8",
"tailwind-merge": "^3.4.0",
"tailwind-merge": "^3.5.0",
"tailwindcss-animate": "^1.0.7",
"uuid": "^13.0.0"
},
"devDependencies": {
"@eslint/js": "^9.39.2",
"@tailwindcss/vite": "^4.1.18",
"@types/node": "^25.0.10",
"@types/react": "^19.2.9",
"@tailwindcss/vite": "^4.2.1",
"@types/node": "^25.3.1",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@types/react-portal": "^4.0.7",
"@vitejs/plugin-react": "^5.1.2",
"@vitejs/plugin-react": "^5.1.4",
"eslint": "^9.39.2",
"eslint-plugin-react-hooks": "7.0.1",
"eslint-plugin-react-refresh": "^0.4.26",
"globals": "^17.0.0",
"eslint-plugin-react-refresh": "^0.5.2",
"globals": "^17.3.0",
"prettier": "^3.8.1",
"tailwindcss": "^4.1.18",
"tailwindcss": "^4.2.1",
"typescript": "^5.9.3",
"typescript-eslint": "^8.53.1",
"typescript-eslint": "^8.56.1",
"vite": "^7.3.1"
},
"packageManager": "pnpm@10.28.1+sha512.7d7dbbca9e99447b7c3bf7a73286afaaf6be99251eb9498baefa7d406892f67b879adb3a1d7e687fc4ccc1a388c7175fbaae567a26ab44d1067b54fcb0d6a316",
"packageManager": "pnpm@10.30.3+sha512.c961d1e0a2d8e354ecaa5166b822516668b7f44cb5bd95122d590dd81922f606f5473b6d23ec4a5be05e7fcd18e8488d47d978bbe981872f1145d06e9a740017",
"pnpm": {
"patchedDependencies": {
"react18-json-view": "patches/react18-json-view.patch"

4140
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
import { BytesDisplay } from "@/codec-components/ViewCodec/CBytes"
import { AccountIdDisplay } from "@/components/AccountIdDisplay"
import { Binary, getSs58AddressInfo } from "polkadot-api"
import { getSs58AddressInfo } from "polkadot-api"
import { FC } from "react"
import { EnumDisplay } from "./EnumDisplay"
import { ArrayDisplay } from "./ListComponents"
@@ -32,7 +32,7 @@ export const ViewValue: FC<{
return <NumberDisplay value={value} />
case "object": {
if (value == null) return <>TODO</>
if (value instanceof Binary) return <BytesDisplay value={value} />
if (value instanceof Uint8Array) return <BytesDisplay value={value} />
if (Array.isArray(value)) return <ArrayDisplay value={value} />
if ("type" in value && typeof value.type === "string" && "value" in value)
return <EnumDisplay value={value as any} />

View File

@@ -1,80 +1,87 @@
import type { Blockchain } from "@acala-network/chopsticks-core"
import { getSyncProvider } from "@polkadot-api/json-rpc-provider-proxy"
import { Blockchain, ChopsticksProvider } from "@acala-network/chopsticks-core"
import {
getSyncProvider,
InnerJsonRpcProvider,
} from "@polkadot-api/json-rpc-provider-proxy"
import { blockHeader } from "@polkadot-api/substrate-bindings"
import { JsonRpcProvider } from "polkadot-api/ws-provider/web"
import type { JsonRpcProvider } from "polkadot-api"
import { BehaviorSubject } from "rxjs"
export const chopsticksInstance$ = new BehaviorSubject<Blockchain | null>(null)
export const createChopsticksProvider = (endpoint: string) =>
withChopsticksEnhancer(
getSyncProvider(async () => {
const { ChopsticksProvider, setup } = await import(
"@acala-network/chopsticks-core"
)
getSyncProvider((onReady) => {
let isRunning = true
let chain: Blockchain
chopsticksInstance$.getValue()?.close()
const chain = await setup({
endpoint,
mockSignatureHost: true,
})
chopsticksInstance$.next(chain)
const innerProvider = new ChopsticksProvider(chain)
return (onMessage) => {
return {
send: async (message: string) => {
const parsed = JSON.parse(message)
if (parsed.method === "chainHead_v1_follow") {
const subscription = await innerProvider.subscribe(
"chainHead_v1_followEvent",
parsed.method,
parsed.params,
(err, result) => {
if (err) {
console.error(err)
return
}
onMessage(
JSON.stringify({
const getProvider =
(
innerProvider: InstanceType<typeof ChopsticksProvider>,
): InnerJsonRpcProvider =>
(onMessage) => {
return {
send: async (msg) => {
if (msg.method === "chainHead_v1_follow") {
const subscription = await innerProvider.subscribe(
"chainHead_v1_followEvent",
msg.method,
msg.params,
(err, result) => {
if (err) {
console.error(err)
return
}
onMessage({
jsonrpc: "2.0",
method: "chainHead_v1_followEvent",
params: {
subscription,
result,
},
}),
)
},
)
onMessage(
JSON.stringify({
})
},
)
onMessage({
jsonrpc: "2.0",
id: parsed.id,
id: msg.id!,
result: subscription,
}),
)
return
}
})
return
}
const response = await innerProvider.send(
parsed.method,
parsed.params,
)
onMessage(
JSON.stringify({
const response = await innerProvider.send(msg.method, msg.params)
onMessage({
jsonrpc: "2.0",
id: parsed.id,
id: msg.id!,
result: response,
}),
)
},
disconnect: () => {
chain?.close()
chopsticksInstance$.next(null)
},
})
},
disconnect: () => {
chain.close()
chopsticksInstance$.next(null)
},
}
}
;(async () => {
try {
const { ChopsticksProvider, setup } =
await import("@acala-network/chopsticks-core")
chain = await setup({
endpoint,
mockSignatureHost: true,
})
if (isRunning) {
onReady(getProvider(new ChopsticksProvider(chain)))
chopsticksInstance$.next(chain)
} else chain.close()
} catch {
if (isRunning) onReady(null)
}
})()
return () => {
isRunning = false
}
}),
)
@@ -101,25 +108,21 @@ const withChopsticksEnhancer =
previousNumber !== null &&
currentNumber > previousNumber + 1
) {
onMessage(
JSON.stringify({
...waitingForNumber,
params: {
...waitingForNumber.params,
result: {
event: "stop",
},
onMessage({
...waitingForNumber,
params: {
...waitingForNumber.params,
result: {
event: "stop",
},
}),
)
inner.send(
JSON.stringify({
jsonrpc: "2.0",
id: "chopsticks-stopped",
method: "chainHead_v1_unfollow",
params: [waitingForNumber.params.subscription],
}),
)
},
})
inner.send({
jsonrpc: "2.0",
id: "chopsticks-stopped",
method: "chainHead_v1_unfollow",
params: [waitingForNumber.params.subscription],
})
messageQueue.length = 0
previousNumber = currentNumber
waitingForNumber = null
@@ -128,7 +131,7 @@ const withChopsticksEnhancer =
previousNumber = currentNumber
if (waitingForNumber) {
onMessage(JSON.stringify(waitingForNumber))
onMessage(waitingForNumber)
waitingForNumber = null
}
@@ -151,29 +154,23 @@ const withChopsticksEnhancer =
const { blockHash } = parsed.params.result
waitingForNumber = parsed
inner.send(
JSON.stringify({
jsonrpc: "2.0",
id: "chopsticks-header-" + blockHash,
method: "chainHead_v1_header",
params: [parsed.params.subscription, blockHash],
}),
)
inner.send({
jsonrpc: "2.0",
id: "chopsticks-header-" + blockHash,
method: "chainHead_v1_header",
params: [parsed.params.subscription, blockHash],
})
return
}
onMessage(JSON.stringify(parsed))
onMessage(parsed)
if (messageQueue.length) {
const [next] = messageQueue.splice(0, 1)
processMessage(next)
}
}
const inner = parent((msg) => {
const parsed = JSON.parse(msg)
processMessage(parsed)
})
const inner = parent(processMessage)
return {
send(message) {

View File

@@ -14,7 +14,7 @@ import {
NOTIN,
} from "@polkadot-api/react-builder"
import { u8 } from "@polkadot-api/substrate-bindings"
import { toHex } from "@polkadot-api/utils"
import { toHex } from "polkadot-api/utils"
import { useStateObservable } from "@react-rxjs/core"
import { FC } from "react"
import { isActive$ } from "../common/paths.state"

View File

@@ -3,8 +3,8 @@ import { BinaryEditButton } from "@/components/BinaryEditButton"
import { CopyText } from "@/components/Copy"
import { ExpandBtn } from "@/components/Expand"
import { CodecComponentType, NOTIN } from "@polkadot-api/react-builder"
import { Binary, HexString } from "@polkadot-api/substrate-bindings"
import { toHex } from "@polkadot-api/utils"
import { HexString } from "@polkadot-api/substrate-bindings"
import { fromHex, toHex } from "polkadot-api/utils"
import { ComponentProps, FC, useState } from "react"
import { twMerge } from "tailwind-merge"
import { EditCodec } from "../EditCodec"
@@ -24,7 +24,7 @@ export const BinaryDisplay: FC<
if (value.type === CodecComponentType.Initial) {
if (!value.value) return null
return typeof value.value === "string"
? Binary.fromHex(value.value).asBytes()
? fromHex(value.value)
: value.value
}
if (value.value.empty || !value.value.encoded) return null
@@ -43,7 +43,7 @@ export const BinaryDisplay: FC<
className={twMerge(
"binary-display-codec",
"text-sm tabular-nums overflow-hidden flex-1",
wrap ? "break-words" : "whitespace-nowrap text-ellipsis h-5",
wrap ? "wrap-break-word" : "whitespace-nowrap text-ellipsis h-5",
)}
>
{isEmpty ? (

View File

@@ -1,9 +1,9 @@
import { getBytesFormat } from "@/components/BinaryInput"
import { SwitchBinary } from "@/components/Icons"
import { ViewBytes } from "@polkadot-api/react-builder"
import { Binary } from "polkadot-api"
import { FC, useState } from "react"
import { useReportBinary } from "./CopyBinary"
import { toHex } from "polkadot-api/utils"
export const CBytes: ViewBytes = ({ value, encodedValue }) => {
useReportBinary(encodedValue)
@@ -11,7 +11,7 @@ export const CBytes: ViewBytes = ({ value, encodedValue }) => {
return <BytesDisplay value={value} />
}
export const BytesDisplay: FC<{ value: Binary }> = ({ value }) => {
export const BytesDisplay: FC<{ value: Uint8Array }> = ({ value }) => {
const [forceBinary, setForceBinary] = useState(false)
const format = getBytesFormat(value)
@@ -27,7 +27,7 @@ export const BytesDisplay: FC<{ value: Binary }> = ({ value }) => {
<SwitchBinary size={24} />
</button>
) : null}
{forceBinary ? value.asHex() : format.value}
{forceBinary ? toHex(value) : format.value}
</div>
)
}

View File

@@ -1,5 +1,5 @@
import { CopyText } from "@/components/Copy"
import { Binary } from "polkadot-api"
import { toHex } from "polkadot-api/utils"
import {
createContext,
FC,
@@ -55,7 +55,7 @@ export const CopyBinary: FC<{ value: Uint8Array; visible?: boolean }> = ({
visible = true,
}) => (
<CopyText
text={Binary.fromBytes(value).asHex()}
text={toHex(value)}
className={twMerge("transition-opacity", !visible ? "opacity-0" : "")}
binary
/>

View File

@@ -5,7 +5,6 @@ import {
import { Modal } from "@/components/Modal"
import { useGenericSynchronizeInput } from "@/components/useSynchroniseInput"
import { NOTIN } from "@polkadot-api/react-builder"
import { Binary } from "@polkadot-api/substrate-bindings"
import { Download, FileUp } from "lucide-react"
import { ComponentProps, FC, useMemo, useState } from "react"
import { twMerge } from "tailwind-merge"
@@ -13,6 +12,7 @@ import { twMerge } from "tailwind-merge"
import { saveAs } from "save-as"
import { BinaryEdit } from "./Icons"
import { ActionButton } from "./ActionButton"
import { fromHex, toHex } from "polkadot-api/utils"
export interface BinaryEditProps {
initialValue?: Uint8Array
@@ -80,17 +80,13 @@ const BinaryEditModalContent: FC<
const [inputValue, setInputValue] = useGenericSynchronizeInput(
value,
setValue as any,
(input) => parseInput(input).asBytes(),
parseInput,
"" as string | Uint8Array,
(value) => {
if (value.length > MAX_DISPLAY_SIZE) return ""
return Binary.fromBytes(value).asHex()
return toHex(value)
},
(input, value) =>
checkEqualInputBinary(
parseInput(input),
value === NOTIN ? NOTIN : Binary.fromBytes(value),
),
(input, value) => checkEqualInputBinary(parseInput(input), value),
)
const placeholder =
@@ -158,7 +154,7 @@ const BinaryEditModalContent: FC<
<BinaryFileInput
validate={validateFile}
onError={() => setError("Error loading file")}
onLoaded={(value) => setValue(value.asBytes())}
onLoaded={setValue}
/>
</label>
</div>
@@ -186,6 +182,4 @@ const BinaryEditModalContent: FC<
}
const parseInput = (value: string | Uint8Array) =>
value instanceof Uint8Array
? Binary.fromBytes(value)
: Binary.fromHex(value.startsWith("0x") ? value : `0x${value}`)
value instanceof Uint8Array ? value : fromHex(value)

View File

@@ -7,17 +7,18 @@ import { twMerge } from "tailwind-merge"
import { SwitchBinary } from "./Icons"
import { TextInputField } from "./TextInputField"
import { useGenericSynchronizeInput } from "./useSynchroniseInput"
import { fromHex, toHex } from "polkadot-api/utils"
export const BinaryInput: React.FC<{
encodedValue: Binary | NOTIN
onValueChanged: (newValue: Binary | NOTIN) => boolean
encodedValue: Uint8Array | NOTIN
onValueChanged: (newValue: Uint8Array | NOTIN) => boolean
len?: number
}> = ({ encodedValue, onValueChanged, len }) => {
const [localInput, setLocalInput] = useGenericSynchronizeInput(
encodedValue,
onValueChanged,
(value) => validate(parseValue(value), len),
"" as string | Binary,
"" as string | Uint8Array,
serializeValue,
checkEqualInputBinary,
)
@@ -44,7 +45,7 @@ export const BinaryInput: React.FC<{
}
const parsed = parseValue(inputValue)
const length = parsed === NOTIN ? null : parsed.asBytes().length
const length = parsed === NOTIN ? null : parsed.length
const oddHexLength =
typeof localInput === "string" &&
@@ -82,9 +83,9 @@ export const BinaryInput: React.FC<{
type="button"
onClick={() => {
if (inputValue.startsWith("0x")) {
setLocalInput(serializeValue(Binary.fromHex(inputValue)))
setLocalInput(serializeValue(fromHex(inputValue)))
} else {
setLocalInput(Binary.fromText(inputValue).asHex())
setLocalInput(toHex(Binary.fromText(inputValue)))
}
}}
>
@@ -110,7 +111,7 @@ export const BinaryInput: React.FC<{
export const BinaryFileInput: FC<{
validate: (file: File) => boolean
onLoaded: (value: Binary) => void
onLoaded: (value: Uint8Array) => void
onError: () => void
}> = ({ validate, onLoaded, onError }) => {
const loadFile = async (file: File) => {
@@ -124,7 +125,7 @@ export const BinaryFileInput: FC<{
reader.onerror = reject
reader.readAsArrayBuffer(file)
})
onLoaded(Binary.fromBytes(new Uint8Array(buffer)))
onLoaded(new Uint8Array(buffer))
} catch (ex) {
console.error(ex)
onError()
@@ -143,19 +144,22 @@ export const BinaryFileInput: FC<{
)
}
const validate = (value: Binary | NOTIN, len?: number): Binary | NOTIN => {
const validate = (
value: Uint8Array | NOTIN,
len?: number,
): Uint8Array | NOTIN => {
if (!len || value === NOTIN) return value
return value.asBytes().length !== len ? NOTIN : value
return value.length !== len ? NOTIN : value
}
const parseValue = (value: string | Binary): Binary | NOTIN => {
if (value instanceof Binary) return value
const parseValue = (value: string | Uint8Array): Uint8Array | NOTIN => {
if (value instanceof Uint8Array) return value
if (value.trim() === "") return Binary.fromText("")
if (value.startsWith("0x")) {
try {
return Binary.fromHex(value)
return fromHex(value)
} catch (_) {
return NOTIN
}
@@ -164,40 +168,35 @@ const parseValue = (value: string | Binary): Binary | NOTIN => {
return Binary.fromText(value)
}
const serializeValue = (value: Binary): string | Binary => {
const bytes = value.asBytes()
if (bytes.length === 0) return ""
if (bytes.length > 5 * 1024 * 1024) return value
const serializeValue = (value: Uint8Array): string | Uint8Array => {
if (value.length === 0) return ""
if (value.length > 5 * 1024 * 1024) return value
return bytesToString(value)
}
const textDecoder = new TextDecoder("utf-8", { fatal: true })
export const getBytesFormat = (value: Binary) => {
export const getBytesFormat = (value: Uint8Array) => {
try {
const bytes = value.asBytes()
if (bytes.slice(0, 5).every((b) => b < 32)) throw null
if (value.slice(0, 5).every((b) => b < 32)) throw null
return {
type: "text",
value: textDecoder.decode(bytes),
value: textDecoder.decode(value),
}
} catch (_) {
return {
type: "hex",
value: value.asHex(),
value: toHex(value),
}
}
}
export const bytesToString = (value: Binary) => getBytesFormat(value).value
export const bytesToString = (value: Uint8Array) => getBytesFormat(value).value
export const checkEqualInputBinary = (
input: string | Binary,
value: Binary | typeof NOTIN,
input: string | Uint8Array,
value: Uint8Array | typeof NOTIN,
) => {
const parsed = parseValue(input)
if (parsed === NOTIN || value === NOTIN) return true
const inputBytes = parsed.asBytes()
const valueBytes = value.asBytes()
return byteArraysAreEqual(inputBytes, valueBytes)
return byteArraysAreEqual(parsed, value)
}

View File

@@ -1,5 +1,4 @@
import { bytesToString } from "@/components/BinaryInput"
import { Binary } from "@polkadot-api/substrate-bindings"
import { FC } from "react"
import ReactJson from "react18-json-view"
import "react18-json-view/src/dark.css"
@@ -18,14 +17,14 @@ export const JsonDisplay: FC<{
src={src}
dark={theme === "dark"}
theme="a11y"
replacer={(v) => (v instanceof Binary ? bytesToString(v) : v)}
replacer={(v) => (v instanceof Uint8Array ? bytesToString(v) : v)}
customizeCopy={(v) =>
JSON.stringify(
v,
(_, v) =>
typeof v === "bigint"
? `${v}n`
: v instanceof Binary
: v instanceof Uint8Array
? bytesToString(v)
: v,
2,

View File

@@ -12,6 +12,7 @@ import {
} from "@react-rxjs/core"
import { Send } from "lucide-react"
import { CompatibilityLevel, SS58String } from "polkadot-api"
import { toHex } from "polkadot-api/utils"
import {
Account,
ledgerProviderId,
@@ -77,7 +78,7 @@ const AccountCard: FC<{
<div className="flex justify-between items-start overflow-hidden">
<AccountIdDisplay
value={account.address}
className="shrink-1 overflow-hidden"
className="shrink overflow-hidden"
/>
<SourceTag account={account} />
</div>
@@ -127,7 +128,7 @@ const balance$ = state(
typedApi.query.System.Account.watchValue(accountId),
),
map((account) => {
const { reserved, free, frozen } = account.data
const { reserved, free, frozen } = account.value.data
const total = reserved + free
// TODO ED
@@ -156,12 +157,12 @@ const getTransferCallData$ = state(
const tokenDecimals = chainProperties?.tokenDecimals
if (tokenDecimals == null) return null
const token = await typedApi.compatibilityToken
const staticApis = await typedApi.getStaticApis()
if (
!typedApi.tx.Balances.transfer_keep_alive.isCompatible(
!staticApis.compat.tx.Balances.transfer_keep_alive.isCompatible(
CompatibilityLevel.BackwardsCompatible,
token,
)
) {
return null
@@ -170,12 +171,12 @@ const getTransferCallData$ = state(
return (dest: SS58String) => {
const value = 10n ** BigInt(tokenDecimals)
return typedApi.tx.Balances.transfer_keep_alive({
dest: MultiAddress.Id(dest),
value,
})
.getEncodedData(token)
.asHex()
return toHex(
staticApis.tx.Balances.transfer_keep_alive.getCallData({
dest: MultiAddress.Id(dest),
value,
}),
)
}
}),
),

View File

@@ -14,7 +14,7 @@ import { BlockStorageDiff } from "./BlockStorageDiff"
import { ApplyExtrinsicEvent, Extrinsic } from "./Extrinsic"
import { getHashParams } from "@/hashParams"
import { Blake2256 } from "@polkadot-api/substrate-bindings"
import { fromHex, toHex } from "@polkadot-api/utils"
import { toHex } from "polkadot-api/utils"
const blockExtrinsics$ = state((hash: string) => {
const body$ = blockInfoState$(hash).pipe(
@@ -31,7 +31,7 @@ const blockExtrinsics$ = state((hash: string) => {
map(([body, { txDecoder }]) =>
body.map((raw, idx) => ({
idx,
hash: toHex(Blake2256(fromHex(raw))),
hash: toHex(Blake2256(raw)),
...txDecoder(raw),
})),
),

View File

@@ -19,7 +19,7 @@ import {
u8,
Vector,
} from "@polkadot-api/substrate-bindings"
import { toHex } from "@polkadot-api/utils"
import { toHex } from "polkadot-api/utils"
import { state, useStateObservable } from "@react-rxjs/core"
import { Binary, Codec } from "polkadot-api"
import { FC } from "react"
@@ -37,12 +37,12 @@ const blockDiff$ = state(
const palletKeys = Object.fromEntries(
lookup.metadata.pallets.map((pallet) => [
toHex(Twox128(Binary.fromText(pallet.name).asBytes())).slice(2),
toHex(Twox128(Binary.fromText(pallet.name))).slice(2),
{
name: pallet.name,
entries: Object.fromEntries(
pallet.storage?.items.map((item) => [
toHex(Twox128(Binary.fromText(item.name).asBytes())).slice(2),
toHex(Twox128(Binary.fromText(item.name))).slice(2),
item.name,
]) ?? [],
),
@@ -149,7 +149,7 @@ export const BlockStorageDiff: FC<{
? `(${JSON.stringify(v, (_, v) =>
typeof v === "bigint"
? `${v}n`
: v instanceof Binary
: v instanceof Uint8Array
? bytesToString(v)
: v,
)})`
@@ -176,7 +176,7 @@ export const BlockStorageDiff: FC<{
)
}
const strToHex = (v: string) => Binary.fromText(v).asHex()
const strToHex = (v: string) => toHex(Binary.fromText(v))
const wellKnownKeys: Record<
string,
{

View File

@@ -9,7 +9,8 @@ import { shortStr } from "@/utils"
import { SystemEvent } from "@polkadot-api/observable-client"
import { DecodedExtrinsic } from "@polkadot-api/tx-utils"
import { Dot, Edit } from "lucide-react"
import { Binary, Enum, HexString, SS58String } from "polkadot-api"
import { Enum, HexString, SS58String } from "polkadot-api"
import { toHex } from "polkadot-api/utils"
import { FC, useEffect, useRef, useState } from "react"
import { twMerge } from "tailwind-merge"
@@ -41,13 +42,13 @@ export const Extrinsic: FC<{
{extrinsic.idx}. {extrinsic.call.type}.{extrinsic.call.value.type}
</button>
<div className="flex gap-2 items-center">
<CopyBinary value={extrinsic.callData.asBytes()} />
{extrinsic.callData.asBytes().length > 1024 ? (
<CopyBinary value={extrinsic.callData} />
{extrinsic.callData.length > 1024 ? (
<span className="opacity-50">
<Edit size={14} />
</span>
) : (
<Link to={"/extrinsics#data=" + extrinsic.callData.asHex()}>
<Link to={"/extrinsics#data=" + toHex(extrinsic.callData)}>
<Edit size={14} />
</Link>
)}
@@ -107,7 +108,7 @@ const SignedExtensions: FC<{ extra: Record<string, unknown> }> = ({
const SignedExtension: FC<{ id: string; value: unknown }> = ({ id, value }) => {
const [expanded, setExpanded] = useState(false)
const inlineJson = JSON.stringify(value, (_, v) =>
typeof v === "bigint" ? String(v) : v instanceof Binary ? v.asHex() : v,
typeof v === "bigint" ? String(v) : v instanceof Uint8Array ? toHex(v) : v,
)
if (!inlineJson || inlineJson.length < 40) {

View File

@@ -50,7 +50,7 @@ const epochFromCall$ = runtimeCtx$.pipe(
}
return (
getFromApi("BabeApi", "configuration")?.then((r) =>
Number(r.epoch_length),
Number((r as any).epoch_length),
) ?? of(null)
)
}),
@@ -72,7 +72,7 @@ const epochStartBlock$ = state(
? client
.getUnsafeApi()
.query[pallet][entry].watchValue()
.pipe(map(([, duration]) => Number(duration)))
.pipe(map(({ value }) => Number((value as any)[1])))
: of(null)
}),
),

View File

@@ -1,16 +1,16 @@
import { chopsticksInstance$ } from "@/chopsticks/chopsticks"
import { chainClient$, client$ } from "@/state/chains/chain.state"
import { SystemEvent } from "@polkadot-api/observable-client"
import { blockHeader } from "@polkadot-api/substrate-bindings"
import { blockHeader, SizedHex } from "@polkadot-api/substrate-bindings"
import { liftSuspense, state } from "@react-rxjs/core"
import { combineKeys, partitionByKey } from "@react-rxjs/utils"
import {
BlockHeader,
FixedSizeBinary,
HexString,
PolkadotClient,
BlockInfo as RawBlockInfo,
} from "polkadot-api"
import { fromHex } from "polkadot-api/utils"
import {
catchError,
combineLatest,
@@ -56,7 +56,7 @@ export interface BlockInfo {
hash: string
parent: string
number: number
body: string[] | null
body: Uint8Array[] | null
events: SystemEvent[] | null
header: BlockHeader | null
status: BlockState
@@ -93,7 +93,7 @@ export const [blockInfo$, recordedBlocks$] = partitionByKey(
hash: of(hash),
parent: of(parent),
number: of(number),
body: client.watchBlockBody(hash).pipe(
body: client.getBlockBody$(hash).pipe(
startWith(null),
catchError((err) => {
console.error("fetch body failed", err)
@@ -103,7 +103,7 @@ export const [blockInfo$, recordedBlocks$] = partitionByKey(
events: from(
client.getUnsafeApi().query.System.Events.getValue({
at: hash,
}),
}) as Promise<SystemEvent[]>,
).pipe(
startWith(null),
catchError((err) => {
@@ -154,10 +154,10 @@ const getUnpinnedBlockInfo$ = (hash: string): Observable<BlockInfo> =>
),
),
),
body: client.watchBlockBody(hash),
body: client.getBlockBody$(hash),
events: client.getUnsafeApi().query.System.Events.getValue({
at: hash,
}),
}) as Promise<SystemEvent[]>,
}).pipe(
map(({ headerAndStatus: { header, status }, body, events }) => ({
hash: hash,
@@ -221,7 +221,7 @@ const getUnpinnedBlockInfoFallback$ = (
({ block: { extrinsics, header }, status, number }): BlockInfo => ({
hash,
parent: header.parentHash,
body: extrinsics,
body: extrinsics.map(fromHex),
events: null,
header: {
digests: header.digest.logs
@@ -254,7 +254,7 @@ export const inMemoryBlocks$ = state(
)
inMemoryBlocks$.pipe(liftSuspense()).subscribe()
export const blockHash$ = (hashOrHeight: string) =>
export const blockHash$ = (hashOrHeight: string): Observable<SizedHex<32>> =>
hashOrHeight.length > 63
? of(hashOrHeight.startsWith("0x") ? hashOrHeight : `0x${hashOrHeight}`)
: client$.pipe(
@@ -268,11 +268,13 @@ export const blockHash$ = (hashOrHeight: string) =>
if (x.length) return x[0]
throw null
}),
catchError(() =>
client
.getUnsafeApi()
.query.System.BlockHash.getValue(Number(hashOrHeight))
.then((x: FixedSizeBinary<32>) => x.asHex()),
catchError(
() =>
client
.getUnsafeApi()
.query.System.BlockHash.getValue(
Number(hashOrHeight),
) as Promise<SizedHex<32>>,
),
),
),

View File

@@ -36,7 +36,7 @@ const fromCall$ = runtimeCtx$.pipe(
return (
getFromApi("AuraApi", "slot_duration")?.then((r) => Number(r)) ??
getFromApi("BabeApi", "configuration")?.then((r) =>
Number(r.slot_duration),
Number((r as any).slot_duration),
) ??
of(null)
)

View File

@@ -8,8 +8,7 @@ import {
CodecComponentType,
CodecComponentValue,
} from "@polkadot-api/react-builder"
import { Binary } from "@polkadot-api/substrate-bindings"
import { toHex } from "@polkadot-api/utils"
import { fromHex, toHex } from "polkadot-api/utils"
import { state, useStateObservable } from "@react-rxjs/core"
import { useLayoutEffect, useState } from "react"
import { useLocation } from "react-router-dom"
@@ -143,7 +142,7 @@ export const Extrinsics = withSubscribe(
<JsonMode
value={
typeof binaryValue === "string"
? Binary.fromHex(binaryValue).asBytes()
? fromHex(binaryValue)
: binaryValue
}
decode={extrinsicProps.codec.dec}

View File

@@ -7,7 +7,7 @@ import {
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { toHex } from "@polkadot-api/utils"
import { toHex } from "polkadot-api/utils"
import { HexString } from "polkadot-api"
import React, { lazy, Suspense, useState } from "react"

View File

@@ -5,7 +5,7 @@ import { trackSignedTx, trackUnsignedTx } from "@/pages/Transactions"
import { unsafeApi$ } from "@/state/chains/chain.state"
import { selectedAccount$ } from "@/state/polkahub"
import { compactNumber } from "@polkadot-api/substrate-bindings"
import { fromHex, mergeUint8, toHex } from "@polkadot-api/utils"
import { fromHex, mergeUint8 } from "polkadot-api/utils"
import { AccountPicker } from "@polkahub/ui-components"
import { useStateObservable } from "@react-rxjs/core"
import { Binary } from "polkadot-api"
@@ -72,7 +72,7 @@ const SubmitUnsigned: FC<{ callData: string; onClose: () => void }> = ({
new Uint8Array([4]),
data,
])
trackUnsignedTx(toHex(unsignedTx))
trackUnsignedTx(unsignedTx)
onClose()
}}
className="flex gap-2 items-center justify-center"

View File

@@ -14,10 +14,9 @@ import {
NOTIN,
} from "@polkadot-api/react-builder"
import { Twox128 } from "@polkadot-api/substrate-bindings"
import { toHex } from "@polkadot-api/utils"
import { fromHex, toHex } from "polkadot-api/utils"
import { state, useStateObservable, withDefault } from "@react-rxjs/core"
import { createSignal } from "@react-rxjs/utils"
import { Binary } from "polkadot-api"
import { FC } from "react"
import {
combineLatest,
@@ -78,11 +77,13 @@ export const StorageQuery: FC = () => {
const hash$ = single
? chainClient$.pipe(
switchMap(({ chainHead }) =>
chainHead.storage$(hash, "hash", (ctx) =>
ctx.dynamicBuilder
.buildStorage(entry!.pallet, entry!.entry)
.keys.enc(...args),
),
chainHead
.storage$(hash, "hash", (ctx) =>
ctx.dynamicBuilder
.buildStorage(entry!.pallet, entry!.entry)
.keys.enc(...args),
)
.pipe(map(({ value }) => value)),
),
)
: of(null)
@@ -366,7 +367,7 @@ const StorageKeyInput: FC<{
<BinaryEditButton
initialValue={
typeof binaryValue === "string"
? Binary.fromHex(binaryValue).asBytes()
? fromHex(binaryValue)
: (binaryValue ?? undefined)
}
onValueChange={(value) => setKeyValue({ idx, value })}
@@ -441,7 +442,7 @@ export const KeyDisplay: FC = () => {
</div>
<CopyText text={key ?? ""} disabled={key === null} binary />
<BinaryEditButton
initialValue={key ? Binary.fromHex(key).asBytes() : undefined}
initialValue={key ? fromHex(key) : undefined}
onValueChange={(value: NonNullable<DecodedKey>) => {
let newKeysEnabled = keysEnabled
if (
@@ -518,9 +519,7 @@ const decodeKey = (
? []
: item.type.value.hashers.map((x) => hashersToLength[x.tag])
let argsRemaining = Binary.fromHex(
keyRemaining.replace(twoxHash(item.name), "0x"),
).asBytes()
let argsRemaining = fromHex(keyRemaining.replace(twoxHash(item.name), "0x"))
const args: any[] = []
const argsLen = codec.args.inner.length

View File

@@ -3,7 +3,7 @@ import { Chopsticks } from "@/components/Icons"
import { Button } from "@/components/ui/button"
import { chainClient$, client$, lookup$ } from "@/state/chains/chain.state"
import { getTypeComplexity } from "@/utils"
import { fromHex, toHex } from "@polkadot-api/utils"
import { fromHex, toHex } from "polkadot-api/utils"
import { state, useStateObservable } from "@react-rxjs/core"
import { createSignal } from "@react-rxjs/utils"
import { FC, useState } from "react"
@@ -31,7 +31,7 @@ const currentValue$ = state(
),
withLatestFrom(lookup$, selectedEntry$.pipe(filter((v) => v != null))),
map(([v, lookup, entry]) => {
if (v != null) return v
if (v != null) return v.value
const pallet = lookup.metadata.pallets.find(
(p) => p.name == entry.pallet,
)!

View File

@@ -17,7 +17,7 @@ import { CodecComponentType, NOTIN } from "@polkadot-api/react-builder"
import { Button } from "@polkahub/ui-components"
import { useStateObservable } from "@react-rxjs/core"
import { ChevronLeft, ChevronRight, StopCircle, Trash2 } from "lucide-react"
import { Binary, Enum } from "polkadot-api"
import { Enum } from "polkadot-api"
import { FC, MouseEvent, ReactNode, useMemo, useState } from "react"
import { Virtuoso } from "react-virtuoso"
import { BlockState } from "../Explorer/block.state"
@@ -30,6 +30,7 @@ import {
storageSubscriptionKeys$,
StorageSubscriptionValue,
} from "./storage.state"
import { fromHex } from "polkadot-api/utils"
export const StorageSubscriptions: FC = () => {
const keys = useStateObservable(storageSubscriptionKeys$)
@@ -460,7 +461,7 @@ const KeyDisplay: FC<{
}> = ({ value, keyCodec }) => {
const binaryValue = (() => {
try {
return keyCodec ? Binary.fromHex(keyCodec.enc(...value)).asBytes() : null
return keyCodec ? fromHex(keyCodec.enc(...value)) : null
} catch (_) {
return null
}

View File

@@ -14,7 +14,7 @@ import {
partitionByKey,
toKeySet,
} from "@react-rxjs/utils"
import { Binary, Enum, HexString } from "polkadot-api"
import { Enum, HexString } from "polkadot-api"
import {
catchError,
combineLatest,
@@ -416,10 +416,7 @@ export const storageSubscription$ = state(
export const stringifyArg = (value: unknown) => {
if (typeof value === "object" && value !== null) {
if (value instanceof Binary) {
return bytesToString(value)
}
return "arg"
return value instanceof Uint8Array ? bytesToString(value) : "arg"
}
return String(value)
}

View File

@@ -5,7 +5,7 @@ import { TxBroadcastEvent } from "polkadot-api"
import * as React from "react"
import { dismissTransaction, onGoingEvents } from "./transactions.state"
import { Trash2 } from "lucide-react"
import { jsonPrint } from "@polkadot-api/utils"
import { jsonSerialize } from "polkadot-api/utils"
export const Transaction: React.FC<{
event:
@@ -23,7 +23,11 @@ export const Transaction: React.FC<{
case "error":
return <span>There was an unexpected error.</span>
case "invalid":
return <span>Invalid transaction. {jsonPrint(event.value)}</span>
return (
<span>
Invalid transaction. {JSON.stringify(event.value, jsonSerialize)}
</span>
)
case "txBestBlocksState": {
return event.found ? (
<span>
@@ -58,7 +62,7 @@ export const Transaction: React.FC<{
</Link>
{event.ok
? "."
: `, but it failed: ${jsonPrint(event.dispatchError)}.`}
: `, but it failed: ${JSON.stringify(event.dispatchError, jsonSerialize)}.`}
</span>
)
}

View File

@@ -6,13 +6,12 @@ import {
mergeWithKey,
partitionByKey,
} from "@react-rxjs/utils"
import { HexString, InvalidTxError, TxBroadcastEvent } from "polkadot-api"
import { InvalidTxError } from "polkadot-api"
import {
catchError,
filter,
merge,
mergeMap,
Observable,
of,
skip,
takeUntil,
@@ -20,8 +19,8 @@ import {
withLatestFrom,
} from "rxjs"
const [signedTx$, trackSignedTx] = createSignal<HexString>()
const [unsignedTx$, trackUnsignedTx] = createSignal<HexString>()
const [signedTx$, trackSignedTx] = createSignal<Uint8Array>()
const [unsignedTx$, trackUnsignedTx] = createSignal<Uint8Array>()
export { trackSignedTx, trackUnsignedTx }
export const [dismissTransaction$, dismissTransaction] = createSignal<string>()
@@ -29,14 +28,8 @@ export const [dismissTransaction$, dismissTransaction] = createSignal<string>()
const transactions$ = mergeWithKey({ signedTx$, unsignedTx$ }).pipe(
withLatestFrom(chainClient$),
mergeMap(([tx, { client }]) => {
const submitAndWatch = client.submitAndWatch as (
tx: HexString,
at: string,
withSigned?: boolean,
) => Observable<TxBroadcastEvent>
let txHash: string = ""
return submitAndWatch(tx.payload, "finalized", true).pipe(
return client.submitAndWatch(tx.payload, "finalized").pipe(
tap((e) => {
txHash = e.txHash
}),

View File

View File

@@ -1,7 +1,4 @@
import {
chopsticksInstance$,
createChopsticksProvider,
} from "@/chopsticks/chopsticks"
import { createChopsticksProvider } from "@/chopsticks/chopsticks"
import { getHashParams, setHashParams } from "@/hashParams"
import { getDynamicBuilder, getLookupFn } from "@polkadot-api/metadata-builders"
import {
@@ -10,7 +7,7 @@ import {
unifyMetadata,
} from "@polkadot-api/substrate-bindings"
import { getExtrinsicDecoder } from "@polkadot-api/tx-utils"
import { fromHex, toHex } from "@polkadot-api/utils"
import { fromHex, toHex } from "polkadot-api/utils"
import { liftSuspense, sinkSuspense, state, SUSPENSE } from "@react-rxjs/core"
import { createSignal } from "@react-rxjs/utils"
import { get, update } from "idb-keyval"
@@ -75,9 +72,6 @@ console.log("You can enable JSON-RPC logs by calling `setRpcLogsEnabled(true)`")
;(window as any).setRpcLogsEnabled = setRpcLogsEnabled
export const getProvider = (source: ChainSource) => {
// TODO bug: provider is not getting disconnected
chopsticksInstance$.next(null)
const provider =
source.type === "websocket"
? source.withChopsticks

View File

@@ -1 +1 @@
export { chainSpec } from "polkadot-api/chains/ksmcc3"
export { chainSpec } from "polkadot-api/chains/kusama"

View File

@@ -1 +1 @@
export { chainSpec } from "polkadot-api/chains/ksmcc3_asset_hub"
export { chainSpec } from "polkadot-api/chains/kusama_asset_hub"

View File

@@ -1 +1 @@
export { chainSpec } from "polkadot-api/chains/ksmcc3_coretime"
export { chainSpec } from "polkadot-api/chains/kusama_coretime"

View File

@@ -1 +1 @@
export { chainSpec } from "polkadot-api/chains/ksmcc3_encointer"
export { chainSpec } from "polkadot-api/chains/kusama_encointer"

View File

@@ -1 +1 @@
export { chainSpec } from "polkadot-api/chains/ksmcc3_people"
export { chainSpec } from "polkadot-api/chains/kusama_people"

View File

@@ -1 +1 @@
export { chainSpec } from "polkadot-api/chains/westend2"
export { chainSpec } from "polkadot-api/chains/westend"

View File

@@ -1 +1 @@
export { chainSpec } from "polkadot-api/chains/westend2_asset_hub"
export { chainSpec } from "polkadot-api/chains/westend_asset_hub"

View File

@@ -1 +1 @@
export { chainSpec } from "polkadot-api/chains/westend2_collectives"
export { chainSpec } from "polkadot-api/chains/westend_collectives"

View File

@@ -1 +1 @@
export { chainSpec } from "polkadot-api/chains/westend2_people"
export { chainSpec } from "polkadot-api/chains/westend_people"

View File

@@ -1,14 +1,13 @@
import type { JsonRpcProvider } from "polkadot-api"
import { getSmProvider } from "polkadot-api/sm-provider"
import { Chain } from "polkadot-api/smoldot"
import { startFromWorker } from "polkadot-api/smoldot/from-worker"
import SmWorker from "polkadot-api/smoldot/worker?worker"
import type { JsonRpcProvider } from "polkadot-api/ws-provider/web"
const [dotChainSpec, ksmChainSpec, paseoChainSpec, westendChainSpec] = [
import("polkadot-api/chains/polkadot"),
import("polkadot-api/chains/ksmcc3"),
import("polkadot-api/chains/kusama"),
import("polkadot-api/chains/paseo"),
import("polkadot-api/chains/westend2"),
import("polkadot-api/chains/westend"),
].map((x) => x.then((y) => y.chainSpec))
const smoldot = startFromWorker(new SmWorker(), {
logCallback: (level, target, message) => {
@@ -20,22 +19,12 @@ const smoldot = startFromWorker(new SmWorker(), {
},
forbidWs: true,
})
const relayChains: Record<
string,
{ chainSpec: Promise<string>; chain: Promise<Chain> | null }
> = {
polkadot: { chainSpec: dotChainSpec, chain: null },
kusama: { chainSpec: ksmChainSpec, chain: null },
paseo: { chainSpec: paseoChainSpec, chain: null },
westend: { chainSpec: westendChainSpec, chain: null },
}
const getRelayChain = async (name: string) => {
if (!relayChains[name].chain) {
relayChains[name].chain = smoldot.addChain({
chainSpec: await relayChains[name].chainSpec,
})
}
return relayChains[name].chain
const relayChains: Record<string, Promise<string>> = {
polkadot: dotChainSpec,
kusama: ksmChainSpec,
paseo: paseoChainSpec,
westend: westendChainSpec,
}
export interface SmoldotSource {
@@ -52,11 +41,12 @@ export async function createSmoldotSource(
relayChain?: string,
): Promise<SmoldotSource> {
if (id in relayChains) {
return relayChains[id].chainSpec.then((chainSpec) => ({
const chainSpec = await relayChains[id]
return {
id,
type: "chainSpec",
value: { chainSpec },
}))
}
}
const { chainSpec } = await import(`./chainspecs/${id}.ts`)
const parsed = JSON.parse(chainSpec)
@@ -71,16 +61,15 @@ export async function createSmoldotSource(
}
export function getSmoldotProvider(source: SmoldotSource): JsonRpcProvider {
const chain = source.value.relayChain
? getRelayChain(source.value.relayChain).then((chain) =>
smoldot.addChain({
chainSpec: source.value.chainSpec,
potentialRelayChains: [chain],
}),
)
: smoldot.addChain({
chainSpec: source.value.chainSpec,
})
const chainFactory = () =>
source.value.relayChain
? relayChains[source.value.relayChain].then(async (chainSpec) =>
smoldot.addChain({
chainSpec: source.value.chainSpec,
potentialRelayChains: [await smoldot.addChain({ chainSpec })],
}),
)
: smoldot.addChain({ chainSpec: source.value.chainSpec })
return getSmProvider(chain)
return getSmProvider(chainFactory)
}

View File

@@ -1,5 +1,5 @@
import { withPolkadotSdkCompat } from "polkadot-api/polkadot-sdk-compat"
import { getWsProvider, JsonRpcProvider } from "polkadot-api/ws-provider"
import type { JsonRpcProvider } from "polkadot-api"
import { getWsProvider } from "polkadot-api/ws"
export interface WebsocketSource {
type: "websocket"
@@ -17,5 +17,5 @@ export async function createWebsocketSource(
}
export function getWebsocketProvider(source: WebsocketSource): JsonRpcProvider {
return withPolkadotSdkCompat(getWsProvider(source.endpoint))
return getWsProvider(source.endpoint)
}

View File

@@ -9,6 +9,7 @@ import { state } from "@react-rxjs/core"
import { Binary, createClient, SS58String } from "polkadot-api"
import { catchError, from, of, tap } from "rxjs"
import { getProvider } from "./chains/chain.state"
import { fromHex } from "polkadot-api/utils"
export interface Identity {
displayName: string
@@ -51,14 +52,16 @@ export const getAddressName = async (
if (!id) {
const sup = await typedApi.query.Identity.SuperOf.getValue(addr)
if (!sup) return null
const subDisplay = readIdentityData(sup[1])?.asText() || ""
const supData = readIdentityData(sup[1])
const subDisplay = supData && Binary.toText(supData)
if (!subDisplay) return null
subIdStr = ` (${subDisplay})`
id = await typedApi.query.Identity.IdentityOf.getValue(sup[0])
if (!id) return null
}
const displayName = readIdentityData(id.info.display)?.asText()
const displayData = readIdentityData(id.info.display)
const displayName = displayData && Binary.toText(displayData)
return displayName
? {
displayName: `${displayName}${subIdStr}`,
@@ -88,9 +91,8 @@ export const identity$ = state(
(address) => cache.getValue()[address] ?? null,
)
const readIdentityData = (identityData: IdentityData): Binary | null => {
const readIdentityData = (identityData: IdentityData): Uint8Array | null => {
if (identityData.type === "None" || identityData.type === "Raw0") return null
if (identityData.type === "Raw1")
return Binary.fromBytes(new Uint8Array(identityData.value))
return identityData.value
if (identityData.type === "Raw1") return new Uint8Array(identityData.value)
return fromHex(identityData.value)
}