@meddleware/dao-ui 0.1.3 → 0.1.5
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/package.json +2 -2
- package/src/composables/useDaoEvents.ts +8 -2
- package/src/composables/useGates.ts +2 -2
- package/src/styles/qt.css +30 -0
- package/src/tabs/GovernanceTab.vue +82 -22
- package/src/tabs/HistoryTab.vue +47 -23
- package/src/tabs/OverviewTab.vue +9 -8
- package/src/tabs/TreasuryTab.vue +21 -21
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meddleware/dao-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Meddleware DAO console — treasury overview, proposals, and governance on Sui.",
|
|
5
5
|
"author": "Meddleware <dev@meddleware.co.uk>",
|
|
6
6
|
"license": "0BSD",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@meddleware/design-tokens": "^0.1.2",
|
|
43
|
-
"@meddleware/ui": "^0.1.
|
|
43
|
+
"@meddleware/ui": "^0.1.11",
|
|
44
44
|
"@meddleware/wallet-adapter": "^0.0.5",
|
|
45
45
|
"@mysten/sui": "^2.30.0",
|
|
46
46
|
"vue": "^3.5.40"
|
|
@@ -53,8 +53,14 @@ export function useDaoEvents(limit = 20) {
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
//
|
|
57
|
-
|
|
56
|
+
// Sort globally by checkpoint descending so the merged list is newest-first across all types.
|
|
57
|
+
all.sort((a, b) => {
|
|
58
|
+
const ca = BigInt(a.checkpoint ?? '0')
|
|
59
|
+
const cb = BigInt(b.checkpoint ?? '0')
|
|
60
|
+
if (cb > ca) return 1
|
|
61
|
+
if (cb < ca) return -1
|
|
62
|
+
return 0
|
|
63
|
+
})
|
|
58
64
|
events.value = all.slice(0, limit)
|
|
59
65
|
lastRefresh.value = new Date()
|
|
60
66
|
} catch (e) {
|
|
@@ -9,7 +9,7 @@ export interface Gate {
|
|
|
9
9
|
paused: boolean
|
|
10
10
|
frozen: boolean
|
|
11
11
|
txDigest: string
|
|
12
|
-
|
|
12
|
+
checkpoint: string | null
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export function useGates() {
|
|
@@ -37,7 +37,7 @@ export function useGates() {
|
|
|
37
37
|
paused: false,
|
|
38
38
|
frozen: false,
|
|
39
39
|
txDigest: e.transactionDigest,
|
|
40
|
-
|
|
40
|
+
checkpoint: e.checkpoint ?? null,
|
|
41
41
|
}
|
|
42
42
|
})
|
|
43
43
|
} catch (e) {
|
package/src/styles/qt.css
CHANGED
|
@@ -322,6 +322,36 @@
|
|
|
322
322
|
font-size: 0.72rem;
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
+
/* ── Info tooltip marker ─────────────────────────────────────────────────── */
|
|
326
|
+
|
|
327
|
+
.dao-info {
|
|
328
|
+
display: inline-flex;
|
|
329
|
+
align-items: center;
|
|
330
|
+
justify-content: center;
|
|
331
|
+
width: 13px;
|
|
332
|
+
height: 13px;
|
|
333
|
+
border-radius: 50%;
|
|
334
|
+
border: 1px solid var(--muted);
|
|
335
|
+
color: var(--muted);
|
|
336
|
+
font-size: 0.58rem;
|
|
337
|
+
font-weight: 700;
|
|
338
|
+
font-style: normal;
|
|
339
|
+
cursor: help;
|
|
340
|
+
vertical-align: middle;
|
|
341
|
+
margin-left: 3px;
|
|
342
|
+
text-decoration: none;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/* ── Pagination ──────────────────────────────────────────────────────────── */
|
|
346
|
+
|
|
347
|
+
.dao-pagination {
|
|
348
|
+
display: flex;
|
|
349
|
+
align-items: center;
|
|
350
|
+
gap: 10px;
|
|
351
|
+
justify-content: center;
|
|
352
|
+
margin-top: 10px;
|
|
353
|
+
}
|
|
354
|
+
|
|
325
355
|
/* ── Misc ────────────────────────────────────────────────────────────────── */
|
|
326
356
|
|
|
327
357
|
.dao-mono {
|
|
@@ -1,19 +1,52 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed } from 'vue'
|
|
2
|
+
import { ref, watch, computed } from 'vue'
|
|
3
3
|
import Panel from '../components/Panel.vue'
|
|
4
4
|
import { usePlatformConfig } from '../composables/usePlatformConfig.js'
|
|
5
|
+
import { useWallet, getSuiClient } from '../wallet.js'
|
|
6
|
+
import { PACKAGE_ID } from '../config.js'
|
|
7
|
+
import { CopyableAddress, ExplorerLink, suiExplorerUrl } from '@meddleware/ui'
|
|
8
|
+
import { NETWORK } from '../config.js'
|
|
5
9
|
|
|
6
10
|
const { config } = usePlatformConfig()
|
|
11
|
+
const { account } = useWallet()
|
|
7
12
|
|
|
8
13
|
const commissionPct = computed(() =>
|
|
9
14
|
config.value ? (config.value.commissionBps / 100).toFixed(2) + '%' : '—',
|
|
10
15
|
)
|
|
16
|
+
|
|
17
|
+
type CapState = 'idle' | 'checking' | 'found' | 'not-found' | 'error'
|
|
18
|
+
const capState = ref<CapState>('idle')
|
|
19
|
+
|
|
20
|
+
async function checkCaps(address: string) {
|
|
21
|
+
if (!PACKAGE_ID) { capState.value = 'not-found'; return }
|
|
22
|
+
capState.value = 'checking'
|
|
23
|
+
try {
|
|
24
|
+
const client = getSuiClient()
|
|
25
|
+
const res = await client.listOwnedObjects({
|
|
26
|
+
owner: address,
|
|
27
|
+
type: `${PACKAGE_ID}::access_gate::PlatformAdminCap`,
|
|
28
|
+
limit: 1,
|
|
29
|
+
})
|
|
30
|
+
capState.value = res.objects.length > 0 ? 'found' : 'not-found'
|
|
31
|
+
} catch {
|
|
32
|
+
capState.value = 'error'
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
watch(
|
|
37
|
+
() => account.value?.address,
|
|
38
|
+
(addr) => {
|
|
39
|
+
if (addr) void checkCaps(addr)
|
|
40
|
+
else capState.value = 'idle'
|
|
41
|
+
},
|
|
42
|
+
{ immediate: true },
|
|
43
|
+
)
|
|
11
44
|
</script>
|
|
12
45
|
|
|
13
46
|
<template>
|
|
14
47
|
<div style="display: flex; flex-direction: column; gap: 10px">
|
|
15
|
-
<Panel title="
|
|
16
|
-
<div class="dao-stat-grid" style="max-width:
|
|
48
|
+
<Panel title="Platform Parameters">
|
|
49
|
+
<div class="dao-stat-grid" style="max-width: 480px">
|
|
17
50
|
<span class="dao-stat-grid__label">Commission rate</span>
|
|
18
51
|
<span class="dao-stat-grid__value dao-mono">{{ commissionPct }}</span>
|
|
19
52
|
|
|
@@ -21,34 +54,61 @@ const commissionPct = computed(() =>
|
|
|
21
54
|
<span class="dao-stat-grid__value dao-mono">10.00% (1000 bps — on-chain hard cap)</span>
|
|
22
55
|
|
|
23
56
|
<span class="dao-stat-grid__label">Treasury address</span>
|
|
24
|
-
<span
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
57
|
+
<span class="dao-stat-grid__value" style="text-align: left">
|
|
58
|
+
<CopyableAddress v-if="config?.treasury" :address="config.treasury">
|
|
59
|
+
<ExplorerLink :href="suiExplorerUrl('account', config.treasury, NETWORK)" :value="config.treasury" />
|
|
60
|
+
</CopyableAddress>
|
|
61
|
+
<span v-else class="dao-mono" style="font-size: 0.7rem">—</span>
|
|
29
62
|
</span>
|
|
30
63
|
</div>
|
|
31
64
|
|
|
32
65
|
<p class="dao-muted" style="margin: 10px 0 0; font-size: 0.72rem">
|
|
33
66
|
Parameters are governed by <code>PlatformAdminCap</code> on-chain.
|
|
34
|
-
Commission is
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
</Panel>
|
|
38
|
-
|
|
39
|
-
<Panel title="Vault DAO Parameters">
|
|
40
|
-
<p class="dao-muted" style="margin: 0; font-size: 0.78rem">
|
|
41
|
-
DAO-governed vault parameters (skim fee, buyback ratio, allocation caps, fee recipients)
|
|
42
|
-
will appear here when <code>vault_config</code> and <code>vault_dao</code> are deployed.
|
|
67
|
+
Commission is charged on every NFT access purchase:
|
|
68
|
+
<code>commission_bps / 10000 × price</code> routes to treasury;
|
|
69
|
+
the remainder goes to the gate operator.
|
|
43
70
|
</p>
|
|
44
71
|
</Panel>
|
|
45
72
|
|
|
46
73
|
<Panel title="Admin Actions">
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
<
|
|
50
|
-
|
|
51
|
-
|
|
74
|
+
<!-- Not connected -->
|
|
75
|
+
<template v-if="!account">
|
|
76
|
+
<p class="dao-muted" style="margin: 0; font-size: 0.78rem">
|
|
77
|
+
Connect a wallet via the header to manage platform settings.
|
|
78
|
+
</p>
|
|
79
|
+
</template>
|
|
80
|
+
|
|
81
|
+
<!-- Connected, checking -->
|
|
82
|
+
<template v-else-if="capState === 'checking'">
|
|
83
|
+
<p class="dao-muted" style="margin: 0; font-size: 0.78rem">
|
|
84
|
+
Checking capabilities for {{ account.address.slice(0, 10) }}…
|
|
85
|
+
</p>
|
|
86
|
+
</template>
|
|
87
|
+
|
|
88
|
+
<!-- Connected, has PlatformAdminCap -->
|
|
89
|
+
<template v-else-if="capState === 'found'">
|
|
90
|
+
<p class="dao-muted" style="margin: 0 0 8px; font-size: 0.78rem">
|
|
91
|
+
<span style="color: var(--ok)">●</span>
|
|
92
|
+
<code>PlatformAdminCap</code> detected. Admin controls will appear here when implemented.
|
|
93
|
+
</p>
|
|
94
|
+
</template>
|
|
95
|
+
|
|
96
|
+
<!-- Connected, no cap -->
|
|
97
|
+
<template v-else-if="capState === 'not-found'">
|
|
98
|
+
<p class="dao-muted" style="margin: 0; font-size: 0.78rem">
|
|
99
|
+
<span>●</span>
|
|
100
|
+
Connected: {{ account.address.slice(0, 10) }}…{{ account.address.slice(-6) }}<br>
|
|
101
|
+
This wallet does not hold <code>PlatformAdminCap</code> or <code>DaoAdminCap</code>.
|
|
102
|
+
Privileged actions are not available.
|
|
103
|
+
</p>
|
|
104
|
+
</template>
|
|
105
|
+
|
|
106
|
+
<!-- Error -->
|
|
107
|
+
<template v-else-if="capState === 'error'">
|
|
108
|
+
<p class="dao-muted" style="margin: 0; font-size: 0.78rem">
|
|
109
|
+
Unable to verify capabilities. Check your connection and try again.
|
|
110
|
+
</p>
|
|
111
|
+
</template>
|
|
52
112
|
</Panel>
|
|
53
113
|
</div>
|
|
54
114
|
</template>
|
package/src/tabs/HistoryTab.vue
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { ref, computed } from 'vue'
|
|
2
3
|
import DataTable from '../components/DataTable.vue'
|
|
3
4
|
import { useDaoEvents } from '../composables/useDaoEvents.js'
|
|
5
|
+
import { CopyableAddress, ExplorerLink, suiExplorerUrl } from '@meddleware/ui'
|
|
6
|
+
import { NETWORK } from '../config.js'
|
|
4
7
|
import type { DaoEvent } from '../composables/useDaoEvents.js'
|
|
5
8
|
|
|
6
|
-
const { events, loading, error, reload } = useDaoEvents(
|
|
9
|
+
const { events, loading, error, reload } = useDaoEvents(200)
|
|
10
|
+
|
|
11
|
+
const PAGE_SIZE = 20
|
|
12
|
+
const page = ref(1)
|
|
13
|
+
|
|
14
|
+
const totalPages = computed(() => Math.max(1, Math.ceil(events.value.length / PAGE_SIZE)))
|
|
15
|
+
const pageEvents = computed(() =>
|
|
16
|
+
events.value.slice((page.value - 1) * PAGE_SIZE, page.value * PAGE_SIZE),
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
function prevPage() { if (page.value > 1) page.value-- }
|
|
20
|
+
function nextPage() { if (page.value < totalPages.value) page.value++ }
|
|
7
21
|
|
|
8
22
|
const eventLabel: Record<DaoEvent['type'], string> = {
|
|
9
23
|
AccessMinted: 'Access Sold',
|
|
@@ -12,18 +26,6 @@ const eventLabel: Record<DaoEvent['type'], string> = {
|
|
|
12
26
|
AccessBurned: 'Access Burned',
|
|
13
27
|
}
|
|
14
28
|
|
|
15
|
-
function shortCkpt(ckpt: string | null): string {
|
|
16
|
-
return ckpt ? `ckpt ${ckpt}` : '—'
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function shortAddr(addr: string | undefined): string {
|
|
20
|
-
if (!addr || addr === 'undefined') return '—'
|
|
21
|
-
return addr.slice(0, 10) + '…' + addr.slice(-6)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function explorerUrl(digest: string): string {
|
|
25
|
-
return `https://suiscan.xyz/testnet/tx/${digest}`
|
|
26
|
-
}
|
|
27
29
|
</script>
|
|
28
30
|
|
|
29
31
|
<template>
|
|
@@ -37,14 +39,23 @@ function explorerUrl(digest: string): string {
|
|
|
37
39
|
|
|
38
40
|
<p v-if="error" class="dao-muted">{{ error }}</p>
|
|
39
41
|
|
|
40
|
-
<DataTable v-if="
|
|
42
|
+
<DataTable v-if="pageEvents.length || loading" :empty="'No events'">
|
|
41
43
|
<template #head>
|
|
42
44
|
<th>Type</th>
|
|
43
|
-
<th>
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
<th>
|
|
46
|
+
Address
|
|
47
|
+
<abbr class="dao-info" title="The wallet address associated with this event (recipient, creator, or initiator depending on event type). Click to view in explorer; click the copy icon to copy the full address.">?</abbr>
|
|
48
|
+
</th>
|
|
49
|
+
<th>
|
|
50
|
+
Block
|
|
51
|
+
<abbr class="dao-info" title="Sui checkpoint sequence number — equivalent to a block height in other blockchains. Each checkpoint finalizes a batch of transactions; higher numbers are more recent.">?</abbr>
|
|
52
|
+
</th>
|
|
53
|
+
<th>
|
|
54
|
+
Transaction
|
|
55
|
+
<abbr class="dao-info" title="Transaction digest — a unique identifier for the transaction that emitted this event. Click to view in explorer; click the copy icon to copy the full digest.">?</abbr>
|
|
56
|
+
</th>
|
|
46
57
|
</template>
|
|
47
|
-
<tr v-for="ev in
|
|
58
|
+
<tr v-for="ev in pageEvents" :key="ev.txDigest">
|
|
48
59
|
<td>
|
|
49
60
|
<span
|
|
50
61
|
class="dao-badge"
|
|
@@ -55,15 +66,28 @@ function explorerUrl(digest: string): string {
|
|
|
55
66
|
}"
|
|
56
67
|
>{{ eventLabel[ev.type] }}</span>
|
|
57
68
|
</td>
|
|
58
|
-
<td class="dao-mono" style="font-size: 0.72rem
|
|
59
|
-
|
|
69
|
+
<td class="dao-mono" style="font-size: 0.72rem; white-space: nowrap">
|
|
70
|
+
<CopyableAddress v-if="ev.address && ev.address !== 'undefined'" :address="ev.address">
|
|
71
|
+
<ExplorerLink :href="suiExplorerUrl('account', ev.address, NETWORK)" :value="ev.address" />
|
|
72
|
+
</CopyableAddress>
|
|
73
|
+
<span v-else>—</span>
|
|
74
|
+
</td>
|
|
60
75
|
<td class="dao-mono" style="font-size: 0.72rem">
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
76
|
+
{{ ev.checkpoint ? '#' + ev.checkpoint : '—' }}
|
|
77
|
+
</td>
|
|
78
|
+
<td class="dao-mono" style="font-size: 0.72rem; white-space: nowrap">
|
|
79
|
+
<CopyableAddress :address="ev.txDigest" label="Copy transaction">
|
|
80
|
+
<ExplorerLink :href="suiExplorerUrl('txblock', ev.txDigest, NETWORK)" :value="ev.txDigest" />
|
|
81
|
+
</CopyableAddress>
|
|
64
82
|
</td>
|
|
65
83
|
</tr>
|
|
66
84
|
</DataTable>
|
|
67
85
|
<p v-else-if="!loading" class="dao-placeholder">No events found.</p>
|
|
86
|
+
|
|
87
|
+
<div v-if="totalPages > 1" class="dao-pagination">
|
|
88
|
+
<button class="dao-toolbar__btn" :disabled="page === 1" @click="prevPage">← Prev</button>
|
|
89
|
+
<span class="dao-muted" style="font-size: 0.78rem">Page {{ page }} / {{ totalPages }}</span>
|
|
90
|
+
<button class="dao-toolbar__btn" :disabled="page === totalPages" @click="nextPage">Next →</button>
|
|
91
|
+
</div>
|
|
68
92
|
</div>
|
|
69
93
|
</template>
|
package/src/tabs/OverviewTab.vue
CHANGED
|
@@ -6,12 +6,14 @@ import { usePlatformConfig } from '../composables/usePlatformConfig.js'
|
|
|
6
6
|
import { useTreasury } from '../composables/useTreasury.js'
|
|
7
7
|
import { useDaoEvents } from '../composables/useDaoEvents.js'
|
|
8
8
|
import { useGates } from '../composables/useGates.js'
|
|
9
|
+
import { CopyableAddress, ExplorerLink, suiExplorerUrl } from '@meddleware/ui'
|
|
10
|
+
import { NETWORK } from '../config.js'
|
|
9
11
|
import type { DaoEvent } from '../composables/useDaoEvents.js'
|
|
10
12
|
|
|
11
13
|
const { config } = usePlatformConfig()
|
|
12
14
|
const { balance } = useTreasury(() => config.value?.treasury ?? null)
|
|
13
15
|
const { events, loading: eventsLoading } = useDaoEvents(12)
|
|
14
|
-
const { gates } = useGates()
|
|
16
|
+
const { gates, loading: gatesLoading } = useGates()
|
|
15
17
|
|
|
16
18
|
const eventLabel: Record<DaoEvent['type'], string> = {
|
|
17
19
|
AccessMinted: 'Access sold',
|
|
@@ -41,12 +43,11 @@ const accessesConsumed = computed(() => events.value.filter((e) => e.type === 'A
|
|
|
41
43
|
<span class="dao-stat-grid__value dao-mono">{{ commissionPct }}</span>
|
|
42
44
|
|
|
43
45
|
<span class="dao-stat-grid__label">Treasury address</span>
|
|
44
|
-
<span
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
{{ config?.treasury ? config.treasury.slice(0, 10) + '…' + config.treasury.slice(-6) : '—' }}
|
|
46
|
+
<span class="dao-stat-grid__value" style="text-align: left">
|
|
47
|
+
<CopyableAddress v-if="config?.treasury" :address="config.treasury">
|
|
48
|
+
<ExplorerLink :href="suiExplorerUrl('account', config.treasury, NETWORK)" :value="config.treasury" />
|
|
49
|
+
</CopyableAddress>
|
|
50
|
+
<span v-else class="dao-mono" style="font-size: 0.7rem">—</span>
|
|
50
51
|
</span>
|
|
51
52
|
</div>
|
|
52
53
|
</Panel>
|
|
@@ -54,7 +55,7 @@ const accessesConsumed = computed(() => events.value.filter((e) => e.type === 'A
|
|
|
54
55
|
<Panel title="Platform Activity">
|
|
55
56
|
<div class="dao-stat-grid">
|
|
56
57
|
<span class="dao-stat-grid__label">Active gates</span>
|
|
57
|
-
<span class="dao-stat-grid__value dao-mono">{{
|
|
58
|
+
<span class="dao-stat-grid__value dao-mono">{{ gatesLoading ? '…' : gates.length }}</span>
|
|
58
59
|
|
|
59
60
|
<span class="dao-stat-grid__label">Accesses minted</span>
|
|
60
61
|
<span class="dao-stat-grid__value dao-mono">{{ accessesMinted || '—' }}</span>
|
package/src/tabs/TreasuryTab.vue
CHANGED
|
@@ -6,6 +6,8 @@ import DataTable from '../components/DataTable.vue'
|
|
|
6
6
|
import { usePlatformConfig } from '../composables/usePlatformConfig.js'
|
|
7
7
|
import { useTreasury } from '../composables/useTreasury.js'
|
|
8
8
|
import { useGates } from '../composables/useGates.js'
|
|
9
|
+
import { CopyableAddress, ExplorerLink, suiExplorerUrl } from '@meddleware/ui'
|
|
10
|
+
import { NETWORK } from '../config.js'
|
|
9
11
|
|
|
10
12
|
const { config, loading: cfgLoading, error: cfgErr } = usePlatformConfig()
|
|
11
13
|
const { balance } = useTreasury(() => config.value?.treasury ?? null)
|
|
@@ -19,15 +21,11 @@ function formatPrice(mist: bigint): string {
|
|
|
19
21
|
const n = Number(mist) / 1e9
|
|
20
22
|
return n >= 0.0001 ? n.toFixed(4) + ' SUI' : n.toFixed(9).replace(/0+$/, '') + ' SUI'
|
|
21
23
|
}
|
|
22
|
-
|
|
23
|
-
function shortDate(ms: number): string {
|
|
24
|
-
return ms ? new Date(ms).toISOString().slice(0, 10) : '—'
|
|
25
|
-
}
|
|
26
24
|
</script>
|
|
27
25
|
|
|
28
26
|
<template>
|
|
29
27
|
<div style="display: flex; flex-direction: column; gap: 10px">
|
|
30
|
-
<Panel title="
|
|
28
|
+
<Panel title="Treasury">
|
|
31
29
|
<p v-if="cfgLoading" class="dao-muted">Loading…</p>
|
|
32
30
|
<p v-else-if="cfgErr" class="dao-muted">{{ cfgErr }}</p>
|
|
33
31
|
<template v-else-if="config">
|
|
@@ -35,40 +33,42 @@ function shortDate(ms: number): string {
|
|
|
35
33
|
<span class="dao-stat-grid__label">Commission rate</span>
|
|
36
34
|
<span class="dao-stat-grid__value dao-mono">{{ commissionPct }} ({{ config.commissionBps }} bps)</span>
|
|
37
35
|
|
|
38
|
-
<span class="dao-stat-grid__label">Treasury address</span>
|
|
39
|
-
<span class="dao-stat-grid__value dao-mono" style="font-size: 0.72rem; text-align: left; word-break: break-all">
|
|
40
|
-
{{ config.treasury }}
|
|
41
|
-
</span>
|
|
42
|
-
|
|
43
36
|
<span class="dao-stat-grid__label">Current balance</span>
|
|
44
37
|
<AmountCell class="dao-stat-grid__value" :mist="balance" />
|
|
38
|
+
|
|
39
|
+
<span class="dao-stat-grid__label">Treasury address</span>
|
|
40
|
+
<span class="dao-stat-grid__value" style="text-align: left">
|
|
41
|
+
<CopyableAddress :address="config.treasury">
|
|
42
|
+
<ExplorerLink :href="suiExplorerUrl('account', config.treasury, NETWORK)" :value="config.treasury" />
|
|
43
|
+
</CopyableAddress>
|
|
44
|
+
</span>
|
|
45
45
|
</div>
|
|
46
46
|
</template>
|
|
47
47
|
<p v-else class="dao-muted">PlatformConfig not loaded.</p>
|
|
48
48
|
</Panel>
|
|
49
49
|
|
|
50
|
-
<Panel title="Fee Distribution">
|
|
51
|
-
<p class="dao-muted" style="margin: 0; font-size: 0.78rem">
|
|
52
|
-
Fee distributor data (buyback/burn ratios, distribution history) will appear here when
|
|
53
|
-
<code>vault_fee_distributor</code> is deployed.
|
|
54
|
-
</p>
|
|
55
|
-
</Panel>
|
|
56
|
-
|
|
57
50
|
<Panel title="Community Gates">
|
|
58
51
|
<p v-if="gatesLoading" class="dao-muted">Loading gates…</p>
|
|
59
52
|
<DataTable v-else-if="gates.length" :empty="'No gates found'">
|
|
60
53
|
<template #head>
|
|
61
54
|
<th>Gate name</th>
|
|
62
55
|
<th>Price</th>
|
|
63
|
-
<th>
|
|
56
|
+
<th>
|
|
57
|
+
Block
|
|
58
|
+
<abbr class="dao-info" title="Sui checkpoint sequence number at which this gate was created. Equivalent to a block height in other blockchains.">?</abbr>
|
|
59
|
+
</th>
|
|
64
60
|
<th>Object ID</th>
|
|
65
61
|
</template>
|
|
66
62
|
<tr v-for="gate in gates" :key="gate.id">
|
|
67
63
|
<td>{{ gate.name }}</td>
|
|
68
64
|
<td class="dao-amount">{{ formatPrice(gate.price) }}</td>
|
|
69
|
-
<td class="dao-mono" style="font-size: 0.72rem">
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
<td class="dao-mono" style="font-size: 0.72rem">
|
|
66
|
+
{{ gate.checkpoint ? '#' + gate.checkpoint : '—' }}
|
|
67
|
+
</td>
|
|
68
|
+
<td class="dao-mono" style="font-size: 0.7rem; white-space: nowrap">
|
|
69
|
+
<CopyableAddress :address="gate.id" label="Copy object ID">
|
|
70
|
+
<ExplorerLink :href="suiExplorerUrl('object', gate.id, NETWORK)" :value="gate.id" />
|
|
71
|
+
</CopyableAddress>
|
|
72
72
|
</td>
|
|
73
73
|
</tr>
|
|
74
74
|
</DataTable>
|