@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,15 @@ A complete e-commerce example demonstrating how to build an online store 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**: Part 1 (Merchant Setup, Steps 1–7) → Part 2 (Customer Flow, Steps 1–9). Run all build steps in sequence before testing any customer flow. Do not skip steps — each depends on objects created by prior steps.
12
+ - **Prerequisites**: `myshop_merchant` with sufficient WOW for gas and order operations. All on-chain operations require `env.confirmed: true`.
13
+
14
+ ---
15
+
7
16
  ## Core Requirements & Features
8
17
 
9
18
  | Requirement | Description | Implementation |
@@ -109,8 +118,10 @@ Before starting, ensure you have:
109
118
  ```json
110
119
  {
111
120
  "transfer": {
112
- "name_or_address": "myshop_merchant",
113
- "amount": 1000000000
121
+ "name_or_address_to": "myshop_merchant",
122
+ "amount": 1000000000,
123
+ "network": "mainnet",
124
+ "confirmed": true
114
125
  }
115
126
  }
116
127
  ```
@@ -137,18 +148,21 @@ First, create a Permission object to manage access control for your store operat
137
148
  },
138
149
  "env": {
139
150
  "account": "myshop_merchant",
140
- "network": "mainnet"
151
+ "network": "mainnet",
152
+ "confirmed": true
141
153
  }
142
154
  }
143
155
  ```
144
156
 
145
157
  ---
146
158
 
147
- ### Step 2: Create Machine (Order Workflow)
159
+ ### Step 2: Create Machine with Workflow Nodes
160
+
161
+ Create a Machine to define the order processing workflow. This includes nodes for order confirmation, shipping, delivery, and completion. The Machine must be created with all nodes and published in a single operation — the protocol requires at least one node when publishing a Machine.
148
162
 
149
- Create a Machine to define the order processing workflow. This includes nodes for order confirmation, shipping, delivery, and completion.
163
+ > **Reference**: The complete node configuration is available in [`myshop_machine_nodes.json`](./myshop_machine_nodes.json). The JSON below mirrors that file's content wrapped in an on-chain operation.
150
164
 
151
- **Prompt**: Create a Machine named "myshop_machine_v2" with permission "myshop_permission_v2" for the toy store workflow.
165
+ **Prompt**: Create a Machine named "myshop_machine_v2" with permission "myshop_permission_v2", including all workflow nodes (Order Confirmation, Shipping, In Transit, Completed, Cancelled), and publish it immediately.
152
166
 
153
167
  ```json
154
168
  {
@@ -159,15 +173,115 @@ Create a Machine to define the order processing workflow. This includes nodes fo
159
173
  "permission": "myshop_permission_v2",
160
174
  "replaceExistName": true
161
175
  },
162
- "description": "Order processing workflow for MyShop toy store"
176
+ "description": "Order processing workflow for MyShop toy store",
177
+ "node": {
178
+ "op": "add",
179
+ "nodes": [
180
+ {
181
+ "name": "Cancelled",
182
+ "pairs": [
183
+ {
184
+ "prev_node": "",
185
+ "threshold": 0,
186
+ "forwards": [
187
+ {
188
+ "name": "Cancel Order",
189
+ "weight": 1,
190
+ "namedOperator": ""
191
+ }
192
+ ]
193
+ },
194
+ {
195
+ "prev_node": "Order Confirmation",
196
+ "threshold": 1,
197
+ "forwards": [
198
+ {
199
+ "name": "Cancel Order",
200
+ "weight": 1,
201
+ "namedOperator": ""
202
+ }
203
+ ]
204
+ }
205
+ ]
206
+ },
207
+ {
208
+ "name": "Completed",
209
+ "pairs": [
210
+ {
211
+ "prev_node": "In Transit",
212
+ "threshold": 1,
213
+ "forwards": [
214
+ {
215
+ "name": "Complete Order",
216
+ "weight": 1,
217
+ "namedOperator": ""
218
+ }
219
+ ]
220
+ }
221
+ ]
222
+ },
223
+ {
224
+ "name": "In Transit",
225
+ "pairs": [
226
+ {
227
+ "prev_node": "Shipping",
228
+ "threshold": 1,
229
+ "forwards": [
230
+ {
231
+ "name": "Confirm Delivery",
232
+ "weight": 1,
233
+ "permissionIndex": 1002
234
+ }
235
+ ]
236
+ }
237
+ ]
238
+ },
239
+ {
240
+ "name": "Order Confirmation",
241
+ "pairs": [
242
+ {
243
+ "prev_node": "",
244
+ "threshold": 0,
245
+ "forwards": [
246
+ {
247
+ "name": "Confirm Order",
248
+ "weight": 1,
249
+ "permissionIndex": 1000
250
+ }
251
+ ]
252
+ }
253
+ ]
254
+ },
255
+ {
256
+ "name": "Shipping",
257
+ "pairs": [
258
+ {
259
+ "prev_node": "Order Confirmation",
260
+ "threshold": 1,
261
+ "forwards": [
262
+ {
263
+ "name": "Ship Goods",
264
+ "weight": 1,
265
+ "permissionIndex": 1001
266
+ }
267
+ ]
268
+ }
269
+ ]
270
+ }
271
+ ]
272
+ },
273
+ "publish": true
163
274
  },
