Skip to content

Commit 2ac3586

Browse files
committed
Add NFT support
1 parent 7e235d7 commit 2ac3586

22 files changed

+673
-49
lines changed

src/App.vue

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,8 @@ const handleConnect = async (url: string) => {
8787
<RpcField v-if="!connected" :connectionError="connectionError" @connect="handleConnect" />
8888

8989
<div v-if="!connected">
90-
The app needs an archive node as a backend because of specific API calls.
91-
<code>https://api.securerpc.com/v1</code> and other non-archive nodes from the list below can
92-
still be used, but the functionality would become limited:<br />
90+
The app needs an archive node as a backend because of specific API calls.<br />
91+
Non-archive nodes from the list below can still be used, but the functionality would become limited:<br />
9392
<ul style="margin-top: 5px">
9493
<li>
9594
<a target="_blank" href="https://chainlist.org/chain/1">chainlist.org</a>

src/cache/address/address-storage.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
TokenBalance,
55
TransactionListItem,
66
UnspentWithUsd,
7+
NftLog,
78
} from '@/types';
89

910
export interface AddressStorage {
@@ -73,4 +74,10 @@ export interface AddressStorage {
7374
addFavoriteAddress(address: string): void;
7475
isFavoriteAddress(address: string): boolean;
7576
removeFavoriteAddress(address: string): void;
77+
78+
addAllNftLogs(logs: Map<string, NftLog[]>): void;
79+
getAllNftLogs(): Map<string, NftLog[]>;
80+
getNftLogs(address: string): NftLog[];
81+
addNftLogs(address: string, logs: NftLog[]): void;
82+
hasNftLogs(address: string): boolean;
7683
}

src/cache/address/address.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
TokenBalance,
55
TransactionListItem,
66
UnspentWithUsd,
7+
NftLog
78
} from '@/types';
89
import { MemoryAddressStorage } from '@/cache/address/memory-address-storage';
910
import { LocalStorageAddressStorage } from '@/cache/address/localstorage-address-storage';
@@ -58,6 +59,7 @@ export class AddressCache {
5859
to.addAllTokenCreator(from.getAllTokenCreator());
5960
to.addAllEns(from.getAllEns());
6061
to.addAllFavoriteAddresses(from.getFavoriteAddresses());
62+
to.addAllNftLogs(from.getAllNftLogs());
6163

6264
from.clearAll();
6365
}
@@ -257,4 +259,20 @@ export class AddressCache {
257259
removeFavoriteAddress(address: string): void {
258260
AddressCache.strategy.removeFavoriteAddress(address);
259261
}
262+
263+
/**
264+
* NFT Cache
265+
*/
266+
267+
getNftLogs(address: string): NftLog[] {
268+
return AddressCache.strategy.getNftLogs(address);
269+
}
270+
271+
addNftLogs(address: string, logs: NftLog[]): void {
272+
AddressCache.strategy.addNftLogs(address, logs);
273+
}
274+
275+
hasNftLogs(address: string): boolean {
276+
return AddressCache.strategy.hasNftLogs(address);
277+
}
260278
}

src/cache/address/localstorage-address-storage.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
TokenBalance,
55
TransactionListItem,
66
UnspentWithUsd,
7+
NftLog
78
} from '@/types';
89
import { type AddressStorage } from '@/cache/address/address-storage';
910
import { stringify, parse } from '@/utils/json';
@@ -75,6 +76,7 @@ export class LocalStorageAddressStorage implements AddressStorage {
7576
this.removeFromLocalStorage('tokenInfo');
7677
this.removeFromLocalStorage('tokenCreator');
7778
this.removeFromLocalStorage('ens');
79+
this.removeFromLocalStorage('nftLogs');
7880
}
7981

8082
// tokenTransfersTransactions is not cleared here (because we are not loading them from scratch later for optimization)
@@ -87,6 +89,7 @@ export class LocalStorageAddressStorage implements AddressStorage {
8789
tokenInfo,
8890
tokenCreator,
8991
ens,
92+
nftLogs
9093
} = this.getAllCachedData();
9194

