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

fix: runes ui #5247

Merged
merged 1 commit into from
Apr 18, 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
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ export function RunesAssetItemLayout({ rune }: RunesAssetItemLayoutProps) {
<Pressable my="space.02">
<ItemLayout
flagImg={<RunesAvatarIcon />}
titleLeft={rune.rune_name.toUpperCase()}
captionLeft="RUNE"
titleLeft={rune.spaced_rune_name ?? rune.rune_name}
captionLeft="Runes"
titleRight={
<BasicTooltip
asChild
label={formattedBalance.isAbbreviated ? balance : undefined}
side="left"
>
<styled.span data-testid={rune.rune_name} fontWeight={500} textStyle="label.02">
{formattedBalance.value}
{formattedBalance.value} {rune.symbol}
</styled.span>
</BasicTooltip>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ interface RunesAssetListProps {
runes: RuneToken[];
}
export function RunesAssetList({ runes }: RunesAssetListProps) {
return runes.map(rune => <RunesAssetItemLayout key={rune.rune_id} rune={rune} />);
return runes.map((rune, i) => <RunesAssetItemLayout key={`${rune.rune_id}${i}`} rune={rune} />);
}
6 changes: 2 additions & 4 deletions src/app/components/loaders/runes-loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ interface RunesLoaderProps {
children(runes: RuneToken[]): React.ReactNode;
}
export function RunesLoader({ addresses, children }: RunesLoaderProps) {
const runes = useRuneTokens(addresses)
.flatMap(query => query.data)
.filter(isDefined);
return children(runes);
const runes = useRuneTokens(addresses);
return children(runes.filter(isDefined));
}
41 changes: 40 additions & 1 deletion src/app/query/bitcoin/bitcoin-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,37 @@ interface RunesWalletBalancesResponse {
data: RuneBalance[];
}

export interface RuneToken extends RuneBalance {
export interface RuneTickerInfo {
rune_id: string;
rune_number: string;
rune_name: string;
spaced_rune_name: string;
symbol: string;
decimals: number;
per_mint_amount: string;
mint_cnt: string;
mint_cnt_limit: string;
premined_supply: string;
total_minted_supply: string;
burned_supply: string;
circulating_supply: string;
mint_progress: number;
mint_start_block: number | null;
mint_end_block: number | null;
genesis_block: number;
deploy_ts: string;
deploy_txid: string;
auto_upgrade: boolean;
holder_count: number;
event_count: number;
mintable: boolean;
}
interface RunesTickerInfoResponse {
block_height: number;
data: RuneTickerInfo;
}

export interface RuneToken extends RuneBalance, RuneTickerInfo {
balance: Money;
}

Expand Down Expand Up @@ -181,6 +211,15 @@ class BestinslotApi {
);
return resp.data.data;
}

async getRunesTickerInfo(runeName: string, network: BitcoinNetworkModes) {
const baseUrl = network === 'mainnet' ? this.url : this.testnetUrl;
const resp = await axios.get<RunesTickerInfoResponse>(
`${baseUrl}/runes/ticker_info?rune_name=${runeName}`,
{ ...this.defaultOptions }
);
return resp.data.data;
}
}

class HiroApi {
Expand Down
24 changes: 24 additions & 0 deletions src/app/query/bitcoin/runes/runes-ticker-info.query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { type UseQueryResult, useQueries } from '@tanstack/react-query';

import { useConfigRunesEnabled } from '@app/query/common/remote-config/remote-config.query';
import { useBitcoinClient } from '@app/store/common/api-clients.hooks';
import { useCurrentNetwork } from '@app/store/networks/networks.selectors';

import type { RuneTickerInfo } from '../bitcoin-client';

export function useGetRunesTickerInfoQuery(runeNames: string[]): UseQueryResult<RuneTickerInfo>[] {
const client = useBitcoinClient();
const network = useCurrentNetwork();
const runesEnabled = useConfigRunesEnabled();

return useQueries({
queries: runeNames.map(runeName => {
return {
enabled: !!runeName && (network.chain.bitcoin.bitcoinNetwork === 'testnet' || runesEnabled),
queryKey: ['runes-ticker-info', runeName],
queryFn: () =>
client.BestinslotApi.getRunesTickerInfo(runeName, network.chain.bitcoin.bitcoinNetwork),
};
}),
});
}
33 changes: 27 additions & 6 deletions src/app/query/bitcoin/runes/runes.hooks.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,38 @@
import { logger } from '@shared/logger';
import { createMoney } from '@shared/models/money.model';
import { isDefined } from '@shared/utils';

import type { RuneBalance, RuneToken } from '../bitcoin-client';
import type { RuneBalance, RuneTickerInfo, RuneToken } from '../bitcoin-client';
import { useGetRunesTickerInfoQuery } from './runes-ticker-info.query';
import { useGetRunesWalletBalancesByAddressesQuery } from './runes-wallet-balances.query';

function makeRuneToken(rune: RuneBalance): RuneToken {
function makeRuneToken(runeBalance: RuneBalance, tickerInfo: RuneTickerInfo): RuneToken {
return {
...rune,
balance: createMoney(Number(rune.total_balance), rune.rune_name, 0),
...runeBalance,
...tickerInfo,
balance: createMoney(
Number(runeBalance.total_balance),
tickerInfo.rune_name,
tickerInfo.decimals
),
};
}

export function useRuneTokens(addresses: string[]) {
return useGetRunesWalletBalancesByAddressesQuery(addresses, {
select: resp => resp.map(makeRuneToken),
const runesBalances = useGetRunesWalletBalancesByAddressesQuery(addresses)
.flatMap(query => query.data)
.filter(isDefined);

const runesTickerInfo = useGetRunesTickerInfoQuery(runesBalances.map(r => r.rune_name))
.flatMap(query => query.data)
.filter(isDefined);

return runesBalances.map(r => {
const tickerInfo = runesTickerInfo.find(t => t.rune_name === r.rune_name);
if (!tickerInfo) {
logger.error('No ticker info found for Rune');
return;
}
return makeRuneToken(r, tickerInfo);
});
}
4 changes: 2 additions & 2 deletions src/app/query/bitcoin/stamps/stamps-by-address.hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import { useStampsByAddressQuery } from './stamps-by-address.query';
export function useStampsByAddress(address: string) {
return useStampsByAddressQuery(address, {
select(data) {
return data.data.stamps;
return data.data?.stamps;
},
});
}

export function useSrc20TokensByAddress(address: string) {
return useStampsByAddressQuery(address, {
select(data) {
return data.data.src20;
return data.data?.src20;
},
});
}
Loading