@visualizevalue/mint-app-base 0.1.42 → 0.1.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@
2
2
  /* GRAYS */
3
3
  --white: white;
4
4
  --gray: gray;
5
- --black: rgb(0, 0, 0);
5
+ --black: black;
6
6
 
7
7
  /* COLORS */
8
8
  --primary: blue;
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <svg viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
3
+ <rect width="64" height="64" fill="var(--black)"/>
4
+ </svg>
5
+ </template>
@@ -70,7 +70,7 @@
70
70
  </td>
71
71
  <td>
72
72
  {{ artistPercentage }}%
73
- <MintGasPrice v-slot="{ dollarPrice }" :mint-count="amount">
73
+ <MintGasPrice v-slot="{ dollarPrice }" :mint-count="parseInt(amount)">
74
74
  <span>(${{ dollarPrice }})</span>
75
75
  </MintGasPrice>
76
76
  </td>
@@ -81,10 +81,7 @@ const mintRequest = computed(() => async () => {
81
81
  })
82
82
 
83
83
  const minted = async () => {
84
- await Promise.all([
85
- store.fetchTokenBalance(props.token, address.value),
86
- // store.fetchTokenMints(props.token),
87
- ])
84
+ await store.fetchTokenBalance(props.token, address.value)
88
85
 
89
86
  emit('minted')
90
87
  }
@@ -2,7 +2,8 @@
2
2
  <article class="token-detail">
3
3
  <div class="artifact">
4
4
  <div>
5
- <Image :src="token.artifact" :alt="token.name" />
5
+ <Image v-if="token.artifact" :src="token.artifact" :alt="token.name" />
6
+ <ImageVoid v-else />
6
7
  </div>
7
8
  </div>
8
9
 
@@ -10,13 +10,13 @@
10
10
  :key="mint.tx"
11
11
  :block="currentBlock"
12
12
  />
13
- <TokenMintTimelineItem v-if="! loading || mints.length">
13
+ <TokenMintTimelineItem v-if="backfillComplete">
14
14
  <Account :address="collection.owner" class="account" />
15
15
 
16
16
  <span class="amount">1<span>×</span></span>
17
17
  <span class="price">Artist Mint</span>
18
18
 
19
- <span class="time-ago"><BlocksTimeAgo v-if="currentBlock" :blocks="currentBlock - (token.untilBlock - 7200n)" /></span>
19
+ <span class="time-ago"><BlocksTimeAgo v-if="currentBlock" :blocks="currentBlock - mintedAtBlock" /></span>
20
20
 
21
21
  <span class="links">
22
22
  <NuxtLink :to="`${config.public.blockExplorer}/nft/${token.collection}/${token.tokenId}`" target="_blank">
@@ -26,12 +26,17 @@
26
26
  </TokenMintTimelineItem>
27
27
  </div>
28
28
 
29
+ <div v-if="! backfillComplete" v-show="! loading" ref="loadMore" class="load-more">
30
+ <Button @click="backfill">Load more</Button>
31
+ </div>
32
+
29
33
  <Loading v-if="loading || ! currentBlock" txt="Mint History..." />
30
34
  </slot>
31
35
  </section>
32
36
  </template>
33
37
 
34
38
  <script setup>
39
+ import { useElementVisibility } from '@vueuse/core'
35
40
  import { useBlockNumber } from '@wagmi/vue'
36
41
 
37
42
  const config = useRuntimeConfig()
