@wowok/skills 1.1.12 → 1.2.1

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.
@@ -4,6 +4,24 @@ A complete example demonstrating how to create an Iceland travel service using W
4
4
 
5
5
  ---
6
6
 
7
+ ## ⚠️ Running Principle
8
+
9
+ > **Run the example in full every time (repeatable).** This example uses `replaceExistName: true` on all object creations — each run generates new objects with new addresses. If you skip build steps, operations may silently act on orphaned objects from previous runs, producing incorrect results. Old objects' configurations do not reflect the current document version.
10
+
11
+ - **Execution order**: Run all build/setup steps in sequence before testing any customer or order flow. Do not skip steps — each depends on objects created by prior steps.
12
+ - **Prerequisites**: `travel_provider`, `weather_provider`, and `alice` (test customer) with sufficient WOW for gas. All on-chain operations require `env.confirmed: true`.
13
+
14
+ ### 🔐 Two-Step Confirmation Flow (Production Safety)
15
+
16
+ This example sets `env.confirmed: true` on irreversible operations (e.g., `publish: true` on Machine) for brevity. In real deployments, follow the two-step flow enforced by the ConfirmGate safety layer:
17
+
18
+ 1. **Phase 1 — Preview**: Call the tool **without** `env.confirmed`. The server returns `{ status: "pending_confirmation", confirmation_text: "..." }` containing the full operation summary, risk assessment, and irreversible-action warnings.
19
+ 2. **Phase 2 — Confirm**: Review `confirmation_text` with the user. Only after explicit user approval, call the tool again **with** `env.confirmed: true` to actually execute the on-chain transaction.
20
+
21
+ > Skipping Phase 1 means the user never sees the risk summary before gas is spent. Always preview first, then confirm.
22
+
23
+ ---
24
+
7
25
  ## Core Requirements & Features
8
26
 
9
27
  | Requirement | Description | Implementation |
@@ -90,6 +108,21 @@ Before running this example, ensure you have:
90
108
 
91
109
  ---
92
110
 
111
+ ## Environment Parameters
112
+
113
+ All on-chain operations in this example use the following `env` fields:
114
+
115
+ | Field | Value | Purpose |
116
+ |-------|-------|---------|
117
+ | `network` | `"testnet"` | Target network |
118
+ | `account` | Account name | Signer account for the transaction |
119
+ | `no_cache` | `true` | Bypass local cache to avoid stale reads during sequential object creation. Without this, operations that depend on recently created objects may fail with "object not found". |
120
+ | `confirmed` | `true` | Explicitly confirm the on-chain transaction (MCP ConfirmGate). Required for all write operations. |
121
+
122
+ Additionally, `onChain: true` is required when an object's name needs to be resolved across different accounts (see Step 0.3).
123
+
124
+ ---
125
+
93
126
  ## Step 0: Setup Weather Data
94
127
 
95
128
  Before creating the travel service, set up the weather Repository with the next 5 days of weather data. The weather data is keyed by timestamp, and the `weather_check_guard` (Step 3.1) will query this repository at runtime when the customer enters the "Ice Scooting" node (Step 7.3). You must use timestamps that are valid at the time you run this example.
@@ -139,7 +172,9 @@ Day 5: 1783900800000 (2026-07-13T00:00:00.000Z)
139
172
  },
140
173
  "env": {
141
174
  "account": "weather_provider",
142
- "network": "testnet"
175
+ "network": "testnet",
176
+ "no_cache": true,
177
+ "confirmed": true
143
178
  }
144
179
  }
145
180
  ```
@@ -155,7 +190,8 @@ Day 5: 1783900800000 (2026-07-13T00:00:00.000Z)
155
190
  "object": {
156
191
  "name": "weather_repo",
157
192
  "permission": "weather_permission",
158
- "replaceExistName": true
193
+ "replaceExistName": true,
194
+ "onChain": true
159
195
  },
160
196
  "description": "Weather data repository for Iceland travel activities",
161
197
  "policies": {
@@ -173,11 +209,15 @@ Day 5: 1783900800000 (2026-07-13T00:00:00.000Z)
173
209
  },
174
210
  "env": {
175
211
  "account": "weather_provider",
176
- "network": "testnet"
212
+ "network": "testnet",
213
+ "no_cache": true,
214
+ "confirmed": true
177
215
  }
178
216
  }
179
217
  ```
180
218
 
219
+ > **Note**: `onChain: true` is required here because `weather_repo` is created by the `weather_provider` account, but its name will be referenced in the Guard table (Step 3.1) by the `travel_provider` account. Without `onChain: true`, the name is stored locally only on `weather_provider`'s device and cannot be resolved by `travel_provider`. When `onChain: true` is set, the name is published on-chain and becomes publicly visible, allowing cross-account name resolution.
220
+
181
221
  ### 0.4 Add Weather Data
