Skip to content

Commit

Permalink
feat: support btc signet explorer
Browse files Browse the repository at this point in the history
lead to signet explorer if the tx is found on btc signet
  • Loading branch information
Keith-CY committed Jun 19, 2024
1 parent a9d2043 commit 4257716
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 43 deletions.
3 changes: 3 additions & 0 deletions .env.development.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ REACT_APP_API_URL=http://your-api-url
REACT_APP_CHAIN_TYPE=testnet
REACT_APP_DID_INDEXER_URL=https://indexer-v1.did.id
REACT_APP_DOBS_SERVICE_URL=https://dobs-api.magickbase.com
REACT_APP_BITCOIN_EXPLORER=https://mempool.space/testnet
REACT_APP_BTC_TESETNET_IDENTIFIER=https://your-identifier-service
REACT_APP_PROB_NODE=https://api-nodes.magickbase.com

# sentry
REACT_APP_SENTRY_DSN=
Expand Down
3 changes: 3 additions & 0 deletions .env.production.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ REACT_APP_API_URL=http://your-api-url
REACT_APP_CHAIN_TYPE=mainnet
REACT_APP_DID_INDEXER_URL=https://indexer-v1.did.id
REACT_APP_DOBS_SERVICE_URL=https://dobs-api.magickbase.com
REACT_APP_BITCOIN_EXPLORER=https://mempool.space/testnet
REACT_APP_BTC_TESETNET_IDENTIFIER=https://your-identifier-service
REACT_APP_PROB_NODE=https://api-nodes.magickbase.com

# sentry
REACT_APP_SENTRY_DSN=
Expand Down
26 changes: 16 additions & 10 deletions src/components/Btc/Transaction/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useMemo, type FC } from 'react'
import { useTranslation } from 'react-i18next'
import { useQuery } from '@tanstack/react-query'
import { Tooltip } from 'antd'
import dayjs from 'dayjs'
import { type RawBtcRPC } from '../../../services/ExplorerService'
Expand All @@ -13,6 +14,8 @@ import { ReactComponent as ViewNewSeal } from './view-new-seal.svg'
import { ReactComponent as MoreIcon } from '../../../assets/more-icon.svg'
import { ReactComponent as BtcIcon } from './btc.svg'
import { ReactComponent as DirectionIcon } from '../../../assets/direction.svg'
import { getBtcChainIdentify } from '../../../services/BTCIdentifier'
import { IS_MAINNET } from '../../../constants/common'

const MAX_ITEMS = 10