@@ -45,11 +50,14 @@ const { token, collection } = defineProps({
45
50
  const state = useOnchainStore()
46
51
 
47
52
  const mints = computed(() => state.tokenMints(token.collection, token.tokenId))
53
+ const mintedAtBlock = computed(() => token.untilBlock - MINT_BLOCKS)
54
+ const backfillComplete = computed(() => token.mintsBackfilledUntilBlock <= mintedAtBlock.value)
48
55
 
49
- const loading = ref(false)
56
+ const loading = ref(true)
50
57
  onMounted(async () => {
51
58
  loading.value = true
52
59
  try {
60
+ console.info(`Attempting to load + backfill token mints for #${token.tokenId}`)
53
61
  await state.fetchTokenMints(token)
54
62
  await state.backfillTokenMints(token)
55
63
  } catch (e) {
@@ -58,7 +66,25 @@ onMounted(async () => {
58
66
  loading.value = false
59
67
  })
60
68
 
61
- watch(currentBlock, () => state.fetchTokenMints(token))
69
+ watch(currentBlock, () => {
70
+ if (loading.value) return
71
+
72
+ state.fetchTokenMints(token)
73
+ })
74
+
75
+ const backfill = async () => {
76
+ loading.value = true
77
+ await state.backfillTokenMints(token)
78
+ loading.value = false
79
+ }
80
+
81
+ const loadMore = ref()
82
+ const loadMoreVisible = useElementVisibility(loadMore)
83
+ watch(loadMoreVisible, () => {
84
+ if (! loadMoreVisible.value) return
85
+
86
+ backfill()
87
+ })
62
88
  </script>
63
89
 
64
90
  <style scoped>
@@ -80,4 +106,11 @@ h1 {
80
106
  display: grid;
81
107
  gap: var(--spacer);
82
108
  }
109
+
110
+ .load-more {
111
+ .button {
112
+ display: block;
113
+ width: 100%;
114
+ }
115
+ }
83
116
  </style>
@@ -1,7 +1,9 @@
1
1
  <template>
2
2
  <div class="token-mint-timeline-item">
3
3
  <slot :mint="mint" :formatted-price="formattedPrice">
4
- <Account :address="mint.address" class="account" />
4
+ <NuxtLink :to="{ name: 'profile-address', params: { address: mint.address } }">
5
+ <Account :address="mint.address" class="account" />
6
+ </NuxtLink>
5
7
 
6
8
  <span class="amount">{{ mint.amount.toString() }}<span>×</span></span>
7
9
 
@@ -32,7 +32,8 @@
32
32
  <p v-if="mintOpen" class="closes-in">Closes in {{ blocksRemaining }} {{ pluralize('block', Number(blocksRemaining))}}</p>
33
33
  <p v-else class="closed-at">Closed at block {{ token.untilBlock }}</p>
34
34
  </header>
35
- <Image :src="token.artifact" :alt="token.name" />
35
+ <Image v-if="token.artifact" :src="token.artifact" :alt="token.name" />
36
+ <ImageVoid v-else />
36
37
  <CardLink :to="{
37
38
  name: 'id-collection-tokenId',
38
39
  params: { id: collection.owner, collection: token.collection, tokenId: `${token.tokenId}` }
@@ -1,9 +1,11 @@
1
1
  import { getBalance, getPublicClient, readContract } from '@wagmi/core'
2
2
  import { type GetBalanceReturnType } from '@wagmi/core'
3
- import { parseAbiItem } from 'viem'
4
- import type { MintEvent } from '~/app/utils/types'
3
+ import { parseAbiItem, type PublicClient } from 'viem'
4
+ import type { MintEvent } from '~/utils/types'
5
5
 
6
- export const CURRENT_STATE_VERSION = 3
6
+ export const CURRENT_STATE_VERSION = 4
7
+ export const MAX_BLOCK_RANGE = 2500n
8
+ export const MINT_BLOCKS = BLOCKS_PER_DAY
7
9
 
8
10
  export const useOnchainStore = () => {
9
11
  const { $wagmi } = useNuxtApp()
@@ -94,7 +96,7 @@ export const useOnchainStore = () => {
94
96
  },
95
97
 
96
98
  async fetchArtistProfile (address: `0x${string}`): Promise<Artist> {
97
- const client = getPublicClient($wagmi, { chainId: 1 })
99
+ const client = getPublicClient($wagmi, { chainId: 1 }) as PublicClient
98
100
  const block = await client.getBlockNumber()
99
101
 
100
102
  // Only update once per hour
@@ -149,7 +151,7 @@ export const useOnchainStore = () => {
149
151
  functionName: 'getCreatorCollections',
150
152
  args: [artist],
151
153
  chainId,
152
- })).map((a: `0x${string}`) => a.toLowerCase())
154
+ })).map((a: `0x${string}`) => a.toLowerCase() as `0x${string}`)
153
155
 
154
156
  if (this.artists[artist].collections.length === collectionAddresses.length) {
155
157
  console.info(`Collections fetched already (${collectionAddresses.length} collections)`)
@@ -318,67 +320,62 @@ export const useOnchainStore = () => {
318
320
  },
319
321
 
320
322
  async fetchTokenMints (token: Token) {
321
- const client = getPublicClient($wagmi)
323
+ const client = getPublicClient($wagmi) as PublicClient
324
+ const currentBlock = await client.getBlockNumber()
325
+ const mintedAtBlock = token.untilBlock - MINT_BLOCKS
326
+ const storedToken = this.collections[token.collection].tokens[token.tokenId.toString()]
322
327
 
323
- // We want to sync backwards from now
324
- const currentBlock = await client.getBlockNumber({ chainId })
325
-
326
- // Until when
328
+ // We want to sync until now, or when the mint closed
327
329
  const toBlock = currentBlock > token.untilBlock ? token.untilBlock : currentBlock
328
330
 
329
- if (token.mintsFetchedUntilBlock >= toBlock) return console.info(`token mints already fetched`)
330
-
331
- // From when
332
- const maxRangeBlock = toBlock - 5000n
333
- const mintedAtBlock = token.untilBlock - 7200n
334
- const fromBlock = token.mintsFetchedUntilBlock > maxRangeBlock
335
- ? token.mintsFetchedUntilBlock + 1n
336
- : maxRangeBlock > mintedAtBlock
337
- ? maxRangeBlock
338
- : mintedAtBlock
339
-
340
- // Load mints
341
- this.collections[token.collection].tokens[token.tokenId.toString()].mints = [
342
- ...await this.loadMintEvents(
343
- token,
344
- fromBlock,
345
- toBlock
346
- ),
347
- ...(this.collections[token.collection].tokens[token.tokenId.toString()].mints) || [],
348
- ]
331
+ if (token.mintsFetchedUntilBlock >= toBlock) {
332
+ return console.info(`mints for #${token.tokenId} already fetched`)
333
+ }
334
+
335
+ // Initially, we want to sync backwards,
336
+ // but at most 5000 blocks (the general max range for an event query)
337
+ const maxRangeBlock = toBlock - MAX_BLOCK_RANGE
338
+ const fromBlock = token.mintsFetchedUntilBlock > maxRangeBlock // If we've already fetched
339
+ ? token.mintsFetchedUntilBlock + 1n // we want to continue where we left off
340
+ : maxRangeBlock > mintedAtBlock // Otherwise we'll go back as far as possible
341
+ ? maxRangeBlock // (to our max range)
342
+ : mintedAtBlock // (or all the way to when the token minted)
349
343
 
350
- console.info(`Token mints fetched from ${fromBlock}-${toBlock}`)
344
+ // Load mints in range
345
+ this.addTokenMints(token, await this.loadMintEvents(token, fromBlock, toBlock))
351
346
 
352
347
  // Set sync status
353
- this.collections[token.collection].tokens[token.tokenId.toString()].mintsFetchedUntilBlock = toBlock
348
+ storedToken.mintsFetchedUntilBlock = toBlock
354
349
 
355
350
  // If this is our first fetch, mark until when we have backfilled
356
351
  if (! token.mintsBackfilledUntilBlock) {
357
- this.collections[token.collection].tokens[token.tokenId.toString()].mintsBackfilledUntilBlock = fromBlock
352
+ storedToken.mintsBackfilledUntilBlock = fromBlock
358
353
  }
359
354
  },
360
355
 
361
356
  async backfillTokenMints (token: Token) {
362
- const mintedAtBlock = token.untilBlock - 7200n
357
+ const mintedAtBlock = token.untilBlock - MINT_BLOCKS
358
+ const storedToken = this.collections[token.collection].tokens[token.tokenId.toString()]
363
359
 
364
- while (
365
- this.collections[token.collection].tokens[token.tokenId.toString()].mintsBackfilledUntilBlock > mintedAtBlock
366
- ) {
367
- const toBlock = this.collections[token.collection].tokens[token.tokenId.toString()].mintsBackfilledUntilBlock
368
- const fromBlock = toBlock - 5000n > mintedAtBlock ? toBlock - 5000n : mintedAtBlock
369
- console.log(`Backfilling token mints blocks ${fromBlock}-${toBlock}`)
360
+ // If we've backfilled all the way;
361
+ if (storedToken.mintsBackfilledUntilBlock <= mintedAtBlock) return
370
362
 
371
- this.collections[token.collection].tokens[token.tokenId.toString()].mints = [
372
- ...this.collections[token.collection].tokens[token.tokenId.toString()].mints,
373
- ...await this.loadMintEvents(token, fromBlock, toBlock)
374
- ]
363
+ // We want to fetch the tokens up until where we stopped backfilling (excluding the last block)
364
+ const toBlock = storedToken.mintsBackfilledUntilBlock - 1n
375
365
 
376
- this.collections[token.collection].tokens[token.tokenId.toString()].mintsBackfilledUntilBlock = fromBlock
377
- }
366
+ // We want to fetch until our max range (5000), or until when the token minted
367
+ const fromBlock = toBlock - MAX_BLOCK_RANGE > mintedAtBlock ? toBlock - MAX_BLOCK_RANGE : mintedAtBlock
368
+ console.log(`Backfilling token mints blocks ${fromBlock}-${toBlock}`)
369
+
370
+ // Finally, we update our database
371
+ this.addTokenMints(token, await this.loadMintEvents(token, fromBlock, toBlock), 'append')
372
+
373
+ // And save until when we have backfilled our tokens.
374
+ storedToken.mintsBackfilledUntilBlock = fromBlock
378
375
  },
379
376
 
380
- async loadMintEvents (token: Token, fromBlock: bigint, toBlock: bigint) {
381
- const client = getPublicClient($wagmi, { chainId })
377
+ async loadMintEvents (token: Token, fromBlock: bigint, toBlock: bigint): Promise<MintEvent[]> {
378
+ const client = getPublicClient($wagmi, { chainId }) as PublicClient
382
379
 
383
380
  const logs = await client.getLogs({
384
381
  address: token.collection,
@@ -390,6 +387,8 @@ export const useOnchainStore = () => {
390
387
  toBlock,
391
388
  })
392
389
 
390
+ console.info(`Token mints fetched from ${fromBlock}-${toBlock}`)
391
+
393
392
  return logs.map(l => ({
394
393
  tokenId: token.tokenId,
395
394
  address: l.args.minter,
@@ -398,8 +397,16 @@ export const useOnchainStore = () => {
398
397
  tx: l.transactionHash,
399
398
  unitPrice: l.args.unitPrice,
400
399
  amount: l.args.amount,
401
- price: l.args.amount * l.args.unitPrice,
402
- })).reverse()
400
+ price: ( l.args.amount || 0n ) * ( l.args.unitPrice || 0n ),
401
+ }) as MintEvent).reverse()
402
+ },
403
+
404
+ async addTokenMints (token: Token, mints: MintEvent[], location: 'prepend'|'append' = 'prepend') {
405
+ const storedToken = this.collections[token.collection].tokens[token.tokenId.toString()]
406
+
407
+ storedToken.mints = location === 'prepend'
408
+ ? [ ...mints, ...storedToken.mints ]
409
+ : [ ...storedToken.mints, ...mints ]
403
410
  },
404
411
 
405
412
  async addCollection (collection: Collection) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@visualizevalue/mint-app-base",
3
- "version": "0.1.42",
3
+ "version": "0.1.44",
4
4
  "type": "module",
5
5
  "main": "./nuxt.config.ts",
6
6
  "dependencies": {