182
222
 
183
223
  Add 5 days of weather data. The `weather_check_guard` (Step 3.1) only verifies that a record **exists** for the activity date (via `repository.data has`), so all 5 days will pass the Guard regardless of the condition value. The "rainy" value on Day 5 is informational only — to actually reject based on weather condition, you would need a Guard that queries `repository.data` and compares the value, which is more complex and not used in this example.
@@ -206,7 +246,9 @@ Add 5 days of weather data. The `weather_check_guard` (Step 3.1) only verifies t
206
246
  },
207
247
  "env": {
208
248
  "account": "weather_provider",
209
- "network": "testnet"
249
+ "network": "testnet",
250
+ "no_cache": true,
251
+ "confirmed": true
210
252
  }
211
253
  }
212
254
  ```
@@ -239,7 +281,9 @@ Create a Permission object to manage access control for the travel service. Add
239
281
  },
240
282
  "env": {
241
283
  "account": "travel_provider",
242
- "network": "testnet"
284
+ "network": "testnet",
285
+ "no_cache": true,
286
+ "confirmed": true
243
287
  }
244
288
  }
245
289
  ```
@@ -267,17 +311,86 @@ Create an Arbitration object for dispute resolution.
267
311
  },
268
312
  "env": {
269
313
  "account": "travel_provider",
270
- "network": "testnet"
314
+ "network": "testnet",
315
+ "no_cache": true,
316
+ "confirmed": true
271
317
  }
272
318
  }
273
319
  ```
274
320
 
275
321
  ---
276
322
 
323
+ ## Step 2.5: Create Service (Unpublished)
324
+
325
+ Create the Service without publishing to obtain its address for Guard creation. The Service address is required by the allocator Guards (Step 3.4–3.6) to verify `order.service == travel_service` (R-C3-05 cross-service theft protection).
326
+
327
+ **Prompt**: Create Service "travel_service" with permission "travel_permission", do not publish.
328
+
329
+ ```json
330
+ {
331
+ "operation_type": "service",
332
+ "data": {
333
+ "object": {
334
+ "name": "travel_service",
335
+ "permission": "travel_permission",
336
+ "replaceExistName": true
337
+ },
338
+ "description": "Iceland travel service: Blue Lagoon SPA + Glacier Ice Scooting.",
339
+ "pause": false
340
+ },
341
+ "env": {
342
+ "account": "travel_provider",
343
+ "network": "testnet",
344
+ "no_cache": true,
345
+ "confirmed": true
346
+ }
347
+ }
348
+ ```
349
+
350
+ **Record the Service address** - it will be needed for allocator Guard creation (Step 3.4–3.6) to bind `order.service` verification.
351
+
352
+ ---
353
+
354
+ ### Step 2.6: Create Treasury (Merchant Revenue Aggregation)
355
+
356
+ Create a Treasury object to aggregate merchant revenue. The Treasury uses the **same Permission** as the Service (`travel_permission`) for consistency — a single permission organization governs both fund collection and service operations.
357
+
358
+ **Prompt**: Create Treasury "travel_treasury" with permission "travel_permission", type parameter "0x2::wow::WOW".
359
+
360
+ ```json
361
+ {
362
+ "operation_type": "treasury",
363
+ "data": {
364
+ "object": {
365
+ "name": "travel_treasury",
366
+ "type_parameter": "0x2::wow::WOW",
367
+ "permission": "travel_permission",
368
+ "replaceExistName": true
369
+ },
370
+ "description": "Treasury for aggregating travel service merchant revenue. Uses the same Permission as the Service (travel_permission) for consistency — a single permission organization governs both fund collection and service operations."
371
+ },
372
+ "env": {
373
+ "account": "travel_provider",
374
+ "network": "testnet",
375
+ "no_cache": true,
376
+ "confirmed": true
377
+ }
378
+ }
379
+ ```
380
+
381
+ > **Treasury-First Rule**: Following the fund-flow design pattern established in the Insurance and MyShop_Advanced examples, merchant revenue flows to `travel_treasury` (not directly to the Service address). This:
382
+ > 1. **Aggregates public funds** for operational distribution and accounting
383
+ > 2. **Makes allocators inherently safe** (R-C3-06) — funds always flow to the fixed Treasury regardless of caller, so no Signer binding is needed in the Guard
384
+ > 3. **Uses permission consistency** — Treasury and Service share `travel_permission`, ensuring unified governance
385
+
386
+ ---
387
+
277
388
  ## Step 3: Create Guards
278
389
 
279
390
  Create all Guards needed for the workflow and fund allocation. Guards are immutable once created, so create them before the Machine and Service.
280
391
 
392
+ > **Prerequisite**: The Service must be created (unpublished) in Step 2.5 first, because the allocator Guards (3.4–3.6) reference the Service address to verify `order.service == travel_service` (R-C3-05 cross-service theft protection).
393
+
281
394
  ### 3.1 Weather Check Guard
282
395
 
283
396
  Creates a Guard that verifies weather data exists for a given date. This Guard is bound to the "go_ice_scooting" forward (entering the weather-dependent Ice Scooting activity) to ensure the activity date has a weather record in the repository.
@@ -318,7 +431,6 @@ repository.data has("Condition", convert_number_address(activity_date))
318
431
  "identifier": 2,
319
432
  "b_submission": true,
320
433
  "value_type": "U64",
321
- "value": 0,
322
434
  "name": "Activity date timestamp (submitted at runtime)"
323
435
  }
324
436
  ],
@@ -337,7 +449,9 @@ repository.data has("Condition", convert_number_address(activity_date))
337
449
  },
338
450
  "env": {
339
451
  "account": "travel_provider",
340
- "network": "testnet"
452
+ "network": "testnet",
453
+ "no_cache": true,
454
+ "confirmed": true
341
455
  }
342
456
  }
343
457
  ```