164
275
  "env": {
165
276
  "account": "myshop_merchant",
166
- "network": "mainnet"
277
+ "network": "mainnet",
278
+ "confirmed": true
167
279
  }
168
280
  }
169
281
  ```
170
282
 
283
+ > **Note**: The Machine must be created with nodes and published in a single operation. Creating an empty Machine and then adding nodes/publishing separately will be rejected by the protocol's constraint checker. The "Cancelled" node has two pairs: one with `prev_node: ""` (cancel from initial state) and one with `prev_node: "Order Confirmation"` (cancel after order confirmation).
284
+
171
285
  ---
172
286
 
173
287
  ### Step 3: Machine Workflow Design
@@ -279,152 +393,11 @@ Before adding nodes, let's understand the order processing workflow:
279
393
 
280
394
  ---
281
395
 
282
- ### Step 4: Add Workflow Nodes
283
-
284
- Add the workflow nodes to the Machine for order processing. The initial pair (prev_node: "") defines transitions from the empty starting state.
285
-
286
- **Prompt**: Add workflow nodes to "myshop_machine_v2" including Order Confirmation, Shipping, In Transit, Completed, and Cancelled nodes.
287
-
288
- ```json
289
- {
290
- "operation_type": "machine",
291
- "data": {
292
- "object": "myshop_machine_v2",
293
- "node": {
294
- "op": "add",
295
- "nodes": [
296
- {
297
- "name": "Order Confirmation",
298
- "pairs": [
299
- {
300
- "prev_node": "",
301
- "threshold": 0,
302
- "forwards": [
303
- {
304
- "name": "Confirm Order",
305
- "permissionIndex": 1000,
306
- "weight": 1
307
- }
308
- ]
309
- },
310
- {
311
- "prev_node": "Order Confirmation",
312
- "threshold": 1,
313
- "forwards": [
314
- {
315
- "name": "Ship Goods",
316
- "permissionIndex": 1001,
317
- "weight": 1
318
- }
319
- ]
320
- }
321
- ]
322
- },
323
- {
324
- "name": "Shipping",
325
- "pairs": [
326
- {
327
- "prev_node": "Order Confirmation",
328
- "threshold": 1,
329
- "forwards": [
330
- {
331
- "name": "Ship Goods",
332
- "permissionIndex": 1001,
333
- "weight": 1
334
- }
335
- ]
336
- }
337
- ]
338
- },
339
- {
340
- "name": "In Transit",
341
- "pairs": [
342
- {
343
- "prev_node": "Shipping",
344
- "threshold": 1,
345
- "forwards": [
346
- {
347
- "name": "Confirm Delivery",
348
- "permissionIndex": 1002,
349
- "weight": 1
350
- }
351
- ]
352
- }
353
- ]
354
- },
355
- {
356
- "name": "Completed",
357
- "pairs": [
358
- {
359
- "prev_node": "In Transit",
360
- "threshold": 1,
361
- "forwards": [
362
- {
363
- "name": "Complete Order",
364
- "namedOperator": "",
365
- "weight": 1
366
- }
367
- ]
368
- }
369
- ]
370
- },
371
- {
372
- "name": "Cancelled",
373
- "pairs": [
374
- {
375
- "prev_node": "Order Confirmation",
376
- "threshold": 0,
377
- "forwards": [
378
- {
379
- "name": "Cancel Order",
380
- "namedOperator": "",
381
- "weight": 1
382
- }
383
- ]
384
- }
385
- ]
386
- }
387
- ]
388
- }
389
- },
390
- "env": {
391
- "account": "myshop_merchant",
392
- "network": "mainnet"
393
- }
394
- }
395
- ```
396
-
397
- > **Note**: The "Cancel Order" forward is defined on the "Cancelled" node with `prev_node: "Order Confirmation"`. This means cancellation can only happen AFTER the merchant confirms the order (transitions from "Order Confirmation" to "Cancelled"). The "Cancelled" node is a terminal state with no further forwards.
398
-
399
- ---
400
-
401
- ### Step 5: Publish the Machine
402
-
403
- Publish the Machine to make it available for creating orders.
404
-
405
- **Prompt**: Publish the Machine "myshop_machine_v2" to enable order creation.
406
-
407
- ```json
408
- {
409
- "operation_type": "machine",
410
- "data": {
411
- "object": "myshop_machine_v2",
412
- "publish": true
413
- },
414
- "env": {
415
- "account": "myshop_merchant",
416
- "network": "mainnet"
417
- }
418
- }
419
- ```
420
-
421
- ---
422
-
423
- ### Step 6: Create Contact Object for Customer Service
396
+ ### Step 4: Create Contact Object for Customer Service
424
397
 
425
398
  Create a Contact object to enable encrypted communication between customers and the store for after-sales support.
426
399
 
427
- #### 6.1 Enable Merchant Messenger
400
+ #### 4.1 Enable Merchant Messenger
428
401
 
429
402
  **Prompt**: Enable messenger for the merchant account.
430
403
 
@@ -437,7 +410,7 @@ Create a Contact object to enable encrypted communication between customers and
437
410
  }
438
411
  ```
