1use serde::{Deserialize, Serialize};
6use std::collections::BTreeMap;
7
8pub const SUPPORTED_ENVELOPE_VERSIONS: &[&str] = &["envelope.v1"];
10
11pub const SUPPORTED_SIGNATURE_ALGORITHMS: &[&str] = &["ed25519"];
13
14pub const SDK_VERSION: &str = "0.0.1";
16
17pub type EnvelopeVersion = String;
18pub type SignatureAlgorithm = String;
19
20#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
26pub struct VerificationKey {
27 #[serde(rename = "keyId")]
28 pub key_id: String,
29 pub algorithm: SignatureAlgorithm,
30 #[serde(rename = "publicKey")]
31 pub public_key: String,
32 #[serde(rename = "notBefore")]
33 pub not_before: String,
34 #[serde(rename = "notAfter")]
35 pub not_after: Option<String>,
36 #[serde(rename = "revokedAt")]
37 pub revoked_at: Option<String>,
38 #[serde(default, skip_serializing_if = "Option::is_none")]
39 pub purpose: Option<String>,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct RuntimeKeysResponse {
45 pub ok: bool,
46 #[serde(rename = "contractVersion")]
47 pub contract_version: String,
48 pub data: RuntimeKeysData,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct RuntimeKeysData {
53 pub keys: Vec<VerificationKey>,
54 #[serde(rename = "issuedAt")]
55 pub issued_at: String,
56 #[serde(default, rename = "snapshotId", skip_serializing_if = "Option::is_none")]
57 pub snapshot_id: Option<String>,
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct ProofReceiptPayload {
67 pub version: String,
68 #[serde(rename = "receiptId")]
69 pub receipt_id: String,
70 #[serde(rename = "correlationId")]
71 pub correlation_id: Option<String>,
72 #[serde(rename = "spatialAnchorId")]
73 pub spatial_anchor_id: String,
74 #[serde(rename = "spatialPlacementId")]
75 pub spatial_placement_id: Option<String>,
76 #[serde(rename = "issuedAt")]
77 pub issued_at: String,
78 #[serde(rename = "renderedAt")]
79 pub rendered_at: String,
80 #[serde(rename = "dwellMs")]
81 pub dwell_ms: i64,
82 pub nonce: String,
83 pub witness: Option<String>,
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize)]
88pub struct ProofRecord {
89 pub payload: ProofReceiptPayload,
90 #[serde(rename = "keyId")]
91 pub key_id: String,
92 pub algorithm: SignatureAlgorithm,
93 pub signature: String,
94 #[serde(rename = "payloadCanonical")]
95 pub payload_canonical: String,
96 #[serde(rename = "beforeHash")]
97 pub before_hash: Option<String>,
98 #[serde(rename = "afterHash")]
99 pub after_hash: String,
100}
101
102#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
103pub enum MeterUnitType {
104 #[serde(rename = "DWELL_SECONDS")]
105 DwellSeconds,
106 #[serde(rename = "IMPRESSION_IN_PLACE")]
107 ImpressionInPlace,
108 #[serde(rename = "ATTENTION_SECONDS")]
109 AttentionSeconds,
110 #[serde(rename = "OCCUPANCY_WEIGHTED_EXPOSURE")]
111 OccupancyWeightedExposure,
112 #[serde(rename = "COMPLIANT_DELIVERY_MINUTE")]
113 CompliantDeliveryMinute,
114 #[serde(rename = "CUSTOM")]
115 Custom,
116}
117
118impl MeterUnitType {
119 pub fn as_wire_str(&self) -> &'static str {
120 match self {
121 MeterUnitType::DwellSeconds => "DWELL_SECONDS",
122 MeterUnitType::ImpressionInPlace => "IMPRESSION_IN_PLACE",
123 MeterUnitType::AttentionSeconds => "ATTENTION_SECONDS",
124 MeterUnitType::OccupancyWeightedExposure => "OCCUPANCY_WEIGHTED_EXPOSURE",
125 MeterUnitType::CompliantDeliveryMinute => "COMPLIANT_DELIVERY_MINUTE",
126 MeterUnitType::Custom => "CUSTOM",
127 }
128 }
129}
130
131#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
132pub enum MeterStatus {
133 #[serde(rename = "PROJECTED")]
134 Projected,
135 #[serde(rename = "ACCEPTED")]
136 Accepted,
137 #[serde(rename = "SETTLED")]
138 Settled,
139 #[serde(rename = "VOID")]
140 Void,
141}
142
143#[derive(Debug, Clone, Serialize, Deserialize)]
144pub struct MeterRecord {
145 #[serde(rename = "idemKey")]
146 pub idem_key: String,
147 #[serde(rename = "proofReceiptId")]
148 pub proof_receipt_id: String,
149 #[serde(rename = "unitType")]
150 pub unit_type: MeterUnitType,
151 #[serde(rename = "unitCount")]
152 pub unit_count: String,
153 pub weight: String,
154 #[serde(rename = "spatialAnchorId")]
155 pub spatial_anchor_id: String,
156 #[serde(rename = "spatialPlacementId")]
157 pub spatial_placement_id: Option<String>,
158 #[serde(rename = "observedAt")]
159 pub observed_at: String,
160 pub status: MeterStatus,
161}
162
163#[derive(Debug, Clone, Serialize, Deserialize)]
164pub struct MeteringSummary {
165 #[serde(rename = "schemaVersion")]
166 pub schema_version: String,
167 #[serde(rename = "orgId")]
168 pub org_id: String,
169 #[serde(rename = "periodStart")]
170 pub period_start: String,
171 #[serde(rename = "periodEnd")]
172 pub period_end: String,
173 pub records: Vec<MeterRecord>,
174 #[serde(default, skip_serializing_if = "Option::is_none")]
175 pub totals: Option<BTreeMap<String, String>>,
176}
177
178#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
179pub enum SettlementPartyRole {
180 #[serde(rename = "TENANT")]
181 Tenant,
182 #[serde(rename = "VENUE")]
183 Venue,
184 #[serde(rename = "CUSTOMER")]
185 Customer,
186 #[serde(rename = "PLATFORM")]
187 Platform,
188}
189
190impl SettlementPartyRole {
191 pub fn as_wire_str(&self) -> &'static str {
192 match self {
193 SettlementPartyRole::Tenant => "TENANT",
194 SettlementPartyRole::Venue => "VENUE",
195 SettlementPartyRole::Customer => "CUSTOMER",
196 SettlementPartyRole::Platform => "PLATFORM",
197 }
198 }
199}
200
201#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
202pub enum SettlementStatus {
203 #[serde(rename = "PROJECTED")]
204 Projected,
205 #[serde(rename = "ACCEPTED")]
206 Accepted,
207 #[serde(rename = "POSTED")]
208 Posted,
209 #[serde(rename = "VOID")]
210 Void,
211}
212
213#[derive(Debug, Clone, Serialize, Deserialize)]
214pub struct SettlementLine {
215 #[serde(rename = "idemKey")]
216 pub idem_key: String,
217 #[serde(rename = "meterRecordIdemKey")]
218 pub meter_record_idem_key: String,
219 #[serde(rename = "partyRole")]
220 pub party_role: SettlementPartyRole,
221 pub share: String,
222 #[serde(rename = "ledgerAccountCode")]
223 pub ledger_account_code: String,
224 #[serde(rename = "amountCents")]
225 pub amount_cents: i64,
226 pub currency: String,
227 pub status: SettlementStatus,
228}
229
230#[derive(Debug, Clone, Serialize, Deserialize)]
231pub struct SettlementTotals {
232 #[serde(rename = "grossCents")]
233 pub gross_cents: i64,
234 #[serde(rename = "netToTenantCents")]
235 pub net_to_tenant_cents: i64,
236 #[serde(rename = "platformFeeCents")]
237 pub platform_fee_cents: i64,
238}
239
240#[derive(Debug, Clone, Serialize, Deserialize)]
241pub struct SettlementSummary {
242 #[serde(rename = "schemaVersion")]
243 pub schema_version: String,
244 #[serde(rename = "orgId")]
245 pub org_id: String,
246 #[serde(rename = "periodStart")]
247 pub period_start: String,
248 #[serde(rename = "periodEnd")]
249 pub period_end: String,
250 pub currency: String,
251 #[serde(rename = "meterGross")]
252 pub meter_gross: BTreeMap<String, i64>,
253 pub lines: Vec<SettlementLine>,
254 #[serde(default, skip_serializing_if = "Option::is_none")]
255 pub totals: Option<SettlementTotals>,
256}
257
258#[derive(Debug, Clone, Serialize, Deserialize)]
259pub struct SignedProofPack {
260 #[serde(rename = "envelopeVersion")]
261 pub envelope_version: EnvelopeVersion,
262 #[serde(rename = "issuedAt")]
263 pub issued_at: String,
264 #[serde(rename = "orgId")]
265 pub org_id: String,
266 #[serde(rename = "packId")]
267 pub pack_id: String,
268 #[serde(default, skip_serializing_if = "Option::is_none")]
269 pub label: Option<String>,
270 pub records: Vec<ProofRecord>,
271 #[serde(default, skip_serializing_if = "Option::is_none")]
272 pub metering: Option<MeteringSummary>,
273 #[serde(default, skip_serializing_if = "Option::is_none")]
274 pub settlement: Option<SettlementSummary>,
275}
276
277#[derive(Debug, Clone)]
278pub struct ProofPack {
279 pub envelope_version: EnvelopeVersion,
280 pub issued_at: String,
281 pub org_id: String,
282 pub pack_id: String,
283 pub records: Vec<ProofRecord>,
284}
285
286#[derive(Debug, Clone)]
287pub struct AuditBundle {
288 pub pack: SignedProofPack,
289 pub metering: Option<MeteringSummary>,
290 pub settlement: Option<SettlementSummary>,
291}
292
293#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
298pub enum AuditStepStatus {
299 #[serde(rename = "VALID")]
300 Valid,
301 #[serde(rename = "INVALID")]
302 Invalid,
303 #[serde(rename = "SKIPPED")]
304 Skipped,
305}
306
307#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
308pub enum AuditStepKind {
309 #[serde(rename = "envelope")]
310 Envelope,
311 #[serde(rename = "signature")]
312 Signature,
313 #[serde(rename = "canonicalisation")]
314 Canonicalisation,
315 #[serde(rename = "chain_link")]
316 ChainLink,
317 #[serde(rename = "meter_projection")]
318 MeterProjection,
319 #[serde(rename = "meter_total")]
320 MeterTotal,
321 #[serde(rename = "settlement_line")]
322 SettlementLine,
323 #[serde(rename = "settlement_total")]
324 SettlementTotal,
325 #[serde(rename = "key_lookup")]
326 KeyLookup,
327}
328
329#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
333pub enum AuditReasonCode {
334 #[serde(rename = "UNSUPPORTED_ENVELOPE_VERSION")]
336 UnsupportedEnvelopeVersion,
337 #[serde(rename = "MALFORMED_PACK")]
338 MalformedPack,
339 #[serde(rename = "EMPTY_PACK")]
340 EmptyPack,
341 #[serde(rename = "PACK_ORG_MISMATCH")]
342 PackOrgMismatch,
343 #[serde(rename = "UNSUPPORTED_ALGORITHM")]
344 UnsupportedAlgorithm,
345 #[serde(rename = "SIGNATURE_INVALID")]
347 SignatureInvalid,
348 #[serde(rename = "SIGNATURE_MALFORMED")]
349 SignatureMalformed,
350 #[serde(rename = "UNKNOWN_KEY_ID")]
351 UnknownKeyId,
352 #[serde(rename = "KEY_OUTSIDE_VALIDITY_WINDOW")]
353 KeyOutsideValidityWindow,
354 #[serde(rename = "KEY_REVOKED_BEFORE_ISSUANCE")]
355 KeyRevokedBeforeIssuance,
356 #[serde(rename = "PAYLOAD_CANONICAL_MISMATCH")]
358 PayloadCanonicalMismatch,
359 #[serde(rename = "AFTER_HASH_MISMATCH")]
360 AfterHashMismatch,
361 #[serde(rename = "GENESIS_BEFORE_HASH_NOT_NULL")]
363 GenesisBeforeHashNotNull,
364 #[serde(rename = "CHAIN_LINK_MISMATCH")]
365 ChainLinkMismatch,
366 #[serde(rename = "CHAIN_OUT_OF_ORDER")]
367 ChainOutOfOrder,
368 #[serde(rename = "METER_RECORD_FOR_UNKNOWN_PROOF")]
370 MeterRecordForUnknownProof,
371 #[serde(rename = "METER_UNIT_COUNT_MISMATCH")]
372 MeterUnitCountMismatch,
373 #[serde(rename = "METER_IDEM_KEY_MISMATCH")]
374 MeterIdemKeyMismatch,
375 #[serde(rename = "METER_TOTAL_MISMATCH")]
376 MeterTotalMismatch,
377 #[serde(rename = "METER_ORG_MISMATCH")]
378 MeterOrgMismatch,
379 #[serde(rename = "SETTLEMENT_LINE_FOR_UNKNOWN_METER")]
381 SettlementLineForUnknownMeter,
382 #[serde(rename = "SETTLEMENT_SHARE_SUM_NOT_ONE")]
383 SettlementShareSumNotOne,
384 #[serde(rename = "SETTLEMENT_AMOUNT_MISMATCH")]
385 SettlementAmountMismatch,
386 #[serde(rename = "SETTLEMENT_IDEM_KEY_MISMATCH")]
387 SettlementIdemKeyMismatch,
388 #[serde(rename = "SETTLEMENT_TOTAL_MISMATCH")]
389 SettlementTotalMismatch,
390 #[serde(rename = "SETTLEMENT_ORG_MISMATCH")]
391 SettlementOrgMismatch,
392 #[serde(rename = "KEYS_FETCH_FAILED")]
394 KeysFetchFailed,
395 #[serde(rename = "KEYS_RESPONSE_MALFORMED")]
396 KeysResponseMalformed,
397}
398
399#[derive(Debug, Clone, Serialize, Deserialize)]
400pub struct AuditStep {
401 pub target: String,
402 pub kind: AuditStepKind,
403 pub status: AuditStepStatus,
404 #[serde(default, skip_serializing_if = "Option::is_none")]
405 pub reason: Option<AuditReasonCode>,
406 pub message: String,
407 #[serde(default, skip_serializing_if = "Option::is_none")]
408 pub detail: Option<serde_json::Value>,
409}
410
411#[derive(Debug, Clone, Serialize, Deserialize)]
412pub struct KeysSnapshot {
413 pub source: String,
414 #[serde(rename = "snapshotId")]
415 pub snapshot_id: Option<String>,
416 #[serde(rename = "keyCount")]
417 pub key_count: usize,
418 #[serde(rename = "keyIds")]
419 pub key_ids: Vec<String>,
420}
421
422#[derive(Debug, Clone, Serialize, Deserialize)]
423pub struct AuditReport {
424 pub status: AuditStepStatus,
425 #[serde(rename = "packId")]
426 pub pack_id: String,
427 #[serde(rename = "orgId")]
428 pub org_id: String,
429 #[serde(rename = "verifiedAt")]
430 pub verified_at: String,
431 #[serde(rename = "sdkVersion")]
432 pub sdk_version: String,
433 #[serde(rename = "envelopeVersion")]
434 pub envelope_version: String,
435 #[serde(rename = "keysSnapshot")]
436 pub keys_snapshot: KeysSnapshot,
437 pub steps: Vec<AuditStep>,
438}
439
440#[derive(Debug, Clone, Serialize, Deserialize)]
441pub struct ChainAuditReport {
442 pub status: AuditStepStatus,
443 #[serde(rename = "verifiedAt")]
444 pub verified_at: String,
445 #[serde(rename = "sdkVersion")]
446 pub sdk_version: String,
447 #[serde(rename = "recordCount")]
448 pub record_count: usize,
449 pub steps: Vec<AuditStep>,
450}
451
452#[derive(Debug, Clone, Serialize, Deserialize)]
453pub struct ProjectionAuditReport {
454 pub status: AuditStepStatus,
455 #[serde(rename = "verifiedAt")]
456 pub verified_at: String,
457 #[serde(rename = "sdkVersion")]
458 pub sdk_version: String,
459 #[serde(rename = "proofRecordCount")]
460 pub proof_record_count: usize,
461 #[serde(rename = "meterRecordCount")]
462 pub meter_record_count: usize,
463 pub steps: Vec<AuditStep>,
464}
465
466#[derive(Debug, Clone, Serialize, Deserialize)]
467pub struct SettlementAuditReport {
468 pub status: AuditStepStatus,
469 #[serde(rename = "verifiedAt")]
470 pub verified_at: String,
471 #[serde(rename = "sdkVersion")]
472 pub sdk_version: String,
473 #[serde(rename = "meterRecordCount")]
474 pub meter_record_count: usize,
475 #[serde(rename = "settlementLineCount")]
476 pub settlement_line_count: usize,
477 pub steps: Vec<AuditStep>,
478}
479
480#[derive(Debug, Clone, Serialize, Deserialize)]
481pub struct FullAuditReport {
482 pub status: AuditStepStatus,
483 #[serde(rename = "packId")]
484 pub pack_id: String,
485 #[serde(rename = "orgId")]
486 pub org_id: String,
487 #[serde(rename = "verifiedAt")]
488 pub verified_at: String,
489 #[serde(rename = "sdkVersion")]
490 pub sdk_version: String,
491 #[serde(rename = "keysSnapshot")]
492 pub keys_snapshot: KeysSnapshot,
493 pub pack: AuditReport,
494 pub chain: ChainAuditReport,
495 pub metering: ProjectionAuditReport,
496 pub settlement: SettlementAuditReport,
497}