@@ -357,7 +471,7 @@ Creates a Guard that verifies the time-lock condition for order completion.
357
471
  **Guard Logic**:
358
472
  ```
359
473
  clock > progress.current_time + 1000
360
- (progress accessed via Order + convert_witness=TypeOrderProgress)
474
+ (progress accessed via Order + convert_witness="OrderProgress")
361
475
  ```
362
476
 
363
477
  **Prompt**: Create a Guard named "travel_complete_guard" for time-lock verification.
@@ -377,7 +491,6 @@ clock > progress.current_time + 1000
377
491
  "identifier": 0,
378
492
  "b_submission": true,
379
493
  "value_type": "Address",
380
- "value": "0x0000000000000000000000000000000000000000000000000000000000000000",
381
494
  "name": "Order ID (submitted at runtime)"
382
495
  },
383
496
  {
@@ -398,7 +511,7 @@ clock > progress.current_time + 1000
398
511
  {
399
512
  "type": "query",
400
513
  "query": "progress.current_time",
401
- "object": {"identifier": 0, "convert_witness": 100},
514
+ "object": {"identifier": 0, "convert_witness": "OrderProgress"},
402
515
  "parameters": []
403
516
  },
404
517
  {"type": "identifier", "identifier": 1}
@@ -409,7 +522,9 @@ clock > progress.current_time + 1000
409
522
  },
410
523
  "env": {
411
524
  "account": "travel_provider",
412
- "network": "testnet"
525
+ "network": "testnet",
526
+ "no_cache": true,
527
+ "confirmed": true
413
528
  }
414
529
  }
415
530
  ```
@@ -455,14 +570,16 @@ Creates a Guard that allows order cancellation. This Guard always passes (return
455
570
  },
456
571
  "env": {
457
572
  "account": "travel_provider",
458
- "network": "testnet"
573
+ "network": "testnet",
574
+ "no_cache": true,
575
+ "confirmed": true
459
576
  }
460
577
  }
461
578
  ```
462
579
 
463
- ### 3.4 Merchant Victory Guard (100% to Service)
580
+ ### 3.4 Merchant Victory Guard (100% to Treasury)
464
581
 
465
- Checks if order progress current node is "Complete". If passed, merchant receives 100% of funds.
582
+ Checks if order progress current node is "Complete" AND order belongs to this service. If passed, merchant (Treasury) receives 100% of funds.
466
583
 
467
584
  **Prompt**: Create Guard "merchant_victory_guard".
468
585
 