439
412
 
440
- #### 6.2 Create After-Sales Contact Object
413
+ #### 4.2 Create After-Sales Contact Object
441
414
 
442
415
  **Prompt**: Create a Contact object named "myshop_aftersales_contact_v2" with permission "myshop_permission_v2" for after-sales support.
443
416
 
@@ -463,7 +436,8 @@ Create a Contact object to enable encrypted communication between customers and
463
436
  },
464
437
  "env": {
465
438
  "account": "myshop_merchant",
466
- "network": "mainnet"
439
+ "network": "mainnet",
440
+ "confirmed": true
467
441
  }
468
442
  }
469
443
  ```
@@ -472,13 +446,13 @@ Create a Contact object to enable encrypted communication between customers and
472
446
 
473
447
  ---
474
448
 
475
- ### Step 7: Create Guards for Fund Allocation
449
+ ### Step 5: Create Guards for Fund Allocation
476
450
 
477
451
  Before creating the Service, create Guards that validate fund allocation conditions. These Guards ensure funds are only released when specific conditions are met.
478
452
 
479
- #### 7.1 Create Withdraw Guard (Merchant Withdrawal)
453
+ #### 5.1 Create Withdraw Guard (Merchant Withdrawal)
480
454
 
481
- Create a Guard that validates the order's Progress has reached the "Completed" node. This Guard uses `convert_witness: 100` (TypeOrderProgress) to query the Order's associated Progress object.
455
+ Create a Guard that validates the order's Progress has reached the "Completed" node. This Guard uses `convert_witness: "OrderProgress"` (TypeOrderProgress) to query the Order's associated Progress object.
482
456
 
483
457
  **Prompt**: Create a Guard named "myshop_withdraw_guard_v2" that verifies the order is completed before allowing merchant withdrawal.
484
458
 
@@ -488,62 +462,118 @@ Create a Guard that validates the order's Progress has reached the "Completed" n
488
462
  "data": {
489
463
  "namedNew": {
490
464
  "name": "myshop_withdraw_guard_v2",
491
- "tags": ["order", "completed", "withdraw"],
465
+ "tags": ["order", "completed", "withdraw", "signer-bound"],
492
466
  "onChain": false,
493
467
  "replaceExistName": true
494
468
  },
495
- "description": "Verify order progress is at Completed node for merchant withdrawal",
469
+ "description": "Verify order progress is at Completed node for merchant withdrawal. RISK ELIMINATION: Three-fold verification - (1) order at Completed node, (2) signer is myshop_merchant (prevents fund theft), (3) order belongs to myshop_service_v2 (prevents cross-service theft).",
496
470
  "table": [
497
471
  {
498
472
  "identifier": 0,
499
473
  "b_submission": true,
500
474
  "value_type": "Address",
501
- "name": "order_address"
475
+ "object_type": "Order",
476
+ "name": "order_address (Order object submitted at runtime)"
502
477
  },
503
478
  {
504
479
  "identifier": 1,
505
480
  "b_submission": false,
506
481
  "value_type": "String",
507
482
  "value": "Completed",
508
- "name": "completed_node"
483
+ "name": "Expected Completed node name (case-sensitive)"
484
+ },
485
+ {
486
+ "identifier": 2,
487
+ "b_submission": false,
488
+ "value_type": "Address",
489
+ "value": "myshop_merchant",
490
+ "name": "Authorized merchant address (prevents fund theft by unauthorized callers)"
491
+ },
492
+ {
493
+ "identifier": 3,
494
+ "b_submission": false,
495
+ "value_type": "Address",
496
+ "value": "myshop_service_v2",
497
+ "name": "Expected service address (prevents cross-service fund theft)"
509
498
  }
510
499
  ],
511
500
  "root": {
512
- "type": "logic_equal",
501
+ "type": "logic_and",
513
502
  "nodes": [
514
503
  {
515
- "type": "query",
516
- "query": 1253,
517
- "object": {
518
- "identifier": 0,
519
- "convert_witness": 100
520
- },
521
- "parameters": []
504
+ "type": "logic_equal",
505
+ "nodes": [
506
+ {
507
+ "type": "query",
508
+ "query": "progress.current",
509
+ "object": {
510
+ "identifier": 0,
511
+ "convert_witness": "OrderProgress"
512
+ },
513
+ "parameters": []
514
+ },
515
+ {
516
+ "type": "identifier",
517
+ "identifier": 1
518
+ }
519
+ ]
522
520
  },
523
521
  {
524
- "type": "identifier",
525
- "identifier": 1
522
+ "type": "logic_equal",
523
+ "nodes": [
524
+ {
525
+ "type": "context",
526
+ "context": "Signer"
527
+ },
528
+ {
529
+ "type": "identifier",
530
+ "identifier": 2
531
+ }
532
+ ]
533
+ },
534
+ {
535
+ "type": "logic_equal",
536
+ "nodes": [
537
+ {
538
+ "type": "query",
539
+ "query": "order.service",
540
+ "object": {
541
+ "identifier": 0
542
+ },
543
+ "parameters": []
544
+ },
545
+ {
546
+ "type": "identifier",
547
+ "identifier": 3
548
+ }
549
+ ]
526
550
  }
527
551
  ]
528
552
  }
529
553
  },
530
554
  "env": {
531
555
  "account": "myshop_merchant",
532
- "network": "mainnet"
556
+ "network": "mainnet",
557
+ "confirmed": true
533
558
  }
534
559
  }
535
560
  ```
