Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fetch balances from Oasis gRPC instead of Web3 RPC #1384

Merged
merged 4 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changelog/1384.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fetch balances from Oasis gRPC instead of Web3 JSON-RPC
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@
"bignumber.js": "9.1.2",
"bip39": "^3.1.0",
"date-fns": "3.6.0",
"ethers": "^6.11.1",
"i18next": "23.10.1",
"react": "18.2.0",
"react-dom": "18.2.0",
Expand Down
33 changes: 0 additions & 33 deletions src/app/utils/__tests__/array-utils.test.ts

This file was deleted.

14 changes: 0 additions & 14 deletions src/app/utils/array-utils.ts

This file was deleted.

47 changes: 47 additions & 0 deletions src/app/utils/getRPCAccountBalances.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Runtime, RuntimeSdkBalance } from '../../oasis-nexus/api'
import * as oasis from '@oasisprotocol/client'
import * as oasisRT from '@oasisprotocol/client-rt'
import { Network } from '../../types/network'
import { getTokensForScope, paraTimesConfig } from '../../config'
import { fromBaseUnits } from './helpers'

const grpcUrls: { [key in Network]: string } = {
[Network.mainnet]: 'https://grpc.oasis.dev',
[Network.testnet]: 'https://testnet.grpc.oasis.dev',
}

export async function getRPCAccountBalances(
oasisAddress: string,
scope: {
network: Network
layer: Runtime
},
): Promise<RuntimeSdkBalance[]> {
const paratimeConfig = paraTimesConfig[scope.layer][scope.network]
if (!paratimeConfig.runtimeId) throw new Error('Paratime is not configured')

const nic = new oasis.client.NodeInternal(grpcUrls[scope.network])
const accountsWrapper = new oasisRT.accounts.Wrapper(oasis.misc.fromHex(paratimeConfig.runtimeId))

const rawBalances = (
await accountsWrapper
.queryBalances()
lubej marked this conversation as resolved.
Show resolved Hide resolved
.setArgs({ address: oasis.staking.addressFromBech32(oasisAddress) })
.query(nic)
).balances

return [...rawBalances.entries()]
.map(([denomination, amount]) => {
return {
balance: oasis.quantity.toBigInt(amount).toString(),
lubej marked this conversation as resolved.
Show resolved Hide resolved
token_symbol: oasis.misc.toStringUTF8(denomination) || getTokensForScope(scope)[0].ticker,
token_decimals: paraTimesConfig[scope.layer].decimals, // TODO: differentiate by token
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That doesn't look right, if this is querying ERC-20 tokens as well, each of the ERC-20 token, can have custom decimals specified. So defaulting to paratime decimals here, is wrong.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's only querying e.g. TEST and EUROe; evm_balances are a different field in Nexus API.
But we don't differentiate decimals between TEST and EUROe - related: #1265 (comment)

Copy link
Collaborator

@lubej lubej Apr 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I verified that both Ocean and EUROe use 18 decimals places, so coincidentally this works as expected.

Looking at the documentation at https://docs.pontus-x.eu/docs/Development/quick_start#setup-metamask the native token has been renamed to GX @csillag are we aware of this?

Scratch the above, was looking at the wrong documentation. The right documentation is linked here: https://docs.pontus-x.eu/docs/ParaTime/quick_start#setup-metamask

}
})
.map(token => {
return {
...token,
balance: fromBaseUnits(token.balance, token.token_decimals),
}
})
Comment on lines +41 to +46
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is iterating twice over an array, for no good reason. This should happen in the previous map.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer this, and it mirrors

.map(token => {
return {
...token,
balance: fromBaseUnits(token.balance, token.token_decimals),
}
}),
.

(I also think https://github.com/oasisprotocol/explorer-frontend/blob/26079807ff9a4e91cc42d106d75a0c824533caba/src/oasis-nexus/api.ts#L709-L752 should be split into multiple iterations over an array)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it is not a large array, but for me it makes no sense, to iterate over the same array multiple times.

}
87 changes: 0 additions & 87 deletions src/app/utils/rpc-utils.ts

This file was deleted.

55 changes: 12 additions & 43 deletions src/oasis-nexus/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import axios, { AxiosResponse } from 'axios'
import { consensusDecimals, getTokensForScope, paraTimesConfig } from '../config'
import * as generated from './generated/api'
import { QueryKey, UseQueryOptions, UseQueryResult } from '@tanstack/react-query'
import { QueryKey, UseQueryOptions, UseQueryResult, useQuery } from '@tanstack/react-query'
import {
EvmToken,
EvmTokenType,
Expand All @@ -13,7 +13,6 @@ import {
NotFoundErrorResponse,
RuntimeAccount,
RuntimeEventType,
RuntimeSdkBalance,
} from './generated/api'
import {
fromBaseUnits,
Expand All @@ -24,10 +23,8 @@ import {
import { Network } from '../types/network'
import { SearchScope } from '../types/searchScope'
import { Ticker } from '../types/ticker'
import { useEffect, useState } from 'react'
import { RpcUtils } from '../app/utils/rpc-utils'
import { getRPCAccountBalances } from '../app/utils/getRPCAccountBalances'
import { toChecksumAddress } from '@ethereumjs/util'
import { ArrayUtils } from '../app/utils/array-utils'

export * from './generated/api'
export type { RuntimeEvmBalance as Token } from './generated/api'
Expand Down Expand Up @@ -328,8 +325,6 @@ export const useGetRuntimeAccountsAddress: typeof generated.useGetRuntimeAccount
address,
options,
) => {
const [rpcAccountBalance, setRpcAccountBalance] = useState<RuntimeSdkBalance | null>(null)

const oasisAddress = getOasisAddressOrNull(address)

const query = generated.useGetRuntimeAccountsAddress(network, runtime, oasisAddress!, {
Expand Down Expand Up @@ -393,46 +388,20 @@ export const useGetRuntimeAccountsAddress: typeof generated.useGetRuntimeAccount
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 and has eth address
if (!runtimeAccount || !!runtimeAccount.evm_contract || !runtimeAccount.address_eth) {
setRpcAccountBalance(null)
return
}

let shouldUpdate = true

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

const balance = await RpcUtils.getAccountBalance(runtimeAccount.address_eth!, {
context: {
network: runtimeAccount.network,
layer: runtimeAccount.layer,
},
})

if (shouldUpdate) {
setRpcAccountBalance(balance)
}
}

fetchAccountBalance()

return () => {
shouldUpdate = false
}
}, [runtimeAccount])
const rpcAccountBalances = useQuery({
enabled: !!oasisAddress,
queryKey: [oasisAddress, network, runtime],
queryFn: async () => {
if (!oasisAddress) throw new Error('Needed to fix types - see `enabled`')
return await getRPCAccountBalances(oasisAddress, { network: network, layer: runtime })
},
}).data

const data =
rpcAccountBalance !== null && runtimeAccount
rpcAccountBalances && runtimeAccount
? {
...runtimeAccount,
balances: ArrayUtils.replaceOrAppend(
runtimeAccount.balances,
rpcAccountBalance,
(a, b) => a.token_symbol === b.token_symbol,
),
balances: rpcAccountBalances,
}
: runtimeAccount

Expand Down
Loading
Loading