@@ -472,16 +589,15 @@ Checks if order progress current node is "Complete". If passed, merchant receive
472
589
  "data": {
473
590
  "namedNew": {
474
591
  "name": "merchant_victory_guard",
475
- "tags": ["merchant", "victory", "complete"],
592
+ "tags": ["merchant", "victory", "complete", "level3-scene-combined"],
476
593
  "replaceExistName": true
477
594
  },
478
- "description": "Guard for merchant victory: checks if order progress current node is Complete. If passed, merchant receives 100% of funds.",
595
+ "description": "Guard for merchant victory: checks if order progress current node is Complete AND order belongs to travel_service. VERIFIER CONSTRAINT LEVEL 3 (scene-combined): No Signer binding needed because the allocator uses sharing.who=Entity (travel_treasury) — funds always flow to the Treasury regardless of caller (R-C3-06 safe). Two-fold verification: (1) order at Complete node, (2) order belongs to this service (prevents cross-service theft, R-C3-05).",
479
596
  "table": [
480
597
  {
481
598
  "identifier": 0,
482
599
  "b_submission": true,
483
600
  "value_type": "Address",
484
- "value": "0x0000000000000000000000000000000000000000000000000000000000000000",
485
601
  "name": "Order ID (submitted at runtime)"
486
602
  },
487
603
  {
@@ -490,31 +606,64 @@ Checks if order progress current node is "Complete". If passed, merchant receive
490
606
  "value_type": "String",
491
607
  "value": "Complete",
492
608
  "name": "Complete node name"
609
+ },
610
+ {
611
+ "identifier": 2,
612
+ "b_submission": false,
613
+ "value_type": "Address",
614
+ "value": "travel_service",
615
+ "name": "Service address (this service)"
493
616
  }
494
617
  ],
495
618
  "root": {
496
- "type": "logic_equal",
619
+ "type": "logic_and",
497
620
  "nodes": [
498
621
  {
499
- "type": "query",
500
- "query": "progress.current",
501
- "object": {"identifier": 0, "convert_witness": 100},
502
- "parameters": []
622
+ "type": "logic_equal",
623
+ "nodes": [
624
+ {
625
+ "type": "query",
626
+ "query": "progress.current",
627
+ "object": {"identifier": 0, "convert_witness": "OrderProgress"},
628
+ "parameters": []
629
+ },
630
+ {"type": "identifier", "identifier": 1}
631
+ ]
503
632
  },
504
- {"type": "identifier", "identifier": 1}
633
+ {
634
+ "type": "logic_equal",
635
+ "nodes": [
636
+ {"type": "query", "query": "order.service", "object": {"identifier": 0}, "parameters": []},
637
+ {"type": "identifier", "identifier": 2}
638
+ ]
639
+ }
505
640
  ]
506
641
  }
507
642
  },
508
643
  "env": {
509
644
  "account": "travel_provider",
510
- "network": "testnet"
645
+ "network": "testnet",
646
+ "no_cache": true,
647
+ "confirmed": true
511
648
  }
512
649
  }
