Skip to content

Commit

Permalink
feat(lc-dapp): account balance (#1899)
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanleecode committed Feb 29, 2024
1 parent 3bf56b4 commit a2d0e5d
Show file tree
Hide file tree
Showing 5 changed files with 296 additions and 50 deletions.
7 changes: 6 additions & 1 deletion examples/light-client-dapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,15 @@
},
"dependencies": {
"@picocss/pico": "^2.0.3",
"@polkadot-api/client": "0.0.1-86c37582599a5aaa7c2dde1d765f8af5ef6def2a.1.0",
"@polkadot-api/metadata-builders": "0.0.1-86c37582599a5aaa7c2dde1d765f8af5ef6def2a.1.0",
"@polkadot-api/substrate-client": "0.0.1-86c37582599a5aaa7c2dde1d765f8af5ef6def2a.1.0",
"@polkadot-api/utils": "0.0.1-86c37582599a5aaa7c2dde1d765f8af5ef6def2a.1.0",
"@polkadot-labs/hdkd-helpers": "^0.0.5",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"react-select": "^5.8.0",
"rxjs": "^7.8.1"
},
"devDependencies": {
"@substrate/unstable-wallet-provider": "workspace:^",
Expand Down
55 changes: 39 additions & 16 deletions examples/light-client-dapp/src/components/Transfer.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { FormEvent, useCallback, useEffect, useState } from "react"
import { FormEvent, useCallback, useEffect, useMemo, useState } from "react"
import { ss58Decode } from "@polkadot-labs/hdkd-helpers"
import { UnstableWallet } from "@substrate/unstable-wallet-provider"
import { toHex } from "@polkadot-api/utils"
import Select from "react-select"
import { useSystemAccount } from "../hooks"

type Props = {
provider: UnstableWallet.Provider
Expand All @@ -14,6 +16,21 @@ const chainId =

export const Transfer = ({ provider }: Props) => {
const [accounts, setAccounts] = useState<UnstableWallet.Account[]>([])
const [selectedAccount, setSelectedAccount] = useState<{
value: string
label: string
} | null>(null)
const connect = useMemo(
() => provider.getChains()[chainId].connect,
[provider],
)
const accountStorage = useSystemAccount(
connect,
selectedAccount ? selectedAccount.value : null,
)

const balance = accountStorage?.data.free ?? 0n

useEffect(() => {
provider.getAccounts(chainId).then((accounts) => {
setAccounts(accounts)
Expand All @@ -24,11 +41,15 @@ export const Transfer = ({ provider }: Props) => {
const handleOnSubmit = useCallback(
async (e: FormEvent) => {
e.preventDefault()
if (!selectedAccount) {
return
}

setIsCreatingTransaction(true)
try {
const tx = await provider.createTx(
chainId,
toHex(ss58Decode(accounts[0].address)[0]),
toHex(ss58Decode(selectedAccount.value)[0]),
"0x04030012aed8a0f7425c9f4c71e75bf087e9c68ab701b1faa23a10e4785d722d962115070010a5d4e8",
)
console.log({ tx })
Expand All @@ -37,12 +58,16 @@ export const Transfer = ({ provider }: Props) => {
}
setIsCreatingTransaction(false)
},
[provider, accounts],
[provider, selectedAccount],
)

const accountOptions = accounts.map((account) => ({
value: account.address,
label: account.address,
}))

// TODO: handle form fields and submission with react
// TODO: fetch accounts from extension
// TODO: fetch selected account balance
// TODO: validate destination address
// TODO: use PAPI to encode the transaction calldata
// TODO: transfer should trigger an extension popup that signs the transaction
Expand All @@ -52,21 +77,19 @@ export const Transfer = ({ provider }: Props) => {
<article>
<header>Transfer funds</header>
<form onSubmit={handleOnSubmit}>
<select defaultValue={""}>
<option disabled value={""}>
Select Account...
</option>
{accounts.map((account) => (
<option key={account.address} value={account.address}>
{account.address}
</option>
))}
</select>
<small>Balance: 123456789</small>
<Select
defaultValue={selectedAccount}
onChange={setSelectedAccount}
options={accountOptions}
/>
<small>Balance: {`${balance}`}</small>
<input placeholder="to"></input>
<input type="number" placeholder="amount"></input>
<footer>
<button type="submit" disabled={isCreatingTransaction}>
<button
type="submit"
disabled={!selectedAccount || isCreatingTransaction}
>
Transfer
</button>
</footer>
Expand Down
1 change: 1 addition & 0 deletions examples/light-client-dapp/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./useProvider"
export * from "./useSystemAccount"
78 changes: 78 additions & 0 deletions examples/light-client-dapp/src/hooks/useSystemAccount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { distinct, filter, first, map, mergeMap, tap } from "rxjs"
import { getObservableClient } from "@polkadot-api/client"
import { ConnectProvider, createClient } from "@polkadot-api/substrate-client"
import { getDynamicBuilder } from "@polkadot-api/metadata-builders"
import { useEffect, useState } from "react"

export type SystemAccountStorage = {
consumers: number
data: {
flags: bigint
free: bigint
frozen: bigint
reserved: bigint
}
nonce: number
providers: number
sufficients: number
}

export const useSystemAccount = (
provider: ConnectProvider,
address: string | null,
) => {
const [systemAccount, setSystemAccount] = useState<SystemAccountStorage>()

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

setSystemAccount(undefined)

const client = getObservableClient(createClient(provider))

const { metadata$, finalized$, unfollow, storage$ } = client.chainHead$()

const subscription = metadata$
.pipe(
filter(Boolean),
first(),
mergeMap((metadata) => {
const dynamicBuilder = getDynamicBuilder(metadata)
const storageAccount = dynamicBuilder.buildStorage(
"System",
"Account",
)

const storageQuery = finalized$.pipe(
mergeMap((blockInfo) =>
storage$(blockInfo.hash, "value", () =>
storageAccount.enc(address),
).pipe(
filter(Boolean),
distinct(),
map(
(value) => storageAccount.dec(value) as SystemAccountStorage,
),
),
),
)

return storageQuery
}),
tap((systemAccountStorage) => {
setSystemAccount(systemAccountStorage)
}),
)
.subscribe()

return () => {
subscription.unsubscribe()
unfollow()
client.destroy()
}
}, [provider, address])

return systemAccount
}

0 comments on commit a2d0e5d

Please sign in to comment.