diff --git a/src/app/features/collectibles/collectibles.tsx b/src/app/features/collectibles/collectibles.tsx
index 82728714..9d18a1f8 100644
--- a/src/app/features/collectibles/collectibles.tsx
+++ b/src/app/features/collectibles/collectibles.tsx
@@ -9,6 +9,7 @@ import { useConfigNftMetadataEnabled } from '@app/query/common/hiro-config/hiro-
import { AddCollectible } from './components/add-collectible';
import { Ordinals } from './components/bitcoin/ordinals';
+import { Stamps } from './components/bitcoin/stamps';
import { CollectiblesLayout } from './components/collectibes.layout';
import { StacksCryptoAssets } from './components/stacks/stacks-crypto-assets';
import { TaprootBalanceDisplayer } from './components/taproot-balance-displayer';
@@ -40,6 +41,7 @@ export function Collectibles() {
<>
+
>
),
ledger: null,
diff --git a/src/app/features/collectibles/components/bitcoin/stamp.tsx b/src/app/features/collectibles/components/bitcoin/stamp.tsx
new file mode 100644
index 00000000..4891e77c
--- /dev/null
+++ b/src/app/features/collectibles/components/bitcoin/stamp.tsx
@@ -0,0 +1,20 @@
+import { openInNewTab } from '@app/common/utils/open-in-new-tab';
+import { Stamp as BitcoinStamp } from '@app/query/bitcoin/stamps/stamp-collection.query';
+
+import { CollectibleImage } from '../_collectible-types/collectible-image';
+
+const stampChainAssetUrl = 'https://stampchain.io/asset.html?stampNumber=';
+
+export function Stamp(props: { bitcoinStamp: BitcoinStamp }) {
+ const { bitcoinStamp } = props;
+
+ return (
+ openInNewTab(`${stampChainAssetUrl}${bitcoinStamp.stamp}`)}
+ src={bitcoinStamp.stamp_url}
+ subtitle="Bitcoin Stamp"
+ title={`# ${bitcoinStamp.stamp}`}
+ />
+ );
+}
diff --git a/src/app/features/collectibles/components/bitcoin/stamps.tsx b/src/app/features/collectibles/components/bitcoin/stamps.tsx
new file mode 100644
index 00000000..005672e1
--- /dev/null
+++ b/src/app/features/collectibles/components/bitcoin/stamps.tsx
@@ -0,0 +1,33 @@
+import { useEffect } from 'react';
+
+import { useAnalytics } from '@app/common/hooks/analytics/use-analytics';
+import { useStampsByAddressQuery } from '@app/query/bitcoin/stamps/stamps-by-address.query';
+import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
+
+import { Stamp } from './stamp';
+
+export function Stamps() {
+ const currentAccountBtcAddress = useCurrentBtcNativeSegwitAccountAddressIndexZero();
+ const { data: stamps } = useStampsByAddressQuery(currentAccountBtcAddress);
+ const analytics = useAnalytics();
+
+ useEffect(() => {
+ if (!stamps) return;
+ if (stamps.length > 0) {
+ void analytics.track('view_collectibles', {
+ stamps_count: stamps.length,
+ });
+ void analytics.identify({ stamps_count: stamps.length });
+ }
+ }, [analytics, stamps]);
+
+ if (!stamps) return null;
+
+ return (
+ <>
+ {stamps.map(s => (
+
+ ))}
+ >
+ );
+}
diff --git a/src/app/query/bitcoin/stamps/stamp-collection.query.ts b/src/app/query/bitcoin/stamps/stamp-collection.query.ts
index 0fcab5d4..c2106a52 100644
--- a/src/app/query/bitcoin/stamps/stamp-collection.query.ts
+++ b/src/app/query/bitcoin/stamps/stamp-collection.query.ts
@@ -3,16 +3,16 @@ import { useQuery } from '@tanstack/react-query';
import { AppUseQueryConfig } from '@app/query/query-config';
import { QueryPrefixes } from '@app/query/query-prefixes';
-interface Stamp {
- message_index: number;
- block_index: number;
- timestamp: number;
- tx_hash: string;
+export interface Stamp {
asset: string;
- tx_index: number;
+ block_index: number;
+ message_index: number;
+ stamp: number;
stamp_mimetype: string;
stamp_url: string;
- stamp: number;
+ timestamp: number;
+ tx_hash: string;
+ tx_index: number;
}
async function fetchStampCollection() {
diff --git a/src/app/query/bitcoin/stamps/stamps-by-address.query.ts b/src/app/query/bitcoin/stamps/stamps-by-address.query.ts
new file mode 100644
index 00000000..f9dae9ed
--- /dev/null
+++ b/src/app/query/bitcoin/stamps/stamps-by-address.query.ts
@@ -0,0 +1,31 @@
+import { useQuery } from '@tanstack/react-query';
+
+import { AppUseQueryConfig } from '@app/query/query-config';
+import { QueryPrefixes } from '@app/query/query-prefixes';
+
+import { Stamp } from './stamp-collection.query';
+
+const stampsByAddressQueryOptions = {
+ staleTime: Infinity,
+ cacheTime: Infinity,
+} as const;
+
+async function fetchStampsByAddress(address: string): Promise {
+ return fetch(`https://stampchain.io/api/stamps?wallet_address=${address}`).then(res =>
+ res.json()
+ );
+}
+
+type FetchStampsByAddressResp = Awaited>;
+
+export function useStampsByAddressQuery(
+ address: string,
+ options?: AppUseQueryConfig
+) {
+ return useQuery({
+ queryKey: [QueryPrefixes.StampsByAddress],
+ queryFn: () => fetchStampsByAddress(address),
+ ...stampsByAddressQueryOptions,
+ ...options,
+ });
+}
diff --git a/src/app/query/query-prefixes.ts b/src/app/query/query-prefixes.ts
index ecfb64f0..bcb04c8f 100644
--- a/src/app/query/query-prefixes.ts
+++ b/src/app/query/query-prefixes.ts
@@ -12,4 +12,5 @@ export enum QueryPrefixes {
GetNftMetadata = 'get-nft-metadata',
StampCollection = 'stamp-collection',
+ StampsByAddress = 'stamps-by-address',
}