513
650
  ```
514
651
 
515
- ### 3.5 No Ice Scooting Guard (80% Service, 20% Refund)
652
+ **Guard Explanation (Two-fold Verification Level 3 Scene-Combined):**
653
+ - **Table Item 0**: Order address (submitted at runtime)
654
+ - **Table Item 1**: Constant string "Complete" (merchant win node name)
655
+ - **Table Item 2**: Constant address `travel_service` (this service's on-chain address)
656
+ - **Condition 1 — Complete Node**: `logic_equal[query(progress.current, witness="OrderProgress"), identifier[1]]` — verifies the order is at the Complete node
657
+ - **Condition 2 — Service Ownership**: `logic_equal[query("order.service"), identifier[2]]` — verifies the submitted Order's `service` field equals `travel_service`, **preventing cross-service theft** where someone submits another service's order (R-C3-05)
658
+ - **root**: `logic_and` of both conditions — all must pass for allocation to proceed
659
+
660
+ > **Risk Elimination (R-C3-05 + R-C3-06) — Level 3 Scene-Combined Design**:
661
+ > - **R-C3-05 (Cross-service theft)**: Eliminated by the Service Ownership check (Condition 2). An attacker cannot submit another service's order because `order.service` won't match `travel_service`.
662
+ > - **R-C3-06 (Fund theft via Signer)**: Eliminated by the scene itself — the allocator uses `"who": {"Entity": {"name_or_address": "travel_treasury"}}` (funds flow to the fixed Treasury address). Funds go to a fixed recipient regardless of caller, so **no Signer binding is needed**. This is the Level 3 scene-combined pattern.
663
+
664
+ ### 3.5 No Ice Scooting Guard (80% Treasury, 20% Refund)
516
665
 
517
- Checks if progress current is "Cancel" or "Ice Scooting". If passed, merchant gets 80%, user gets 20% refund.
666
+ Checks if progress current is "Cancel" or "Ice Scooting" AND order belongs to this service. If passed, merchant (Treasury) gets 80%, user gets 20% refund.
518
667
 
519
668
  **Prompt**: Create Guard "no_ice_scooting_guard".
520
669
 
@@ -524,16 +673,15 @@ Checks if progress current is "Cancel" or "Ice Scooting". If passed, merchant ge
524
673
  "data": {
525
674
  "namedNew": {
526
675
  "name": "no_ice_scooting_guard",
527
- "tags": ["user", "cancel", "ice_scooting"],
676
+ "tags": ["user", "cancel", "ice_scooting", "level3-scene-combined"],
528
677
  "replaceExistName": true
529
678
  },
530
- "description": "Guard for user not participating in ice scooting: checks if progress current is Cancel or Ice Scooting. If passed, merchant gets 80%, user gets 20% refund.",
679
+ "description": "Guard for user not participating in ice scooting: checks if progress current is Cancel or Ice Scooting AND order belongs to travel_service. VERIFIER CONSTRAINT LEVEL 3 (scene-combined): No Signer binding needed because the allocator uses sharing.who=Entity (travel_treasury) for merchant portion and sharing.who=GuardIdentifier(0) for customer refund (escrow to Order address). Two-fold verification: (1) order at Cancel/Ice Scooting node, (2) order belongs to this service (prevents cross-service theft, R-C3-05).",
531
680
  "table": [
532
681
  {
533
682
  "identifier": 0,
534
683
  "b_submission": true,
535
684
  "value_type": "Address",
536
- "value": "0x0000000000000000000000000000000000000000000000000000000000000000",
537
685
  "name": "Order ID (submitted at runtime)"
538
686
  },
539
687
  {
@@ -549,33 +697,52 @@ Checks if progress current is "Cancel" or "Ice Scooting". If passed, merchant ge
549
697
  "value_type": "String",
550
698
  "value": "Ice Scooting",
551
699
  "name": "Ice Scooting node name"
700
+ },
701
+ {
702
+ "identifier": 3,
703
+ "b_submission": false,
704
+ "value_type": "Address",
705
+ "value": "travel_service",
706
+ "name": "Service address (this service)"
552
707
  }
553
708
  ],
554
709
  "root": {
555
- "type": "logic_or",
710
+ "type": "logic_and",
556
711
  "nodes": [
557
712
  {
558
- "type": "logic_equal",
713
+ "type": "logic_or",
559
714
  "nodes": [
560
715
  {
561
- "type": "query",
562
- "query": "progress.current",
563
- "object": {"identifier": 0, "convert_witness": 100},
564
- "parameters": []
716
+ "type": "logic_equal",
717
+ "nodes": [
718
+ {
719
+ "type": "query",
720
+ "query": "progress.current",
721
+ "object": {"identifier": 0, "convert_witness": "OrderProgress"},
722
+ "parameters": []
723
+ },
724
+ {"type": "identifier", "identifier": 1}
725
+ ]
565
726
  },
566
- {"type": "identifier", "identifier": 1}
727
+ {
728
+ "type": "logic_equal",
729
+ "nodes": [
730
+ {
731
+ "type": "query",
732
+ "query": "progress.current",
733
+ "object": {"identifier": 0, "convert_witness": "OrderProgress"},
734
+ "parameters": []
735
+ },
736
+ {"type": "identifier", "identifier": 2}
737
+ ]
738
+ }
567
739
  ]
568
740
  },
569
741
  {
570
742
  "type": "logic_equal",
571
743
  "nodes": [
572
- {
573
- "type": "query",
574
- "query": "progress.current",
575
- "object": {"identifier": 0, "convert_witness": 100},
576
- "parameters": []
577
- },
578
- {"type": "identifier", "identifier": 2}
744
+ {"type": "query", "query": "order.service", "object": {"identifier": 0}, "parameters": []},
745
+ {"type": "identifier", "identifier": 3}
579
746
  ]
580
747
  }
581
748
  ]
@@ -583,14 +750,28 @@ Checks if progress current is "Cancel" or "Ice Scooting". If passed, merchant ge
583
750
  },
584
751
  "env": {
585
752
  "account": "travel_provider",
586
- "network": "testnet"
753
+ "network": "testnet",
754
+ "no_cache": true,
755
+ "confirmed": true
587
756
  }
588
757
  }
589
758
  ```
590
759
 