9295
addresses.forEach((address) => {
@@ -97,6 +100,7 @@ export class LocalStorageAddressStorage implements AddressStorage {
97100
delete tokenInfo[address];
98101
delete tokenCreator[address];
99102
delete ens[address];
103+
delete nftLogs[address];
100104
});
101105

102106
this.saveToLocalStorage('tokens', tokens);
@@ -106,6 +110,7 @@ export class LocalStorageAddressStorage implements AddressStorage {
106110
this.saveToLocalStorage('tokenInfo', tokenInfo);
107111
this.saveToLocalStorage('tokenCreator', tokenCreator);
108112
this.saveToLocalStorage('ens', ens);
113+
this.saveToLocalStorage('nftLogs', nftLogs);
109114
}
110115

111116
clearFavorites(): void {
@@ -118,6 +123,7 @@ export class LocalStorageAddressStorage implements AddressStorage {
118123
tokenInfo,
119124
tokenCreator,
120125
ens,
126+
nftLogs
121127
} = this.getAllCachedData();
122128

123129
const favorites = this.getFavoriteAddresses();
@@ -131,6 +137,7 @@ export class LocalStorageAddressStorage implements AddressStorage {
131137
delete tokenInfo[address];
132138
delete tokenCreator[address];
133139
delete ens[address];
140+
delete nftLogs[address];
134141
});
135142

136143
this.saveToLocalStorage('tokens', tokens);
@@ -141,6 +148,7 @@ export class LocalStorageAddressStorage implements AddressStorage {
141148
this.saveToLocalStorage('tokenInfo', tokenInfo);
142149
this.saveToLocalStorage('tokenCreator', tokenCreator);
143150
this.saveToLocalStorage('ens', ens);
151+
this.saveToLocalStorage('nftLogs', nftLogs);
144152

145153
this.removeFromLocalStorage('favoriteAddresses');
146154
}
@@ -155,6 +163,7 @@ export class LocalStorageAddressStorage implements AddressStorage {
155163
tokenInfo,
156164
tokenCreator,
157165
ens,
166+
nftLogs
158167
} = this.getAllCachedData();
159168

160169
return Array.from(
@@ -167,6 +176,7 @@ export class LocalStorageAddressStorage implements AddressStorage {
167176
...Object.keys(tokenInfo),
168177
...Object.keys(tokenCreator),
169178
...Object.keys(ens),
179+
...Object.keys(nftLogs)
170180
])
171181
);
172182
}
@@ -180,6 +190,7 @@ export class LocalStorageAddressStorage implements AddressStorage {
180190
const tokenInfo = this.getFromLocalStorage('tokenInfo') ?? {};
181191
const tokenCreator = this.getFromLocalStorage('tokenCreator') ?? {};
182192
const ens = this.getFromLocalStorage('ens') ?? {};
193+
const nftLogs = this.getFromLocalStorage('nftLogs') ?? {};
183194

184195
return {
185196
tokens,
@@ -190,6 +201,7 @@ export class LocalStorageAddressStorage implements AddressStorage {
190201
tokenInfo,
191202
tokenCreator,
192203
ens,
204+
nftLogs
193205
};
194206
};
195207

@@ -512,4 +524,32 @@ export class LocalStorageAddressStorage implements AddressStorage {
512524
const updated = cached.filter((item: string) => item !== addr);
513525
this.saveToLocalStorage('favoriteAddresses', updated);
514526
}
527+
528+
/**
529+
* NFT Cache
530+
*/
531+
532+
addAllNftLogs(logs: Map<string, NftLog[]>): void {
533+
this.addAllUnitToCache('nftLogs', logs);
534+
}
535+
536+
getAllNftLogs(): Map<string, NftLog[]> {
537+
return this.getAllCachedUnitAsMap('nftLogs');
538+
}
539+
540+
getNftLogs(address: string): NftLog[] {
541+
const cached = this.getFromLocalStorage('nftLogs') ?? {};
542+
return cached[address] || [];
543+
}
544+
545+
addNftLogs(address: string, logs: NftLog[]): void {
546+
const cached = this.getFromLocalStorage('nftLogs') ?? {};
547+
cached[address] = logs;
548+
this.saveToLocalStorage('nftLogs', cached);
549+
}
550+
551+
hasNftLogs(address: string): boolean {
552+
const cached = this.getFromLocalStorage('nftLogs') ?? {};
553+
return address in cached;
554+
}
515555
}

src/cache/address/memory-address-storage.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
TokenBalance,
55
TransactionListItem,
66
UnspentWithUsd,
7+
NftLog
78
} from '@/types';
89
import { type AddressStorage } from '@/cache/address/address-storage';
910