Expand All @@ -23,6 +26,14 @@ const BtcTransaction: FC<{
}> = ({ tx, boundCellIndex, showId = true }) => {
const { t } = useTranslation()

const { data: identity } = useQuery({
queryKey: ['btc-testnet-identity', tx.txid],
queryFn: () => (tx.txid ? getBtcChainIdentify(tx.txid) : null),
enabled: !IS_MAINNET && !!tx.txid,
})

const btcExplorer = `${config.BITCOIN_EXPLORER}${IS_MAINNET ? '' : `/${identity}`}`

const time = tx.blocktime ? dayjs(tx.blocktime * 1000) : null

const commitment = useMemo(() => {
Expand All @@ -38,12 +49,7 @@ const BtcTransaction: FC<{
{showId ? (
<div className={styles.header}>
<h3 className={styles.txid}>
<a
href={`${config.BITCOIN_EXPLORER}/tx/${tx.txid}`}
title={tx.txid}
rel="noopener noreferrer"
target="_blank"
>
<a href={`${btcExplorer}/tx/${tx.txid}`} title={tx.txid} rel="noopener noreferrer" target="_blank">
<EllipsisMiddle className="monospace" text={tx.txid} />
</a>
</h3>
Expand All @@ -66,7 +72,7 @@ const BtcTransaction: FC<{
return (
<div key={key} className={styles.input}>
<a
href={`${config.BITCOIN_EXPLORER}/address/${input.prevout.scriptPubKey.address}`}
href={`${btcExplorer}/address/${input.prevout.scriptPubKey.address}`}
rel="noopener noreferrer"
target="_blank"
>
Expand Down Expand Up @@ -96,7 +102,7 @@ const BtcTransaction: FC<{
})}
{viewMoreInputs ? (
<div style={{ marginTop: 4 }}>
<a href={`${config.BITCOIN_EXPLORER}/tx/${tx.txid}`} rel="noopener noreferrer" target="_blank">
<a href={`${btcExplorer}/tx/${tx.txid}`} rel="noopener noreferrer" target="_blank">
View more in BTC Explorer
</a>
</div>
Expand All @@ -112,7 +118,7 @@ const BtcTransaction: FC<{
<div key={key} className={styles.output}>
{output.scriptPubKey.address ? (
<a
href={`${config.BITCOIN_EXPLORER}/address/${output.scriptPubKey.address}`}
href={`${btcExplorer}/address/${output.scriptPubKey.address}`}
rel="noopener noreferrer"
target="_blank"
>
Expand Down Expand Up @@ -169,7 +175,7 @@ const BtcTransaction: FC<{
})}
{viewMoreOutputs ? (
<div style={{ marginTop: 4 }}>
<a href={`${config.BITCOIN_EXPLORER}/tx/${tx.txid}`} rel="noopener noreferrer" target="_blank">
<a href={`${btcExplorer}/tx/${tx.txid}`} rel="noopener noreferrer" target="_blank">
View more in BTC Explorer
</a>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useMemo } from 'react'
import { useQuery } from '@tanstack/react-query'
import { useTranslation } from 'react-i18next'
import BigNumber from 'bignumber.js'
import { ReactComponent as CopyIcon } from '../../../assets/copy_icon.svg'
Expand All @@ -14,6 +15,8 @@ import { useIsMobile } from '../../../hooks'
import { Link } from '../../Link'
import config from '../../../config'
import SmallLoading from '../../Loading/SmallLoading'
import { getBtcChainIdentify } from '../../../services/BTCIdentifier'
import { IS_MAINNET } from '../../../constants/common'

export const TransactionRGBPPDigestContent = ({
hash,
Expand All @@ -28,6 +31,14 @@ export const TransactionRGBPPDigestContent = ({
const setToast = useSetToast()
const isMobile = useIsMobile()

const btcTxId = digest?.txid

const { data: identity } = useQuery({
queryKey: ['btc-testnet-identity', btcTxId],
queryFn: () => (btcTxId ? getBtcChainIdentify(btcTxId) : null),
enabled: !IS_MAINNET && !!btcTxId,
})

const transfers = useMemo(() => {
const m = new Map<string, LiteTransfer.Transfer[]>()
digest?.transfers.forEach(tf => {
Expand Down Expand Up @@ -112,7 +123,10 @@ export const TransactionRGBPPDigestContent = ({
>
{digest.txid}
</AddressText>
<Link to={`${config.BITCOIN_EXPLORER}/tx/${digest.txid}`} className={styles.action}>
<Link
to={`${config.BITCOIN_EXPLORER}${IS_MAINNET ? '' : `/${identity}`}/tx/${digest.txid}`}
className={styles.action}
>
<RedirectIcon />
</Link>
</>
Expand Down
1 change: 1 addition & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export default {
PROB_NODE: process.env.REACT_APP_PROB_NODE || 'https://api-nodes.magickbase.com',
DID_INDEXER_URL: process.env.REACT_APP_DID_INDEXER_URL?.split(',') || ['https://indexer-v1.did.id'],
DOBS_SERVICE_URL: process.env.REACT_APP_DOBS_SERVICE_URL,
BTC_TEST_IDENTIFIER: process.env.REACT_APP_BTC_TESETNET_IDENTIFIER!,
}
97 changes: 65 additions & 32 deletions src/pages/Transaction/TransactionCellScript/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
import { useState, ReactNode, useRef } from 'react'
import { useState, ReactNode, useRef, FC } from 'react'
import BigNumber from 'bignumber.js'
import { useTranslation } from 'react-i18next'
import { useQuery } from '@tanstack/react-query'
Expand Down Expand Up @@ -31,6 +31,8 @@ import { isAxiosError } from '../../../utils/error'
import { Script } from '../../../models/Script'
import { ReactComponent as CompassIcon } from './compass.svg'
import styles from './styles.module.scss'
import { getBtcChainIdentify } from '../../../services/BTCIdentifier'
import { IS_MAINNET } from '../../../constants/common'

enum CellInfo {
LOCK = 1,
Expand Down Expand Up @@ -150,6 +152,66 @@ const JSONKeyValueView = ({ title = '', value = '' }: { title?: string; value?:
</div>
)

const RGBPP: FC<{ btcUtxo: Partial<Record<'txid' | 'index', string>> }> = ({ btcUtxo }) => {
const { data: identity } = useQuery({
queryKey: ['btc-testnet-identity', btcUtxo.txid],
queryFn: () => (btcUtxo?.txid ? getBtcChainIdentify(btcUtxo.txid) : null),
enabled: !IS_MAINNET && !!btcUtxo.txid,
})

if (!IS_MAINNET && !identity) return null

return (
<JSONKeyValueView
value={
<a
href={`${config.BITCOIN_EXPLORER}${IS_MAINNET ? '' : `/${identity}`}/tx/${btcUtxo.txid}#vout=${parseInt(
btcUtxo.index!,
16,
)}`}
target="_blank"
rel="noopener noreferrer"
className={styles.btcUtxo}
>
BTC UTXO
<CompassIcon />
</a>
}
/>
)
}

const BTCTimeLock: FC<{
btcTimeLockInfo: {
txid: string | undefined
after: number
}
}> = ({ btcTimeLockInfo }) => {
const { data: identity } = useQuery({
queryKey: ['btc-testnet-identity', btcTimeLockInfo.txid],
queryFn: () => (btcTimeLockInfo?.txid ? getBtcChainIdentify(btcTimeLockInfo.txid) : null),
enabled: !IS_MAINNET && !!btcTimeLockInfo.txid,
})

if (!IS_MAINNET && !identity) return null

return (
<JSONKeyValueView
value={
<a
href={`${config.BITCOIN_EXPLORER}${IS_MAINNET ? '' : `/${identity}`}/tx/${btcTimeLockInfo.txid}`}
target="_blank"
rel="noopener noreferrer"
className={styles.btcUtxo}
>
{`${btcTimeLockInfo.after} confirmations after BTC Tx`}
<CompassIcon />
</a>
}
/>
)
}

const CellInfoValueRender = ({ content }: { content: CellInfoValue }) => {
const { t } = useTranslation()

Expand All @@ -171,37 +233,8 @@ const CellInfoValueRender = ({ content }: { content: CellInfoValue }) => {
)}
<JSONKeyValueView title={`"${t('transaction.script_hash_type')}": `} value={content.hashType} />
<JSONKeyValueView title={`"${t('transaction.script_args')}": `} value={content.args} />
{btcUtxo ? (
<JSONKeyValueView
value={
<a
href={`${config.BITCOIN_EXPLORER}/tx/${btcUtxo.txid}#vout=${parseInt(btcUtxo.index!, 16)}`}
target="_blank"
rel="noopener noreferrer"
className={styles.btcUtxo}
>
BTC UTXO
<CompassIcon />
</a>
}
/>
) : null}

{btcTimeLockInfo ? (
<JSONKeyValueView
value={
<a
href={`${config.BITCOIN_EXPLORER}/tx/${btcTimeLockInfo.txid}`}
target="_blank"
rel="noopener noreferrer"
className={styles.btcUtxo}
>
{`${btcTimeLockInfo.after} confirmations after BTC Tx`}
<CompassIcon />
</a>
}
/>
) : null}
{btcUtxo ? <RGBPP btcUtxo={btcUtxo} /> : null}
{btcTimeLockInfo ? <BTCTimeLock btcTimeLockInfo={btcTimeLockInfo} /> : null}
</>
)
}
Expand Down
22 changes: 22 additions & 0 deletions src/services/BTCIdentifier/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import axios from 'axios'
import config from '../../config'
import { IS_MAINNET } from '../../constants/common'

const { BTC_TEST_IDENTIFIER } = config

export const getBtcChainIdentify = async (txid: string) => {
if (IS_MAINNET) {
return 'mainnet'
}

const identify = await axios
.get<{ chain: string }>(`${BTC_TEST_IDENTIFIER}/api/signet?${new URLSearchParams({ txid })}`)
.catch(() => {
return {
data: {
chain: 'testnet',
},
}
})
return identify.data.chain
}

0 comments on commit 4257716

Please sign in to comment.