536
561
 
537
- **Guard Explanation:**
538
- - **Table Item 0**: Order address (submitted when activating allocation)
562
+ **Guard Explanation (Three-fold Verification):**
563
+ - **Table Item 0**: Order address (submitted at runtime, typed as Order object)
539
564
  - **Table Item 1**: Constant string "Completed" (the target node name)
540
- - **convert_witness: 100**: TypeOrderProgress - converts Order to its associated Progress
541
- - **Query "progress.current"**: Returns the current node name of the Progress
542
- - **logic_equal**: Verifies current node equals "Completed"
543
-
544
- > **Note**: The Guard `root` field directly specifies the GuardNode (e.g., `type: "logic_equal"`), not wrapped in a `type: "node"` object.
565
+ - **Table Item 2**: Constant address `myshop_merchant` (authorized merchant)
566
+ - **Table Item 3**: Constant address `myshop_service_v2` (this service's on-chain address)
567
+ - **Condition 1 — Order Completed**: `logic_equal[query("progress.current", witness="OrderProgress"), identifier[1]]` — queries the submitted Order's Progress (via witness "OrderProgress") and verifies the current node is "Completed"
568
+ - **Condition 2 — Signer is Merchant**: `logic_equal[context(Signer), identifier[2]]` — verifies the transaction caller is `myshop_merchant`, **preventing fund theft by unauthorized callers** (R-C3-01/R-C3-06)
569
+ - **Condition 3 Service Ownership**: `logic_equal[query("order.service"), identifier[3]]` queries the submitted Order's `service` field and verifies it equals `myshop_service_v2`, **preventing cross-service theft** where someone submits another service's Completed order (R-C3-05)
570
+ - **root**: `logic_and` of all three conditions — all must pass for allocation to proceed
571
+
572
+ > **Risk Elimination (R-C3-06)**: The allocator uses `"who": {"Signer": "signer"}` (funds go to the caller). This is safe ONLY because Condition 2 binds the Signer to `myshop_merchant`. Without this binding, anyone could submit any Completed order and steal 100% of funds. The three-fold verification ensures only the authorized merchant can trigger withdrawal.
573
+ >
574
+ > **Note**: The Guard `root` field directly specifies the GuardNode (e.g., `type: "logic_and"`), not wrapped in a `type: "node"` object.
545
575
 
546
- #### 7.2 Create Refund Guard (Customer Refund)
576
+ #### 5.2 Create Refund Guard (Customer Refund)
547
577
 
548
578
  Create a Guard for customer refunds when order is cancelled.
549
579
 
@@ -555,61 +585,122 @@ Create a Guard for customer refunds when order is cancelled.
555
585
  "data": {
556
586
  "namedNew": {
557
587
  "name": "myshop_refund_guard_v2",
558
- "tags": ["order", "cancelled", "refund"],
588
+ "tags": ["order", "cancelled", "refund", "signer-bound"],
559
589
  "onChain": false,
560
590
  "replaceExistName": true
561
591
  },
562
- "description": "Verify order progress is at Cancelled node for customer refund",
592
+ "description": "Verify order progress is at Cancelled node for customer refund. RISK ELIMINATION: Three-fold verification - (1) order at Cancelled node, (2) signer is order.owner (dynamic query, prevents fund theft - only order owner can trigger their own refund), (3) order belongs to myshop_service_v2 (prevents cross-service theft).",
563
593
  "table": [
564
594
  {
565
595
  "identifier": 0,
566
596
  "b_submission": true,
567
597
  "value_type": "Address",
568
- "name": "order_address"
598
+ "object_type": "Order",
599
+ "name": "order_address (Order object submitted at runtime)"
569
600
  },
570
601
  {
571
602
  "identifier": 1,
572
603
  "b_submission": false,
573
604
  "value_type": "String",
574
605
  "value": "Cancelled",
575
- "name": "cancelled_node"
606
+ "name": "Expected Cancelled node name (case-sensitive)"
607
+ },
608
+ {
609
+ "identifier": 2,
610
+ "b_submission": false,
611
+ "value_type": "Address",
612
+ "value": "myshop_service_v2",
613
+ "name": "Expected service address (prevents cross-service fund theft)"
576
614
  }
577
615
  ],
578
616
  "root": {
579
- "type": "logic_equal",
617
+ "type": "logic_and",
580
618
  "nodes": [
581
619
  {
582
- "type": "query",
583
- "query": 1253,
584
- "object": {
585
- "identifier": 0,
586
- "convert_witness": 100
587
- },
588
- "parameters": []
620
+ "type": "logic_equal",
621
+ "nodes": [
622
+ {
623
+ "type": "query",
624
+ "query": "progress.current",
625
+ "object": {
626
+ "identifier": 0,
627
+ "convert_witness": "OrderProgress"
628
+ },
629
+ "parameters": []
630
+ },
631
+ {
632
+ "type": "identifier",
633
+ "identifier": 1
634
+ }
635
+ ]
589
636
  },
590
637
  {
591
- "type": "identifier",
592
- "identifier": 1
638
+ "type": "logic_equal",
639
+ "nodes": [
640
+ {
641
+ "type": "context",
642
+ "context": "Signer"
643
+ },
644
+ {
645
+ "type": "query",
646
+ "query": "order.owner",
647
+ "object": {
648
+ "identifier": 0
649
+ },
650
+ "parameters": []
651
+ }
652
+ ]
653
+ },
654
+ {
655
+ "type": "logic_equal",
656
+ "nodes": [
657
+ {
658
+ "type": "query",
659
+ "query": "order.service",
660
+ "object": {
661
+ "identifier": 0
662
+ },
663
+ "parameters": []
664
+ },
665
+ {
666
+ "type": "identifier",
667
+ "identifier": 2
668
+ }
669
+ ]
593
670
  }
594
671
  ]
595
672
  }
596
673
  },
597
674
  "env": {
598
675
  "account": "myshop_merchant",
599
- "network": "mainnet"
676
+ "network": "mainnet",
677
+ "confirmed": true
600
678
  }
601
679
  }
