Skip to content

Commit ba4e704

Browse files
authored
fix(docs): correct Dune SQL to real Stellar schema (decode + partition) (#97)
The queries merged in #80 return zero rows against Dune: they filtered on JSON_EXTRACT_SCALAR(topics_decoded,'$[0]') (an ScVal object, never the event name) and read data_decoded as flat $.field (it's a type-wrapped ScVal map). Both silently yield null, so every dashboard panel is empty. Verified the real stellar.history_contract_events shapes on live Dune data and rewrote all 10 dune-queries/*.sql to: - filter the event name via topics_decoded '$[0].symbol' - decode fields by rebuilding data_decoded '$.map' into MAP(field -> ScVal JSON) with map_from_entries(), then reading each by ScVal type ($.u64, $.i128, $.address, $.string, $.vec[0].symbol) - add the closed_at_date partition filter (avoids full-table scans) - to_hex(transaction_hash) (it is varbinary) Every primitive was executed against live Soroban events on Dune. The one field that can't be checked without a real Boundless event — pillar's unit- enum encoding — is emitted as pillar_raw in the decode test for confirmation. Doc fixes: rewrote the §1 decoding reference; corrected the fee accounting (escrow holds the full budget, fee charged on top; fee revenue is not in the events); added the ManagerProposed/ManagerChanged/PendingManagerCancelled events (#88); pointed §4 at the canonical .sql files instead of duplicating now-corrected SQL inline.
1 parent 02153d4 commit ba4e704

11 files changed

Lines changed: 373 additions & 443 deletions

docs/dune-analytics.md

Lines changed: 69 additions & 249 deletions
Large diffs are not rendered by default.
Lines changed: 36 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,48 @@
11
-- Boundless On-chain: Current TVL
22
-- Panel type: counter
3-
-- Description: Total escrow balance currently held by the contract.
3+
-- Total escrow currently held by the contract = inflows - outflows.
44
--
5-
-- Real Dune column names (stellar.history_contract_events):
6-
-- topics_decoded VARCHAR — JSON array; index 0 is the event-name symbol
7-
-- data_decoded VARCHAR — JSON object with all event fields
5+
-- Decoding (see 10_event_created_decode_test.sql for the why):
6+
-- event name -> topics_decoded '$[0].symbol'
7+
-- fields -> rebuild data_decoded '$.map' into MAP(name -> ScVal JSON),
8+
-- then read each field by its ScVal type ($.i128, $.u64, ...).
89
--
9-
-- Inflows:
10-
-- EventCreated.total_budget (non-Crowdfunding pillars — escrowed at creation)
11-
-- FundsAdded.amount (partner top-ups and crowdfunding contributions)
12-
-- Outflows:
13-
-- WinnerPaid.amount (single-release payout at select_winners)
14-
-- MilestoneClaimed.amount (grant / crowdfunding milestone payout)
15-
-- ContributorRefunded.amount (partner refund during paged cancel)
16-
-- OwnerResidualRefunded.amount (owner residual at cancel)
17-
--
18-
-- All amounts are net-of-fee (protocol fee is deducted before events fire).
19-
-- Divide by 1e7 to convert from stroops to USDC / XLM display units.
10+
-- Inflows: EventCreated.total_budget (non-Crowdfunding — escrowed at creation)
11+
-- FundsAdded.amount (partner top-ups + crowdfunding contributions)
12+
-- Outflows: WinnerPaid.amount, MilestoneClaimed.amount,
13+
-- ContributorRefunded.amount, OwnerResidualRefunded.amount
14+
-- Amounts are the values the contract actually escrows/releases (the protocol
15+
-- fee is charged separately, not embedded here). Divide by 1e7 for display.
2016

21-
WITH inflows AS (
22-
-- Non-crowdfunding events: budget deposited at creation
23-
SELECT CAST(JSON_EXTRACT_SCALAR(data_decoded, '$.total_budget') AS DOUBLE) AS amount
17+
WITH ev AS (
18+
SELECT
19+
JSON_EXTRACT_SCALAR(topics_decoded, '$[0].symbol') AS ev_name,
20+
map_from_entries(
21+
transform(
22+
CAST(JSON_EXTRACT(data_decoded, '$.map') AS ARRAY(JSON)),
23+
e -> ROW(JSON_EXTRACT_SCALAR(e, '$.key.symbol'), JSON_EXTRACT(e, '$.val'))
24+
)
25+
) AS f
2426
FROM stellar.history_contract_events
2527
WHERE contract_id = '{{CONTRACT_ADDRESS}}'
26-
AND JSON_EXTRACT_SCALAR(topics_decoded, '$[0]') = 'EventCreated'
27-
AND JSON_EXTRACT_SCALAR(data_decoded, '$.pillar') != 'Crowdfunding'
28-
28+
AND closed_at_date >= DATE '{{START_DATE}}'
29+
AND data_decoded LIKE '%"map"%'
30+
),
31+
inflows AS (
32+
SELECT CAST(JSON_EXTRACT_SCALAR(f['total_budget'], '$.i128') AS DOUBLE) AS amount
33+
FROM ev
34+
WHERE ev_name = 'EventCreated'
35+
AND JSON_EXTRACT_SCALAR(f['pillar'], '$.vec[0].symbol') <> 'Crowdfunding'
2936
UNION ALL
30-
31-
-- All add_funds deposits (crowdfunding contributions + partner top-ups)
32-
SELECT CAST(JSON_EXTRACT_SCALAR(data_decoded, '$.amount') AS DOUBLE) AS amount
33-
FROM stellar.history_contract_events
34-
WHERE contract_id = '{{CONTRACT_ADDRESS}}'
35-
AND JSON_EXTRACT_SCALAR(topics_decoded, '$[0]') = 'FundsAdded'
37+
SELECT CAST(JSON_EXTRACT_SCALAR(f['amount'], '$.i128') AS DOUBLE)
38+
FROM ev
39+
WHERE ev_name = 'FundsAdded'
3640
),
3741
outflows AS (
38-
SELECT CAST(JSON_EXTRACT_SCALAR(data_decoded, '$.amount') AS DOUBLE) AS amount
39-
FROM stellar.history_contract_events
40-
WHERE contract_id = '{{CONTRACT_ADDRESS}}'
41-
AND JSON_EXTRACT_SCALAR(topics_decoded, '$[0]') IN (
42-
'WinnerPaid',
43-
'MilestoneClaimed',
44-
'ContributorRefunded',
45-
'OwnerResidualRefunded'
46-
)
42+
SELECT CAST(JSON_EXTRACT_SCALAR(f['amount'], '$.i128') AS DOUBLE) AS amount
43+
FROM ev
44+
WHERE ev_name IN ('WinnerPaid', 'MilestoneClaimed', 'ContributorRefunded', 'OwnerResidualRefunded')
4745
)
4846
SELECT
49-
(COALESCE(SUM(i.amount), 0) - COALESCE(SUM(o.amount), 0)) / 1e7 AS tvl_usdc
50-
FROM inflows i
51-
FULL OUTER JOIN outflows o ON 1 = 1
47+
(COALESCE((SELECT SUM(amount) FROM inflows), 0)
48+
- COALESCE((SELECT SUM(amount) FROM outflows), 0)) / 1e7 AS tvl_display
Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,57 @@
11
-- Boundless On-chain: TVL over time (daily running balance)
2-
-- Panel type: area chart x=day y=tvl_usdc
2+
-- Panel type: area chart x=day y=tvl_display
33
--
4-
-- topics_decoded: JSON array — index 0 is the event-name symbol
5-
-- data_decoded: JSON object — field values
4+
-- Decoding (see 10_event_created_decode_test.sql): event name is
5+
-- topics_decoded '$[0].symbol'; fields come from the data_decoded '$.map'
6+
-- ScVal map, read by type ($.i128, ...).
67

7-
WITH raw_events AS (
8+
WITH ev AS (
89
SELECT
910
DATE_TRUNC('day', closed_at) AS day,
11+
JSON_EXTRACT_SCALAR(topics_decoded, '$[0].symbol') AS ev_name,
12+
map_from_entries(
13+
transform(
14+
CAST(JSON_EXTRACT(data_decoded, '$.map') AS ARRAY(JSON)),
15+
e -> ROW(JSON_EXTRACT_SCALAR(e, '$.key.symbol'), JSON_EXTRACT(e, '$.val'))
16+
)
17+
) AS f
18+
FROM stellar.history_contract_events
19+
WHERE contract_id = '{{CONTRACT_ADDRESS}}'
20+
AND closed_at_date >= DATE '{{START_DATE}}'
21+
AND data_decoded LIKE '%"map"%'
22+
),
23+
signed AS (
24+
SELECT
25+
day,
1026
CASE
11-
-- Inflow: non-crowdfunding creation
12-
WHEN JSON_EXTRACT_SCALAR(topics_decoded, '$[0]') = 'EventCreated'
13-
AND JSON_EXTRACT_SCALAR(data_decoded, '$.pillar') != 'Crowdfunding'
14-
THEN CAST(JSON_EXTRACT_SCALAR(data_decoded, '$.total_budget') AS DOUBLE)
27+
-- Inflow: non-crowdfunding creation escrows the budget
28+
WHEN ev_name = 'EventCreated'
29+
AND JSON_EXTRACT_SCALAR(f['pillar'], '$.vec[0].symbol') <> 'Crowdfunding'
30+
THEN CAST(JSON_EXTRACT_SCALAR(f['total_budget'], '$.i128') AS DOUBLE)
1531

1632
-- Inflow: add_funds (crowdfunding + partner top-ups)
17-
WHEN JSON_EXTRACT_SCALAR(topics_decoded, '$[0]') = 'FundsAdded'
18-
THEN CAST(JSON_EXTRACT_SCALAR(data_decoded, '$.amount') AS DOUBLE)
33+
WHEN ev_name = 'FundsAdded'
34+
THEN CAST(JSON_EXTRACT_SCALAR(f['amount'], '$.i128') AS DOUBLE)
1935

20-
-- Outflow: winner / milestone payouts and refunds
21-
WHEN JSON_EXTRACT_SCALAR(topics_decoded, '$[0]') IN (
22-
'WinnerPaid', 'MilestoneClaimed',
23-
'ContributorRefunded', 'OwnerResidualRefunded'
24-
)
25-
THEN -CAST(JSON_EXTRACT_SCALAR(data_decoded, '$.amount') AS DOUBLE)
36+
-- Outflow: payouts and refunds
37+
WHEN ev_name IN ('WinnerPaid', 'MilestoneClaimed',
38+
'ContributorRefunded', 'OwnerResidualRefunded')
39+
THEN -CAST(JSON_EXTRACT_SCALAR(f['amount'], '$.i128') AS DOUBLE)
2640

2741
ELSE 0
2842
END AS delta
29-
FROM stellar.history_contract_events
30-
WHERE contract_id = '{{CONTRACT_ADDRESS}}'
31-
AND JSON_EXTRACT_SCALAR(topics_decoded, '$[0]') IN (
32-
'EventCreated', 'FundsAdded',
33-
'WinnerPaid', 'MilestoneClaimed',
34-
'ContributorRefunded', 'OwnerResidualRefunded'
35-
)
43+
FROM ev
44+
WHERE ev_name IN ('EventCreated', 'FundsAdded', 'WinnerPaid',
45+
'MilestoneClaimed', 'ContributorRefunded', 'OwnerResidualRefunded')
3646
),
3747
daily_delta AS (
38-
SELECT
39-
day,
40-
SUM(delta) / 1e7 AS daily_change_usdc
41-
FROM raw_events
48+
SELECT day, SUM(delta) / 1e7 AS daily_change_display
49+
FROM signed
4250
GROUP BY 1
4351
)
4452
SELECT
4553
day,
46-
daily_change_usdc,
47-
SUM(daily_change_usdc) OVER (ORDER BY day ROWS UNBOUNDED PRECEDING) AS tvl_usdc
54+
daily_change_display,
55+
SUM(daily_change_display) OVER (ORDER BY day ROWS UNBOUNDED PRECEDING) AS tvl_display
4856
FROM daily_delta
4957
ORDER BY day ASC
Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,28 @@
11
-- Boundless On-chain: Events created — count and budget by pillar and month
2-
-- Panel type: bar chart (grouped) x=month y=events_created color=pillar
2+
-- Panel type: grouped bar chart x=month y=events_created color=pillar
3+
--
4+
-- Decoding: see 10_event_created_decode_test.sql.
35

6+
WITH ev AS (
7+
SELECT
8+
DATE_TRUNC('month', closed_at) AS month,
9+
map_from_entries(
10+
transform(
11+
CAST(JSON_EXTRACT(data_decoded, '$.map') AS ARRAY(JSON)),
12+
e -> ROW(JSON_EXTRACT_SCALAR(e, '$.key.symbol'), JSON_EXTRACT(e, '$.val'))
13+
)
14+
) AS f
15+
FROM stellar.history_contract_events
16+
WHERE contract_id = '{{CONTRACT_ADDRESS}}'
17+
AND closed_at_date >= DATE '{{START_DATE}}'
18+
AND JSON_EXTRACT_SCALAR(topics_decoded, '$[0].symbol') = 'EventCreated'
19+
)
420
SELECT
5-
DATE_TRUNC('month', closed_at) AS month,
6-
JSON_EXTRACT_SCALAR(data_decoded, '$.pillar') AS pillar,
7-
COUNT(*) AS events_created,
8-
SUM(CAST(JSON_EXTRACT_SCALAR(data_decoded, '$.total_budget') AS DOUBLE)) / 1e7 AS total_budget_usdc
9-
FROM stellar.history_contract_events
10-
WHERE contract_id = '{{CONTRACT_ADDRESS}}'
11-
AND JSON_EXTRACT_SCALAR(topics_decoded, '$[0]') = 'EventCreated'
21+
month,
22+
JSON_EXTRACT_SCALAR(f['pillar'], '$.vec[0].symbol') AS pillar,
23+
COUNT(*) AS events_created,
24+
SUM(CAST(JSON_EXTRACT_SCALAR(f['total_budget'], '$.i128') AS DOUBLE)) / 1e7
25+
AS total_budget_display
26+
FROM ev
1227
GROUP BY 1, 2
1328
ORDER BY 1 DESC, 2 ASC
Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,32 @@
11
-- Boundless On-chain: Total payouts to builders
2-
-- Panel type: bar chart x=month y=total_paid_usdc color=payout_type
2+
-- Panel type: bar chart x=month y=total_paid_display color=payout_type
33
--
4-
-- WinnerPaid → Hackathon / Bounty (single-release, paid at select_winners)
5-
-- MilestoneClaimed → Grant / Crowdfunding (multi-release, paid per milestone)
4+
-- WinnerPaid -> Hackathon / Bounty (single-release; fires at claim_prize)
5+
-- MilestoneClaimed -> Grant / Crowdfunding (multi-release, per milestone)
6+
-- Both carry event_id, recipient (address), amount (i128).
7+
-- Decoding: see 10_event_created_decode_test.sql.
68

9+
WITH ev AS (
10+
SELECT
11+
DATE_TRUNC('month', closed_at) AS month,
12+
JSON_EXTRACT_SCALAR(topics_decoded, '$[0].symbol') AS ev_name,
13+
map_from_entries(
14+
transform(
15+
CAST(JSON_EXTRACT(data_decoded, '$.map') AS ARRAY(JSON)),
16+
e -> ROW(JSON_EXTRACT_SCALAR(e, '$.key.symbol'), JSON_EXTRACT(e, '$.val'))
17+
)
18+
) AS f
19+
FROM stellar.history_contract_events
20+
WHERE contract_id = '{{CONTRACT_ADDRESS}}'
21+
AND closed_at_date >= DATE '{{START_DATE}}'
22+
AND JSON_EXTRACT_SCALAR(topics_decoded, '$[0].symbol') IN ('WinnerPaid', 'MilestoneClaimed')
23+
)
724
SELECT
8-
DATE_TRUNC('month', closed_at) AS month,
9-
JSON_EXTRACT_SCALAR(topics_decoded, '$[0]') AS payout_type,
10-
COUNT(*) AS payout_count,
11-
COUNT(DISTINCT JSON_EXTRACT_SCALAR(data_decoded, '$.recipient')) AS unique_recipients,
12-
SUM(CAST(JSON_EXTRACT_SCALAR(data_decoded, '$.amount') AS DOUBLE)) / 1e7 AS total_paid_usdc
13-
FROM stellar.history_contract_events
14-
WHERE contract_id = '{{CONTRACT_ADDRESS}}'
15-
AND JSON_EXTRACT_SCALAR(topics_decoded, '$[0]') IN ('WinnerPaid', 'MilestoneClaimed')
25+
month,
26+
ev_name AS payout_type,
27+
COUNT(*) AS payout_count,
28+
COUNT(DISTINCT JSON_EXTRACT_SCALAR(f['recipient'], '$.address')) AS unique_recipients,
29+
SUM(CAST(JSON_EXTRACT_SCALAR(f['amount'], '$.i128') AS DOUBLE)) / 1e7 AS total_paid_display
30+
FROM ev
1631
GROUP BY 1, 2
1732
ORDER BY 1 DESC, 2 ASC
Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,41 @@
11
-- Boundless On-chain: Unique builder and organizer wallets
2-
-- Panel type: counter (two numbers side-by-side)
2+
-- Panel type: counter (two rows: builders, organizers)
33
--
4-
-- topics_decoded index 0 = event name symbol
5-
-- data_decoded = JSON object with event fields
4+
-- Decoding: event name is topics_decoded '$[0].symbol'; addresses are read
5+
-- from the data_decoded '$.map' as '$.address'. See 10_event_created_decode_test.sql.
66

7-
-- Unique builders: wallets that applied to or received a payout from any event
7+
WITH ev AS (
8+
SELECT
9+
JSON_EXTRACT_SCALAR(topics_decoded, '$[0].symbol') AS ev_name,
10+
map_from_entries(
11+
transform(
12+
CAST(JSON_EXTRACT(data_decoded, '$.map') AS ARRAY(JSON)),
13+
e -> ROW(JSON_EXTRACT_SCALAR(e, '$.key.symbol'), JSON_EXTRACT(e, '$.val'))
14+
)
15+
) AS f
16+
FROM stellar.history_contract_events
17+
WHERE contract_id = '{{CONTRACT_ADDRESS}}'
18+
AND closed_at_date >= DATE '{{START_DATE}}'
19+
AND JSON_EXTRACT_SCALAR(topics_decoded, '$[0].symbol')
20+
IN ('Applied', 'WinnerPaid', 'MilestoneClaimed', 'EventCreated')
21+
)
22+
-- Builders: applied to or received a payout from any event
823
SELECT
924
'builders' AS role,
1025
COUNT(DISTINCT addr) AS unique_wallets
1126
FROM (
12-
SELECT JSON_EXTRACT_SCALAR(data_decoded, '$.applicant') AS addr
13-
FROM stellar.history_contract_events
14-
WHERE contract_id = '{{CONTRACT_ADDRESS}}'
15-
AND JSON_EXTRACT_SCALAR(topics_decoded, '$[0]') = 'Applied'
16-
27+
SELECT JSON_EXTRACT_SCALAR(f['applicant'], '$.address') AS addr
28+
FROM ev WHERE ev_name = 'Applied'
1729
UNION
18-
19-
SELECT JSON_EXTRACT_SCALAR(data_decoded, '$.recipient') AS addr
20-
FROM stellar.history_contract_events
21-
WHERE contract_id = '{{CONTRACT_ADDRESS}}'
22-
AND JSON_EXTRACT_SCALAR(topics_decoded, '$[0]') IN ('WinnerPaid', 'MilestoneClaimed')
30+
SELECT JSON_EXTRACT_SCALAR(f['recipient'], '$.address')
31+
FROM ev WHERE ev_name IN ('WinnerPaid', 'MilestoneClaimed')
2332
) t
2433

2534
UNION ALL
2635

27-
-- Unique organizers: wallets that created at least one event
36+
-- Organizers: created at least one event
2837
SELECT
2938
'organizers' AS role,
30-
COUNT(DISTINCT JSON_EXTRACT_SCALAR(data_decoded, '$.owner')) AS unique_wallets
31-
FROM stellar.history_contract_events
32-
WHERE contract_id = '{{CONTRACT_ADDRESS}}'
33-
AND JSON_EXTRACT_SCALAR(topics_decoded, '$[0]') = 'EventCreated'
39+
COUNT(DISTINCT JSON_EXTRACT_SCALAR(f['owner'], '$.address')) AS unique_wallets
40+
FROM ev
41+
WHERE ev_name = 'EventCreated'
Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,49 @@
11
-- Boundless On-chain: Event outcome funnel
22
-- Panel type: bar chart or table
33
--
4-
-- Buckets every created event into:
5-
-- completed_with_payout — had at least one WinnerPaid or MilestoneClaimed
6-
-- cancelled — received an EventCancelled
7-
-- active_or_pending — neither (still running or awaiting selection)
4+
-- Buckets every created event into completed_with_payout / cancelled /
5+
-- active_or_pending. Note the id field differs by event:
6+
-- EventCreated carries 'id'; all later events carry 'event_id'.
7+
-- Decoding: see 10_event_created_decode_test.sql.
88

9-
WITH created AS (
9+
WITH ev AS (
1010
SELECT
11-
CAST(JSON_EXTRACT_SCALAR(data_decoded, '$.id') AS BIGINT) AS event_id,
12-
JSON_EXTRACT_SCALAR(data_decoded, '$.pillar') AS pillar,
13-
closed_at AS created_at
11+
closed_at,
12+
JSON_EXTRACT_SCALAR(topics_decoded, '$[0].symbol') AS ev_name,
13+
map_from_entries(
14+
transform(
15+
CAST(JSON_EXTRACT(data_decoded, '$.map') AS ARRAY(JSON)),
16+
e -> ROW(JSON_EXTRACT_SCALAR(e, '$.key.symbol'), JSON_EXTRACT(e, '$.val'))
17+
)
18+
) AS f
1419
FROM stellar.history_contract_events
1520
WHERE contract_id = '{{CONTRACT_ADDRESS}}'
16-
AND JSON_EXTRACT_SCALAR(topics_decoded, '$[0]') = 'EventCreated'
21+
AND closed_at_date >= DATE '{{START_DATE}}'
22+
AND JSON_EXTRACT_SCALAR(topics_decoded, '$[0].symbol')
23+
IN ('EventCreated', 'EventCancelled', 'WinnerPaid', 'MilestoneClaimed')
24+
),
25+
created AS (
26+
SELECT
27+
CAST(JSON_EXTRACT_SCALAR(f['id'], '$.u64') AS BIGINT) AS event_id,
28+
JSON_EXTRACT_SCALAR(f['pillar'], '$.vec[0].symbol') AS pillar
29+
FROM ev WHERE ev_name = 'EventCreated'
1730
),
1831
cancelled AS (
19-
SELECT DISTINCT
20-
CAST(JSON_EXTRACT_SCALAR(data_decoded, '$.id') AS BIGINT) AS event_id
21-
FROM stellar.history_contract_events
22-
WHERE contract_id = '{{CONTRACT_ADDRESS}}'
23-
AND JSON_EXTRACT_SCALAR(topics_decoded, '$[0]') = 'EventCancelled'
32+
SELECT DISTINCT CAST(JSON_EXTRACT_SCALAR(f['id'], '$.u64') AS BIGINT) AS event_id
33+
FROM ev WHERE ev_name = 'EventCancelled'
2434
),
2535
paid AS (
26-
SELECT DISTINCT
27-
CAST(JSON_EXTRACT_SCALAR(data_decoded, '$.event_id') AS BIGINT) AS event_id
28-
FROM stellar.history_contract_events
29-
WHERE contract_id = '{{CONTRACT_ADDRESS}}'
30-
AND JSON_EXTRACT_SCALAR(topics_decoded, '$[0]') IN ('WinnerPaid', 'MilestoneClaimed')
36+
SELECT DISTINCT CAST(JSON_EXTRACT_SCALAR(f['event_id'], '$.u64') AS BIGINT) AS event_id
37+
FROM ev WHERE ev_name IN ('WinnerPaid', 'MilestoneClaimed')
3138
)
3239
SELECT
3340
c.pillar,
34-
COUNT(c.event_id) AS total_created,
35-
COUNT(p.event_id) AS completed_with_payout,
36-
COUNT(cx.event_id) AS cancelled,
37-
COUNT(c.event_id) - COUNT(p.event_id) - COUNT(cx.event_id) AS active_or_pending
41+
COUNT(c.event_id) AS total_created,
42+
COUNT(p.event_id) AS completed_with_payout,
43+
COUNT(cx.event_id) AS cancelled,
44+
COUNT(c.event_id) - COUNT(p.event_id) - COUNT(cx.event_id) AS active_or_pending
3845
FROM created c
39-
LEFT JOIN paid p ON c.event_id = p.event_id
40-
LEFT JOIN cancelled cx ON c.event_id = cx.event_id
46+
LEFT JOIN paid p ON c.event_id = p.event_id
47+
LEFT JOIN cancelled cx ON c.event_id = cx.event_id
4148
GROUP BY 1
4249
ORDER BY total_created DESC

0 commit comments

Comments
 (0)