From 599ef34163fc8577139dbc1566706a02b50e4db0 Mon Sep 17 00:00:00 2001
From: Ryan Lee
Date: Fri, 1 Mar 2024 06:13:30 -0500
Subject: [PATCH 1/8] feat(lc-dapp): transfers
---
examples/light-client-dapp/package.json | 4 +-
.../src/components/Transfer.tsx | 48 ++++++----
examples/light-client-dapp/src/hooks/index.ts | 1 +
.../src/hooks/useTransfer.ts | 89 +++++++++++++++++++
pnpm-lock.yaml | 15 ++++
5 files changed, 137 insertions(+), 20 deletions(-)
create mode 100644 examples/light-client-dapp/src/hooks/useTransfer.ts
diff --git a/examples/light-client-dapp/package.json b/examples/light-client-dapp/package.json
index b4b3ed558..e4cd5c42c 100644
--- a/examples/light-client-dapp/package.json
+++ b/examples/light-client-dapp/package.json
@@ -20,12 +20,14 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-select": "^5.8.0",
- "rxjs": "^7.8.1"
+ "rxjs": "^7.8.1",
+ "uuid": "^9.0.1"
},
"devDependencies": {
"@substrate/unstable-wallet-provider": "workspace:^",
"@types/react": "^18.2.60",
"@types/react-dom": "^18.2.19",
+ "@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^7.0.2",
"@typescript-eslint/parser": "^7.1.0",
"@vitejs/plugin-react-swc": "^3.5.0",
diff --git a/examples/light-client-dapp/src/components/Transfer.tsx b/examples/light-client-dapp/src/components/Transfer.tsx
index 4225a3611..5b6013015 100644
--- a/examples/light-client-dapp/src/components/Transfer.tsx
+++ b/examples/light-client-dapp/src/components/Transfer.tsx
@@ -1,14 +1,8 @@
import { FormEvent, useCallback, useEffect, useMemo, useState } from "react"
-import { ss58Decode } from "@polkadot-labs/hdkd-helpers"
import { UnstableWallet } from "@substrate/unstable-wallet-provider"
-import { mergeUint8, toHex } from "@polkadot-api/utils"
import Select from "react-select"
-import { useSystemAccount } from "../hooks"
-import { getObservableClient } from "@polkadot-api/client"
-import { ConnectProvider, createClient } from "@polkadot-api/substrate-client"
-import { Enum, SS58String } from "@polkadot-api/substrate-bindings"
-import { getDynamicBuilder } from "@polkadot-api/metadata-builders"
-import { firstValueFrom, filter, map } from "rxjs"
+import { useSystemAccount, useTransfer } from "../hooks"
+import { lastValueFrom, tap } from "rxjs"
type Props = {
provider: UnstableWallet.Provider
@@ -64,7 +58,9 @@ const createTransfer = (
export const Transfer = ({ provider }: Props) => {
const [accounts, setAccounts] = useState([])
- const [destination, setDestination] = useState("")
+ const [destination, setDestination] = useState(
+ "5CofVLAGjwvdGXvBiP6ddtZYMVbhT5Xke8ZrshUpj2ZXAnND",
+ )
const [amount, setAmount] = useState(0n)
const [selectedAccount, setSelectedAccount] = useState<{
value: string
@@ -78,6 +74,10 @@ export const Transfer = ({ provider }: Props) => {
connect,
selectedAccount ? selectedAccount.value : null,
)
+ const { transfer, subscriptions: transferSubscriptions } = useTransfer(
+ { ...provider, connect },
+ chainId,
+ )
const balance = accountStorage?.data.free ?? 0n
@@ -87,7 +87,7 @@ export const Transfer = ({ provider }: Props) => {
})
}, [provider])
- const [isCreatingTransaction, setIsCreatingTransaction] = useState(false)
+ const [isSubmittingTransaction, setIsSubmittingTransaction] = useState(false)
const handleOnSubmit = useCallback(
async (e: FormEvent) => {
e.preventDefault()
@@ -95,20 +95,30 @@ export const Transfer = ({ provider }: Props) => {
return
}
- setIsCreatingTransaction(true)
+ setIsSubmittingTransaction(true)
try {
- const tx = await provider.createTx(
- chainId,
- toHex(ss58Decode(selectedAccount.value)[0]),
- await createTransfer(connect, destination, amount),
+ const sender = selectedAccount.value
+ const { txId, tx } = await transfer(sender, destination, amount)
+ console.log({ txId, tx })
+
+ lastValueFrom(
+ transferSubscriptions[txId].pipe(
+ tap({
+ next: (e) => {
+ console.log(`event:`, e)
+ },
+ error: (e) => {
+ console.error(`ERROR:`, e)
+ },
+ }),
+ ),
)
- console.log({ tx })
} catch (error) {
console.error(error)
}
- setIsCreatingTransaction(false)
+ setIsSubmittingTransaction(false)
},
- [provider, selectedAccount, connect, destination, amount],
+ [selectedAccount, transfer, destination, amount, transferSubscriptions],
)
const accountOptions = accounts.map((account) => ({
@@ -147,7 +157,7 @@ export const Transfer = ({ provider }: Props) => {
diff --git a/examples/light-client-dapp/src/hooks/useTransfer.ts b/examples/light-client-dapp/src/hooks/useTransfer.ts
index 8d575dc5b..ba2be23bf 100644
--- a/examples/light-client-dapp/src/hooks/useTransfer.ts
+++ b/examples/light-client-dapp/src/hooks/useTransfer.ts
@@ -67,8 +67,6 @@ export const useTransfer = (provider: Provider, chainId: string) => {
),
)
- console.log("sender", sender)
-
const tx = await provider.createTx(
chainId,
toHex(ss58Decode(sender)[0]),
@@ -79,7 +77,7 @@ export const useTransfer = (provider: Provider, chainId: string) => {
subscriptions[txId] = txEvents
- const destroy$ = new Subject()
+ const destroy$ = new Subject()
client.tx$(tx).pipe(tap(txEvents), takeUntil(destroy$)).subscribe()
return { txId, tx, destroy$ }
From ef50d708007f36b280ee71b1c196df44962dcba4 Mon Sep 17 00:00:00 2001
From: Ryan Lee
Date: Fri, 1 Mar 2024 10:31:13 -0500
Subject: [PATCH 3/8] more
---
examples/light-client-dapp/src/components/Transfer.tsx | 2 ++
1 file changed, 2 insertions(+)
diff --git a/examples/light-client-dapp/src/components/Transfer.tsx b/examples/light-client-dapp/src/components/Transfer.tsx
index 7dce8f173..02670e420 100644
--- a/examples/light-client-dapp/src/components/Transfer.tsx
+++ b/examples/light-client-dapp/src/components/Transfer.tsx
@@ -56,6 +56,8 @@ export const Transfer = ({ provider }: Props) => {
setIsSubmittingTransaction(true)
setTransactionStatus("")
+ setFinalizedHash("")
+
try {
const sender = selectedAccount.value
const { txId, destroy$ } = await transfer(sender, destination, amount)
From 7726e664327d08b76db21be5405cbba8507edf3d Mon Sep 17 00:00:00 2001
From: Ryan Lee
Date: Fri, 1 Mar 2024 11:08:51 -0500
Subject: [PATCH 4/8] gogo
---
.../src/components/Transfer.tsx | 40 +++++++++++++------
1 file changed, 27 insertions(+), 13 deletions(-)
diff --git a/examples/light-client-dapp/src/components/Transfer.tsx b/examples/light-client-dapp/src/components/Transfer.tsx
index 02670e420..8eda1f542 100644
--- a/examples/light-client-dapp/src/components/Transfer.tsx
+++ b/examples/light-client-dapp/src/components/Transfer.tsx
@@ -8,6 +8,11 @@ type Props = {
provider: UnstableWallet.Provider
}
+type FinalizedTransaction = {
+ blockHash: string
+ index: number
+}
+
// FIXME: use dynamic chainId
// Westend chainId
const chainId =
@@ -36,7 +41,8 @@ export const Transfer = ({ provider }: Props) => {
chainId,
)
const [transactionStatus, setTransactionStatus] = useState("")
- const [finalizedHash, setFinalizedHash] = useState("")
+ const [finalizedTransaction, setFinalizedTransaction] =
+ useState()
const balance = accountStorage?.data.free ?? 0n
@@ -56,7 +62,7 @@ export const Transfer = ({ provider }: Props) => {
setIsSubmittingTransaction(true)
setTransactionStatus("")
- setFinalizedHash("")
+ setFinalizedTransaction(null)
try {
const sender = selectedAccount.value
@@ -74,7 +80,11 @@ export const Transfer = ({ provider }: Props) => {
next: (e): void => {
setTransactionStatus(e.type)
if (e.type === "finalized") {
- setFinalizedHash(e.block.hash)
+ e.block.index
+ setFinalizedTransaction({
+ blockHash: e.block.hash,
+ index: e.block.index,
+ })
cleanup()
}
},
@@ -98,13 +108,7 @@ export const Transfer = ({ provider }: Props) => {
label: account.address,
}))
- // TODO: handle form fields and submission with react
- // TODO: fetch accounts from extension
// TODO: validate destination address
- // TODO: use PAPI to encode the transaction calldata
- // TODO: transfer should trigger an extension popup that signs the transaction
- // TODO: extract transaction submission into a hook
- // TODO: follow transaction submission events until it is finalized
return (
@@ -138,10 +142,20 @@ export const Transfer = ({ provider }: Props) => {
Transaction Status: {`${transactionStatus}`}
) : null}
- {finalizedHash ? (
-
- Finalized Hash: {`${finalizedHash}`}
-
+ {finalizedTransaction ? (
+
) : null}
From faa9ceb13bc489702bd8ea211953d3150d619ae1 Mon Sep 17 00:00:00 2001
From: Ryan Lee
Date: Fri, 1 Mar 2024 14:27:44 -0500
Subject: [PATCH 5/8] use single tx
---
examples/light-client-dapp/package.json | 4 +---
.../src/components/Transfer.tsx | 21 ++++------------
.../src/hooks/useTransfer.ts | 24 ++++---------------
3 files changed, 10 insertions(+), 39 deletions(-)
diff --git a/examples/light-client-dapp/package.json b/examples/light-client-dapp/package.json
index ca1c45363..ffc4d5ba0 100644
--- a/examples/light-client-dapp/package.json
+++ b/examples/light-client-dapp/package.json
@@ -20,14 +20,12 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-select": "^5.8.0",
- "rxjs": "^7.8.1",
- "uuid": "^9.0.1"
+ "rxjs": "^7.8.1"
},
"devDependencies": {
"@substrate/unstable-wallet-provider": "workspace:^",
"@types/react": "^18.2.60",
"@types/react-dom": "^18.2.19",
- "@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^7.1.0",
"@typescript-eslint/parser": "^7.1.0",
"@vitejs/plugin-react-swc": "^3.5.0",
diff --git a/examples/light-client-dapp/src/components/Transfer.tsx b/examples/light-client-dapp/src/components/Transfer.tsx
index 8eda1f542..11ed2263b 100644
--- a/examples/light-client-dapp/src/components/Transfer.tsx
+++ b/examples/light-client-dapp/src/components/Transfer.tsx
@@ -36,10 +36,7 @@ export const Transfer = ({ provider }: Props) => {
connect,
selectedAccount ? selectedAccount.value : null,
)
- const { transfer, subscriptions: transferSubscriptions } = useTransfer(
- { ...provider, connect },
- chainId,
- )
+ const { transfer } = useTransfer({ ...provider, connect }, chainId)
const [transactionStatus, setTransactionStatus] = useState("")
const [finalizedTransaction, setFinalizedTransaction] =
useState()
@@ -66,16 +63,10 @@ export const Transfer = ({ provider }: Props) => {
try {
const sender = selectedAccount.value
- const { txId, destroy$ } = await transfer(sender, destination, amount)
-
- const cleanup = () => {
- destroy$.next()
- destroy$.complete()
- delete transferSubscriptions[txId]
- }
+ const { txEvents } = await transfer(sender, destination, amount)
- lastValueFrom(
- transferSubscriptions[txId].pipe(
+ await lastValueFrom(
+ txEvents.pipe(
tap({
next: (e): void => {
setTransactionStatus(e.type)
@@ -85,12 +76,10 @@ export const Transfer = ({ provider }: Props) => {
blockHash: e.block.hash,
index: e.block.index,
})
- cleanup()
}
},
error: (e) => {
setTransactionStatus(e.type)
- cleanup()
},
}),
),
@@ -100,7 +89,7 @@ export const Transfer = ({ provider }: Props) => {
}
setIsSubmittingTransaction(false)
},
- [selectedAccount, transfer, destination, amount, transferSubscriptions],
+ [selectedAccount, transfer, destination, amount],
)
const accountOptions = accounts.map((account) => ({
diff --git a/examples/light-client-dapp/src/hooks/useTransfer.ts b/examples/light-client-dapp/src/hooks/useTransfer.ts
index ba2be23bf..4812bb3ba 100644
--- a/examples/light-client-dapp/src/hooks/useTransfer.ts
+++ b/examples/light-client-dapp/src/hooks/useTransfer.ts
@@ -7,19 +7,9 @@ import {
createClient,
} from "@polkadot-api/substrate-client"
import { getDynamicBuilder } from "@polkadot-api/metadata-builders"
-import {
- firstValueFrom,
- filter,
- map,
- Observable,
- tap,
- ReplaySubject,
- Subject,
- takeUntil,
-} from "rxjs"
+import { firstValueFrom, filter, map, tap, ReplaySubject } from "rxjs"
import { mergeUint8, toHex } from "@polkadot-api/utils"
import { UnstableWallet } from "@substrate/unstable-wallet-provider"
-import { v4 as uuidv4 } from "uuid"
import { ss58Decode } from "@polkadot-labs/hdkd-helpers"
const AccountId = (value: SS58String) =>
@@ -34,8 +24,6 @@ const AccountId = (value: SS58String) =>
type Provider = UnstableWallet.Provider & { connect: ConnectProvider }
export const useTransfer = (provider: Provider, chainId: string) => {
- const subscriptions: Record> = {}
-
const transfer = async (
sender: SS58String,
destination: SS58String,
@@ -72,16 +60,12 @@ export const useTransfer = (provider: Provider, chainId: string) => {
toHex(ss58Decode(sender)[0]),
callData,
)
- const txId = uuidv4()
const txEvents = new ReplaySubject()
- subscriptions[txId] = txEvents
-
- const destroy$ = new Subject()
- client.tx$(tx).pipe(tap(txEvents), takeUntil(destroy$)).subscribe()
+ client.tx$(tx).pipe(tap(txEvents)).subscribe()
- return { txId, tx, destroy$ }
+ return { tx, txEvents }
}
- return { subscriptions, transfer }
+ return { transfer }
}
From 206804479437250e3315df3dda25a841c7f2178f Mon Sep 17 00:00:00 2001
From: Ryan Lee
Date: Fri, 1 Mar 2024 14:30:32 -0500
Subject: [PATCH 6/8] fix lockfile
---
pnpm-lock.yaml | 15 ---------------
1 file changed, 15 deletions(-)
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 3819ba458..b8af7b935 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -113,9 +113,6 @@ importers:
rxjs:
specifier: ^7.8.1
version: 7.8.1
- uuid:
- specifier: ^9.0.1
- version: 9.0.1
devDependencies:
'@substrate/unstable-wallet-provider':
specifier: workspace:^
@@ -126,9 +123,6 @@ importers:
'@types/react-dom':
specifier: ^18.2.19
version: 18.2.19
- '@types/uuid':
- specifier: ^9.0.8
- version: 9.0.8
'@typescript-eslint/eslint-plugin':
specifier: ^7.1.0
version: 7.1.0(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)(typescript@5.3.3)
@@ -3888,10 +3882,6 @@ packages:
resolution: {integrity: sha512-n4sx2bqL0mW1tvDf/loQ+aMX7GQD3lc3fkCMC55VFNDu/vBOabO+LTIeXKM14xK0ppk5TUGcWRjiSpIlUpghKw==}
dev: false
- /@types/uuid@9.0.8:
- resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==}
- dev: true
-
/@types/webextension-polyfill@0.10.7:
resolution: {integrity: sha512-10ql7A0qzBmFB+F+qAke/nP1PIonS0TXZAOMVOxEUsm+lGSW6uwVcISFNa0I4Oyj0884TZVWGGMIWeXOVSNFHw==}
dev: true
@@ -11053,11 +11043,6 @@ packages:
hasBin: true
dev: true
- /uuid@9.0.1:
- resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
- hasBin: true
- dev: false
-
/verror@1.10.0:
resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==}
engines: {'0': node >=0.6.0}
From 5dc5fddf1871e8baa9e5ee08e95bd5da4e18d0f3 Mon Sep 17 00:00:00 2001
From: Ryan Lee
Date: Mon, 4 Mar 2024 14:08:32 -0500
Subject: [PATCH 7/8] fix: updates
---
.../src/components/Transfer.tsx | 50 ++++++-------
examples/light-client-dapp/src/hooks/index.ts | 1 -
.../src/hooks/useTransfer.ts | 71 -------------------
examples/light-client-dapp/src/transaction.ts | 67 +++++++++++++++++
4 files changed, 89 insertions(+), 100 deletions(-)
delete mode 100644 examples/light-client-dapp/src/hooks/useTransfer.ts
create mode 100644 examples/light-client-dapp/src/transaction.ts
diff --git a/examples/light-client-dapp/src/components/Transfer.tsx b/examples/light-client-dapp/src/components/Transfer.tsx
index 11ed2263b..75059b9b6 100644
--- a/examples/light-client-dapp/src/components/Transfer.tsx
+++ b/examples/light-client-dapp/src/components/Transfer.tsx
@@ -1,8 +1,9 @@
import { FormEvent, useCallback, useEffect, useMemo, useState } from "react"
import { UnstableWallet } from "@substrate/unstable-wallet-provider"
import Select from "react-select"
-import { useSystemAccount, useTransfer } from "../hooks"
-import { lastValueFrom, tap } from "rxjs"
+import { transaction, transferAllowDeathCallData } from "../transaction"
+import { lastValueFrom, mergeMap, tap } from "rxjs"
+import { useSystemAccount } from "../hooks"
type Props = {
provider: UnstableWallet.Provider
@@ -36,7 +37,6 @@ export const Transfer = ({ provider }: Props) => {
connect,
selectedAccount ? selectedAccount.value : null,
)
- const { transfer } = useTransfer({ ...provider, connect }, chainId)
const [transactionStatus, setTransactionStatus] = useState("")
const [finalizedTransaction, setFinalizedTransaction] =
useState()
@@ -61,35 +61,29 @@ export const Transfer = ({ provider }: Props) => {
setTransactionStatus("")
setFinalizedTransaction(null)
- try {
- const sender = selectedAccount.value
- const { txEvents } = await transfer(sender, destination, amount)
+ const sender = selectedAccount.value
+ const connectProvider = { ...provider, connect }
- await lastValueFrom(
- txEvents.pipe(
- tap({
- next: (e): void => {
- setTransactionStatus(e.type)
- if (e.type === "finalized") {
- e.block.index
- setFinalizedTransaction({
- blockHash: e.block.hash,
- index: e.block.index,
- })
- }
- },
- error: (e) => {
- setTransactionStatus(e.type)
- },
- }),
+ await lastValueFrom(
+ transferAllowDeathCallData(connectProvider, destination, amount).pipe(
+ mergeMap((callData) =>
+ transaction(connectProvider, chainId, sender, callData),
),
- )
- } catch (error) {
- console.error(error)
- }
+ tap(({ txEvent }) => {
+ setTransactionStatus(txEvent.type)
+ if (txEvent.type === "finalized") {
+ setFinalizedTransaction({
+ blockHash: txEvent.block.hash,
+ index: txEvent.block.index,
+ })
+ }
+ }),
+ ),
+ )
+
setIsSubmittingTransaction(false)
},
- [selectedAccount, transfer, destination, amount],
+ [selectedAccount, provider, connect, destination, amount],
)
const accountOptions = accounts.map((account) => ({
diff --git a/examples/light-client-dapp/src/hooks/index.ts b/examples/light-client-dapp/src/hooks/index.ts
index 3029e3930..e23feee2e 100644
--- a/examples/light-client-dapp/src/hooks/index.ts
+++ b/examples/light-client-dapp/src/hooks/index.ts
@@ -1,3 +1,2 @@
export * from "./useProvider"
export * from "./useSystemAccount"
-export * from "./useTransfer"
diff --git a/examples/light-client-dapp/src/hooks/useTransfer.ts b/examples/light-client-dapp/src/hooks/useTransfer.ts
deleted file mode 100644
index 4812bb3ba..000000000
--- a/examples/light-client-dapp/src/hooks/useTransfer.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-import { getObservableClient } from "@polkadot-api/client"
-import { Enum } from "@polkadot-api/substrate-bindings"
-import type { SS58String } from "@polkadot-api/substrate-bindings"
-import {
- ConnectProvider,
- TxEvent,
- createClient,
-} from "@polkadot-api/substrate-client"
-import { getDynamicBuilder } from "@polkadot-api/metadata-builders"
-import { firstValueFrom, filter, map, tap, ReplaySubject } from "rxjs"
-import { mergeUint8, toHex } from "@polkadot-api/utils"
-import { UnstableWallet } from "@substrate/unstable-wallet-provider"
-import { ss58Decode } from "@polkadot-labs/hdkd-helpers"
-
-const AccountId = (value: SS58String) =>
- Enum<
- {
- type: "Id"
- value: SS58String
- },
- "Id"
- >("Id", value)
-
-type Provider = UnstableWallet.Provider & { connect: ConnectProvider }
-
-export const useTransfer = (provider: Provider, chainId: string) => {
- const transfer = async (
- sender: SS58String,
- destination: SS58String,
- amount: bigint,
- ) => {
- const client = getObservableClient(createClient(provider.connect))
- const { metadata$ } = client.chainHead$()
-
- const callData = await firstValueFrom(
- metadata$.pipe(
- filter(Boolean),
- map((metadata) => {
- const dynamicBuilder = getDynamicBuilder(metadata)
- const { location, args } = dynamicBuilder.buildCall(
- "Balances",
- "transfer_allow_death",
- )
-
- return toHex(
- mergeUint8(
- new Uint8Array(location),
- args.enc({
- dest: AccountId(destination),
- value: amount,
- }),
- ),
- )
- }),
- ),
- )
-
- const tx = await provider.createTx(
- chainId,
- toHex(ss58Decode(sender)[0]),
- callData,
- )
- const txEvents = new ReplaySubject()
-
- client.tx$(tx).pipe(tap(txEvents)).subscribe()
-
- return { tx, txEvents }
- }
-
- return { transfer }
-}
diff --git a/examples/light-client-dapp/src/transaction.ts b/examples/light-client-dapp/src/transaction.ts
new file mode 100644
index 000000000..d48e1d09b
--- /dev/null
+++ b/examples/light-client-dapp/src/transaction.ts
@@ -0,0 +1,67 @@
+import { getObservableClient } from "@polkadot-api/client"
+import { Enum } from "@polkadot-api/substrate-bindings"
+import type { SS58String } from "@polkadot-api/substrate-bindings"
+import { ConnectProvider, createClient } from "@polkadot-api/substrate-client"
+import { getDynamicBuilder } from "@polkadot-api/metadata-builders"
+import { filter, map, mergeMap, first } from "rxjs"
+import { mergeUint8, toHex } from "@polkadot-api/utils"
+import { UnstableWallet } from "@substrate/unstable-wallet-provider"
+import { ss58Decode } from "@polkadot-labs/hdkd-helpers"
+import { fromPromise } from "rxjs/internal/observable/innerFrom"
+
+const AccountId = (value: SS58String) =>
+ Enum<
+ {
+ type: "Id"
+ value: SS58String
+ },
+ "Id"
+ >("Id", value)
+
+type Provider = UnstableWallet.Provider & { connect: ConnectProvider }
+
+export const transaction = (
+ provider: Provider,
+ chainId: string,
+ from: SS58String,
+ callData: string,
+) => {
+ const client = getObservableClient(createClient(provider.connect))
+
+ return fromPromise(
+ provider.createTx(chainId, toHex(ss58Decode(from)[0]), callData),
+ ).pipe(
+ mergeMap((tx) => client.tx$(tx).pipe(map((txEvent) => ({ tx, txEvent })))),
+ )
+}
+
+export const transferAllowDeathCallData = (
+ provider: Provider,
+ destination: SS58String,
+ amount: bigint,
+) => {
+ const client = getObservableClient(createClient(provider.connect))
+ const { metadata$ } = client.chainHead$()
+
+ return metadata$.pipe(
+ filter(Boolean),
+ map((metadata) => {
+ const dynamicBuilder = getDynamicBuilder(metadata)
+ const { location, args } = dynamicBuilder.buildCall(
+ "Balances",
+ "transfer_allow_death",
+ )
+
+ return toHex(
+ mergeUint8(
+ new Uint8Array(location),
+ args.enc({
+ dest: AccountId(destination),
+ value: amount,
+ }),
+ ),
+ )
+ }),
+ first(),
+ )
+}
From 8c45ac846e67bb0f5439c44bb5fc40e737e574e7 Mon Sep 17 00:00:00 2001
From: Ryan Lee
Date: Mon, 4 Mar 2024 14:38:16 -0500
Subject: [PATCH 8/8] fixes
---
.../src/components/Transfer.tsx | 46 +++++++++++++------
1 file changed, 31 insertions(+), 15 deletions(-)
diff --git a/examples/light-client-dapp/src/components/Transfer.tsx b/examples/light-client-dapp/src/components/Transfer.tsx
index 75059b9b6..917b5f173 100644
--- a/examples/light-client-dapp/src/components/Transfer.tsx
+++ b/examples/light-client-dapp/src/components/Transfer.tsx
@@ -40,6 +40,7 @@ export const Transfer = ({ provider }: Props) => {
const [transactionStatus, setTransactionStatus] = useState("")
const [finalizedTransaction, setFinalizedTransaction] =
useState()
+ const [error, setError] = useState<{ type: string; error: string }>()
const balance = accountStorage?.data.free ?? 0n
@@ -64,22 +65,32 @@ export const Transfer = ({ provider }: Props) => {
const sender = selectedAccount.value
const connectProvider = { ...provider, connect }
- await lastValueFrom(
- transferAllowDeathCallData(connectProvider, destination, amount).pipe(
- mergeMap((callData) =>
- transaction(connectProvider, chainId, sender, callData),
+ try {
+ await lastValueFrom(
+ transferAllowDeathCallData(connectProvider, destination, amount).pipe(
+ mergeMap((callData) =>
+ transaction(connectProvider, chainId, sender, callData),
+ ),
+ tap(({ txEvent }) => {
+ setTransactionStatus(txEvent.type)
+ if (txEvent.type === "finalized") {
+ setFinalizedTransaction({
+ blockHash: txEvent.block.hash,
+ index: txEvent.block.index,
+ })
+ }
+ if (txEvent.type === "invalid" || txEvent.type === "dropped") {
+ setError({ type: txEvent.type, error: txEvent.error })
+ }
+ }),
),
- tap(({ txEvent }) => {
- setTransactionStatus(txEvent.type)
- if (txEvent.type === "finalized") {
- setFinalizedTransaction({
- blockHash: txEvent.block.hash,
- index: txEvent.block.index,
- })
- }
- }),
- ),
- )
+ )
+ } catch (err) {
+ if (err instanceof Error) {
+ setError({ type: "error", error: err.message })
+ }
+ console.error(err)
+ }
setIsSubmittingTransaction(false)
},
@@ -140,6 +151,11 @@ export const Transfer = ({ provider }: Props) => {
) : null}
+ {error ? (
+
+ Error: {`type: ${error.type}, error: ${error.error}`}
+
+ ) : null}