602
680
  ```
603
681
 
682
+ **Guard Explanation (Three-fold Verification):**
683
+ - **Table Item 0**: Order address (submitted at runtime, typed as Order object)
684
+ - **Table Item 1**: Constant string "Cancelled" (the target node name)
685
+ - **Table Item 2**: Constant address `myshop_service_v2` (this service's on-chain address)
686
+ - **Condition 1 — Order Cancelled**: `logic_equal[query("progress.current", witness="OrderProgress"), identifier[1]]` — queries the submitted Order's Progress (via witness "OrderProgress") and verifies the current node is "Cancelled"
687
+ - **Condition 2 — Signer is Order Owner**: `logic_equal[context(Signer), query("order.owner")]` — verifies the transaction caller is the Order's owner (dynamic query, not a fixed address), **preventing fund theft by unauthorized callers** (R-C3-01/R-C3-06). Only the customer who placed the order can trigger their own refund.
688
+ - **Condition 3 — Service Ownership**: `logic_equal[query("order.service"), identifier[2]]` — queries the submitted Order's `service` field and verifies it equals `myshop_service_v2`, **preventing cross-service theft** (R-C3-05)
689
+ - **root**: `logic_and` of all three conditions — all must pass for refund allocation to proceed
690
+
691
+ > **Risk Elimination (R-C3-06)**: Unlike the withdraw Guard (which binds Signer to a fixed merchant address), the refund Guard binds Signer to `order.owner` via a **dynamic query** (query 1562). This is because refunds flow to the customer, and each order has a different customer. Only the order's rightful owner can trigger the refund — an attacker cannot submit another customer's Cancelled order.
692
+ >
693
+ > **Refund Recipient Design**: The allocator uses `"who": {"GuardIdentifier": 0}` (funds go to the Order object's address, not the caller's wallet). This creates an escrow pattern: the refund is held at the Order object's address, and the customer subsequently claims it via a separate withdraw operation. This ensures traceability and audit trail.
694
+
604
695
  ---
605
696
 
606
- ### Step 8: Create Service (Store)
697
+ ### Step 6: Create Service (Store)
607
698
 
608
699
  Create the Service object that represents your online store with products. This step binds all previously created components together.
609
700
 
610
701
  > **Important**: For Service creation, provide a complete configuration including machine, order_allocators with Guards, and products. The Service will be created and published in a single transaction.
611
702
 
612
- #### 8.1 Understanding Order Allocators
703
+ #### 6.1 Understanding Order Allocators
613
704
 
614
705
  The `order_allocators` configuration defines how order payments are distributed:
615
706
 
@@ -621,13 +712,19 @@ The `order_allocators` configuration defines how order payments are distributed:
621
712
  | **Threshold** | Minimum amount to trigger allocation |
622
713
 
623
714
  **Recipient Types:**
624
- - `{ "Signer": "signer" }` - Transaction sender (merchant)
625
- - `{ "Entity": { "name_or_address": "..." } }` - Specific address or account name
626
- - `{ "GuardIdentifier": 0 }` - Address from Guard table
715
+ - `{ "Signer": "signer" }` - Transaction sender (caller). **⚠️ R-C3-06 Risk**: If the Guard does NOT bind the Signer to an authorized address, anyone who passes the Guard can steal 100% of funds. Safe ONLY when the Guard includes a `logic_equal[context(Signer), <authorized_address>]` check.
716
+ - `{ "Entity": { "name_or_address": "..." } }` - Specific address or account name (safest — funds go to a fixed address regardless of caller)
717
+ - `{ "GuardIdentifier": 0 }` - Address from Guard table (e.g., the submitted Order object's address)
718
+
719
+ > **R-C3-06 Risk Elimination — Guard + Sharing Coupling**: The `order_allocators` scene couples Guard verification (WHO can trigger) with sharing recipient (WHERE funds go). This example uses two risk-elimination strategies:
720
+ > - **Withdraw allocator** (`sharing.who = Signer`): Safe because `myshop_withdraw_guard_v2` binds `context(Signer)` to `myshop_merchant` (identifier 2). Only the merchant can pass the Guard, so funds correctly flow to the merchant.
721
+ > - **Refund allocator** (`sharing.who = GuardIdentifier 0`): Funds go to the Order object's address (escrow), not to the caller. The Guard additionally binds `context(Signer)` to `order.owner` (dynamic query 1562), ensuring only the order's rightful owner can trigger the refund.
722
+ >
723
+ > **Alternative approach**: Instead of Signer binding in the Guard, you can use `sharing.who = Entity` to send funds to a fixed Treasury or personal address. This is even more robust because funds are directed regardless of who passes the Guard. See the Insurance example for this pattern.
627
724
 
628
725
  > **Design Decision — Refund Recipient**: When using `{ "GuardIdentifier": 0 }` in the refund allocation, the refund is sent to the **Order object's on-chain address** (not the customer's wallet address). This is by design: the Order object acts as an escrow holding the refunded payment at its own address. The customer subsequently claims the refund from the Order object via a separate withdraw operation. This two-step design ensures the refund is traceable on-chain and tied to the specific order, providing better dispute resolution and audit trail.
629
726
 
630
- #### 8.2 Create and Publish Service
727
+ #### 6.2 Create and Publish Service
631
728
 
632
729
  **Prompt**: Create and publish a Service named "myshop_service_v2" with machine "myshop_machine_v2", order allocation using Guards, after-sales contact, and toy products.
633
730
 
@@ -706,7 +803,8 @@ The `order_allocators` configuration defines how order payments are distributed:
706
803
  },
707
804
  "env": {
708
805
  "account": "myshop_merchant",
709
- "network": "mainnet"
806
+ "network": "mainnet",
807
+ "confirmed": true
710
808
  }
711
809
  }
712
810
  ```