591
- ### 3.6 No SPA Guard (5% Service, 95% Refund)
760
+ **Guard Explanation (Two-fold Verification Level 3 Scene-Combined):**
761
+ - **Table Item 0**: Order address (submitted at runtime)
762
+ - **Table Items 1-2**: Constant strings "Cancel" and "Ice Scooting" (node names)
763
+ - **Table Item 3**: Constant address `travel_service` (this service's on-chain address)
764
+ - **Condition 1 — Cancel/Ice Scooting Node**: `logic_or` of two `logic_equal` checks against `query(progress.current, witness="OrderProgress")` — verifies the order is at Cancel or Ice Scooting node
765
+ - **Condition 2 — Service Ownership**: `logic_equal[query("order.service"), identifier[3]]` — verifies the submitted Order's `service` field equals `travel_service`, **preventing cross-service theft** (R-C3-05)
766
+ - **root**: `logic_and` of both conditions — all must pass for allocation to proceed
767
+
768
+ > **Risk Elimination (R-C3-05 + R-C3-06) — Level 3 Scene-Combined Design**:
769
+ > - **R-C3-05 (Cross-service theft)**: Eliminated by the Service Ownership check (Condition 2). An attacker cannot submit another service's order because `order.service` won't match `travel_service`.
770
+ > - **R-C3-06 (Fund theft via Signer)**: Eliminated by the scene itself — the merchant portion uses `"who": {"Entity": {"name_or_address": "travel_treasury"}}` (funds flow to the fixed Treasury address), and the customer refund uses `"who": {"GuardIdentifier": 0}` (funds flow to the Order object's address as escrow). Neither portion flows to the caller's wallet, so **no Signer binding is needed**.
771
+
772
+ ### 3.6 No SPA Guard (5% Treasury, 95% Refund)
592
773
 
593
- Checks if progress current is "SPA". If passed, merchant gets 5%, user gets 95% refund.
774
+ Checks if progress current is "SPA" AND order belongs to this service. If passed, merchant (Treasury) gets 5%, user gets 95% refund.
594
775
 
595
776
  **Prompt**: Create Guard "no_spa_guard".
596
777
 
@@ -600,16 +781,15 @@ Checks if progress current is "SPA". If passed, merchant gets 5%, user gets 95%
600
781
  "data": {
601
782
  "namedNew": {
602
783
  "name": "no_spa_guard",
603
- "tags": ["user", "cancel", "spa"],
784
+ "tags": ["user", "cancel", "spa", "level3-scene-combined"],
604
785
  "replaceExistName": true
605
786
  },
606
- "description": "Guard for user not participating in SPA: checks if progress current is SPA. If passed, merchant gets 5%, user gets 95% refund.",
787
+ "description": "Guard for user not participating in SPA: checks if progress current is SPA AND order belongs to travel_service. VERIFIER CONSTRAINT LEVEL 3 (scene-combined): No Signer binding needed because the allocator uses sharing.who=Entity (travel_treasury) for merchant portion and sharing.who=GuardIdentifier(0) for customer refund (escrow to Order address). Two-fold verification: (1) order at SPA node, (2) order belongs to this service (prevents cross-service theft, R-C3-05).",
607
788
  "table": [
608
789
  {
609
790
  "identifier": 0,
610
791
  "b_submission": true,
611
792
  "value_type": "Address",
612
- "value": "0x0000000000000000000000000000000000000000000000000000000000000000",
613
793
  "name": "Order ID (submitted at runtime)"
614
794
  },
615
795
  {
@@ -618,28 +798,61 @@ Checks if progress current is "SPA". If passed, merchant gets 5%, user gets 95%
618
798
  "value_type": "String",
619
799
  "value": "SPA",
620
800
  "name": "SPA node name"
801
+ },
802
+ {
803
+ "identifier": 2,
804
+ "b_submission": false,
805
+ "value_type": "Address",
806
+ "value": "travel_service",
807
+ "name": "Service address (this service)"
621
808
  }
622
809
  ],
623
810
  "root": {
624
- "type": "logic_equal",
811
+ "type": "logic_and",
625
812
  "nodes": [
626
813
  {
627
- "type": "query",
628
- "query": "progress.current",
629
- "object": {"identifier": 0, "convert_witness": 100},
630
- "parameters": []
814
+ "type": "logic_equal",
815
+ "nodes": [
816
+ {
817
+ "type": "query",
818
+ "query": "progress.current",
819
+ "object": {"identifier": 0, "convert_witness": "OrderProgress"},
820
+ "parameters": []
821
+ },
822
+ {"type": "identifier", "identifier": 1}
823
+ ]
631
824
  },
632
- {"type": "identifier", "identifier": 1}
825
+ {
826
+ "type": "logic_equal",
827
+ "nodes": [
828
+ {"type": "query", "query": "order.service", "object": {"identifier": 0}, "parameters": []},
829
+ {"type": "identifier", "identifier": 2}
830
+ ]
831
+ }
633
832
  ]
634
833
  }
635
834
  },
636
835
  "env": {
637
836
  "account": "travel_provider",
638
- "network": "testnet"
837
+ "network": "testnet",
838
+ "no_cache": true,
839
+ "confirmed": true
639
840
  }
640
841
  }
641
842
  ```
642
843
 
844
+ **Guard Explanation (Two-fold Verification — Level 3 Scene-Combined):**
845
+ - **Table Item 0**: Order address (submitted at runtime)
846
+ - **Table Item 1**: Constant string "SPA" (node name)
847
+ - **Table Item 2**: Constant address `travel_service` (this service's on-chain address)
848
+ - **Condition 1 — SPA Node**: `logic_equal[query(progress.current, witness="OrderProgress"), identifier[1]]` — verifies the order is at the SPA node
849
+ - **Condition 2 — Service Ownership**: `logic_equal[query("order.service"), identifier[2]]` — verifies the submitted Order's `service` field equals `travel_service`, **preventing cross-service theft** (R-C3-05)
850
+ - **root**: `logic_and` of both conditions — all must pass for allocation to proceed
851
+
852
+ > **Risk Elimination (R-C3-05 + R-C3-06) — Level 3 Scene-Combined Design**:
853
+ > - **R-C3-05 (Cross-service theft)**: Eliminated by the Service Ownership check (Condition 2). An attacker cannot submit another service's order because `order.service` won't match `travel_service`.
854
+ > - **R-C3-06 (Fund theft via Signer)**: Eliminated by the scene itself — the merchant portion uses `"who": {"Entity": {"name_or_address": "travel_treasury"}}` (funds flow to the fixed Treasury address), and the customer refund uses `"who": {"GuardIdentifier": 0}` (funds flow to the Order object's address as escrow). Neither portion flows to the caller's wallet, so **no Signer binding is needed**.
855
+
643
856
  ---
644
857
 
645
858
  ## Step 4: Create and Publish Machine
@@ -762,7 +975,9 @@ Create a Machine to define the travel service workflow with all nodes and forwar
762
975
  },
763
976
  "env": {
764
977
  "account": "travel_provider",
765
- "network": "testnet"
978
+ "network": "testnet",
979
+ "no_cache": true,
980
+ "confirmed": true
766
981
  }
767
982
  }
768
983
  ```
@@ -790,16 +1005,16 @@ Create a Machine to define the travel service workflow with all nodes and forwar
790
1005
 
791
1006
  ---
792
1007
 
793
- ## Step 5: Create and Publish Service
1008
+ ## Step 5: Configure and Publish Service
794
1009
 
795
- Create the travel service with all configurations and publish it in one operation. The Service requires:
1010
+ Configure the travel service (created unpublished in Step 2.5) with all bindings and publish it. The Service requires:
796
1011
  - Machine binding (must be published first)
797
1012
  - Sales items (product listing)
798
1013
  - Arbitration binding
799
- - Order allocators (fund distribution rules)
1014
+ - Order allocators (fund distribution rules — merchant funds flow to `travel_treasury`)
800
1015
  - `pause: false` and `publish: true` to make it active
801
1016
 
802
- **Prompt**: Create and publish a Service named "travel_service".
1017
+ **Prompt**: Configure and publish the Service named "travel_service".
803
1018
 
804
1019
  ```json
805
1020
  {
@@ -838,7 +1053,7 @@ Create the travel service with all configurations and publish it in one operatio
838
1053
  "fix": "0",
839
1054
  "sharing": [
840
1055
  {
841
- "who": {"Entity": {"name_or_address": "travel_service"}},
1056
+ "who": {"Entity": {"name_or_address": "travel_treasury"}},
842
1057
  "sharing": 10000,
843
1058
  "mode": "Rate"
844
1059
  }
@@ -849,7 +1064,7 @@ Create the travel service with all configurations and publish it in one operatio
849
1064
  "fix": "0",
850
1065
  "sharing": [
851
1066
  {
852
- "who": {"Entity": {"name_or_address": "travel_service"}},
1067
+ "who": {"Entity": {"name_or_address": "travel_treasury"}},
853
1068
  "sharing": 8000,
854
1069
  "mode": "Rate"
855
1070
  },
@@ -865,7 +1080,7 @@ Create the travel service with all configurations and publish it in one operatio
865
1080
  "fix": "0",
866
1081
  "sharing": [
867
1082
  {
868
- "who": {"Entity": {"name_or_address": "travel_service"}},
1083
+ "who": {"Entity": {"name_or_address": "travel_treasury"}},
869
1084
  "sharing": 500,
870
1085
  "mode": "Rate"
871
1086
  },
@@ -883,7 +1098,9 @@ Create the travel service with all configurations and publish it in one operatio
883
1098
  },
884
1099
  "env": {
885
1100
  "account": "travel_provider",
886
- "network": "testnet"
1101
+ "network": "testnet",
1102
+ "no_cache": true,
1103
+ "confirmed": true
887
1104
  }
888
1105
  }
889
1106
  ```
@@ -906,19 +1123,21 @@ Create the travel service with all configurations and publish it in one operatio
906
1123
 
907
1124
  | Type | Syntax | Resolves To | Use Case |
908
1125
  |------|--------|-------------|----------|
909
- | `Entity` | `{"Entity": {"name_or_address": "travel_service"}}` | The named address | Merchant receipts (Service object) |
1126
+ | `Entity` | `{"Entity": {"name_or_address": "travel_treasury"}}` | The named Treasury address | Merchant receipts (Treasury object — Treasury-first rule) |
910
1127
  | `GuardIdentifier` | `{"GuardIdentifier": 0}` | Address from Guard table index 0 (submitted at runtime) | Customer refunds (Order ID submitted to Guard) |
911
- | `Signer` | `{"Signer": "signer"}` | The caller of `alloc_by_guard` | When caller should receive all funds |
1128
+ | `Signer` | `{"Signer": "signer"}` | The caller of `alloc_by_guard` | When caller should receive all funds (**⚠️ R-C3-06 Risk**: unsafe without Guard Signer binding) |
912
1129
 
913
1130
  > **Important**: All allocation Guards (merchant_victory_guard, no_ice_scooting_guard, no_spa_guard) have `identifier: 0` as a submission field accepting the Order ID at runtime. `{"GuardIdentifier": 0}` resolves to this submitted Order ID, so funds are sent to the Order object — the customer (Order builder) can then withdraw.
914
1131
 
1132
+ > **Treasury-First Rule**: Merchant funds flow to `travel_treasury` (not `travel_service`) following the fund-flow design pattern. This makes all allocators inherently safe (R-C3-06) — funds go to a fixed Treasury regardless of caller, so no Signer binding is needed in the Guards. Combined with the R-C3-05 service ownership check in each Guard, the allocators are protected against both cross-service theft and fund theft via Signer.
1133
+
915
1134
  **Allocation Logic**:
916
1135
 
917
- | Guard | Condition | Service Receives | Customer Receives |
918
- |-------|-----------|-----------------|-------------------|
919
- | merchant_victory_guard | Progress is "Complete" | 100% (Entity → travel_service) | 0% |
920
- | no_ice_scooting_guard | Progress is "Cancel" or "Ice Scooting" | 80% (Entity → travel_service) | 20% (GuardIdentifier: 0 → Order) |
921
- | no_spa_guard | Progress is "SPA" | 5% (Entity → travel_service) | 95% (GuardIdentifier: 0 → Order) |
1136
+ | Guard | Condition | Treasury Receives | Customer Receives | Verifier Level |
1137
+ |-------|-----------|-------------------|-------------------|----------------|
1138
+ | merchant_victory_guard | Progress is "Complete" + order.service verified | 100% (Entity → travel_treasury) | 0% | Level 3 (scene-combined) |
1139
+ | no_ice_scooting_guard | Progress is "Cancel" or "Ice Scooting" + order.service verified | 80% (Entity → travel_treasury) | 20% (GuardIdentifier: 0 → Order) | Level 3 (scene-combined) |
1140
+ | no_spa_guard | Progress is "SPA" + order.service verified | 5% (Entity → travel_treasury) | 95% (GuardIdentifier: 0 → Order) | Level 3 (scene-combined) |
922
1141
 
923
1142
  ---
924
1143
 
@@ -960,7 +1179,9 @@ The customer (Alice) purchases the travel package. This creates an Order, a Prog
960
1179
  },