@@ -22,6 +23,8 @@ export class MemoryAddressStorage implements AddressStorage {
2223

2324
private favoriteAddresses = new Set<string>();
2425

26+
private nftLogs: Map<string, NftLog[]> = new Map();
27+
2528
private constructor() {}
2629

2730
static getInstance(): MemoryAddressStorage {
@@ -49,6 +52,7 @@ export class MemoryAddressStorage implements AddressStorage {
4952
this.tokenInfo.clear();
5053
this.tokenCreator.clear();
5154
this.ens.clear();
55+
this.nftLogs.clear();
5256
}
5357

5458
// tokenTransfersTransactions is not cleared here (because we are not loading them from scratch later for optimization)
@@ -60,6 +64,7 @@ export class MemoryAddressStorage implements AddressStorage {
6064
this.tokenInfo.delete(address);
6165
this.tokenCreator.delete(address);
6266
this.ens.delete(address);
67+
this.nftLogs.delete(address);
6368
}
6469

6570
clearFavorites(): void {
@@ -72,6 +77,7 @@ export class MemoryAddressStorage implements AddressStorage {
7277
this.tokenInfo.delete(address);
7378
this.tokenCreator.delete(address);
7479
this.ens.delete(address);
80+
this.nftLogs.delete(address);
7581
});
7682
this.favoriteAddresses.clear();
7783
}
@@ -93,6 +99,7 @@ export class MemoryAddressStorage implements AddressStorage {
9399
...this.tokenInfo.keys(),
94100
...this.tokenCreator.keys(),
95101
...this.ens.keys(),
102+
...this.nftLogs.keys()
96103
])
97104
);
98105
}
@@ -351,4 +358,28 @@ export class MemoryAddressStorage implements AddressStorage {
351358
const addr = address.toLowerCase();
352359
this.favoriteAddresses.delete(addr);
353360
}
361+
362+
/**
363+
* NFT Cache
364+
*/
365+
366+
addAllNftLogs(nftLogs: Map<string, NftLog[]>): void {
367+
this.nftLogs = nftLogs;
368+
}
369+
370+
getAllNftLogs(): Map<string, NftLog[]> {
371+
return this.nftLogs;
372+
}
373+
374+
getNftLogs(address: string): NftLog[] {
375+
return this.nftLogs.get(address) || [];
376+
}
377+
378+
addNftLogs(address: string, logs: NftLog[]): void {
379+
this.nftLogs.set(address, logs);
380+
}
381+
382+
hasNftLogs(address: string): boolean {
383+
return this.nftLogs.has(address);
384+
}
354385
}

src/components/Breadcrumbs.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,14 @@ const addressBreadcrumb = (address: string) => {
7373
<template>
7474
<div v-if="$route.name !== 'main'" class="breadcrumbs">
7575
<span
76-
v-if="$route.name !== 'settings' && $route.name !== 'address' && $route.name !== 'sourcify'"
76+
v-if="$route.name !== 'settings' && $route.name !== 'address' && $route.name !== 'sourcify' && $route.name !== 'nft'"
7777
>
7878
/ {{ $route.name }} {{ pageHasParams ? '/' : '' }}
7979
{{ $route.params.tx?.length ? shortenTx($route.params.tx as string) : '' }}
8080
{{ $route.params.block?.length ? $route.params.block : '' }}
8181
</span>
8282

83-
<span v-if="$route.name === 'address' || $route.name === 'sourcify'">
83+
<span v-if="$route.name === 'address' || $route.name === 'sourcify' || $route.name === 'nft'">
8484
{{ $route.params.address?.length ? addressBreadcrumb($route.params.address as string) : '' }}
8585
</span>
8686

src/components/address-view/AddressHeader.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { shortenTx } from '@/utils/utils';
33
import type { TokenBalance, OtsGetContractCreatorResponse, ERC20TokenInfo } from '@/types';
44
import TokensList from '@/components/address-view/TokensList.vue';
55
import AddressHeaderAddrInfo from '@/components/address-view/AddressHeaderAddrInfo.vue';
6+
import NFTsList from '@/components/address-view/NFTsList.vue';
67
78
const emit = defineEmits(['updateData']);
89
@@ -23,6 +24,7 @@ const props = defineProps<{
2324
unspentPriceError: boolean;
2425
unspentError: boolean;
2526
isSourcify: boolean;
27+
isNFT: boolean;
2628
}>();
2729
2830
const handleUpdateData = (addresses: string[]) => {
@@ -41,6 +43,7 @@ const handleUpdateData = (addresses: string[]) => {
4143
:loadingUnspent="loadingUnspent"
4244
:unspentError="unspentError"
4345
:isSourcify="isSourcify"
46+
:isNFT="isNFT"
4447
@updateData="handleUpdateData"
4548
/>
4649
</div>
@@ -63,8 +66,10 @@ const handleUpdateData = (addresses: string[]) => {
6366
</RouterLink>
6467
</div>
6568

69+
<NFTsList v-if="isNFT" :address="address" />
70+
6671
<TokensList
67-
v-if="!isSourcify"
72+
v-if="!isSourcify && !isNFT"
6873
:unspentEth="sumBalance"
6974
:unspentEthUsd="unspentEthUsd"
7075
:tokens="tokens"

0 commit comments

Comments
 (0)