@@ -718,7 +816,7 @@ The `order_allocators` configuration defines how order payments are distributed:
718
816
 
719
817
  ---
720
818
 
721
- ### Step 9: Update Product Pricing (Optional)
819
+ ### Step 7: Update Product Pricing (Optional)
722
820
 
723
821
  To offer promotional pricing, update product prices using the `sales` operation with `op: "set"`:
724
822
 
@@ -745,7 +843,8 @@ To offer promotional pricing, update product prices using the `sales` operation
745
843
  },
746
844
  "env": {
747
845
  "account": "myshop_merchant",
748
- "network": "mainnet"
846
+ "network": "mainnet",
847
+ "confirmed": true
749
848
  }
750
849
  }
751
850
  ```
@@ -778,8 +877,10 @@ Create a customer account:
778
877
  ```json
779
878
  {
780
879
  "transfer": {
781
- "name_or_address": "myshop_customer",
782
- "amount": 1000000000
880
+ "name_or_address_to": "myshop_customer",
881
+ "amount": 1000000000,
882
+ "network": "mainnet",
883
+ "confirmed": true
783
884
  }
784
885
  }
785
886
  ```
@@ -802,7 +903,7 @@ Customers can query the Service to see available products.
802
903
  }
803
904
  ```
804
905
 
805
- > **AI Note**: Capture the `wip_hash` from the Service query result for each product. When the customer places an order, pass the captured `wip_hash` in `buy.items[].wip_hash`. This is a dispute-prevention mechanism — the on-chain contract compares `item.wip_hash` against the Service's current `sale.wip_hash` to ensure the product hasn't been swapped between browse and purchase time.
906
+ > **AI Note**: Capture the `wip_hash` from the Service query result for each product. When the customer places an order, pass the captured `wip_hash` in `buy.items[].wip_hash`. **The `wip_hash` field cannot be an empty string** — it must match the hash stored in the Service. This is a dispute-prevention mechanism — the on-chain contract compares `item.wip_hash` against the Service's current `sale.wip_hash` to ensure the product hasn't been swapped between browse and purchase time.
806
907
 
