@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,15 @@ A complete example demonstrating how to create an outdoor accident insurance ser
|
|
|
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 claim or order flow. Do not skip steps — each depends on objects created by prior steps.
|
|
12
|
+
- **Prerequisites**: `insurance_provider_v1` with sufficient WOW for gas. All on-chain operations require `env.confirmed: true`.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
7
16
|
## Core Requirements & Features
|
|
8
17
|
|
|
9
18
|
| Requirement | Description | Implementation |
|
|
@@ -12,13 +21,17 @@ A complete example demonstrating how to create an outdoor accident insurance ser
|
|
|
12
21
|
| **Time-Lock Guard** | Prevent premature claim completion | Guard using Order + convert_witness(TypeOrderProgress) to verify clock > progress.current_time + lock_duration |
|
|
13
22
|
| **Supply Chain Integration** | Support sub-order creation by travel service providers | Order can be created by authorized agents (travel_provider) |
|
|
14
23
|
| **Permission Control** | Role-based access for insurance operations | Permission object with custom indexes for claim processing |
|
|
24
|
+
| **Safe Fund Allocation** | Merchant revenue collection without theft risk | 2 alternative allocators with `sharing.who = {"Entity": ...}` (funds flow to fixed Treasury or personal address) |
|
|
15
25
|
|
|
16
26
|
### Key Design Decisions
|
|
17
27
|
|
|
18
|
-
1. **Time-Lock via Witness Conversion**: The Complete node Guard uses `convert_witness:
|
|
28
|
+
1. **Time-Lock via Witness Conversion**: The Complete node Guard uses `convert_witness: "OrderProgress"` (TypeOrderProgress) to convert the submitted Order ID into its associated Progress object, then queries `progress.current_time` to verify the time-lock condition.
|
|
19
29
|
2. **Simple Two-Node Workflow**: Insurance claims follow a straightforward Start -> Complete path, keeping the workflow simple and predictable.
|
|
20
30
|
3. **Order ID as Submission**: The Order ID is submitted at runtime (`b_submission: true`) and used for witness conversion.
|
|
21
31
|
4. **Machine Creation Pattern**: Machine can be created with nodes and published in a single transaction (as shown in this example).
|
|
32
|
+
5. **Entity Sharing for Fund Safety**: Order allocators use `sharing.who = {"Entity": "address"}` instead of `{"Signer": "signer"}`. Funds always flow to a fixed address (Treasury or personal) regardless of who triggers the allocation — even if the Guard is somehow bypassed, an attacker cannot redirect funds to themselves. This eliminates the fatal fund-theft risk of Signer sharing.
|
|
33
|
+
6. **Project Binding as Defense-in-Depth**: Each withdraw Guard verifies `order.service == insurance_service_v1` (query 1563) to ensure the submitted Order belongs to this Service, preventing cross-service order theft.
|
|
34
|
+
7. **Permission Consistency**: The Treasury object uses the same Permission (`insurance_permission_v1`) as the Service, ensuring a single consistent permission organization governs all insurance operations.
|
|
22
35
|
|
|
23
36
|
---
|
|
24
37
|
|
|
@@ -26,8 +39,9 @@ A complete example demonstrating how to create an outdoor accident insurance ser
|
|
|
26
39
|
|
|
27
40
|
This example demonstrates:
|
|
28
41
|
|
|
29
|
-
- **Insurance Service Setup**: Permission, Guard, Machine, and Service creation
|
|
42
|
+
- **Insurance Service Setup**: Permission, Treasury, Guard, Machine, and Service creation
|
|
30
43
|
- **Time-Lock Guard**: Using Order + convert_witness to access Progress data
|
|
44
|
+
- **Safe Fund Allocation**: Two alternative merchant collection approaches via Entity sharing
|
|
31
45
|
- **Workflow Automation**: Machine-driven claim processing
|
|
32
46
|
|
|
33
47
|
---
|
|
@@ -49,12 +63,20 @@ This example demonstrates:
|
|
|
49
63
|
| | | |
|
|
50
64
|
| v v |
|
|
51
65
|
| +-----------------+ +-----------------+ |
|
|
52
|
-
| |
|
|
53
|
-
| | (insurance_
|
|
54
|
-
| |
|
|
66
|
+
| | Treasury | | Machine | |
|
|
67
|
+
| | (insurance_ | | (insurance_ | |
|
|
68
|
+
| | treasury) | | machine) | |
|
|
69
|
+
| +--------+--------+ +--------+--------+ |
|
|
70
|
+
| | | |
|
|
71
|
+
| v v |
|
|
72
|
+
| +-----------------+ +-----------------+ |
|
|
73
|
+
| | withdraw guards | | Service | |
|
|
74
|
+
| | (treasury + |<---| (insurance_ | |
|
|
75
|
+
| | personal) | | service) | |
|
|
55
76
|
| +-----------------+ +-----------------+ |
|
|
56
77
|
| |
|
|
57
78
|
| Workflow: Start -> Complete (Time-Lock Guard) |
|
|
79
|
+
| Allocators: 2 Entity-sharing approaches (first-match-wins) |
|
|
58
80
|
| |
|
|
59
81
|
------------------------------------------------------------------
|
|
60
82
|
```
|
|
@@ -71,9 +93,32 @@ This example demonstrates:
|
|
|
71
93
|
**Guard Logic**:
|
|
72
94
|
```
|
|
73
95
|
clock > progress.current_time + 1000ms
|
|
74
|
-
(progress accessed via Order + convert_witness=
|
|
96
|
+
(progress accessed via Order + convert_witness="OrderProgress")
|
|
75
97
|
```
|
|
76
98
|
|
|
99
|
+
### Fund Allocation Flow (2 Alternative Approaches)
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
Order reaches Complete
|
|
103
|
+
|
|
|
104
|
+
v
|
|
105
|
+
Allocation triggered
|
|
106
|
+
|
|
|
107
|
+
+----+----+
|
|
108
|
+
| |
|
|
109
|
+
v v
|
|
110
|
+
Approach 1: Approach 2:
|
|
111
|
+
Treasury Personal
|
|
112
|
+
guard guard
|
|
113
|
+
| |
|
|
114
|
+
v v
|
|
115
|
+
Entity: Entity:
|
|
116
|
+
insurance_ insurance_
|
|
117
|
+
treasury provider
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
> **first-match-wins**: Allocators execute the FIRST Allocator whose Guard passes. Listing both approaches in one Service illustrates the 2 design options; in production you would typically pick ONE approach (delete the other allocator).
|
|
121
|
+
|
|
77
122
|
---
|
|
78
123
|
|
|
79
124
|
## Prerequisites
|
|
@@ -150,9 +195,38 @@ Create a Permission object to manage access control for the insurance service. T
|
|
|
150
195
|
|
|
151
196
|
---
|
|
152
197
|
|
|
153
|
-
## Step 2: Create
|
|
198
|
+
## Step 2: Create Treasury Object
|
|
199
|
+
|
|
200
|
+
Create a Treasury object to aggregate insurance service revenue (public funds for operations and distribution). The Treasury uses the same Permission as the Service (`insurance_permission_v1`) — this ensures a single consistent permission organization governs both fund collection and service operations.
|
|
201
|
+
|
|
202
|
+
**Prompt**: Create a Treasury object named "insurance_treasury" for aggregating insurance revenue.
|
|
203
|
+
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"operation_type": "treasury",
|
|
207
|
+
"data": {
|
|
208
|
+
"object": {
|
|
209
|
+
"name": "insurance_treasury_v1",
|
|
210
|
+
"type_parameter": "0x2::wow::WOW",
|
|
211
|
+
"permission": "insurance_permission_v1",
|
|
212
|
+
"replaceExistName": true
|
|
213
|
+
},
|
|
214
|
+
"description": "Treasury for aggregating insurance service revenue (public funds for operations and distribution). Uses the same Permission as the Service for consistency."
|
|
215
|
+
},
|
|
216
|
+
"env": {
|
|
217
|
+
"account": "insurance_provider_v1",
|
|
218
|
+
"network": "testnet"
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
> **Important — Permission Consistency**: The Treasury's Permission should match the Service's Permission (`insurance_permission_v1`). Using different Permissions for Treasury and Service means different permission organizations govern fund collection vs service operations — this is a minor design risk. Keep them consistent unless you have a specific reason to separate them.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Step 3: Create Time-Lock Complete Guard
|
|
154
228
|
|
|
155
|
-
Create a Guard that verifies the time-lock condition for claim completion. The Guard uses the submitted Order ID with `convert_witness:
|
|
229
|
+
Create a Guard that verifies the time-lock condition for claim completion. The Guard uses the submitted Order ID with `convert_witness: "OrderProgress"` (TypeOrderProgress) to access the associated Progress object and query `progress.current_time`.
|
|
156
230
|
|
|
157
231
|
**Guard Logic**:
|
|
158
232
|
```
|
|
@@ -170,7 +244,7 @@ clock > progress.current_time + 1000
|
|
|
170
244
|
"tags": ["insurance", "time-lock", "complete"],
|
|
171
245
|
"replaceExistName": true
|
|
172
246
|
},
|
|
173
|
-
"description": "Time-lock guard for insurance claim completion. Requires current clock > progress.current_time + 10000ms (10 seconds for TESTING; in production set to reasonable duration like 8 hours). Progress is accessed via Order with convert_witness=
|
|
247
|
+
"description": "Time-lock guard for insurance claim completion. Requires current clock > progress.current_time + 10000ms (10 seconds for TESTING; in production set to reasonable duration like 8 hours). Progress is accessed via Order with convert_witness="OrderProgress"(100).",
|
|
174
248
|
|
|
175
249
|
"table": [
|
|
176
250
|
{
|
|
@@ -198,10 +272,10 @@ clock > progress.current_time + 1000
|
|
|
198
272
|
"nodes": [
|
|
199
273
|
{
|
|
200
274
|
"type": "query",
|
|
201
|
-
"query":
|
|
275
|
+
"query": "progress.current_time",
|
|
202
276
|
"object": {
|
|
203
277
|
"identifier": 0,
|
|
204
|
-
"convert_witness":
|
|
278
|
+
"convert_witness": "OrderProgress"
|
|
205
279
|
},
|
|
206
280
|
"parameters": []
|
|
207
281
|
},
|
|
@@ -232,52 +306,181 @@ clock > progress.current_time + 1000
|
|
|
232
306
|
|
|
233
307
|
---
|
|
234
308
|
|
|
235
|
-
## Step
|
|
309
|
+
## Step 4: Create Withdraw Guards for Order Allocators
|
|
236
310
|
|
|
237
|
-
Create
|
|
311
|
+
Create **two** withdraw Guards — one for each merchant collection approach. Both Guards share identical root/table logic (order at Complete node + project binding) but differ in `description` to indicate their distinct purposes. Allocators require unique Guard addresses, so two Guard objects are needed.
|
|
238
312
|
|
|
239
|
-
**
|
|
313
|
+
**Guard Logic** (identical for both):
|
|
314
|
+
```
|
|
315
|
+
logic_and[
|
|
316
|
+
query("progress.current") == "Complete", // order is at Complete node
|
|
317
|
+
query("order.service") == insurance_service_v1 // order belongs to THIS service
|
|
318
|
+
]
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
**Risk Elimination**:
|
|
322
|
+
- **Project binding** (query 1563): prevents cross-service order theft — an attacker cannot submit another Service's completed Order to trigger allocation.
|
|
323
|
+
- **Entity sharing** (configured in Step 6): funds flow to a fixed address regardless of caller — no Signer binding needed in the Guard.
|
|
324
|
+
|
|
325
|
+
### 4.1 Treasury Collection Guard
|
|
326
|
+
|
|
327
|
+
**Prompt**: Create a Guard named "insurance_withdraw_guard_treasury" for Treasury fund collection.
|
|
240
328
|
|
|
241
329
|
```json
|
|
242
330
|
{
|
|
243
331
|
"operation_type": "guard",
|
|
244
332
|
"data": {
|
|
245
333
|
"namedNew": {
|
|
246
|
-
"name": "
|
|
247
|
-
"tags": ["insurance", "withdraw"],
|
|
334
|
+
"name": "insurance_withdraw_guard_treasury_v1",
|
|
335
|
+
"tags": ["insurance", "withdraw", "treasury"],
|
|
248
336
|
"replaceExistName": true
|
|
249
337
|
},
|
|
250
|
-
"description": "Allow
|
|
338
|
+
"description": "Allow fund allocation to Treasury after order is completed. RISK ELIMINATION: order must be at Complete node AND belong to insurance_service_v1 (prevents cross-service theft). Funds flow to fixed Treasury Entity (safe — no Signer binding needed).",
|
|
251
339
|
"table": [
|
|
252
340
|
{
|
|
253
341
|
"identifier": 0,
|
|
254
342
|
"b_submission": true,
|
|
255
343
|
"value_type": "Address",
|
|
256
|
-
"
|
|
344
|
+
"object_type": "Order",
|
|
345
|
+
"name": "order_id (Order object submitted at runtime)"
|
|
257
346
|
},
|
|
258
347
|
{
|
|
259
348
|
"identifier": 1,
|
|
260
349
|
"b_submission": false,
|
|
261
350
|
"value_type": "String",
|
|
262
351
|
"value": "Complete",
|
|
263
|
-
"name": "
|
|
352
|
+
"name": "Expected Complete node name (case-sensitive)"
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
"identifier": 2,
|
|
356
|
+
"b_submission": false,
|
|
357
|
+
"value_type": "Address",
|
|
358
|
+
"value": "insurance_service_v1",
|
|
359
|
+
"name": "Expected service address (prevents cross-service fund theft)"
|
|
264
360
|
}
|
|
265
361
|
],
|
|
266
362
|
"root": {
|
|
267
|
-
"type": "
|
|
363
|
+
"type": "logic_and",
|
|
268
364
|
"nodes": [
|
|
269
365
|
{
|
|
270
|
-
"type": "
|
|
271
|
-
"
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
366
|
+
"type": "logic_equal",
|
|
367
|
+
"nodes": [
|
|
368
|
+
{
|
|
369
|
+
"type": "query",
|
|
370
|
+
"query": "progress.current",
|
|
371
|
+
"object": {
|
|
372
|
+
"identifier": 0,
|
|
373
|
+
"convert_witness": "OrderProgress"
|
|
374
|
+
},
|
|
375
|
+
"parameters": []
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
"type": "identifier",
|
|
379
|
+
"identifier": 1
|
|
380
|
+
}
|
|
381
|
+
]
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
"type": "logic_equal",
|
|
385
|
+
"nodes": [
|
|
386
|
+
{
|
|
387
|
+
"type": "query",
|
|
388
|
+
"query": "order.service",
|
|
389
|
+
"object": {
|
|
390
|
+
"identifier": 0
|
|
391
|
+
},
|
|
392
|
+
"parameters": []
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
"type": "identifier",
|
|
396
|
+
"identifier": 2
|
|
397
|
+
}
|
|
398
|
+
]
|
|
399
|
+
}
|
|
400
|
+
]
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
"env": {
|
|
404
|
+
"account": "insurance_provider_v1",
|
|
405
|
+
"network": "testnet"
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### 4.2 Personal Collection Guard
|
|
411
|
+
|
|
412
|
+
**Prompt**: Create a Guard named "insurance_withdraw_guard_personal" for personal fund collection.
|
|
413
|
+
|
|
414
|
+
```json
|
|
415
|
+
{
|
|
416
|
+
"operation_type": "guard",
|
|
417
|
+
"data": {
|
|
418
|
+
"namedNew": {
|
|
419
|
+
"name": "insurance_withdraw_guard_personal_v1",
|
|
420
|
+
"tags": ["insurance", "withdraw", "personal"],
|
|
421
|
+
"replaceExistName": true
|
|
422
|
+
},
|
|
423
|
+
"description": "Allow fund allocation to personal collection address after order is completed. RISK ELIMINATION: order must be at Complete node AND belong to insurance_service_v1. Funds flow to fixed personal Entity (safe — no Signer binding needed).",
|
|
424
|
+
"table": [
|
|
425
|
+
{
|
|
426
|
+
"identifier": 0,
|
|
427
|
+
"b_submission": true,
|
|
428
|
+
"value_type": "Address",
|
|
429
|
+
"object_type": "Order",
|
|
430
|
+
"name": "order_id (Order object submitted at runtime)"
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
"identifier": 1,
|
|
434
|
+
"b_submission": false,
|
|
435
|
+
"value_type": "String",
|
|
436
|
+
"value": "Complete",
|
|
437
|
+
"name": "Expected Complete node name (case-sensitive)"
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
"identifier": 2,
|
|
441
|
+
"b_submission": false,
|
|
442
|
+
"value_type": "Address",
|
|
443
|
+
"value": "insurance_service_v1",
|
|
444
|
+
"name": "Expected service address (prevents cross-service fund theft)"
|
|
445
|
+
}
|
|
446
|
+
],
|
|
447
|
+
"root": {
|
|
448
|
+
"type": "logic_and",
|
|
449
|
+
"nodes": [
|
|
450
|
+
{
|
|
451
|
+
"type": "logic_equal",
|
|
452
|
+
"nodes": [
|
|
453
|
+
{
|
|
454
|
+
"type": "query",
|
|
455
|
+
"query": "progress.current",
|
|
456
|
+
"object": {
|
|
457
|
+
"identifier": 0,
|
|
458
|
+
"convert_witness": "OrderProgress"
|
|
459
|
+
},
|
|
460
|
+
"parameters": []
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
"type": "identifier",
|
|
464
|
+
"identifier": 1
|
|
465
|
+
}
|
|
466
|
+
]
|
|
277
467
|
},
|
|
278
468
|
{
|
|
279
|
-
"type": "
|
|
280
|
-
"
|
|
469
|
+
"type": "logic_equal",
|
|
470
|
+
"nodes": [
|
|
471
|
+
{
|
|
472
|
+
"type": "query",
|
|
473
|
+
"query": "order.service",
|
|
474
|
+
"object": {
|
|
475
|
+
"identifier": 0
|
|
476
|
+
},
|
|
477
|
+
"parameters": []
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
"type": "identifier",
|
|
481
|
+
"identifier": 2
|
|
482
|
+
}
|
|
483
|
+
]
|
|
281
484
|
}
|
|
282
485
|
]
|
|
283
486
|
}
|
|
@@ -289,9 +492,19 @@ Create a Guard that allows the insurance provider to withdraw funds after the or
|
|
|
289
492
|
}
|
|
290
493
|
```
|
|
291
494
|
|
|
495
|
+
**Guard Table** (identical for both guards):
|
|
496
|
+
|
|
497
|
+
| identifier | b_submission | value_type | value | Purpose |
|
|
498
|
+
|------------|-------------|-----------|-------|---------|
|
|
499
|
+
| 0 | **true** | Address | (submitted at runtime) | Order ID submitted at runtime, converted to Progress via convert_witness="OrderProgress" |
|
|
500
|
+
| 1 | false | String | "Complete" | Expected node name (case-sensitive) |
|
|
501
|
+
| 2 | false | Address | insurance_service_v1 | Expected Service address (project binding — prevents cross-service fund theft) |
|
|
502
|
+
|
|
503
|
+
> **Why 2 Guards?** Allocators require unique Guard addresses. The 2 Guards have identical root/table logic but different `description` and `tags` to indicate their distinct purposes (Treasury collection vs personal collection). In production you would typically pick ONE approach and delete the other Guard + Allocator.
|
|
504
|
+
|
|
292
505
|
---
|
|
293
506
|
|
|
294
|
-
## Step
|
|
507
|
+
## Step 5: Create, Configure and Publish Machine
|
|
295
508
|
|
|
296
509
|
Create a Machine with workflow nodes and publish it in a single transaction.
|
|
297
510
|
|
|
@@ -370,9 +583,9 @@ Create a Machine with workflow nodes and publish it in a single transaction.
|
|
|
370
583
|
|
|
371
584
|
---
|
|
372
585
|
|
|
373
|
-
## Step
|
|
586
|
+
## Step 6: Create and Publish Service
|
|
374
587
|
|
|
375
|
-
Create the insurance service with machine, order_allocators, sales, and publish in a single transaction.
|
|
588
|
+
Create the insurance service with machine, order_allocators (2 alternative approaches), sales, and publish in a single transaction.
|
|
376
589
|
|
|
377
590
|
> **Important**:
|
|
378
591
|
> - Service must include `order_allocators` when publishing
|
|
@@ -394,14 +607,24 @@ Create the insurance service with machine, order_allocators, sales, and publish
|
|
|
394
607
|
"description": "Outdoor accident insurance for Iceland travel. Provides coverage for ice scooting and other outdoor activities.",
|
|
395
608
|
"machine": "insurance_machine_v1",
|
|
396
609
|
"order_allocators": {
|
|
397
|
-
"description": "Insurance order revenue allocation",
|
|
610
|
+
"description": "Insurance order revenue allocation — 2 alternative merchant collection approaches (first-match-wins means only the first passing allocator executes)",
|
|
398
611
|
"threshold": 0,
|
|
399
612
|
"allocators": [
|
|
400
613
|
{
|
|
401
|
-
"guard": "
|
|
614
|
+
"guard": "insurance_withdraw_guard_treasury_v1",
|
|
615
|
+
"sharing": [
|
|
616
|
+
{
|
|
617
|
+
"who": {"Entity": "insurance_treasury_v1"},
|
|
618
|
+
"sharing": 10000,
|
|
619
|
+
"mode": "Rate"
|
|
620
|
+
}
|
|
621
|
+
]
|
|
622
|
+
},
|
|
623
|
+
{
|
|
624
|
+
"guard": "insurance_withdraw_guard_personal_v1",
|
|
402
625
|
"sharing": [
|
|
403
626
|
{
|
|
404
|
-
"who": {"
|
|
627
|
+
"who": {"Entity": "insurance_provider_v1"},
|
|
405
628
|
"sharing": 10000,
|
|
406
629
|
"mode": "Rate"
|
|
407
630
|
}
|
|
@@ -417,7 +640,7 @@ Create the insurance service with machine, order_allocators, sales, and publish
|
|
|
417
640
|
"price": 100000000,
|
|
418
641
|
"stock": 1000,
|
|
419
642
|
"suspension": false,
|
|
420
|
-
"wip": "",
|
|
643
|
+
"wip": "https://cdn.jsdelivr.net/gh/wowok-ai/docs@main/wip-examples/three_body.wip",
|
|
421
644
|
"wip_hash": ""
|
|
422
645
|
}
|
|
423
646
|
]
|
|
@@ -431,13 +654,19 @@ Create the insurance service with machine, order_allocators, sales, and publish
|
|
|
431
654
|
}
|
|
432
655
|
```
|
|
433
656
|
|
|
434
|
-
> **Important**:
|
|
657
|
+
> **Important — Fund Allocation Safety**:
|
|
435
658
|
> - `mode: "Rate"` represents Rate allocation mode (valid values: `"Amount"`, `"Rate"`, `"Surplus"`)
|
|
436
|
-
> - `who: {"
|
|
659
|
+
> - `who: {"Entity": "name_or_address"}` — funds flow to a FIXED address (Treasury or personal). This is the SAFE pattern: even if the Guard is somehow bypassed or an attacker submits a forged Order, funds still go to the fixed Entity — the attacker cannot redirect funds to themselves.
|
|
660
|
+
> - **NEVER use `who: {"Signer": "signer"}` for merchant collection** — this means funds flow to whoever calls the allocation. Combined with a Guard that only checks order status (no Signer binding), anyone can submit any completed Order and steal 100% of funds.
|
|
661
|
+
> - **2 allocators = 2 alternative approaches**: first-match-wins means only the FIRST allocator whose Guard passes will execute. In production, pick ONE approach (Treasury OR personal) and delete the other. Listing both here illustrates the 2 design options.
|
|
662
|
+
> - **Permission consistency**: the Treasury uses `insurance_permission_v1` (same as Service) — keep Permissions consistent unless you have a specific reason to separate them.
|
|
663
|
+
> - `wip_hash: ""` (empty string) means the system will automatically extract and use the hash from within the WIP file (`meta.hash` field). The WIP file at the `wip` URL must be a valid JSON file in WIP format. Do NOT use the SHA-256 of the file bytes as `wip_hash` — it must be the `meta.hash` value inside the WIP JSON, or empty string for auto-extraction.
|
|
437
664
|
|
|
438
665
|
---
|
|
439
666
|
|
|
440
|
-
## Step
|
|
667
|
+
## Step 7: Unpause Service (Optional)
|
|
668
|
+
|
|
669
|
+
> **Note**: A newly created Service is **not paused by default**. This step is only needed if you explicitly paused the service earlier. You can safely skip this step and proceed to Step 8.
|
|
441
670
|
|
|
442
671
|
Unpause the service to allow order creation.
|
|
443
672
|
|
|
@@ -459,7 +688,7 @@ Unpause the service to allow order creation.
|
|
|
459
688
|
|
|
460
689
|
---
|
|
461
690
|
|
|
462
|
-
## Step
|
|
691
|
+
## Step 8: Verify Service Configuration
|
|
463
692
|
|
|
464
693
|
Query the service to verify all configurations are correct.
|
|
465
694
|
|
|
@@ -475,9 +704,9 @@ Query the service to verify all configurations are correct.
|
|
|
475
704
|
|
|
476
705
|
---
|
|
477
706
|
|
|
478
|
-
## Step
|
|
707
|
+
## Step 9: Test Order Creation and Progress
|
|
479
708
|
|
|
480
|
-
###
|
|
709
|
+
### 9.1 Create Insurance Order
|
|
481
710
|
|
|
482
711
|
Create an order on the insurance service using the `order_new` field of the `service` operation. In production, this would be done by the travel service provider as a supply chain sub-order.
|
|
483
712
|
|
|
@@ -504,6 +733,14 @@ Create an order on the insurance service using the `order_new` field of the `ser
|
|
|
504
733
|
"namedNewOrder": {
|
|
505
734
|
"name": "test_insurance_order_v1",
|
|
506
735
|
"replaceExistName": true
|
|
736
|
+
},
|
|
737
|
+
"namedNewAllocation": {
|
|
738
|
+
"name": "insurance_test_alloc_v1",
|
|
739
|
+
"replaceExistName": true
|
|
740
|
+
},
|
|
741
|
+
"namedNewProgress": {
|
|
742
|
+
"name": "insurance_test_progress_v1",
|
|
743
|
+
"replaceExistName": true
|
|
507
744
|
}
|
|
508
745
|
}
|
|
509
746
|
},
|
|
@@ -514,7 +751,9 @@ Create an order on the insurance service using the `order_new` field of the `ser
|
|
|
514
751
|
}
|
|
515
752
|
```
|
|
516
753
|
|
|
517
|
-
> **
|
|
754
|
+
> **Named Objects**: The `namedNewOrder`, `namedNewAllocation`, and `namedNewProgress` fields assign local names to the created objects. You can reference them by name (e.g., `"test_insurance_order_v1"`, `"insurance_test_alloc_v1"`, `"insurance_test_progress_v1"`) in subsequent operations instead of using raw on-chain IDs.
|
|
755
|
+
>
|
|
756
|
+
> **Optional — Query the Order**: To verify the order or obtain on-chain object IDs:
|
|
518
757
|
> ```json
|
|
519
758
|
> {
|
|
520
759
|
> "query_type": "onchain_objects",
|
|
@@ -523,9 +762,9 @@ Create an order on the insurance service using the `order_new` field of the `ser
|
|
|
523
762
|
> "no_cache": true
|
|
524
763
|
> }
|
|
525
764
|
> ```
|
|
526
|
-
> The response includes
|
|
765
|
+
> The response includes `progress` and `allocation` fields with the on-chain object IDs.
|
|
527
766
|
|
|
528
|
-
###
|
|
767
|
+
### 9.2 Advance Progress: Initial -> Start
|
|
529
768
|
|
|
530
769
|
First, advance the progress from initial state to Start node.
|
|
531
770
|
|
|
@@ -533,10 +772,10 @@ First, advance the progress from initial state to Start node.
|
|
|
533
772
|
|
|
534
773
|
```json
|
|
535
774
|
{
|
|
536
|
-
"operation_type": "
|
|
775
|
+
"operation_type": "order",
|
|
537
776
|
"data": {
|
|
538
|
-
"object": "
|
|
539
|
-
"
|
|
777
|
+
"object": "test_insurance_order_v1",
|
|
778
|
+
"progress": {
|
|
540
779
|
"operation": {
|
|
541
780
|
"next_node_name": "Start",
|
|
542
781
|
"forward": "start_claim"
|
|
@@ -553,9 +792,9 @@ First, advance the progress from initial state to Start node.
|
|
|
553
792
|
> **Note**:
|
|
554
793
|
> - Both `next_node_name` and `forward` fields are required in the operation object
|
|
555
794
|
> - Use simple forward name (e.g., `"start_claim"`) without node prefix. The system automatically resolves the path from current node
|
|
556
|
-
> - The Progress
|
|
795
|
+
> - The Progress is advanced via the Order object's `progress` field, using the Order name as reference
|
|
557
796
|
|
|
558
|
-
###
|
|
797
|
+
### 9.3 Advance Progress: Start -> Complete
|
|
559
798
|
|
|
560
799
|
Wait at least 10 seconds after entering Start node, then advance the progress to Complete with the Order ID as submission.
|
|
561
800
|
|
|
@@ -569,10 +808,10 @@ Wait at least 10 seconds after entering Start node, then advance the progress to
|
|
|
569
808
|
|
|
570
809
|
```json
|
|
571
810
|
{
|
|
572
|
-
"operation_type": "
|
|
811
|
+
"operation_type": "order",
|
|
573
812
|
"data": {
|
|
574
|
-
"object": "
|
|
575
|
-
"
|
|
813
|
+
"object": "test_insurance_order_v1",
|
|
814
|
+
"progress": {
|
|
576
815
|
"operation": {
|
|
577
816
|
"next_node_name": "Complete",
|
|
578
817
|
"forward": "complete_claim"
|
|
@@ -617,10 +856,10 @@ The server will return a `submission` prompt like:
|
|
|
617
856
|
|
|
618
857
|
```json
|
|
619
858
|
{
|
|
620
|
-
"operation_type": "
|
|
859
|
+
"operation_type": "order",
|
|
621
860
|
"data": {
|
|
622
|
-
"object": "
|
|
623
|
-
"
|
|
861
|
+
"object": "test_insurance_order_v1",
|
|
862
|
+
"progress": {
|
|
624
863
|
"operation": {
|
|
625
864
|
"next_node_name": "Complete",
|
|
626
865
|
"forward": "complete_claim"
|
|
@@ -645,7 +884,7 @@ The server will return a `submission` prompt like:
|
|
|
645
884
|
"value_type": "Address",
|
|
646
885
|
"name": "Order ID (submitted at runtime)",
|
|
647
886
|
"object_type": "Order",
|
|
648
|
-
"value": "
|
|
887
|
+
"value": "test_insurance_order_v1"
|
|
649
888
|
}
|
|
650
889
|
]
|
|
651
890
|
}
|
|
@@ -659,15 +898,126 @@ The server will return a `submission` prompt like:
|
|
|
659
898
|
```
|
|
660
899
|
|
|
661
900
|
> **⚠️ Important**:
|
|
662
|
-
> - The `submission` field must be at the **root level** of the request (sibling to `operation_type`, `data`, and `env`), NOT nested inside `data` or `
|
|
663
|
-
> - The `guard` objects in the submission use on-chain addresses (not names), as returned by the Phase 1 response.
|
|
664
|
-
> -
|
|
665
|
-
> -
|
|
901
|
+
> - The `submission` field must be at the **root level** of the request (sibling to `operation_type`, `data`, and `env`), NOT nested inside `data` or `progress.operation`.
|
|
902
|
+
> - The `guard` objects in the submission use on-chain addresses (not names), as returned by the Phase 1 response. Replace `0x1508ded8...` with the actual guard address from your Phase 1 response.
|
|
903
|
+
> - The `value` field accepts either an on-chain object ID or a named object reference (e.g., `"test_insurance_order_v1"`). Keep the other fields (`identifier`, `value_type`, `name`, `object_type`) as returned by Phase 1.
|
|
904
|
+
> - The Order is referenced by its name (`"test_insurance_order_v1"`) in the `data.object` field.
|
|
666
905
|
> - Both `next_node_name` and `forward` fields are required in the operation object.
|
|
667
906
|
> - Use simple forward name `"complete_claim"` without node prefix.
|
|
668
907
|
|
|
669
908
|
---
|
|
670
909
|
|
|
910
|
+
## Step 10: Withdraw Funds via Allocation
|
|
911
|
+
|
|
912
|
+
After the Progress reaches the Complete node, funds can be withdrawn using one of the withdraw Guards. This example uses the Treasury collection Guard (`insurance_withdraw_guard_treasury_v1`). To use the personal collection approach instead, substitute `insurance_withdraw_guard_personal_v1`.
|
|
913
|
+
|
|
914
|
+
The Guard verifies:
|
|
915
|
+
1. `progress.current == "Complete"` (query 1253) via the submitted Order ID with `convert_witness: "OrderProgress"` (TypeOrderProgress)
|
|
916
|
+
2. `order.service == insurance_service_v1` (query 1563) — project binding prevents cross-service order theft
|
|
917
|
+
|
|
918
|
+
The Allocation object was created automatically when the Order was placed (Step 9.1). Query the Order to obtain the Allocation object ID — it is in the `allocation` field of the Order object.
|
|
919
|
+
|
|
920
|
+
> **Fund Flow**: With `sharing.who = {"Entity": "insurance_treasury_v1"}`, 100% of the order amount flows to the Treasury object regardless of who triggers the allocation. The caller cannot redirect funds — this is the safe Entity-sharing pattern.
|
|
921
|
+
|
|
922
|
+
> **Two-Phase Submission**: The `alloc_by_guard` operation also uses two-phase submission when the Guard has `b_submission: true` fields, just like the Progress operation in Step 9.3.
|
|
923
|
+
|
|
924
|
+
### 10.1 Phase 1: Request Submission Prompt
|
|
925
|
+
|
|
926
|
+
Call the allocation operation WITHOUT the `submission` field to obtain the Guard submission structure.
|
|
927
|
+
|
|
928
|
+
**Prompt**: Withdraw funds from allocation "insurance_test_alloc_v1" using Treasury withdraw guard.
|
|
929
|
+
|
|
930
|
+
```json
|
|
931
|
+
{
|
|
932
|
+
"operation_type": "allocation",
|
|
933
|
+
"data": {
|
|
934
|
+
"object": "insurance_test_alloc_v1",
|
|
935
|
+
"alloc_by_guard": "insurance_withdraw_guard_treasury_v1"
|
|
936
|
+
},
|
|
937
|
+
"env": {
|
|
938
|
+
"account": "insurance_provider_v1",
|
|
939
|
+
"network": "testnet"
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
```
|
|
943
|
+
|
|
944
|
+
The server will return a `submission` prompt like:
|
|
945
|
+
|
|
946
|
+
```json
|
|
947
|
+
{
|
|
948
|
+
"type": "submission",
|
|
949
|
+
"guard": [
|
|
950
|
+
{ "object": "0xfb8bed2f...", "impack": true }
|
|
951
|
+
],
|
|
952
|
+
"submission": [
|
|
953
|
+
{
|
|
954
|
+
"guard": "0xfb8bed2f...",
|
|
955
|
+
"submission": [
|
|
956
|
+
{
|
|
957
|
+
"identifier": 0,
|
|
958
|
+
"b_submission": true,
|
|
959
|
+
"value_type": "Address",
|
|
960
|
+
"name": "order_id (Order object submitted at runtime)",
|
|
961
|
+
"object_type": "Order"
|
|
962
|
+
}
|
|
963
|
+
]
|
|
964
|
+
}
|
|
965
|
+
]
|
|
966
|
+
}
|
|
967
|
+
```
|
|
968
|
+
|
|
969
|
+
### 10.2 Phase 2: Submit with Order ID
|
|
970
|
+
|
|
971
|
+
Fill in the `value` field with the Order ID (or Order name) and resubmit. The `submission` field must be placed at the **root level** of the request.
|
|
972
|
+
|
|
973
|
+
**Prompt**: Withdraw funds from allocation with Order ID submission.
|
|
974
|
+
|
|
975
|
+
```json
|
|
976
|
+
{
|
|
977
|
+
"operation_type": "allocation",
|
|
978
|
+
"data": {
|
|
979
|
+
"object": "insurance_test_alloc_v1",
|
|
980
|
+
"alloc_by_guard": "insurance_withdraw_guard_treasury_v1"
|
|
981
|
+
},
|
|
982
|
+
"submission": {
|
|
983
|
+
"type": "submission",
|
|
984
|
+
"guard": [
|
|
985
|
+
{
|
|
986
|
+
"object": "0xfb8bed2f...",
|
|
987
|
+
"impack": true
|
|
988
|
+
}
|
|
989
|
+
],
|
|
990
|
+
"submission": [
|
|
991
|
+
{
|
|
992
|
+
"guard": "0xfb8bed2f...",
|
|
993
|
+
"submission": [
|
|
994
|
+
{
|
|
995
|
+
"identifier": 0,
|
|
996
|
+
"b_submission": true,
|
|
997
|
+
"value_type": "Address",
|
|
998
|
+
"name": "order_id (Order object submitted at runtime)",
|
|
999
|
+
"object_type": "Order",
|
|
1000
|
+
"value": "test_insurance_order_v1"
|
|
1001
|
+
}
|
|
1002
|
+
]
|
|
1003
|
+
}
|
|
1004
|
+
]
|
|
1005
|
+
},
|
|
1006
|
+
"env": {
|
|
1007
|
+
"account": "insurance_provider_v1",
|
|
1008
|
+
"network": "testnet"
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
```
|
|
1012
|
+
|
|
1013
|
+
> **⚠️ Important**:
|
|
1014
|
+
> - Replace `0xfb8bed2f...` with the actual `insurance_withdraw_guard_treasury_v1` address from your Phase 1 response.
|
|
1015
|
+
> - The `value` field accepts either an on-chain object ID or a named object reference (e.g., `"test_insurance_order_v1"`).
|
|
1016
|
+
> - The `sharing` configuration (`{"Entity": "insurance_treasury_v1"}` at 100% Rate) determines where funds flow. Funds go to the fixed Treasury address regardless of who calls the allocation — this is the safe Entity-sharing pattern that prevents fund theft.
|
|
1017
|
+
> - After a successful withdrawal, the Allocation `balance` becomes `0` and a Payment object is created as an immutable record.
|
|
1018
|
+
|
|
1019
|
+
---
|
|
1020
|
+
|
|
671
1021
|
## Troubleshooting
|
|
672
1022
|
|
|
673
1023
|
### MoveAbort code: 7 (Guard Verification Failed)
|
|
@@ -676,6 +1026,10 @@ When advancing Progress, if you get `abort code: 7 (Verify failed)`, the Guard c
|
|
|
676
1026
|
- Wait longer than the time-lock duration (10000ms = 10 seconds) before advancing to Complete
|
|
677
1027
|
- Verify the submitted Order ID is correct and corresponds to the Progress being advanced
|
|
678
1028
|
|
|
1029
|
+
For the withdraw Guard:
|
|
1030
|
+
- Verify the Order's Progress is at the "Complete" node (case-sensitive — "Complete" ≠ "complete")
|
|
1031
|
+
- Verify the Order belongs to `insurance_service_v1` (project binding check via query 1563)
|
|
1032
|
+
|
|
679
1033
|
### Forward validation failed
|
|
680
1034
|
|
|
681
1035
|
If you see `Connection from current node "" to target node "Complete" does not exist`, use simple forward names without node prefix:
|
|
@@ -711,12 +1065,14 @@ Published Machine nodes are immutable (`MoveAbort code: 3`). Create a new Machin
|
|
|
711
1065
|
- [ ] Create `insurance_provider_v1` account
|
|
712
1066
|
- [ ] Get test tokens for `insurance_provider_v1`
|
|
713
1067
|
- [ ] Step 1: Create `insurance_permission_v1` with all required indexes
|
|
714
|
-
- [ ] Step 2: Create `
|
|
715
|
-
- [ ] Step 3: Create `
|
|
716
|
-
- [ ] Step 4: Create `
|
|
717
|
-
- [ ] Step 5: Create
|
|
718
|
-
- [ ] Step 6:
|
|
719
|
-
- [ ] Step 7:
|
|
720
|
-
- [ ] Step 8
|
|
721
|
-
- [ ] Step
|
|
722
|
-
- [ ] Step
|
|
1068
|
+
- [ ] Step 2: Create `insurance_treasury_v1` (same Permission as Service)
|
|
1069
|
+
- [ ] Step 3: Create `insurance_complete_guard_v1` (time-lock)
|
|
1070
|
+
- [ ] Step 4: Create `insurance_withdraw_guard_treasury_v1` + `insurance_withdraw_guard_personal_v1` (project binding)
|
|
1071
|
+
- [ ] Step 5: Create `insurance_machine_v1` with nodes and publish
|
|
1072
|
+
- [ ] Step 6: Create and publish `insurance_service_v1` (with machine, 2 Entity-sharing allocators, sales)
|
|
1073
|
+
- [ ] Step 7: Unpause Service (Optional — skip if service was never paused)
|
|
1074
|
+
- [ ] Step 8: Verify Service configuration
|
|
1075
|
+
- [ ] Step 9.1: Create test insurance order
|
|
1076
|
+
- [ ] Step 9.2: Advance progress Initial -> Start
|
|
1077
|
+
- [ ] Step 9.3: Advance progress Start -> Complete with submission (wait 10s after Step 9.2)
|
|
1078
|
+
- [ ] Step 10: Withdraw funds via Allocation (alloc_by_guard with Treasury or personal withdraw guard)
|