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

Feature fix other asset balance by wallet #112

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
Open
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
18 changes: 13 additions & 5 deletions src/hooks/useREG.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import {
selectUserAddressList,
selectUserIncludesEth,
} from 'src/store/features/settings/settingsSelector'
import { REGRealtoken } from 'src/store/features/wallets/walletsSelector'
import {
REGRealtoken,
updateBalanceValues,
} from 'src/store/features/wallets/walletsSelector'
import { APIRealTokenProductType } from 'src/types/APIRealToken'
import { Currency } from 'src/types/Currencies'
import { ERC20ABI } from 'src/utils/blockchain/abi/ERC20ABI'
Expand Down Expand Up @@ -64,20 +67,19 @@ const getREG = async (
ERC20ABI,
GnosisRpcProvider,
)
const availableBalance = await getAddressesBalances(
const balances = await getAddressesBalances(
REG_ContractAddress,
addressList,
providers,
)

const regVaultAbiGetUserGlobalStateOnly =
getRegVaultAbiGetUserGlobalStateOnly()

const lockedBalance = await getAddressesLockedBalances(
[
// First provider
[
// First vault
// First vault: Gnosis
[
REG_Vault_Gnosis_ContractAddress, // Contract address
regVaultAbiGetUserGlobalStateOnly, // Contract ABI
Expand All @@ -102,7 +104,10 @@ const getREG = async (
providers,
)

const totalAmount = availableBalance + lockedBalance
// Add locked balance to balance.balance.gnosis.amount
balances.balance.gnosis.amount += lockedBalance
// Add locked balance to total amount
const totalAmount = balances?.totalAmount + lockedBalance
const contractRegTotalSupply = await RegContract_Gnosis.totalSupply()
const totalTokens = Number(contractRegTotalSupply) / 10 ** REGtokenDecimals
const amount = totalAmount / 10 ** REGtokenDecimals
Expand Down Expand Up @@ -143,6 +148,8 @@ const getREG = async (
: DEFAULT_REG_PRICE / userRate
const value = tokenPrice * amount
const totalInvestment = totalTokens * tokenPrice
// Update all balance values with token price
updateBalanceValues(balances.balance, tokenPrice)

return {
id: `${REG_asset_ID}`,
Expand All @@ -159,6 +166,7 @@ const getREG = async (
value,
totalInvestment,
unitPriceCost: tokenPrice,
balance: balances.balance,
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/hooks/useREGVotingPower.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,20 @@ const getRegVotingPower = async (
ERC20ABI,
GnosisRpcProvider,
)
const totalAmount = await getAddressesBalances(
const balances = await getAddressesBalances(
RegVotingPower_Gnosis_ContractAddress,
addressList,
providers,
)

const contractRegVotePowerTotalSupply =
await RegVotingPowerContract.totalSupply()
const totalTokens =
Number(contractRegVotePowerTotalSupply) / 10 ** REGVotingPowertokenDecimals
const amount = totalAmount / 10 ** REGVotingPowertokenDecimals
const amount = balances?.totalAmount / 10 ** REGVotingPowertokenDecimals
const tokenPrice = DEFAULT_REGVotingPower_PRICE
const value = tokenPrice * amount
const totalInvestment = tokenPrice * totalTokens

// Reg voting power does not have (yet) a unit price cost
return {
id: `${REGVotingPower_asset_ID}`,
fullName: 'REG Voting Power Registry',
Expand All @@ -56,6 +55,7 @@ const getRegVotingPower = async (
value,
totalInvestment,
unitPriceCost: tokenPrice,
balance: balances.balance,
}
}

Expand Down
12 changes: 9 additions & 3 deletions src/hooks/useRWA.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import {
import {
selectUserAddressList, // selectUserIncludesEth,
} from 'src/store/features/settings/settingsSelector'
import { RWARealtoken } from 'src/store/features/wallets/walletsSelector'
import {
RWARealtoken,
updateBalanceValues,
} from 'src/store/features/wallets/walletsSelector'
import { APIRealTokenProductType } from 'src/types/APIRealToken'
import { Currency } from 'src/types/Currencies'
import { ERC20ABI } from 'src/utils/blockchain/abi/ERC20ABI'
Expand Down Expand Up @@ -49,14 +52,14 @@ const getRWA = async (
ERC20ABI,
GnosisRpcProvider,
)
const totalAmount = await getAddressesBalances(
const balances = await getAddressesBalances(
RWA_ContractAddress,
addressList,
providers,
)
const RwaContractTotalSupply = await contractRwa_Gnosis.totalSupply()
const totalTokens = Number(RwaContractTotalSupply) / 10 ** RWAtokenDecimals
const amount = totalAmount / 10 ** RWAtokenDecimals
const amount = balances?.totalAmount / 10 ** RWAtokenDecimals

// RWA token prices in USDC and WXDAI from LPs
const rwaPriceUsdc = await getUniV2AssetPrice(
Expand Down Expand Up @@ -92,6 +95,8 @@ const getRWA = async (
const tokenPrice = (assetAveragePriceUSD ?? DEFAULT_RWA_PRICE) / userRate
const value = tokenPrice * amount
const totalInvestment = totalTokens * tokenPrice
// Update all balance values with token price
updateBalanceValues(balances.balance, tokenPrice)

return {
id: `${RWA_asset_ID}`,
Expand All @@ -113,6 +118,7 @@ const getRWA = async (
timezone_type: 3,
timezone: 'UTC',
},
balance: balances.balance,
}
}

Expand Down
13 changes: 13 additions & 0 deletions src/repositories/RpcProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,3 +239,16 @@ export async function getTransactionReceipt(

return receipt
}

/**
* Get chain ID
* @param provider (Ethers) RPC provider
* @returns Chain ID as number | undefined
*/
export const getChainId = (
provider: JsonRpcProvider | undefined,
): number | undefined => {
return provider?._network?.chainId
? Number(provider?._network?.chainId)
: undefined
}
49 changes: 41 additions & 8 deletions src/store/features/wallets/walletsSelector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import _max from 'lodash/max'
import _sumBy from 'lodash/sumBy'
import moment from 'moment'

import { AssetProductType } from 'src/components/assetsView'
import { WalletBalances, WalletType } from 'src/repositories'
import { UserRealTokenTransfer } from 'src/repositories/transfers/transfers.type'
import { RootState } from 'src/store/store'
Expand All @@ -20,9 +19,23 @@ import {
} from 'src/types/RentCalculation'
import { computeUCP } from 'src/utils/transfer/computeUCP'

import {
CHAIN_ID_ETHEREUM,
CHAIN_ID_GNOSIS_XDAI,
CHAIN_NAME_ETHEREUM,
CHAIN_NAME_GNOSIS_XDAI,
} from '../../../utils/blockchain/consts/otherTokens'
import { selectRealtokens } from '../realtokens/realtokensSelector'
import { selectUserRentCalculation } from '../settings/settingsSelector'

export type BalanceByWalletType = Record<
WalletType,
{
amount: number
value: number
}
>

export interface UserRealtoken extends RealToken {
id: string
isWhitelisted: boolean
Expand All @@ -33,13 +46,7 @@ export interface UserRealtoken extends RealToken {
priceCost?: number
unrealizedCapitalGain?: number
lastChanges: string
balance: Record<
WalletType,
{
amount: number
value: number
}
>
balance: BalanceByWalletType
}

export interface OtherRealtoken {
Expand All @@ -55,6 +62,23 @@ export interface OtherRealtoken {
imageLink: string[]
isRmmAvailable: boolean
unitPriceCost: number
balance: BalanceByWalletType
}

/**
* Updates all balance values with token price
* @param balance
* @param tokenPrice
*/
export const updateBalanceValues = (
balance: BalanceByWalletType,
tokenPrice: number,
) => {
// Loop on each record
Object.keys(balance).forEach((key) => {
balance[key as WalletType].value =
balance[key as WalletType].amount * tokenPrice
})
}

// eslint-disable-next-line @typescript-eslint/no-empty-interface
Expand Down Expand Up @@ -248,3 +272,12 @@ export const selectRmmDetails = createSelector(
return _mapValues(rmmDetails, (value) => value / rates.XDAI)
},
)

export const getWalletChainName = (chainId: number) => {
switch (chainId) {
case CHAIN_ID_ETHEREUM:
return CHAIN_NAME_ETHEREUM
case CHAIN_ID_GNOSIS_XDAI:
return CHAIN_NAME_GNOSIS_XDAI
}
}
10 changes: 10 additions & 0 deletions src/utils/blockchain/consts/otherTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ const WXDAItokenDecimals = 18

const HoneySwapFactory_Address = '0xA818b4F111Ccac7AA31D0BCc0806d64F2E0737D7'

const CHAIN_ID_GNOSIS_XDAI = 100
const CHAIN_ID_ETHEREUM = 1

const CHAIN_NAME_GNOSIS_XDAI = 'gnosis'
const CHAIN_NAME_ETHEREUM = 'ethereum'

export {
RWA_ContractAddress,
REG_ContractAddress,
Expand All @@ -54,4 +60,8 @@ export {
RWA_asset_ID,
REG_asset_ID,
REGVotingPower_asset_ID,
CHAIN_ID_GNOSIS_XDAI,
CHAIN_ID_ETHEREUM,
CHAIN_NAME_GNOSIS_XDAI,
CHAIN_NAME_ETHEREUM,
}
85 changes: 69 additions & 16 deletions src/utils/blockchain/erc20Infos.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,56 @@
import { Contract, JsonRpcProvider } from 'ethers'

import { getChainId } from 'src/repositories/RpcProvider'
import { BalanceByWalletType } from 'src/store/features/wallets/walletsSelector'
import { getWalletChainName } from 'src/store/features/wallets/walletsSelector'
import { getErc20AbiBalanceOfOnly } from 'src/utils/blockchain/ERC20'

import { batchCallOneContractOneFunctionMultipleParams } from './contract'

export interface Balances {
totalAmount: number
balance: BalanceByWalletType
}

const getAddressesBalances = async (
contractAddress: string,
addressList: string[],
providers: JsonRpcProvider[],
consoleWarnOnError = false,
) => {
let totalAmount = 0
): Promise<Balances> => {
const balances: Balances = {
totalAmount: 0,
balance: {
gnosis: {
amount: 0,
value: 0,
},
ethereum: {
amount: 0,
value: 0,
},
rmm: {
amount: 0,
value: 0,
},
levinSwap: {
amount: 0,
value: 0,
},
},
}
try {
if (!contractAddress) {
consoleWarnOnError && console.error('Invalid contract address')
return totalAmount
return balances
}
if (!addressList?.length) {
consoleWarnOnError && console.error('Invalid address list')
return totalAmount
return balances
}
if (!providers?.length) {
consoleWarnOnError && console.error('Invalid providers')
return totalAmount
return balances
}
const erc20AbiBalanceOfOnly = getErc20AbiBalanceOfOnly()
if (!erc20AbiBalanceOfOnly) {
Expand All @@ -41,22 +69,47 @@ const getAddressesBalances = async (
)
return balances
})

const balancesArray = await Promise.all(balancesPromises.flat())
const balances = balancesArray.flat()
// Sum all valid balances
balances.forEach((balance: object | null | undefined) => {
try {
if (balance) {
totalAmount += Number(balance)
}
} catch (error) {}
// warn but don't stop
balancesArray?.length !== providers.length &&
consoleWarnOnError &&
console.warn(
`Invalid balances array length (${balancesArray?.length}) (inconsistent with providers length (${providers.length}))`,
)
providers.forEach((provider: JsonRpcProvider, providerIdx) => {
const chainId = getChainId(provider)
const wt = chainId ? getWalletChainName(chainId) : null
if (wt) {
balances.balance[wt].value = 0
// warn but don't stop
balancesArray[providerIdx]?.length !== addressList.length &&
consoleWarnOnError &&
console.warn(
'Invalid balances array (inconsistent addressList length)',
)
;(balancesArray[providerIdx] as unknown as bigint[])?.forEach(
(addressBalanceBI: bigint, addressIdx) => {
try {
const addressBalance = Number(addressBalanceBI)
balances.balance[wt].amount += addressBalance
} catch (error) {
// warn but don't stop
consoleWarnOnError &&
console.warn(
`Invalid balance conversion for address ${addressList[addressIdx]} on chain ${chainId}`,
error,
)
}
},
)
balances.totalAmount += balances.balance[wt].amount
}
})
return totalAmount
return balances
} catch (error) {
console.warn('Failed to get balances', error)
}
return totalAmount
return balances
}

export { getAddressesBalances }
Loading