807
908
  ---
808
909
 
@@ -823,7 +924,7 @@ Customer creates an order by purchasing products from the Service.
823
924
  {
824
925
  "name": "Play Purse Set 35PCS",
825
926
  "stock": 1,
826
- "wip_hash": ""
927
+ "wip_hash": "03c18561efa8faf4d75480eb1f732c4a46ffde95599e92eca06167785fc07a5b"
827
928
  }
828
929
  ],
829
930
  "total_pay": {
@@ -846,7 +947,8 @@ Customer creates an order by purchasing products from the Service.
846
947
  },
847
948
  "env": {
848
949
  "account": "myshop_customer",
849
- "network": "mainnet"
950
+ "network": "mainnet",
951
+ "confirmed": true
850
952
  }
851
953
  }
852
954
  ```
@@ -1010,7 +1112,8 @@ Merchant advances the order from initial state to "Order Confirmation" node.
1010
1112
  },
1011
1113
  "env": {
1012
1114
  "account": "myshop_merchant",
1013
- "network": "mainnet"
1115
+ "network": "mainnet",
1116
+ "confirmed": true
1014
1117
  }
1015
1118
  }
1016
1119
  ```
@@ -1039,7 +1142,8 @@ Merchant ships the order and advances from "Order Confirmation" to "Shipping".
1039
1142
  },
1040
1143
  "env": {
1041
1144
  "account": "myshop_merchant",
1042
- "network": "mainnet"
1145
+ "network": "mainnet",
1146
+ "confirmed": true
1043
1147
  }
1044
1148
  }
1045
1149
  ```
@@ -1068,7 +1172,8 @@ Merchant or delivery service confirms the order has been delivered.
1068
1172
  },
1069
1173
  "env": {
1070
1174
  "account": "myshop_merchant",
1071
- "network": "mainnet"
1175
+ "network": "mainnet",
1176
+ "confirmed": true
1072
1177
  }
1073
1178
  }
1074
1179
  ```
@@ -1097,7 +1202,8 @@ Customer confirms receipt and completes the order.
1097
1202
  },
1098
1203
  "env": {
1099
1204
  "account": "myshop_customer",
1100
- "network": "mainnet"
1205
+ "network": "mainnet",
1206
+ "confirmed": true
1101
1207
  }
1102
1208
  }
1103
1209
  ```
@@ -1110,7 +1216,7 @@ After order completion, the merchant needs to:
1110
1216
  1. Activate the Allocation by verifying the Guard (order completion status)
1111
1217
  2. Withdraw funds from the Service
1112
1218
 
1113
- #### 9.1 Activate Allocation (Guard Verification)
1219
+ #### 7.1 Activate Allocation (Guard Verification)
1114
1220
 
1115
1221
  First, activate the Allocation by submitting the Guard verification with the Order ID.
1116
1222
 
@@ -1151,6 +1257,7 @@ First, activate the Allocation by submitting the Guard verification with the Ord
1151
1257
  "env": {
1152
1258
  "account": "myshop_merchant",
1153
1259
  "network": "mainnet",
1260
+ "confirmed": true,
1154
1261
  "no_cache": true
1155
1262
  }
1156
1263
  }
@@ -1158,7 +1265,7 @@ First, activate the Allocation by submitting the Guard verification with the Ord
1158
1265
 
1159
1266
  > **Note**: Replace the Guard address `0x5af9...1074` and Order address `0xa6db...3d5` with your actual object addresses. Use the full 64-character addresses in actual operations.
1160
1267
 
1161
- #### 9.2 Withdraw Funds from Service
1268
+ #### 7.2 Withdraw Funds from Service
1162
1269
 
1163
1270
  After the Allocation is activated, withdraw the funds from the Service.
1164
1271
 
@@ -1173,7 +1280,8 @@ After the Allocation is activated, withdraw the funds from the Service.
1173
1280
  },
1174
1281
  "env": {
1175
1282
  "account": "myshop_merchant",
1176
- "network": "mainnet"
1283
+ "network": "mainnet",
1284
+ "confirmed": true
1177
1285
  }
1178
1286
  }
1179
1287
  ```
@@ -1204,7 +1312,8 @@ Customer can cancel the order after the merchant confirms it. The "Cancel Order"
1204
1312
  },
1205
1313
  "env": {
1206
1314
  "account": "myshop_merchant",
1207
- "network": "mainnet"
1315
+ "network": "mainnet",
1316
+ "confirmed": true
1208
1317
  }
1209
1318
  }
1210
1319
  ```
@@ -1229,7 +1338,8 @@ Customer can cancel the order after the merchant confirms it. The "Cancel Order"
1229
1338
  },
1230
1339
  "env": {
1231
1340
  "account": "myshop_customer",
1232
- "network": "mainnet"
1341
+ "network": "mainnet",
1342
+ "confirmed": true
1233
1343
  }
1234
1344
  }
1235
1345
  ```
