Skip to content

Commit

Permalink
Fetch balance from RPC node
Browse files Browse the repository at this point in the history
  • Loading branch information
lubej committed Dec 7, 2023
1 parent c577985 commit 0adbfc2
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 2 deletions.
1 change: 1 addition & 0 deletions .changelog/1073.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fetch account balance from RPC node
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
"bignumber.js": "9.1.2",
"bip39": "^3.1.0",
"date-fns": "2.30.0",
"ethers": "^6.9.0",
"i18next": "23.7.7",
"react": "18.2.0",
"react-dom": "18.2.0",
Expand Down
53 changes: 52 additions & 1 deletion src/app/pages/AccountDetailsPage/hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,66 @@ import { NUMBER_OF_ITEMS_ON_SEPARATE_PAGE } from '../../config'
import { SearchScope } from '../../../types/searchScope'
import { EventFilterMode } from '../../components/RuntimeEvents/EventListFilterSwitch'
import { useTransformToOasisAddress } from '../../hooks/useTransformToOasisAddress'
import { useEffect, useState } from 'react'
import { RpcUtils } from '../../utils/rpc-utils'

export const useAccount = (scope: SearchScope, address: string) => {
const [accountBalance, setAccountBalance] = useState<string | null>(null)

const { network, layer } = scope
if (layer === Layer.consensus) {
// There can be no ERC-20 or ERC-721 tokens on consensus
throw AppErrors.UnsupportedLayer
}
const query = useGetRuntimeAccountsAddress(network, layer, address)
const account = query.data?.data
const runtimeAccount = query.data?.data

// TODO: Remove after account balances on Nexus are in sync with the node
useEffect(() => {
// Trigger only if the account has been fetched from Nexus and is not a contract
if (!runtimeAccount || !!runtimeAccount.evm_contract) {
return
}

let shouldUpdate = true

const fetchAccountBalance = async () => {
setAccountBalance(null)

const balance = await RpcUtils.getAccountBalance(address, {
context: {
network: scope.network,
layer: scope.layer,
},
})

if (shouldUpdate) {
setAccountBalance(balance)
}
}

fetchAccountBalance()

return () => {
shouldUpdate = false
}
}, [runtimeAccount, address, scope.network, scope.layer])

const account =
accountBalance !== null && runtimeAccount
? {
...runtimeAccount,
balances: runtimeAccount.balances?.length
? [
{
...runtimeAccount.balances[0],
balance: accountBalance,
},
]
: [],
}
: runtimeAccount

const { isLoading, isError, isFetched } = query

return { account, isLoading, isError, isFetched }
Expand Down
67 changes: 67 additions & 0 deletions src/app/utils/rpc-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { JsonRpcProvider, formatUnits } from 'ethers'
import { Network } from '../../types/network'
import { paraTimesConfig } from '../../config'
import { Layer } from '../../oasis-nexus/api'

const RPC_ENDPOINTS: Partial<Record<Network, Partial<Record<Layer, string>>>> = {
[Network.mainnet]: {
[Layer.emerald]: 'https://emerald.oasis.dev',
[Layer.sapphire]: 'https://sapphire.oasis.io',
},
[Network.testnet]: {
[Layer.emerald]: 'https://testnet.emerald.oasis.dev',
[Layer.sapphire]: 'https://testnet.sapphire.oasis.dev',
},
}

const NETWORK_DECIMALS: Partial<Record<Layer, number>> = {
[Layer.emerald]: paraTimesConfig[Layer.emerald].decimals,
[Layer.sapphire]: paraTimesConfig[Layer.sapphire].decimals,
[Layer.cipher]: paraTimesConfig[Layer.cipher].decimals,
}

interface RpcProviderOptions {
context: {
network: Network
layer: Layer
}
}

export abstract class RpcUtils {
private static _provider: JsonRpcProvider | null = null
private static _providerLayer: Layer | null = null
private static _providerNetwork: Network | null = null

private static _getProvider(opts: RpcProviderOptions) {
const {
context: { network, layer },
} = opts
const rpcEndpoint = RPC_ENDPOINTS[network]?.[layer]

if (!rpcEndpoint) {
throw new Error('Invalid scope, unable to create Provider!')
}

if (RpcUtils._providerNetwork === network && RpcUtils._providerLayer === layer && RpcUtils._provider) {
return RpcUtils._provider
}

RpcUtils._provider = new JsonRpcProvider(rpcEndpoint)
RpcUtils._providerNetwork = network
RpcUtils._providerLayer = layer

return RpcUtils._provider
}

static async getAccountBalance(address: string, opts: RpcProviderOptions): Promise<string> {
const provider = RpcUtils._getProvider(opts)

const balance = await provider.getBalance(address)

const {
context: { layer },
} = opts
const decimals = NETWORK_DECIMALS[layer] ?? 18
return formatUnits(balance.toString(), decimals)
}
}
47 changes: 46 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.3.1.tgz#abfccb8ca78075a2b6187345c26243c1a0842f28"
integrity sha512-/62yikz7NLScCGAAST5SHdnjaDJQBDq0M2muyRTpf2VQhw6StBg2ALiu73zSJQ4fMVLA+0uBhBHAle7Wg+2kSg==

"@adraffy/[email protected]":
version "1.10.0"
resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz#d2a39395c587e092d77cbbc80acf956a54f38bf7"
integrity sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==

"@ampproject/remapping@^2.2.0":
version "2.2.1"
resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630"
Expand Down Expand Up @@ -2952,12 +2957,19 @@
dependencies:
"@noble/hashes" "1.3.1"

"@noble/[email protected]":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35"
integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==
dependencies:
"@noble/hashes" "1.3.2"

"@noble/[email protected]":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9"
integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==

"@noble/hashes@^1.2.0", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1":
"@noble/hashes@1.3.2", "@noble/hashes@^1.2.0", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39"
integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==
Expand Down Expand Up @@ -5374,6 +5386,11 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.5.6.tgz#5e9aaa86be03a09decafd61b128d6cec64a5fe40"
integrity sha512-Gi5wRGPbbyOTX+4Y2iULQ27oUPrefaB0PxGQJnfyWN3kvEDGM3mIB5M/gQLmitZf7A9FmLeaqxD3L1CXpm3VKQ==

"@types/[email protected]":
version "18.15.13"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469"
integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==

"@types/[email protected]":
version "20.8.10"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.10.tgz#a5448b895c753ae929c26ce85cab557c6d4a365e"
Expand Down Expand Up @@ -5908,6 +5925,11 @@ address@^1.0.1:
resolved "https://registry.yarnpkg.com/address/-/address-1.2.2.tgz#2b5248dac5485a6390532c6a517fda2e3faac89e"
integrity sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==

[email protected]:
version "4.0.0-beta.5"
resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873"
integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==

agent-base@5:
version "5.1.1"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c"
Expand Down Expand Up @@ -8160,6 +8182,19 @@ ethereum-cryptography@^2.1.2:
"@scure/bip32" "1.3.1"
"@scure/bip39" "1.2.1"

ethers@^6.9.0:
version "6.9.0"
resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.9.0.tgz#a4534bdcdfde306aee94ef32f3d5c70d7e33fcb9"
integrity sha512-pmfNyQzc2mseLe91FnT2vmNaTt8dDzhxZ/xItAV7uGsF4dI4ek2ufMu3rAkgQETL/TIs0GS5A+U05g9QyWnv3Q==
dependencies:
"@adraffy/ens-normalize" "1.10.0"
"@noble/curves" "1.2.0"
"@noble/hashes" "1.3.2"
"@types/node" "18.15.13"
aes-js "4.0.0-beta.5"
tslib "2.4.0"
ws "8.5.0"

eventemitter3@^4.0.1:
version "4.0.7"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
Expand Down Expand Up @@ -13013,6 +13048,11 @@ tsconfig-paths@^3.14.2:
minimist "^1.2.6"
strip-bom "^3.0.0"

[email protected]:
version "2.4.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==

tslib@>=2.0.0, tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.0:
version "2.6.2"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
Expand Down Expand Up @@ -13643,6 +13683,11 @@ write-file-atomic@^4.0.2:
imurmurhash "^0.1.4"
signal-exit "^3.0.7"

[email protected]:
version "8.5.0"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f"
integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==

ws@^6.1.0:
version "6.2.2"
resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e"
Expand Down

0 comments on commit 0adbfc2

Please sign in to comment.