@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.
- package/LICENSE +1 -2
- package/examples/Insurance/Insurance.md +426 -70
- package/examples/MyShop/MyShop.md +349 -228
- package/examples/MyShop/myshop_machine_nodes.json +14 -8
- package/examples/MyShop_Advanced/MyShop_Advanced.md +472 -105
- package/examples/ThreeBody_Signature/ThreeBody_Signature.md +623 -121
- package/examples/Travel/Travel.md +298 -77
- package/package.json +1 -1
- package/wowok-guard/SKILL.md +317 -20
- package/wowok-machine/SKILL.md +72 -0
- package/wowok-order/APPENDIX.md +33 -33
- package/wowok-provider/SKILL.md +26 -12
- package/wowok-scenario/SKILL.md +10 -0
- package/wowok-tools/SKILL.md +2 -2
|
@@ -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=
|
|
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":
|
|
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
|
|
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.
|
|
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": "
|
|
619
|
+
"type": "logic_and",
|
|
497
620
|
"nodes": [
|
|
498
621
|
{
|
|
499
|
-
"type": "
|
|
500
|
-
"
|
|
501
|
-
|
|
502
|
-
|
|
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
|
-
{
|
|
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
|
-
|
|
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.
|
|
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": "
|
|
710
|
+
"type": "logic_and",
|
|
556
711
|
"nodes": [
|
|
557
712
|
{
|
|
558
|
-
"type": "
|
|
713
|
+
"type": "logic_or",
|
|
559
714
|
"nodes": [
|
|
560
715
|
{
|
|
561
|
-
"type": "
|
|
562
|
-
"
|
|
563
|
-
|
|
564
|
-
|
|
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
|
-
{
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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": "
|
|
811
|
+
"type": "logic_and",
|
|
625
812
|
"nodes": [
|
|
626
813
|
{
|
|
627
|
-
"type": "
|
|
628
|
-
"
|
|
629
|
-
|
|
630
|
-
|
|
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
|
-
{
|
|
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:
|
|
1008
|
+
## Step 5: Configure and Publish Service
|
|
794
1009
|
|
|
795
|
-
|
|
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**:
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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 |
|
|
918
|
-
|
|
919
|
-
| merchant_victory_guard | Progress is "Complete" | 100% (Entity →
|
|
920
|
-
| no_ice_scooting_guard | Progress is "Cancel" or "Ice Scooting" | 80% (Entity →
|
|
921
|
-
| no_spa_guard | Progress is "SPA" | 5% (Entity →
|
|
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
|
```
|