@visualizevalue/mint-app-base 0.1.47 → 0.1.49
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.
- package/app.config.ts +12 -0
- package/components/CodeEditor.client.vue +49 -0
- package/components/Collection/Actions.vue +19 -0
- package/components/Collection/Intro.vue +1 -12
- package/components/Embed.vue +33 -0
- package/components/Form/Group.vue +1 -1
- package/components/Form/SelectFile.vue +4 -0
- package/components/Icon.vue +1 -0
- package/components/Mint/Action.client.vue +51 -0
- package/components/Mint/Detail.client.vue +49 -0
- package/components/Mint/Preview.client.vue +58 -0
- package/components/Mint/Renderer/Base.client.vue +107 -0
- package/components/Mint/Renderer/P5.client.vue +67 -0
- package/components/Mint/SelectRenderer.client.vue +52 -0
- package/components/Page/Frame.vue +1 -0
- package/components/Renderer/InstallButton.vue +62 -0
- package/components/Renderer/InstallCustom.client.vue +91 -0
- package/components/Renderer/Overview.client.vue +75 -0
- package/components/Renderer/OverviewCard.vue +32 -0
- package/components/Tabs.vue +37 -0
- package/components/Token/Detail.client.vue +2 -1
- package/components/Token/OverviewCard.vue +2 -1
- package/components/TransactionFlow.vue +5 -3
- package/composables/collections.ts +50 -4
- package/composables/createMint.ts +155 -0
- package/index.d.ts +11 -0
- package/nuxt.config.ts +1 -1
- package/package.json +4 -1
- package/pages/[id]/[collection]/mint.vue +5 -240
- package/pages/[id]/[collection]/renderers.vue +43 -0
- package/utils/abis.ts +6 -1
- package/utils/p5Script.ts +33 -0
- package/utils/types.ts +13 -2
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<article class="install-custom-renderer">
|
|
3
|
+
<h1>Add Custom Renderer</h1>
|
|
4
|
+
<FormInput v-model="rendererAddressInput" placeholder="0x..." />
|
|
5
|
+
|
|
6
|
+
<Loading v-if="loading" />
|
|
7
|
+
<RendererOverviewCard
|
|
8
|
+
v-else-if="rendererAddress && rendererName"
|
|
9
|
+
:renderer="renderer"
|
|
10
|
+
>
|
|
11
|
+
<template #after>
|
|
12
|
+
<RendererInstallButton
|
|
13
|
+
:collection="collection"
|
|
14
|
+
:renderer="renderer"
|
|
15
|
+
#after
|
|
16
|
+
/>
|
|
17
|
+
</template>
|
|
18
|
+
</RendererOverviewCard>
|
|
19
|
+
</article>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<script setup>
|
|
23
|
+
const { $wagmi } = useNuxtApp()
|
|
24
|
+
const chainId = useMainChainId()
|
|
25
|
+
const { collection } = defineProps(['collection'])
|
|
26
|
+
|
|
27
|
+
const rendererAddressInput = ref(``)
|
|
28
|
+
const rendererAddress = ref()
|
|
29
|
+
const rendererName = ref()
|
|
30
|
+
const rendererVersion = ref()
|
|
31
|
+
|
|
32
|
+
const renderer = computed(() => ({
|
|
33
|
+
address: rendererAddress.value,
|
|
34
|
+
name: rendererName.value,
|
|
35
|
+
version: rendererVersion.value,
|
|
36
|
+
}))
|
|
37
|
+
|
|
38
|
+
watch(rendererAddressInput, () => {
|
|
39
|
+
if (isAddress(rendererAddressInput.value)) {
|
|
40
|
+
rendererAddress.value = rendererAddressInput.value
|
|
41
|
+
} else {
|
|
42
|
+
rendererAddress.value = ``
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const loading = ref(false)
|
|
47
|
+
watch(rendererAddress, async () => {
|
|
48
|
+
if (! rendererAddress.value) {
|
|
49
|
+
rendererName.value = ''
|
|
50
|
+
rendererVersion.value = null
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
loading.value = true
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
const rendererArgs = {
|
|
58
|
+
abi: RENDERER_ABI,
|
|
59
|
+
address: rendererAddress.value,
|
|
60
|
+
chainId
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const [name, version] = await Promise.all([
|
|
64
|
+
await readContract($wagmi, {
|
|
65
|
+
...rendererArgs,
|
|
66
|
+
functionName: 'name',
|
|
67
|
+
}),
|
|
68
|
+
await readContract($wagmi, {
|
|
69
|
+
...rendererArgs,
|
|
70
|
+
functionName: 'version',
|
|
71
|
+
}),
|
|
72
|
+
])
|
|
73
|
+
|
|
74
|
+
rendererName.value = name
|
|
75
|
+
rendererVersion.value = version
|
|
76
|
+
} catch (e) {
|
|
77
|
+
console.error(e)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
loading.value = false
|
|
81
|
+
})
|
|
82
|
+
</script>
|
|
83
|
+
|
|
84
|
+
<style scoped>
|
|
85
|
+
.install-custom-renderer {
|
|
86
|
+
padding: var(--spacer);
|
|
87
|
+
border: var(--border);
|
|
88
|
+
display: grid;
|
|
89
|
+
gap: var(--spacer);
|
|
90
|
+
}
|
|
91
|
+
</style>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<section class="renderers" id="installed-renderers">
|
|
3
|
+
<h1>Installed Renderers</h1>
|
|
4
|
+
|
|
5
|
+
<div>
|
|
6
|
+
<RendererOverviewCard
|
|
7
|
+
v-for="renderer of installedRenderers"
|
|
8
|
+
:renderer="renderer"
|
|
9
|
+
/>
|
|
10
|
+
</div>
|
|
11
|
+
</section>
|
|
12
|
+
|
|
13
|
+
<section class="renderers" id="available-renderers">
|
|
14
|
+
<h1>Available Renderers</h1>
|
|
15
|
+
|
|
16
|
+
<div v-if="availableRenderers.length">
|
|
17
|
+
<RendererOverviewCard
|
|
18
|
+
v-for="renderer of availableRenderers"
|
|
19
|
+
:renderer="renderer"
|
|
20
|
+
>
|
|
21
|
+
<template #after>
|
|
22
|
+
<div class="actions">
|
|
23
|
+
<RendererInstallButton
|
|
24
|
+
:collection="collection"
|
|
25
|
+
:renderer="renderer"
|
|
26
|
+
/>
|
|
27
|
+
</div>
|
|
28
|
+
</template>
|
|
29
|
+
</RendererOverviewCard>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<div v-if="! availableRenderers.length" class="empty">
|
|
33
|
+
<p>All known Renderers installed</p>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<RendererInstallCustom :collection="collection" />
|
|
37
|
+
</section>
|
|
38
|
+
</template>
|
|
39
|
+
|
|
40
|
+
<script setup>
|
|
41
|
+
const props = defineProps(['collection'])
|
|
42
|
+
|
|
43
|
+
const appConfig = useAppConfig()
|
|
44
|
+
const store = useOnchainStore()
|
|
45
|
+
|
|
46
|
+
const installedRenderers = computed(() => props.collection.renderers)
|
|
47
|
+
|
|
48
|
+
const availableRenderers = computed(
|
|
49
|
+
() => appConfig.knownRenderers.filter(r =>
|
|
50
|
+
!installedRenderers.value.map(cr => cr.address).includes(r.address)
|
|
51
|
+
)
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
onMounted(() => {
|
|
55
|
+
store.fetchCollectionRenderers(props.collection.address)
|
|
56
|
+
})
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<style scoped>
|
|
60
|
+
.renderers {
|
|
61
|
+
display: grid;
|
|
62
|
+
gap: var(--spacer);
|
|
63
|
+
overflow-x: hidden;
|
|
64
|
+
|
|
65
|
+
> h1 {
|
|
66
|
+
font-size: var(--font-lg);
|
|
67
|
+
border-bottom: var(--border);
|
|
68
|
+
padding-bottom: var(--size-2);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.empty {
|
|
72
|
+
color: var(--muted);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
</style>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<article class="renderer-overview-card">
|
|
3
|
+
<div class="details">
|
|
4
|
+
<h1>{{ renderer.name }} <small>v{{ renderer.version }}</small></h1>
|
|
5
|
+
<p v-if="renderer.description">{{ renderer.description }}</p>
|
|
6
|
+
<p class="address">{{ renderer.address }}</p>
|
|
7
|
+
</div>
|
|
8
|
+
<slot name="after" />
|
|
9
|
+
</article>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script setup>
|
|
13
|
+
const { renderer } = defineProps(['renderer'])
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<style scoped>
|
|
17
|
+
article {
|
|
18
|
+
display: flex;
|
|
19
|
+
gap: var(--spacer);
|
|
20
|
+
align-items: center;
|
|
21
|
+
justify-content: space-between;
|
|
22
|
+
padding: var(--spacer-sm);
|
|
23
|
+
|
|
24
|
+
&:not(:last-child) {
|
|
25
|
+
border-bottom: var(--border);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.address {
|
|
29
|
+
color: var(--muted);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
</style>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<menu class="tabs">
|
|
3
|
+
<slot name="menu" :active="active" :select="select" />
|
|
4
|
+
</menu>
|
|
5
|
+
|
|
6
|
+
<section class="tabs-content">
|
|
7
|
+
<slot name="content" :active="active" />
|
|
8
|
+
</section>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup>
|
|
12
|
+
const props = defineProps(['initial'])
|
|
13
|
+
|
|
14
|
+
const active = ref(props.initial)
|
|
15
|
+
const select = k => active.value = k
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<style>
|
|
19
|
+
.tabs {
|
|
20
|
+
border-bottom: var(--border);
|
|
21
|
+
padding: 0 var(--size-1);
|
|
22
|
+
margin: 0;
|
|
23
|
+
display: flex;
|
|
24
|
+
gap: var(--size-1);
|
|
25
|
+
|
|
26
|
+
> Button {
|
|
27
|
+
/* border-bottom-color: transparent; */
|
|
28
|
+
margin-bottom: calc(-1 * var(--border-width));
|
|
29
|
+
|
|
30
|
+
&.active {
|
|
31
|
+
border-color: var(--border-color);
|
|
32
|
+
border-bottom-color: var(--background);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
</style>
|
|
37
|
+
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
<article class="token-detail">
|
|
3
3
|
<div class="artifact">
|
|
4
4
|
<div>
|
|
5
|
-
<
|
|
5
|
+
<Embed v-if="token.animationUrl" :src="token.animationUrl" />
|
|
6
|
+
<Image v-else-if="token.image" :src="token.image" :alt="token.name" />
|
|
6
7
|
<ImageVoid v-else />
|
|
7
8
|
</div>
|
|
8
9
|
</div>
|
|
@@ -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
|
-
<
|
|
35
|
+
<Embed v-if="token.animationUrl" :src="token.animationUrl" />
|
|
36
|
+
<Image v-else-if="token.image" :src="token.image" :alt="token.name" />
|
|
36
37
|
<ImageVoid v-else />
|
|
37
38
|
<CardLink :to="{
|
|
38
39
|
name: 'id-collection-tokenId',
|
|
@@ -34,10 +34,8 @@
|
|
|
34
34
|
</template>
|
|
35
35
|
|
|
36
36
|
<script setup>
|
|
37
|
-
import { useChainId } from '@wagmi/vue'
|
|
38
37
|
import { waitForTransactionReceipt, watchChainId } from '@wagmi/core'
|
|
39
38
|
const checkChain = useEnsureChainIdCheck()
|
|
40
|
-
const chainId = useChainId()
|
|
41
39
|
|
|
42
40
|
const { $wagmi } = useNuxtApp()
|
|
43
41
|
const config = useRuntimeConfig()
|
|
@@ -83,6 +81,9 @@ watchChainId($wagmi, {
|
|
|
83
81
|
}
|
|
84
82
|
})
|
|
85
83
|
|
|
84
|
+
const cachedRequest = ref(props.request)
|
|
85
|
+
watch(props, () => { cachedRequest.value = props.request })
|
|
86
|
+
|
|
86
87
|
const requesting = ref(false)
|
|
87
88
|
const waiting = ref(false)
|
|
88
89
|
const complete = ref(false)
|
|
@@ -121,7 +122,8 @@ const step = computed(() => {
|
|
|
121
122
|
return 'error'
|
|
122
123
|
})
|
|
123
124
|
|
|
124
|
-
const initializeRequest = async (request =
|
|
125
|
+
const initializeRequest = async (request = cachedRequest.value) => {
|
|
126
|
+
cachedRequest.value = request
|
|
125
127
|
complete.value = false
|
|
126
128
|
open.value = true
|
|
127
129
|
error.value = ''
|
|
@@ -3,7 +3,7 @@ import { type GetBalanceReturnType } from '@wagmi/core'
|
|
|
3
3
|
import { parseAbiItem, type PublicClient } from 'viem'
|
|
4
4
|
import type { MintEvent } from '~/utils/types'
|
|
5
5
|
|
|
6
|
-
export const CURRENT_STATE_VERSION =
|
|
6
|
+
export const CURRENT_STATE_VERSION = 6
|
|
7
7
|
export const MAX_BLOCK_RANGE = 1800n
|
|
8
8
|
export const MINT_BLOCKS = BLOCKS_PER_DAY
|
|
9
9
|
|
|
@@ -220,6 +220,7 @@ export const useOnchainStore = () => {
|
|
|
220
220
|
owner: artist,
|
|
221
221
|
tokens: {},
|
|
222
222
|
balance: balance.value,
|
|
223
|
+
renderers: [],
|
|
223
224
|
})
|
|
224
225
|
},
|
|
225
226
|
|
|
@@ -228,6 +229,47 @@ export const useOnchainStore = () => {
|
|
|
228
229
|
this.collections[address].balance = balance.value
|
|
229
230
|
},
|
|
230
231
|
|
|
232
|
+
async fetchCollectionRenderers (address: `0x${string}`) {
|
|
233
|
+
const renderers = this.collections[address].renderers
|
|
234
|
+
|
|
235
|
+
let index = renderers.length
|
|
236
|
+
while (true) {
|
|
237
|
+
try {
|
|
238
|
+
const rendererAddress = await readContract($wagmi, {
|
|
239
|
+
abi: MINT_ABI,
|
|
240
|
+
address,
|
|
241
|
+
functionName: 'renderers',
|
|
242
|
+
args: [BigInt(index)],
|
|
243
|
+
chainId,
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
const rendererArgs = { abi: RENDERER_ABI, address: rendererAddress, chainId }
|
|
247
|
+
|
|
248
|
+
const [name, version] = await Promise.all([
|
|
249
|
+
await readContract($wagmi, {
|
|
250
|
+
...rendererArgs,
|
|
251
|
+
functionName: 'name',
|
|
252
|
+
}),
|
|
253
|
+
await readContract($wagmi, {
|
|
254
|
+
...rendererArgs,
|
|
255
|
+
functionName: 'version',
|
|
256
|
+
}),
|
|
257
|
+
])
|
|
258
|
+
|
|
259
|
+
this.collections[address].renderers.push({
|
|
260
|
+
address: rendererAddress.toLowerCase() as `0x${string}`,
|
|
261
|
+
name,
|
|
262
|
+
version,
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
index ++
|
|
266
|
+
} catch (e) {
|
|
267
|
+
console.info(`Stopped parsing renderers ${e.shortMessage || e.message}`)
|
|
268
|
+
return
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
|
|
231
273
|
async fetchCollectionTokens (address: `0x${string}`): Promise<Token[]> {
|
|
232
274
|
this.collections[address].latestTokenId = await readContract($wagmi, {
|
|
233
275
|
abi: MINT_ABI,
|
|
@@ -278,7 +320,7 @@ export const useOnchainStore = () => {
|
|
|
278
320
|
console.info(`Fetching token #${tokenId}`)
|
|
279
321
|
|
|
280
322
|
const [data, untilBlock] = await Promise.all([
|
|
281
|
-
mintContract.read.uri([tokenId], { gas:
|
|
323
|
+
mintContract.read.uri([tokenId], { gas: 100_000_000_000 }) as Promise<string>,
|
|
282
324
|
mintContract.read.mintOpenUntil([tokenId]) as Promise<bigint>,
|
|
283
325
|
])
|
|
284
326
|
|
|
@@ -290,7 +332,9 @@ export const useOnchainStore = () => {
|
|
|
290
332
|
collection: address,
|
|
291
333
|
name: metadata.name,
|
|
292
334
|
description: metadata.description,
|
|
293
|
-
|
|
335
|
+
image: metadata.image,
|
|
336
|
+
animationUrl: metadata.animation_url,
|
|
337
|
+
scriptUrl: metadata.script_url,
|
|
294
338
|
untilBlock,
|
|
295
339
|
mintsBackfilledUntilBlock: 0n,
|
|
296
340
|
mintsFetchedUntilBlock: 0n,
|
|
@@ -298,7 +342,9 @@ export const useOnchainStore = () => {
|
|
|
298
342
|
}
|
|
299
343
|
|
|
300
344
|
this.collections[address].tokens[`${token.tokenId}`] = token
|
|
301
|
-
} catch (e) {
|
|
345
|
+
} catch (e) {
|
|
346
|
+
console.error(e)
|
|
347
|
+
}
|
|
302
348
|
},
|
|
303
349
|
|
|
304
350
|
async fetchTokenBalance (token: Token, address: `0x${string}`) {
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import type { TransactionReceipt } from "viem"
|
|
2
|
+
|
|
3
|
+
// Base token data
|
|
4
|
+
const name = ref('')
|
|
5
|
+
const artifact = ref('')
|
|
6
|
+
const description = ref('')
|
|
7
|
+
|
|
8
|
+
// Derived data based on artifact // renderer
|
|
9
|
+
const image = ref('')
|
|
10
|
+
const animationUrl = ref('')
|
|
11
|
+
|
|
12
|
+
// Renderer data
|
|
13
|
+
const renderer: Ref<number> = ref(0)
|
|
14
|
+
const extraData: Ref<bigint> = ref(0n)
|
|
15
|
+
|
|
16
|
+
// Main token creation composable
|
|
17
|
+
export const useCreateMintData = () => {
|
|
18
|
+
// Reset the creation form values
|
|
19
|
+
const reset = () => {
|
|
20
|
+
name.value = ''
|
|
21
|
+
artifact.value = ''
|
|
22
|
+
description.value = ''
|
|
23
|
+
|
|
24
|
+
image.value = ''
|
|
25
|
+
animationUrl.value = ''
|
|
26
|
+
|
|
27
|
+
extraData.value = 0n
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
name,
|
|
32
|
+
artifact,
|
|
33
|
+
description,
|
|
34
|
+
image,
|
|
35
|
+
animationUrl,
|
|
36
|
+
renderer,
|
|
37
|
+
extraData,
|
|
38
|
+
|
|
39
|
+
reset,
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Expose the mint component based on the selected renderer
|
|
44
|
+
export const useCreateMintRendererComponent = (collection: Collection) => {
|
|
45
|
+
const appConfig = useAppConfig()
|
|
46
|
+
const rendererAddress: Ref<string | null> = computed(() => {
|
|
47
|
+
if (! collection.renderers?.length) return null
|
|
48
|
+
|
|
49
|
+
return collection.renderers[renderer.value].address.toLowerCase()
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
const component = computed(() => appConfig.knownRenderers
|
|
53
|
+
.find((r: Renderer) => r.address.toLowerCase() === rendererAddress.value)?.component || 'Base'
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
component,
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Token creation flow
|
|
62
|
+
export const useCreateMintFlow = (collection: Collection, txFlow: Ref) => {
|
|
63
|
+
const { $wagmi } = useNuxtApp()
|
|
64
|
+
const id = useArtistId()
|
|
65
|
+
const chainId = useMainChainId()
|
|
66
|
+
const store = useOnchainStore()
|
|
67
|
+
|
|
68
|
+
// Mint flow
|
|
69
|
+
const txFlowKey = ref(0)
|
|
70
|
+
const mint = async () => {
|
|
71
|
+
if (! artifact.value) {
|
|
72
|
+
alert(`Empty artifact data. Please try again.`)
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const artifactByteArray = toByteArray(artifact.value)
|
|
77
|
+
const artifactChunks = chunkArray(artifactByteArray, 4)
|
|
78
|
+
const multiTransactionPrepare = artifactChunks.length > 1
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
if (multiTransactionPrepare) {
|
|
82
|
+
if (! confirm(`Due to the large artifact size, we have to split it into ${artifactChunks.length} chunks and store them in separate transactions. You will be prompted with multiple transaction requests before minting the final token.`)) {
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// On the first iteration we want to clear existing artifact data
|
|
87
|
+
let clearExisting = true
|
|
88
|
+
|
|
89
|
+
for (const chunk of artifactChunks) {
|
|
90
|
+
await txFlow.value.initializeRequest(() => writeContract($wagmi, {
|
|
91
|
+
abi: MINT_ABI,
|
|
92
|
+
chainId,
|
|
93
|
+
address: collection.address,
|
|
94
|
+
functionName: 'prepareArtifact',
|
|
95
|
+
args: [
|
|
96
|
+
collection.latestTokenId + 1n,
|
|
97
|
+
chunk,
|
|
98
|
+
clearExisting
|
|
99
|
+
],
|
|
100
|
+
}))
|
|
101
|
+
|
|
102
|
+
// Make sure to rerender the tx flow component
|
|
103
|
+
txFlowKey.value ++
|
|
104
|
+
|
|
105
|
+
// On following iterations we want to keep existing artifact data
|
|
106
|
+
clearExisting = false
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
await txFlow.value.initializeRequest(() => writeContract($wagmi, {
|
|
111
|
+
abi: MINT_ABI,
|
|
112
|
+
chainId,
|
|
113
|
+
address: collection.address,
|
|
114
|
+
functionName: 'create',
|
|
115
|
+
args: [
|
|
116
|
+
name.value,
|
|
117
|
+
description.value,
|
|
118
|
+
multiTransactionPrepare ? [] : artifactByteArray,
|
|
119
|
+
renderer.value,
|
|
120
|
+
0n, // Additional Data
|
|
121
|
+
],
|
|
122
|
+
}))
|
|
123
|
+
} catch (e) {
|
|
124
|
+
console.error(e)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// On created
|
|
129
|
+
const mintCreated = async (receipt: TransactionReceipt) => {
|
|
130
|
+
const logs = receipt.logs.map(log => decodeEventLog({
|
|
131
|
+
abi: MINT_ABI,
|
|
132
|
+
data: log.data,
|
|
133
|
+
topics: log.topics,
|
|
134
|
+
strict: false,
|
|
135
|
+
}))
|
|
136
|
+
|
|
137
|
+
const mintedEvent = logs.find(log => log.eventName === 'TransferSingle')
|
|
138
|
+
|
|
139
|
+
await store.fetchToken(collection.address, mintedEvent.args.id)
|
|
140
|
+
|
|
141
|
+
// Force update the collection mint ID
|
|
142
|
+
store.collections[collection.address].latestTokenId = mintedEvent.args.id
|
|
143
|
+
|
|
144
|
+
await navigateTo({
|
|
145
|
+
name: 'id-collection-tokenId',
|
|
146
|
+
params: { id: id.value, collection: collection.address, tokenId: mintedEvent.args.id }
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
mint,
|
|
152
|
+
mintCreated,
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Renderer } from './utils/types'
|
|
2
|
+
|
|
3
|
+
declare module 'nuxt/schema' {
|
|
4
|
+
interface AppConfigInput {
|
|
5
|
+
// Known renderers besides the base renderer
|
|
6
|
+
knownRenderers: Renderer[],
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// It is always important to ensure you import/export something when augmenting a type
|
|
11
|
+
export {}
|
package/nuxt.config.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@visualizevalue/mint-app-base",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.49",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./nuxt.config.ts",
|
|
6
6
|
"dependencies": {
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
"@wagmi/core": "^2.13.5",
|
|
15
15
|
"@wagmi/vue": "^0.0.40",
|
|
16
16
|
"buffer": "^6.0.3",
|
|
17
|
+
"codemirror": "^5",
|
|
18
|
+
"codemirror-editor-vue3": "^2.8.0",
|
|
17
19
|
"multiformats": "^13.2.2",
|
|
18
20
|
"postcss-custom-media": "^10.0.6",
|
|
19
21
|
"postcss-custom-selectors": "^7.1.10",
|
|
@@ -25,6 +27,7 @@
|
|
|
25
27
|
"@visualizevalue/mint-utils": "^0.0.3"
|
|
26
28
|
},
|
|
27
29
|
"devDependencies": {
|
|
30
|
+
"@types/codemirror": "^5.60.15",
|
|
28
31
|
"nuxt": "^3.13.2",
|
|
29
32
|
"typescript": "^5.5.4"
|
|
30
33
|
},
|