-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add base data setup with jotai
- Loading branch information
1 parent
1d25f11
commit 5737fd1
Showing
14 changed files
with
1,278 additions
and
2,431 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { useLatestBlocks } from '../data' | ||
|
||
export function LatestBlocks() { | ||
const latestBlocks = useLatestBlocks() | ||
|
||
return ( | ||
<div> | ||
<h3>Latest Blocks:</h3> | ||
{latestBlocks.map((block, i) => ( | ||
<p key={i}> | ||
{block.round} - {block.parentTransactionCount} | ||
</p> | ||
))} | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import { atom, useAtom, useAtomValue } from 'jotai' | ||
import * as algokit from '@algorandfoundation/algokit-utils' | ||
import { atomEffect } from 'jotai-effect' | ||
import { transactionsAtom } from '@/features/transactions/data' | ||
import { AlgorandSubscriber } from '@algorandfoundation/algokit-subscriber' | ||
// import { BlockMetadata } from '@algorandfoundation/algokit-subscriber/types/subscription' | ||
import { Buffer } from 'buffer' | ||
|
||
type BlockMetadata = { | ||
round: number | ||
parentTransactionCount: number | ||
} | ||
|
||
// TODO: NC - Remove once https://github.com/algorandfoundation/algokit-subscriber-ts/pull/49 is merged | ||
window.Buffer = Buffer | ||
|
||
// TODO: Move this elsewhere and make it configurable once we start using it more | ||
const algod = algokit.getAlgoClient({ | ||
server: 'https://testnet-api.algonode.cloud/', | ||
port: 443, | ||
}) | ||
|
||
const syncedRoundAtom = atom<number | undefined>(undefined) | ||
|
||
// TODO: Size should be capped at some limit, so memory usage doesn't grow indefinitely | ||
const blocksAtom = atom<BlockMetadata[]>([]) | ||
|
||
const latestBlockAtom = atom((get) => { | ||
return get(blocksAtom).slice(0, 5) | ||
}) | ||
|
||
const subscribeToBlocksEffect = atomEffect((get, set) => { | ||
algokit.Config.configure({ | ||
logger: algokit.Config.getLogger(true), | ||
}) | ||
const subscriber = new AlgorandSubscriber( | ||
{ | ||
filters: [ | ||
{ | ||
name: 'all-transactions', | ||
filter: { | ||
customFilter: () => true, | ||
}, | ||
}, | ||
], | ||
maxRoundsToSync: 1, // TODO: NC - Do we want this higher? | ||
waitForBlockWhenAtTip: true, | ||
syncBehaviour: 'skip-sync-newest', | ||
watermarkPersistence: { | ||
get: async () => get(syncedRoundAtom) ?? 0, | ||
set: async (watermark) => { | ||
set(syncedRoundAtom, watermark) | ||
}, | ||
}, | ||
}, | ||
algod | ||
) | ||
|
||
subscriber.onPoll(async (result) => { | ||
// TODO: NC - Add this back in once subscriber supports it | ||
// const blocks = result.blockMetadata | ||
const blocks = [ | ||
{ | ||
round: result.syncedRoundRange[0], | ||
parentTransactionCount: result.subscribedTransactions.length, | ||
} satisfies BlockMetadata, | ||
] | ||
|
||
if (blocks) { | ||
set(blocksAtom, (previous) => { | ||
return blocks.concat(previous) | ||
}) | ||
} | ||
|
||
set(transactionsAtom, (previous) => { | ||
return result.subscribedTransactions.concat(previous) | ||
}) | ||
}) | ||
|
||
subscriber.start() | ||
|
||
return async () => { | ||
await subscriber.stop('unmounted') | ||
} | ||
}) | ||
|
||
export const useSubscribeToBlocksEffect = () => { | ||
useAtom(subscribeToBlocksEffect) | ||
} | ||
|
||
export const useLatestBlocks = () => { | ||
return useAtomValue(latestBlockAtom) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,17 @@ | ||
import { cn } from '@/features/common/utils' | ||
import { PaymentTransactionModel, TransactionType } from '../models/models' | ||
import { PaymentTransaction } from './payment-transaction' | ||
import { TransactionResult } from '@algorandfoundation/algokit-utils/types/indexer' | ||
import { TransactionType } from 'algosdk' | ||
|
||
type Props = { | ||
transaction: PaymentTransactionModel | ||
transaction: TransactionResult | ||
} | ||
|
||
export function Transaction({ transaction }: Props) { | ||
return ( | ||
<div> | ||
<h1 className={cn('text-2xl text-primary font-bold')}>Transaction</h1> | ||
{transaction.type === TransactionType.Payment && <PaymentTransaction transaction={transaction} />} | ||
{transaction['tx-type'] === TransactionType.pay && <PaymentTransaction transaction={transaction} />} | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { atom, useAtomValue, getDefaultStore } from 'jotai' | ||
import * as algokit from '@algorandfoundation/algokit-utils' | ||
import { useMemo } from 'react' | ||
import { TransactionResult } from '@algorandfoundation/algokit-utils/types/indexer' | ||
import { atomEffect } from 'jotai-effect' | ||
import { loadable } from 'jotai/utils' | ||
|
||
// TODO: Move this elsewhere and make it configurable once we start using it more | ||
const indexer = algokit.getAlgoIndexerClient({ | ||
server: 'https://testnet-idx.algonode.cloud/', | ||
port: 443, | ||
}) | ||
|
||
// TODO: Size should be capped at some limit, so memory usage doesn't grow indefinitely | ||
export const transactionsAtom = atom<TransactionResult[]>([]) | ||
|
||
const useTransactionAtom = (transactionId: string) => { | ||
return useMemo(() => { | ||
const syncEffect = atomEffect((get, set) => { | ||
;(async () => { | ||
try { | ||
const transaction = await get(transactionAtom) | ||
set(transactionsAtom, (prev) => { | ||
return prev.concat(transaction) | ||
}) | ||
} catch (e) { | ||
// Ignore any errors as there is nothing to sync | ||
} | ||
})() | ||
}) | ||
const store = getDefaultStore() | ||
const transactionAtom = atom((get) => { | ||
// store.get prevents the atom from being subscribed to changes in transactionsAtom | ||
const transactions = store.get(transactionsAtom) | ||
const transaction = transactions.find((t) => t.id === transactionId) | ||
if (transaction) { | ||
return transaction | ||
} | ||
|
||
get(syncEffect) | ||
|
||
return algokit.lookupTransactionById(transactionId, indexer).then((result) => { | ||
return result.transaction | ||
}) | ||
}) | ||
return transactionAtom | ||
}, [transactionId]) | ||
} | ||
|
||
export const useLoadableTransaction = (transactionId: string) => { | ||
return useAtomValue( | ||
// Unfortunately we can't leverage Suspense here, as react doesn't support async useMemo inside the Suspense component | ||
// https://github.com/facebook/react/issues/20877 | ||
loadable(useTransactionAtom(transactionId)) | ||
) | ||
} |
Oops, something went wrong.