@@ -1273,6 +1383,7 @@ After the order is cancelled, the customer can activate the refund allocation us
1273
1383
  "env": {
1274
1384
  "account": "myshop_customer",
1275
1385
  "network": "mainnet",
1386
+ "confirmed": true,
1276
1387
  "no_cache": true
1277
1388
  }
1278
1389
  }
@@ -1308,7 +1419,8 @@ The Service must have a compensation fund balance ≥ the arbitration indemnity
1308
1419
  },
1309
1420
  "env": {
1310
1421
  "account": "myshop_merchant",
1311
- "network": "mainnet"
1422
+ "network": "mainnet",
1423
+ "confirmed": true
1312
1424
  }
1313
1425
  }
1314
1426
  ```
@@ -1336,7 +1448,8 @@ Create an Arbitration object for handling order disputes.
1336
1448
  },
1337
1449
  "env": {
1338
1450
  "account": "myshop_merchant",
1339
- "network": "mainnet"
1451
+ "network": "mainnet",
1452
+ "confirmed": true
1340
1453
  }
1341
1454
  }
1342
1455
  ```
@@ -1358,7 +1471,8 @@ The merchant unpauses the Arbitration object to enable dispute submissions.
1358
1471
  },
1359
1472
  "env": {
1360
1473
  "account": "myshop_merchant",
1361
- "network": "mainnet"
1474
+ "network": "mainnet",
1475
+ "confirmed": true
1362
1476
  }
1363
1477
  }
1364
1478
  ```
@@ -1379,7 +1493,8 @@ Create a new order for testing the arbitration flow (if you don't have one alrea
1379
1493
  "items": [
1380
1494
  {
1381
1495
  "name": "Tree House Building Set",
1382
- "stock": 1
1496
+ "stock": 1,
1497
+ "wip_hash": "03c18561efa8faf4d75480eb1f732c4a46ffde95599e92eca06167785fc07a5b"
1383
1498
  }
1384
1499
  ],
1385
1500
  "total_pay": {"balance": 30000000}
@@ -1391,12 +1506,13 @@ Create a new order for testing the arbitration flow (if you don't have one alrea
1391
1506
  },
1392
1507
  "env": {
1393
1508
  "account": "myshop_customer",
1394
- "network": "mainnet"
1509
+ "network": "mainnet",
1510
+ "confirmed": true
1395
1511
  }
1396
1512
  }
1397
1513
  ```
1398
1514
 
1399
- > **Note**: The WIP hash is auto-computed by the SDK from the Service's WIP URL configuration.
1515
+ > **Note**: The `wip_hash` must be obtained from the Service query result (Step 1 of Part 2). It cannot be omitted or set to an empty string — the on-chain contract validates it against the Service's current `sale.wip_hash`.
1400
1516
 
1401
1517
  ### Step 5: Customer Submits Dispute
1402
1518
 
@@ -1419,7 +1535,8 @@ The customer submits a dispute against the order, creating an Arb object.
1419
1535
  },
1420
1536
  "env": {
1421
1537
  "account": "myshop_customer",
1422
- "network": "mainnet"
1538
+ "network": "mainnet",
1539
+ "confirmed": true
1423
1540
  }
1424
1541
  }
1425
1542
  ```
@@ -1444,7 +1561,8 @@ The merchant confirms the dispute materials are valid and sets the voting deadli
1444
1561
  },
1445
1562
  "env": {
1446
1563
  "account": "myshop_merchant",
1447
- "network": "mainnet"
1564
+ "network": "mainnet",
1565
+ "confirmed": true
1448
1566
  }
1449
1567
  }
1450
1568
  ```
@@ -1470,7 +1588,8 @@ The merchant provides the final arbitration result with feedback and indemnity a
1470
1588
  },
1471
1589
  "env": {
1472
1590
  "account": "myshop_merchant",
1473
- "network": "mainnet"
1591
+ "network": "mainnet",
1592
+ "confirmed": true
1474
1593
  }
1475
1594
  }
1476
1595
  ```
@@ -1494,7 +1613,8 @@ The customer claims the compensation from the Service's compensation fund.
1494
1613
  },
1495
1614
  "env": {
1496
1615
  "account": "myshop_customer",
1497
- "network": "mainnet"
1616
+ "network": "mainnet",
1617
+ "confirmed": true
1498
1618
  }
1499
1619
  }
1500
1620
  ```
@@ -1573,7 +1693,8 @@ When advancing order workflows, use `operation_type: "progress"` with the `opera
1573
1693
  },
1574
1694
  "env": {
1575
1695
  "account": "operator_account",
1576
- "network": "mainnet"
1696
+ "network": "mainnet",
1697
+ "confirmed": true
1577
1698
  }
1578
1699
  }
1579
1700
  ```