961
1180
  "env": {
962
1181
  "account": "alice",
963
- "network": "testnet"
1182
+ "network": "testnet",
1183
+ "no_cache": true,
1184
+ "confirmed": true
964
1185
  }
965
1186
  }
966
1187
  ```
@@ -1284,7 +1505,7 @@ For refund scenarios (Cancel or SPA), use the corresponding Guard. The same subm
1284
1505
  "submission": [{"identifier": 0, "b_submission": true, "value_type": "Address", "value": "<ORDER_OBJECT_ID>", "name": "Order ID"}]
1285
1506
  }]
1286
1507
  },
1287
- "env": {"account": "travel_provider", "network": "testnet", "no_cache": true}
1508
+ "env": {"account": "travel_provider", "network": "testnet", "no_cache": true, "confirmed": true}
1288
1509
  }
1289
1510
  ```
1290
1511
 
@@ -1305,7 +1526,7 @@ For refund scenarios (Cancel or SPA), use the corresponding Guard. The same subm
1305
1526
  "submission": [{"identifier": 0, "b_submission": true, "value_type": "Address", "value": "<ORDER_OBJECT_ID>", "name": "Order ID"}]
1306
1527
  }]
1307
1528
  },
1308
- "env": {"account": "travel_provider", "network": "testnet", "no_cache": true}
1529
+ "env": {"account": "travel_provider", "network": "testnet", "no_cache": true, "confirmed": true}
1309
1530
  }
1310
1531
  ```
1311
1532
 
@@ -1440,6 +1661,6 @@ Customers place orders using the `order_new` field in the Service operation. Thi
1440
1661
  "namedNewAllocation": {"name": "allocation_name", "replaceExistName": true}
1441
1662
  }
1442
1663
  },
1443
- "env": {"account": "customer", "network": "testnet"}
1664
+ "env": {"account": "customer", "network": "testnet", "no_cache": true, "confirmed": true}
1444
1665
  }
1445
1666
  ```