@meddleware/dao-ui 0.1.5 → 0.1.7

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meddleware/dao-ui",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
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",
@@ -3,7 +3,7 @@ import { getSuiClient } from '../wallet.js'
3
3
  import { PACKAGE_ID } from '../config.js'
4
4
 
5
5
  export interface DaoEvent {
6
- type: 'AccessMinted' | 'AccessConsumed' | 'GateCreated' | 'AccessBurned'
6
+ type: 'AccessMinted' | 'AccessConsumed' | 'AccessBurned'
7
7
  txDigest: string
8
8
  checkpoint: string | null
9
9
  address?: string
@@ -24,7 +24,6 @@ export function useDaoEvents(limit = 20) {
24
24
  const eventTypes = [
25
25
  `${PACKAGE_ID}::access_gate::AccessMintedEvent`,
26
26
  `${PACKAGE_ID}::access_gate::AccessConsumedEvent`,
27
- `${PACKAGE_ID}::access_gate::GateCreatedEvent`,
28
27
  ]
29
28
 
30
29
  const results = await Promise.allSettled(
@@ -41,7 +40,6 @@ export function useDaoEvents(limit = 20) {
41
40
  const label =
42
41
  typeName === 'AccessMintedEvent' ? 'AccessMinted'
43
42
  : typeName === 'AccessConsumedEvent' ? 'AccessConsumed'
44
- : typeName === 'GateCreatedEvent' ? 'GateCreated'
45
43
  : 'AccessBurned'
46
44
  const f = (e.json ?? {}) as Record<string, unknown>
47
45
  all.push({
@@ -1,6 +1,6 @@
1
1
  import { ref, onMounted } from 'vue'
2
2
  import { getSuiClient } from '../wallet.js'
3
- import { PACKAGE_ID } from '../config.js'
3
+ import { PACKAGE_ID, CONFIG_ID } from '../config.js'
4
4
 
5
5
  export interface Gate {
6
6
  id: string
@@ -8,8 +8,6 @@ export interface Gate {
8
8
  price: bigint
9
9
  paused: boolean
10
10
  frozen: boolean
11
- txDigest: string
12
- checkpoint: string | null
13
11
  }
14
12
 
15
13
  export function useGates() {
@@ -18,28 +16,53 @@ export function useGates() {
18
16
  const error = ref<string | null>(null)
19
17
 
20
18
  async function load() {
21
- if (!PACKAGE_ID) return
19
+ if (!PACKAGE_ID || !CONFIG_ID) return
22
20
  loading.value = true
23
21
  error.value = null
24
22
  try {
25
23
  const client = getSuiClient()
26
- const events = await client.listEvents({
27
- filter: { eventType: `${PACKAGE_ID}::access_gate::GateCreatedEvent` },
28
- limit: 50,
29
- order: 'descending',
30
- })
31
- gates.value = events.events.map((e) => {
32
- const f = (e.json ?? {}) as Record<string, unknown>
33
- return {
34
- id: String(f.gate_id ?? ''),
35
- name: String(f.nft_name ?? 'Unnamed Gate'),
36
- price: BigInt(String(f.price ?? '0')),
37
- paused: false,
38
- frozen: false,
39
- txDigest: e.transactionDigest,
40
- checkpoint: e.checkpoint ?? null,
41
- }
24
+
25
+ // Get treasury address from PlatformConfig so we know whose AdminCaps to look for.
26
+ // This is resilient to event pruning (the GateCreatedEvent is pruned on testnet
27
+ // after ~3 months, making event-based discovery unreliable).
28
+ const configRes = await client.getObject({ objectId: CONFIG_ID, include: { json: true } })
29
+ const configFields = configRes.object?.json as Record<string, unknown> | null
30
+ const treasury = configFields?.treasury as string | undefined
31
+ if (!treasury) {
32
+ gates.value = []
33
+ return
34
+ }
35
+
36
+ // List AdminCap objects owned by treasury — one per gate the treasury controls.
37
+ const { objects } = await client.listOwnedObjects({
38
+ owner: treasury,
39
+ type: `${PACKAGE_ID}::access_gate::AdminCap`,
40
+ include: { json: true },
42
41
  })
42
+
43
+ // Fetch each Gate shared object referenced by the AdminCap's gate_id.
44
+ const gateList = await Promise.all(
45
+ (objects ?? []).map(async (o: any): Promise<Gate | null> => {
46
+ const capFields = o?.json ?? o?.object?.json
47
+ const gateId = String(capFields?.gate_id ?? '')
48
+ if (!gateId || gateId === 'undefined') return null
49
+ try {
50
+ const gateRes = await client.getObject({ objectId: gateId, include: { json: true } })
51
+ const f = gateRes.object?.json as Record<string, unknown> | null
52
+ if (!f) return null
53
+ return {
54
+ id: gateId,
55
+ name: String(f.nft_name ?? 'Unnamed Gate'),
56
+ price: BigInt(String(f.price_mist ?? '0')),
57
+ paused: Boolean(f.paused),
58
+ frozen: Boolean(f.frozen),
59
+ }
60
+ } catch {
61
+ return null
62
+ }
63
+ }),
64
+ )
65
+ gates.value = gateList.filter((g): g is Gate => g !== null)
43
66
  } catch (e) {
44
67
  error.value = e instanceof Error ? e.message : String(e)
45
68
  } finally {
@@ -22,7 +22,6 @@ function nextPage() { if (page.value < totalPages.value) page.value++ }
22
22
  const eventLabel: Record<DaoEvent['type'], string> = {
23
23
  AccessMinted: 'Access Sold',
24
24
  AccessConsumed: 'Access Used',
25
- GateCreated: 'Gate Created',
26
25
  AccessBurned: 'Access Burned',
27
26
  }
28
27
 
@@ -61,7 +60,6 @@ const eventLabel: Record<DaoEvent['type'], string> = {
61
60
  class="dao-badge"
62
61
  :class="{
63
62
  'dao-badge--active': ev.type === 'AccessMinted',
64
- 'dao-badge--pending': ev.type === 'GateCreated',
65
63
  'dao-badge--closed': ev.type === 'AccessConsumed' || ev.type === 'AccessBurned',
66
64
  }"
67
65
  >{{ eventLabel[ev.type] }}</span>
@@ -18,7 +18,6 @@ const { gates, loading: gatesLoading } = useGates()
18
18
  const eventLabel: Record<DaoEvent['type'], string> = {
19
19
  AccessMinted: 'Access sold',
20
20
  AccessConsumed: 'Access used',
21
- GateCreated: 'Gate created',
22
21
  AccessBurned: 'Access burned',
23
22
  }
24
23
 
@@ -53,18 +53,11 @@ function formatPrice(mist: bigint): string {
53
53
  <template #head>
54
54
  <th>Gate name</th>
55
55
  <th>Price</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>
60
56
  <th>Object ID</th>
61
57
  </template>
62
58
  <tr v-for="gate in gates" :key="gate.id">
63
59
  <td>{{ gate.name }}</td>
64
60
  <td class="dao-amount">{{ formatPrice(gate.price) }}</td>
65
- <td class="dao-mono" style="font-size: 0.72rem">
66
- {{ gate.checkpoint ? '#' + gate.checkpoint : '—' }}
67
- </td>
68
61
  <td class="dao-mono" style="font-size: 0.7rem; white-space: nowrap">
69
62
  <CopyableAddress :address="gate.id" label="Copy object ID">
70
63
  <ExplorerLink :href="suiExplorerUrl('object', gate.id, NETWORK)" :value="gate.id" />