fetch mints and correctly display decimals

This commit is contained in:
Maximilian Schneider 2021-04-26 01:04:32 +03:00
parent c362ebf233
commit 37b3c9d627
6 changed files with 112 additions and 28 deletions

33
components/Balances.jsx Normal file
View File

@ -0,0 +1,33 @@
import BN from 'bn.js'
import useWalletStore from '../stores/useWalletStore'
const Balances = () => {
var { tokenAccounts, mints } = useWalletStore((state) => state)
function fixedPointNumber(value, decimals) {
const divisor = new BN(10).pow(new BN(decimals))
const quotient = value.div(divisor)
const remainder = value.mod(divisor)
return quotient.toNumber() + remainder.toNumber() / divisor.toNumber()
}
function calculateBalance(a) {
const mint = mints[a.account.mint.toBase58()]
return mint ? fixedPointNumber(a.account.amount, mint.decimals) : 0
}
const displayedBalances = tokenAccounts
.map((a) => `${a.publicKey.toBase58()}: ${calculateBalance(a)}`)
.sort()
return (
<ul>
{displayedBalances.map((b, i) => (
<li key={i}>{b}</li>
))}
</ul>
)
}
export default Balances

View File

@ -19,8 +19,6 @@ const NotificationList = () => {
})
}, 5000)
console.log('notifications', notifications)
return () => {
clearInterval(id)
}

View File

@ -104,12 +104,14 @@ export default function useWallet() {
'...' +
wallet.publicKey.toString().substr(-5),
})
actions.fetchWalletBalances()
await actions.fetchWalletTokenAccounts()
await actions.fetchWalletMints()
})
wallet.on('disconnect', () => {
setWalletStore((state) => {
state.connected = false
state.balances = []
state.tokenAccounts = []
state.mints = {}
})
notify({
type: 'info',
@ -126,8 +128,9 @@ export default function useWallet() {
}
}, [wallet, setWalletStore])
useInterval(() => {
actions.fetchWalletBalances()
useInterval(async () => {
await actions.fetchWalletTokenAccounts()
await actions.fetchWalletMints()
}, 20 * SECONDS)
return { connected, wallet }

View File

@ -1,10 +1,12 @@
import Notifications from '../components/Notification'
import Balances from '../components/Balances'
import TopBar from '../components/TopBar'
const Index = () => {
return (
<div className={`bg-th-bkg-1 text-th-fgd-1 transition-all `}>
<TopBar />
<Balances />
<Notifications />
</div>
)

View File

@ -3,7 +3,13 @@ import produce from 'immer'
import { Connection, PublicKey } from '@solana/web3.js'
import { EndpointInfo, WalletAdapter } from '../@types/types'
import { getOwnedTokenAccounts } from '../utils/tokens'
import {
getOwnedTokenAccounts,
getMint,
ProgramAccount,
TokenAccount,
MintAccount,
} from '../utils/tokens'
export const ENDPOINTS: EndpointInfo[] = [
{
@ -33,7 +39,8 @@ interface WalletStore extends State {
}
current: WalletAdapter | undefined
providerUrl: string
balances: Array<{ account: any; publicKey: PublicKey }>
tokenAccounts: ProgramAccount<TokenAccount>[]
mints: { [pubkey: string]: MintAccount }
set: (x: any) => void
actions: any
}
@ -48,9 +55,10 @@ const useWalletStore = create<WalletStore>((set, get) => ({
},
current: null,
providerUrl: null,
balances: [],
tokenAccounts: [],
mints: {},
actions: {
async fetchWalletBalances() {
async fetchWalletTokenAccounts() {
const connection = get().connection.current
const connected = get().connected
const wallet = get().current
@ -63,14 +71,39 @@ const useWalletStore = create<WalletStore>((set, get) => ({
walletOwner
)
console.log('fetched wallet balances', ownedTokenAccounts)
set((state) => {
state.balances = ownedTokenAccounts
state.tokenAccounts = ownedTokenAccounts
})
} else {
set((state) => {
state.balances = []
state.tokenAccounts = []
})
}
},
async fetchWalletMints() {
const connection = get().connection.current
const connected = get().connected
const tokenAccounts = get().tokenAccounts
const mints = get().mints
const set = get().set
if (connected) {
var fetchMints = tokenAccounts.map((a) =>
getMint(connection, a.account.mint)
)
const mintResults = await Promise.all(fetchMints)
const newMints: { [pubkey: string]: MintAccount } = {}
mintResults.forEach(
(m) => (newMints[m.publicKey.toBase58()] = m.account)
)
set((state) => {
state.mints = newMints
})
} else {
set((state) => {
state.mints = {}
})
}
},

View File

@ -1,27 +1,26 @@
import { Connection, PublicKey } from '@solana/web3.js'
import * as bs58 from 'bs58'
import {
AccountLayout as TokenLayout,
AccountInfo as TokenAccount,
} from '@solana/spl-token'
export const TOKEN_PROGRAM_ID = new PublicKey(
'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'
)
import { Connection, ParsedAccountData, PublicKey } from '@solana/web3.js'
import { AccountLayout, AccountInfo, MintInfo, u64 } from '@solana/spl-token'
export type TokenAccount = AccountInfo
export type MintAccount = MintInfo
export type ProgramAccount<T> = {
publicKey: PublicKey
account: T
}
export const TOKEN_PROGRAM_ID = new PublicKey(
'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'
)
export function parseTokenAccountData(
data: Buffer
): { mint: PublicKey; owner: PublicKey; amount: number } {
const { mint, owner, amount } = TokenLayout.decode(data)
): { mint: PublicKey; owner: PublicKey; amount: u64 } {
const { mint, owner, amount } = AccountLayout.decode(data)
return {
mint: new PublicKey(mint),
owner: new PublicKey(owner),
amount,
amount: u64.fromBuffer(amount),
}
}
@ -59,12 +58,28 @@ export function getOwnedAccountsFilters(publicKey: PublicKey) {
return [
{
memcmp: {
offset: TokenLayout.offsetOf('owner'),
offset: AccountLayout.offsetOf('owner'),
bytes: publicKey.toBase58(),
},
},
{
dataSize: TokenLayout.span,
dataSize: AccountLayout.span,
},
]
}
export async function getMint(
connection: Connection,
publicKey: PublicKey
): Promise<ProgramAccount<MintAccount>> {
const result = await connection.getParsedAccountInfo(publicKey)
const account = (result.value.data as ParsedAccountData).parsed.info
account.freezeAuthority =
account.freezeAuthority && new PublicKey(account.freezeAuthority)
account.mintAuthority =
account.mintAuthority && new PublicKey(account.mintAuthority)
return {
publicKey,
account,
}
}