@wowok/skills 3.0.4 → 3.1.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/README.md +146 -122
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +223 -837
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -1
- package/dist/index.js.map +1 -1
- package/dist/installer.d.ts +121 -0
- package/dist/installer.d.ts.map +1 -0
- package/dist/installer.js +802 -0
- package/dist/installer.js.map +1 -0
- package/dist/skills.d.ts +5 -2
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +86 -62
- package/dist/skills.js.map +1 -1
- package/dist/targets.d.ts +94 -0
- package/dist/targets.d.ts.map +1 -0
- package/dist/targets.js +421 -0
- package/dist/targets.js.map +1 -0
- package/dist/types.d.ts +5 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -32
- package/dist/types.js.map +1 -1
- package/package.json +5 -4
- package/scripts/install.js +21 -859
- package/wowok-arbitrator/SKILL.md +5 -12
- package/wowok-auditor/SKILL.md +5 -17
- package/wowok-collaborator/SKILL.md +5 -17
- package/wowok-governance/SKILL.md +10 -30
- package/wowok-machine/SKILL.md +5 -18
- package/wowok-market/SKILL.md +5 -21
- package/wowok-messenger/SKILL.md +32 -50
- package/wowok-onboard/SKILL.md +5 -22
- package/wowok-order/SKILL.md +6 -19
- package/wowok-output/SKILL.md +5 -10
- package/wowok-planner/SKILL.md +6 -20
- package/wowok-provider/SKILL.md +6 -18
- package/wowok-supplier/SKILL.md +5 -16
- package/examples/Insurance/Insurance.md +0 -1245
- package/examples/MyShop/MyShop.md +0 -2003
- package/examples/MyShop/myshop_machine_nodes.json +0 -93
- package/examples/MyShop_Advanced/MyShop_Advanced.md +0 -2880
- package/examples/ThreeBody_Signature/ThreeBody_Signature.md +0 -1831
- package/examples/Travel/Travel.md +0 -1849
- package/examples/Travel/calc-weather-timestamps.js +0 -12
|
@@ -1,1245 +0,0 @@
|
|
|
1
|
-
# Insurance Service Example
|
|
2
|
-
|
|
3
|
-
A complete example demonstrating how to create an outdoor accident insurance service using WoWok protocol. This example demonstrates the **single-payer flow** — the insurance provider creates a test order with its own account. Supply-chain sub-ordering (a travel service provider purchasing on behalf of travelers via the `order_new.agents` field, with its own account and permissions) is out of scope for this document.
|
|
4
|
-
|
|
5
|
-
---
|
|
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
|
-
|
|
16
|
-
> **💡 Call Format**: All WoWok operations go through a single unified `wowok` tool. The AI calls `wowok({ tool: "<sub-tool>", data: {<params>} })`. If parameters don't match the schema, the response includes the correct schema for self-correction. See [Response Format](../../docs/response-format.md) for details.
|
|
17
|
-
|
|
18
|
-
## Core Requirements & Features
|
|
19
|
-
|
|
20
|
-
| Requirement | Description | Implementation |
|
|
21
|
-
|-------------|-------------|----------------|
|
|
22
|
-
| **Insurance Claims** | Process insurance claims with time-lock verification | Machine with Start -> Complete workflow |
|
|
23
|
-
| **Time-Lock Guard** | Prevent premature claim completion | Guard using Order + convert_witness(TypeOrderProgress) to verify clock > progress.current_time + lock_duration |
|
|
24
|
-
| **Single-Payer Order Flow** | Demonstrates order creation by the insurance provider's own account | `order_new` on the Service (supply-chain sub-ordering via the `agents` field is out of scope for this example) |
|
|
25
|
-
| **Permission Control** | Role-based access for insurance operations | Permission object with custom indexes for claim processing |
|
|
26
|
-
| **Safe Fund Allocation** | Merchant revenue collection without theft risk | 2 alternative allocators with `sharing.who = {"Entity": ...}` (funds flow to fixed Treasury or personal address) |
|
|
27
|
-
|
|
28
|
-
### Key Design Decisions
|
|
29
|
-
|
|
30
|
-
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.
|
|
31
|
-
2. **Simple Two-Node Workflow**: Insurance claims follow a straightforward Start -> Complete path, keeping the workflow simple and predictable.
|
|
32
|
-
3. **Order ID as Submission**: The Order ID is submitted at runtime (`b_submission: true`) and used for witness conversion.
|
|
33
|
-
4. **Machine Creation Pattern**: Machine can be created with nodes and published in a single transaction (as shown in this example).
|
|
34
|
-
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.
|
|
35
|
-
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.
|
|
36
|
-
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.
|
|
37
|
-
|
|
38
|
-
---
|
|
39
|
-
|
|
40
|
-
## Overview
|
|
41
|
-
|
|
42
|
-
This example demonstrates:
|
|
43
|
-
|
|
44
|
-
- **Insurance Service Setup**: Permission, Treasury, Guard, Machine, and Service creation
|
|
45
|
-
- **Time-Lock Guard**: Using Order + convert_witness to access Progress data
|
|
46
|
-
- **Safe Fund Allocation**: Two alternative merchant collection approaches via Entity sharing
|
|
47
|
-
- **Workflow Automation**: Machine-driven claim processing
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## Architecture
|
|
52
|
-
|
|
53
|
-
### System Components
|
|
54
|
-
|
|
55
|
-
```
|
|
56
|
-
------------------------------------------------------------------
|
|
57
|
-
| Insurance Service System |
|
|
58
|
-
|------------------------------------------------------------------|
|
|
59
|
-
| |
|
|
60
|
-
| +-----------------+ +-----------------+ |
|
|
61
|
-
| | Permission | | Guard | |
|
|
62
|
-
| | (insurance_ | | (insurance_ | |
|
|
63
|
-
| | permission) | | complete_guard)| |
|
|
64
|
-
| +--------+--------+ +--------+--------+ |
|
|
65
|
-
| | | |
|
|
66
|
-
| v v |
|
|
67
|
-
| +-----------------+ +-----------------+ |
|
|
68
|
-
| | Treasury | | Machine | |
|
|
69
|
-
| | (insurance_ | | (insurance_ | |
|
|
70
|
-
| | treasury) | | machine) | |
|
|
71
|
-
| +--------+--------+ +--------+--------+ |
|
|
72
|
-
| | | |
|
|
73
|
-
| v v |
|
|
74
|
-
| +-----------------+ +-----------------+ |
|
|
75
|
-
| | withdraw guards | | Service | |
|
|
76
|
-
| | (treasury + |<---| (insurance_ | |
|
|
77
|
-
| | personal) | | service) | |
|
|
78
|
-
| +-----------------+ +-----------------+ |
|
|
79
|
-
| |
|
|
80
|
-
| Workflow: Start -> Complete (Time-Lock Guard) |
|
|
81
|
-
| Allocators: 2 Entity-sharing approaches (first-match-wins) |
|
|
82
|
-
| |
|
|
83
|
-
------------------------------------------------------------------
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### Claim Workflow
|
|
87
|
-
|
|
88
|
-
```
|
|
89
|
-
+----------+ +--------------+
|
|
90
|
-
| Start |-------->| Complete |
|
|
91
|
-
| | | (Time-Lock) |
|
|
92
|
-
+----------+ +--------------+
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
**Guard Logic**:
|
|
96
|
-
```
|
|
97
|
-
clock > progress.current_time + 10000ms
|
|
98
|
-
(progress accessed via Order + convert_witness="OrderProgress")
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### Fund Allocation Flow (2 Alternative Approaches)
|
|
102
|
-
|
|
103
|
-
```
|
|
104
|
-
Order reaches Complete
|
|
105
|
-
|
|
|
106
|
-
v
|
|
107
|
-
Allocation triggered
|
|
108
|
-
|
|
|
109
|
-
+----+----+
|
|
110
|
-
| |
|
|
111
|
-
v v
|
|
112
|
-
Approach 1: Approach 2:
|
|
113
|
-
Treasury Personal
|
|
114
|
-
guard guard
|
|
115
|
-
| |
|
|
116
|
-
v v
|
|
117
|
-
Entity: Entity:
|
|
118
|
-
insurance_ insurance_
|
|
119
|
-
treasury provider
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
> **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).
|
|
123
|
-
|
|
124
|
-
---
|
|
125
|
-
|
|
126
|
-
## Prerequisites
|
|
127
|
-
|
|
128
|
-
Before running this example, ensure you have:
|
|
129
|
-
|
|
130
|
-
1. An account named `insurance_provider_v1` with sufficient WOW tokens
|
|
131
|
-
2. Access to the WoWok MCP server
|
|
132
|
-
|
|
133
|
-
### Create Insurance Provider Account
|
|
134
|
-
|
|
135
|
-
**Prompt**: Create a new account named "insurance_provider_v1" for the insurance service provider.
|
|
136
|
-
|
|
137
|
-
```json
|
|
138
|
-
{
|
|
139
|
-
"tool": "account_operation",
|
|
140
|
-
"data": {
|
|
141
|
-
"gen": {
|
|
142
|
-
"name": "insurance_provider_v1",
|
|
143
|
-
"replaceExistName": true
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
### Get Test Tokens
|
|
150
|
-
|
|
151
|
-
**Prompt**: Request testnet WOW tokens for account "insurance_provider_v1".
|
|
152
|
-
|
|
153
|
-
```json
|
|
154
|
-
{
|
|
155
|
-
"tool": "account_operation",
|
|
156
|
-
"data": {
|
|
157
|
-
"faucet": {
|
|
158
|
-
"network": "testnet",
|
|
159
|
-
"name_or_address": "insurance_provider_v1"
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
> **Best Practice — `no_cache: true`**: When building multiple interdependent objects in one session, set `"no_cache": true` in the `env` object of every on-chain operation to ensure fresh chain state. The examples below omit it for brevity.
|
|
166
|
-
|
|
167
|
-
---
|
|
168
|
-
|
|
169
|
-
## Step 1: Create Permission Object
|
|
170
|
-
|
|
171
|
-
Create a Permission object to manage access control for the insurance service. The Permission must include all permission indexes that will be used in the Machine workflow.
|
|
172
|
-
|
|
173
|
-
**Prompt**: Create a Permission object named "insurance_permission" for the insurance service.
|
|
174
|
-
|
|
175
|
-
```json
|
|
176
|
-
{
|
|
177
|
-
"tool": "onchain_operations",
|
|
178
|
-
"data": {
|
|
179
|
-
"operation_type": "permission",
|
|
180
|
-
"data": {
|
|
181
|
-
"object": {
|
|
182
|
-
"name": "insurance_permission_v1",
|
|
183
|
-
"replaceExistName": true
|
|
184
|
-
},
|
|
185
|
-
"description": "Permission for outdoor accident insurance service",
|
|
186
|
-
"table": {
|
|
187
|
-
"op": "add perm by entity",
|
|
188
|
-
"entity": {"name_or_address": "insurance_provider_v1"},
|
|
189
|
-
"index": [1000, 1001, 1002, 1003, 1004, 1005]
|
|
190
|
-
}
|
|
191
|
-
},
|
|
192
|
-
"env": {
|
|
193
|
-
"account": "insurance_provider_v1",
|
|
194
|
-
"network": "testnet"
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
> **Important**: The `index` array must include all permission indexes used in Machine forwards:
|
|
201
|
-
> - `1000`: for `start_claim` forward (Start node)
|
|
202
|
-
> - `1001`: for `complete_claim` forward (Complete node)
|
|
203
|
-
> - Additional indexes for future operations
|
|
204
|
-
>
|
|
205
|
-
> Without these permissions, advancing Progress will fail with `MoveAbort code: 7`.
|
|
206
|
-
|
|
207
|
-
---
|
|
208
|
-
|
|
209
|
-
## Step 2: Create Treasury Object
|
|
210
|
-
|
|
211
|
-
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.
|
|
212
|
-
|
|
213
|
-
**Prompt**: Create a Treasury object named "insurance_treasury" for aggregating insurance revenue.
|
|
214
|
-
|
|
215
|
-
```json
|
|
216
|
-
{
|
|
217
|
-
"tool": "onchain_operations",
|
|
218
|
-
"data": {
|
|
219
|
-
"operation_type": "treasury",
|
|
220
|
-
"data": {
|
|
221
|
-
"object": {
|
|
222
|
-
"name": "insurance_treasury_v1",
|
|
223
|
-
"type_parameter": "0x2::wow::WOW",
|
|
224
|
-
"permission": "insurance_permission_v1",
|
|
225
|
-
"replaceExistName": true
|
|
226
|
-
},
|
|
227
|
-
"description": "Treasury for aggregating insurance service revenue (public funds for operations and distribution). Uses the same Permission as the Service for consistency."
|
|
228
|
-
},
|
|
229
|
-
"env": {
|
|
230
|
-
"account": "insurance_provider_v1",
|
|
231
|
-
"network": "testnet"
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
> **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.
|
|
238
|
-
|
|
239
|
-
---
|
|
240
|
-
|
|
241
|
-
## Step 3: Create Time-Lock Complete Guard
|
|
242
|
-
|
|
243
|
-
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`.
|
|
244
|
-
|
|
245
|
-
**Guard Logic**:
|
|
246
|
-
```
|
|
247
|
-
clock > progress.current_time + 10000
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
**Prompt**: Create a Guard named "insurance_complete_guard" for time-lock verification on claim completion.
|
|
251
|
-
|
|
252
|
-
```json
|
|
253
|
-
{
|
|
254
|
-
"tool": "onchain_operations",
|
|
255
|
-
"data": {
|
|
256
|
-
"operation_type": "guard",
|
|
257
|
-
"data": {
|
|
258
|
-
"namedNew": {
|
|
259
|
-
"name": "insurance_complete_guard_v1",
|
|
260
|
-
"tags": ["insurance", "time-lock", "complete"],
|
|
261
|
-
"replaceExistName": true
|
|
262
|
-
},
|
|
263
|
-
"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).",
|
|
264
|
-
|
|
265
|
-
"table": [
|
|
266
|
-
{
|
|
267
|
-
"identifier": 0,
|
|
268
|
-
"b_submission": true,
|
|
269
|
-
"value_type": "Address",
|
|
270
|
-
"name": "Order ID (submitted at runtime)"
|
|
271
|
-
},
|
|
272
|
-
{
|
|
273
|
-
"identifier": 1,
|
|
274
|
-
"b_submission": false,
|
|
275
|
-
"value_type": "U64",
|
|
276
|
-
"value": 10000
|
|
277
|
-
}
|
|
278
|
-
],
|
|
279
|
-
"root": {
|
|
280
|
-
"type": "logic_as_u256_greater",
|
|
281
|
-
"nodes": [
|
|
282
|
-
{
|
|
283
|
-
"type": "context",
|
|
284
|
-
"context": "Clock"
|
|
285
|
-
},
|
|
286
|
-
{
|
|
287
|
-
"type": "calc_number_add",
|
|
288
|
-
"nodes": [
|
|
289
|
-
{
|
|
290
|
-
"type": "query",
|
|
291
|
-
"query": "progress.current_time",
|
|
292
|
-
"object": {
|
|
293
|
-
"identifier": 0,
|
|
294
|
-
"convert_witness": "OrderProgress"
|
|
295
|
-
},
|
|
296
|
-
"parameters": []
|
|
297
|
-
},
|
|
298
|
-
{
|
|
299
|
-
"type": "identifier",
|
|
300
|
-
"identifier": 1
|
|
301
|
-
}
|
|
302
|
-
]
|
|
303
|
-
}
|
|
304
|
-
]
|
|
305
|
-
}
|
|
306
|
-
},
|
|
307
|
-
"env": {
|
|
308
|
-
"account": "insurance_provider_v1",
|
|
309
|
-
"network": "testnet"
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
**Guard Table**:
|
|
316
|
-
|
|
317
|
-
| identifier | b_submission | value_type | value | name | Purpose |
|
|
318
|
-
|------------|-------------|-----------|-------|------|---------|
|
|
319
|
-
| 0 | **true** | Address | (submitted at runtime) | Order ID (submitted at runtime) | Order ID submitted at runtime, converted to Progress via convert_witness |
|
|
320
|
-
| 1 | false | U64 | 10000 | lock_duration_ms | Time-lock duration in ms (10 seconds for testing) |
|
|
321
|
-
|
|
322
|
-
> **Important**: `10000` ms (10 seconds) is for testing only. In production, set to a reasonable duration (e.g., 8 hours = 28800000 ms).
|
|
323
|
-
|
|
324
|
-
---
|
|
325
|
-
|
|
326
|
-
## Step 4: Create, Configure and Publish Machine
|
|
327
|
-
|
|
328
|
-
Create a Machine with workflow nodes and publish it in a single transaction.
|
|
329
|
-
|
|
330
|
-
> **IMPORTANT**:
|
|
331
|
-
> - Machine nodes are added during creation in the same transaction
|
|
332
|
-
> - Once published, Machine nodes become immutable and cannot be modified
|
|
333
|
-
> - If you need to change nodes after publishing, you must create a new Machine
|
|
334
|
-
|
|
335
|
-
**Prompt**: Create a Machine named "insurance_machine" with the claim processing workflow and publish it.
|
|
336
|
-
|
|
337
|
-
```json
|
|
338
|
-
{
|
|
339
|
-
"tool": "onchain_operations",
|
|
340
|
-
"data": {
|
|
341
|
-
"operation_type": "machine",
|
|
342
|
-
"data": {
|
|
343
|
-
"object": {
|
|
344
|
-
"name": "insurance_machine_v1",
|
|
345
|
-
"permission": "insurance_permission_v1",
|
|
346
|
-
"replaceExistName": true
|
|
347
|
-
},
|
|
348
|
-
"description": "Insurance claim processing workflow: Start -> Complete (with time-lock guard)",
|
|
349
|
-
"node": {
|
|
350
|
-
"op": "add",
|
|
351
|
-
"nodes": [
|
|
352
|
-
{
|
|
353
|
-
"name": "Start",
|
|
354
|
-
"pairs": [
|
|
355
|
-
{
|
|
356
|
-
"prev_node": "",
|
|
357
|
-
"threshold": 0,
|
|
358
|
-
"forwards": [
|
|
359
|
-
{
|
|
360
|
-
"name": "start_claim",
|
|
361
|
-
"permissionIndex": 1000,
|
|
362
|
-
"weight": 1
|
|
363
|
-
}
|
|
364
|
-
]
|
|
365
|
-
}
|
|
366
|
-
]
|
|
367
|
-
},
|
|
368
|
-
{
|
|
369
|
-
"name": "Complete",
|
|
370
|
-
"pairs": [
|
|
371
|
-
{
|
|
372
|
-
"prev_node": "Start",
|
|
373
|
-
"threshold": 1,
|
|
374
|
-
"forwards": [
|
|
375
|
-
{
|
|
376
|
-
"name": "complete_claim",
|
|
377
|
-
"permissionIndex": 1001,
|
|
378
|
-
"weight": 1,
|
|
379
|
-
"guard": {
|
|
380
|
-
"guard": "insurance_complete_guard_v1"
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
]
|
|
384
|
-
}
|
|
385
|
-
]
|
|
386
|
-
}
|
|
387
|
-
]
|
|
388
|
-
},
|
|
389
|
-
"publish": true
|
|
390
|
-
},
|
|
391
|
-
"env": {
|
|
392
|
-
"account": "insurance_provider_v1",
|
|
393
|
-
"network": "testnet"
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
**Workflow Nodes**:
|
|
400
|
-
|
|
401
|
-
| Node | Forward | Guard | Description |
|
|
402
|
-
|------|---------|-------|-------------|
|
|
403
|
-
| Start | start_claim -> Start | - | Enter the Start node from initial state |
|
|
404
|
-
| Complete | complete_claim -> Complete | insurance_complete_guard_v1 | Complete the claim after time-lock verification |
|
|
405
|
-
|
|
406
|
-
---
|
|
407
|
-
|
|
408
|
-
## Step 5: Create Service (Unpublished)
|
|
409
|
-
|
|
410
|
-
Create the insurance service with machine, sales, and description — WITHOUT `order_allocators` and WITHOUT publishing (`publish: false`).
|
|
411
|
-
|
|
412
|
-
> **Why create the Service before the withdraw Guards?** Each withdraw Guard's static table (Step 6) stores the Service address as `value: "insurance_service_v1"`, and this name must resolve to an on-chain object at transaction build time. Creating the Service first (unpublished) makes the name resolvable — otherwise Guard creation fails at build time, or (on re-runs with `replaceExistName`) silently binds to the previous run's orphaned Service address. `order_allocators` is then added in Step 7 together with `publish: true` (allocators can only be set before publish). This is the standard object–Guard circular-reference pattern: create the object → create the Guards that reference it → update the object to bind the Guards.
|
|
413
|
-
|
|
414
|
-
**Prompt**: Create a Service named "insurance_service_v1" with machine and insurance product (unpublished).
|
|
415
|
-
|
|
416
|
-
```json
|
|
417
|
-
{
|
|
418
|
-
"tool": "onchain_operations",
|
|
419
|
-
"data": {
|
|
420
|
-
"operation_type": "service",
|
|
421
|
-
"data": {
|
|
422
|
-
"object": {
|
|
423
|
-
"name": "insurance_service_v1",
|
|
424
|
-
"type_parameter": "0x2::wow::WOW",
|
|
425
|
-
"permission": "insurance_permission_v1",
|
|
426
|
-
"replaceExistName": true
|
|
427
|
-
},
|
|
428
|
-
"description": "Outdoor accident insurance for Iceland travel. Provides coverage for ice scooting and other outdoor activities.",
|
|
429
|
-
"machine": "insurance_machine_v1",
|
|
430
|
-
"sales": {
|
|
431
|
-
"op": "add",
|
|
432
|
-
"sales": [
|
|
433
|
-
{
|
|
434
|
-
"name": "Outdoor Accident Insurance",
|
|
435
|
-
"price": 100000000,
|
|
436
|
-
"stock": 1000,
|
|
437
|
-
"suspension": false,
|
|
438
|
-
"wip": "https://cdn.jsdelivr.net/gh/wowok-ai/docs@main/wip-examples/three_body.wip",
|
|
439
|
-
"wip_hash": ""
|
|
440
|
-
}
|
|
441
|
-
]
|
|
442
|
-
},
|
|
443
|
-
"publish": false
|
|
444
|
-
},
|
|
445
|
-
"env": {
|
|
446
|
-
"account": "insurance_provider_v1",
|
|
447
|
-
"network": "testnet"
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
> **Note**: The `wip` URL above is a **placeholder** (a sample WIP file from the Three-Body example) — replace it with your own insurance product WIP file in real use. `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.
|
|
454
|
-
|
|
455
|
-
---
|
|
456
|
-
|
|
457
|
-
## Step 6: Create Withdraw Guards for Order Allocators
|
|
458
|
-
|
|
459
|
-
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.
|
|
460
|
-
|
|
461
|
-
The `insurance_service_v1` name used in each Guard's static table below (`value: "insurance_service_v1"`) was created in Step 5, so it resolves to the current run's Service address at transaction build time.
|
|
462
|
-
|
|
463
|
-
**Guard Logic** (identical for both):
|
|
464
|
-
```
|
|
465
|
-
logic_and[
|
|
466
|
-
query("progress.current") == "Complete", // order is at Complete node
|
|
467
|
-
query("order.service") == insurance_service_v1 // order belongs to THIS service
|
|
468
|
-
]
|
|
469
|
-
```
|
|
470
|
-
|
|
471
|
-
**Risk Elimination**:
|
|
472
|
-
- **Project binding** (query 1563): prevents cross-service order theft — an attacker cannot submit another Service's completed Order to trigger allocation.
|
|
473
|
-
- **Entity sharing** (configured in Step 7): funds flow to a fixed address regardless of caller — no Signer binding needed in the Guard.
|
|
474
|
-
|
|
475
|
-
### 6.1 Treasury Collection Guard
|
|
476
|
-
|
|
477
|
-
**Prompt**: Create a Guard named "insurance_withdraw_guard_treasury" for Treasury fund collection.
|
|
478
|
-
|
|
479
|
-
```json
|
|
480
|
-
{
|
|
481
|
-
"tool": "onchain_operations",
|
|
482
|
-
"data": {
|
|
483
|
-
"operation_type": "guard",
|
|
484
|
-
"data": {
|
|
485
|
-
"namedNew": {
|
|
486
|
-
"name": "insurance_withdraw_guard_treasury_v1",
|
|
487
|
-
"tags": ["insurance", "withdraw", "treasury"],
|
|
488
|
-
"replaceExistName": true
|
|
489
|
-
},
|
|
490
|
-
"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).",
|
|
491
|
-
"table": [
|
|
492
|
-
{
|
|
493
|
-
"identifier": 0,
|
|
494
|
-
"b_submission": true,
|
|
495
|
-
"value_type": "Address",
|
|
496
|
-
"name": "order_id (Order object submitted at runtime)"
|
|
497
|
-
},
|
|
498
|
-
{
|
|
499
|
-
"identifier": 1,
|
|
500
|
-
"b_submission": false,
|
|
501
|
-
"value_type": "String",
|
|
502
|
-
"value": "Complete",
|
|
503
|
-
"name": "Expected Complete node name (case-sensitive)"
|
|
504
|
-
},
|
|
505
|
-
{
|
|
506
|
-
"identifier": 2,
|
|
507
|
-
"b_submission": false,
|
|
508
|
-
"value_type": "Address",
|
|
509
|
-
"value": "insurance_service_v1",
|
|
510
|
-
"name": "Expected service address (prevents cross-service fund theft)"
|
|
511
|
-
}
|
|
512
|
-
],
|
|
513
|
-
"root": {
|
|
514
|
-
"type": "logic_and",
|
|
515
|
-
"nodes": [
|
|
516
|
-
{
|
|
517
|
-
"type": "logic_equal",
|
|
518
|
-
"nodes": [
|
|
519
|
-
{
|
|
520
|
-
"type": "query",
|
|
521
|
-
"query": "progress.current",
|
|
522
|
-
"object": {
|
|
523
|
-
"identifier": 0,
|
|
524
|
-
"convert_witness": "OrderProgress"
|
|
525
|
-
},
|
|
526
|
-
"parameters": []
|
|
527
|
-
},
|
|
528
|
-
{
|
|
529
|
-
"type": "identifier",
|
|
530
|
-
"identifier": 1
|
|
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": 2
|
|
548
|
-
}
|
|
549
|
-
]
|
|
550
|
-
}
|
|
551
|
-
]
|
|
552
|
-
}
|
|
553
|
-
},
|
|
554
|
-
"env": {
|
|
555
|
-
"account": "insurance_provider_v1",
|
|
556
|
-
"network": "testnet"
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
```
|
|
561
|
-
|
|
562
|
-
### 6.2 Personal Collection Guard
|
|
563
|
-
|
|
564
|
-
**Prompt**: Create a Guard named "insurance_withdraw_guard_personal" for personal fund collection.
|
|
565
|
-
|
|
566
|
-
```json
|
|
567
|
-
{
|
|
568
|
-
"tool": "onchain_operations",
|
|
569
|
-
"data": {
|
|
570
|
-
"operation_type": "guard",
|
|
571
|
-
"data": {
|
|
572
|
-
"namedNew": {
|
|
573
|
-
"name": "insurance_withdraw_guard_personal_v1",
|
|
574
|
-
"tags": ["insurance", "withdraw", "personal"],
|
|
575
|
-
"replaceExistName": true
|
|
576
|
-
},
|
|
577
|
-
"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).",
|
|
578
|
-
"table": [
|
|
579
|
-
{
|
|
580
|
-
"identifier": 0,
|
|
581
|
-
"b_submission": true,
|
|
582
|
-
"value_type": "Address",
|
|
583
|
-
"name": "order_id (Order object submitted at runtime)"
|
|
584
|
-
},
|
|
585
|
-
{
|
|
586
|
-
"identifier": 1,
|
|
587
|
-
"b_submission": false,
|
|
588
|
-
"value_type": "String",
|
|
589
|
-
"value": "Complete",
|
|
590
|
-
"name": "Expected Complete node name (case-sensitive)"
|
|
591
|
-
},
|
|
592
|
-
{
|
|
593
|
-
"identifier": 2,
|
|
594
|
-
"b_submission": false,
|
|
595
|
-
"value_type": "Address",
|
|
596
|
-
"value": "insurance_service_v1",
|
|
597
|
-
"name": "Expected service address (prevents cross-service fund theft)"
|
|
598
|
-
}
|
|
599
|
-
],
|
|
600
|
-
"root": {
|
|
601
|
-
"type": "logic_and",
|
|
602
|
-
"nodes": [
|
|
603
|
-
{
|
|
604
|
-
"type": "logic_equal",
|
|
605
|
-
"nodes": [
|
|
606
|
-
{
|
|
607
|
-
"type": "query",
|
|
608
|
-
"query": "progress.current",
|
|
609
|
-
"object": {
|
|
610
|
-
"identifier": 0,
|
|
611
|
-
"convert_witness": "OrderProgress"
|
|
612
|
-
},
|
|
613
|
-
"parameters": []
|
|
614
|
-
},
|
|
615
|
-
{
|
|
616
|
-
"type": "identifier",
|
|
617
|
-
"identifier": 1
|
|
618
|
-
}
|
|
619
|
-
]
|
|
620
|
-
},
|
|
621
|
-
{
|
|
622
|
-
"type": "logic_equal",
|
|
623
|
-
"nodes": [
|
|
624
|
-
{
|
|
625
|
-
"type": "query",
|
|
626
|
-
"query": "order.service",
|
|
627
|
-
"object": {
|
|
628
|
-
"identifier": 0
|
|
629
|
-
},
|
|
630
|
-
"parameters": []
|
|
631
|
-
},
|
|
632
|
-
{
|
|
633
|
-
"type": "identifier",
|
|
634
|
-
"identifier": 2
|
|
635
|
-
}
|
|
636
|
-
]
|
|
637
|
-
}
|
|
638
|
-
]
|
|
639
|
-
}
|
|
640
|
-
},
|
|
641
|
-
"env": {
|
|
642
|
-
"account": "insurance_provider_v1",
|
|
643
|
-
"network": "testnet"
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
```
|
|
648
|
-
|
|
649
|
-
**Guard Table** (identical for both guards):
|
|
650
|
-
|
|
651
|
-
| identifier | b_submission | value_type | value | Purpose |
|
|
652
|
-
|------------|-------------|-----------|-------|---------|
|
|
653
|
-
| 0 | **true** | Address | (submitted at runtime) | Order ID submitted at runtime, converted to Progress via convert_witness="OrderProgress" |
|
|
654
|
-
| 1 | false | String | "Complete" | Expected node name (case-sensitive) |
|
|
655
|
-
| 2 | false | Address | insurance_service_v1 | Expected Service address (project binding — prevents cross-service fund theft) |
|
|
656
|
-
|
|
657
|
-
> **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.
|
|
658
|
-
|
|
659
|
-
---
|
|
660
|
-
|
|
661
|
-
## Step 7: Add Order Allocators and Publish Service
|
|
662
|
-
|
|
663
|
-
Update `insurance_service_v1` to add the `order_allocators` (2 alternative merchant collection approaches referencing the withdraw Guards created in Step 6) and publish the Service in a single transaction.
|
|
664
|
-
|
|
665
|
-
> **Important**:
|
|
666
|
-
> - Service must include `order_allocators` when publishing
|
|
667
|
-
> - After publishing, `machine`, `order_allocators`, and `arbitrations` become immutable
|
|
668
|
-
> - Ensure the Machine is properly configured (Step 4) and both withdraw Guards exist (Step 6) before publishing
|
|
669
|
-
|
|
670
|
-
**Prompt**: Update "insurance_service_v1" to add order allocation rules and publish it.
|
|
671
|
-
|
|
672
|
-
```json
|
|
673
|
-
{
|
|
674
|
-
"tool": "onchain_operations",
|
|
675
|
-
"data": {
|
|
676
|
-
"operation_type": "service",
|
|
677
|
-
"data": {
|
|
678
|
-
"object": "insurance_service_v1",
|
|
679
|
-
"order_allocators": {
|
|
680
|
-
"description": "Insurance order revenue allocation — 2 alternative merchant collection approaches (first-match-wins means only the first passing allocator executes)",
|
|
681
|
-
"threshold": 0,
|
|
682
|
-
"allocators": [
|
|
683
|
-
{
|
|
684
|
-
"guard": "insurance_withdraw_guard_treasury_v1",
|
|
685
|
-
"sharing": [
|
|
686
|
-
{
|
|
687
|
-
"who": {"Entity": {"name_or_address": "insurance_treasury_v1"}},
|
|
688
|
-
"sharing": 10000,
|
|
689
|
-
"mode": "Rate"
|
|
690
|
-
}
|
|
691
|
-
]
|
|
692
|
-
},
|
|
693
|
-
{
|
|
694
|
-
"guard": "insurance_withdraw_guard_personal_v1",
|
|
695
|
-
"sharing": [
|
|
696
|
-
{
|
|
697
|
-
"who": {"Entity": {"name_or_address": "insurance_provider_v1"}},
|
|
698
|
-
"sharing": 10000,
|
|
699
|
-
"mode": "Rate"
|
|
700
|
-
}
|
|
701
|
-
]
|
|
702
|
-
}
|
|
703
|
-
]
|
|
704
|
-
},
|
|
705
|
-
"publish": true
|
|
706
|
-
},
|
|
707
|
-
"env": {
|
|
708
|
-
"account": "insurance_provider_v1",
|
|
709
|
-
"network": "testnet"
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
```
|
|
714
|
-
|
|
715
|
-
> **Important — Fund Allocation Safety**:
|
|
716
|
-
> - `mode: "Rate"` represents Rate allocation mode (valid values: `"Amount"`, `"Rate"`, `"Surplus"`)
|
|
717
|
-
> - `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.
|
|
718
|
-
> - **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.
|
|
719
|
-
> - **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.
|
|
720
|
-
> - **Permission consistency**: the Treasury uses `insurance_permission_v1` (same as Service) — keep Permissions consistent unless you have a specific reason to separate them.
|
|
721
|
-
|
|
722
|
-
---
|
|
723
|
-
|
|
724
|
-
## Step 8: Unpause Service (Optional)
|
|
725
|
-
|
|
726
|
-
> **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 9.
|
|
727
|
-
|
|
728
|
-
Unpause the service to allow order creation.
|
|
729
|
-
|
|
730
|
-
**Prompt**: Unpause "insurance_service_v1".
|
|
731
|
-
|
|
732
|
-
```json
|
|
733
|
-
{
|
|
734
|
-
"tool": "onchain_operations",
|
|
735
|
-
"data": {
|
|
736
|
-
"operation_type": "service",
|
|
737
|
-
"data": {
|
|
738
|
-
"object": "insurance_service_v1",
|
|
739
|
-
"pause": false
|
|
740
|
-
},
|
|
741
|
-
"env": {
|
|
742
|
-
"account": "insurance_provider_v1",
|
|
743
|
-
"network": "testnet"
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
```
|
|
748
|
-
|
|
749
|
-
---
|
|
750
|
-
|
|
751
|
-
## Step 9: Verify Service Configuration
|
|
752
|
-
|
|
753
|
-
Query the service to verify all configurations are correct.
|
|
754
|
-
|
|
755
|
-
**Prompt**: Query "insurance_service_v1" to verify configuration.
|
|
756
|
-
|
|
757
|
-
```json
|
|
758
|
-
{
|
|
759
|
-
"tool": "query_toolkit",
|
|
760
|
-
"data": {
|
|
761
|
-
"query_type": "onchain_objects",
|
|
762
|
-
"objects": ["insurance_service_v1"],
|
|
763
|
-
"network": "testnet"
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
```
|
|
767
|
-
|
|
768
|
-
---
|
|
769
|
-
|
|
770
|
-
## Step 10: Test Order Creation and Progress
|
|
771
|
-
|
|
772
|
-
### 10.1 Create Insurance Order
|
|
773
|
-
|
|
774
|
-
Create an order on the insurance service using the `order_new` field of the `service` operation. This example uses a single-payer flow — the insurance provider creates the test order with its own account. Supply-chain sub-ordering (a travel agency purchasing via `order_new.agents`) is out of scope for this example.
|
|
775
|
-
|
|
776
|
-
**Prompt**: Create an order on "insurance_service_v1" using account "insurance_provider_v1".
|
|
777
|
-
|
|
778
|
-
```json
|
|
779
|
-
{
|
|
780
|
-
"tool": "onchain_operations",
|
|
781
|
-
"data": {
|
|
782
|
-
"operation_type": "service",
|
|
783
|
-
"data": {
|
|
784
|
-
"object": "insurance_service_v1",
|
|
785
|
-
"order_new": {
|
|
786
|
-
"buy": {
|
|
787
|
-
"items": [
|
|
788
|
-
{
|
|
789
|
-
"name": "Outdoor Accident Insurance",
|
|
790
|
-
"stock": 1,
|
|
791
|
-
"wip_hash": ""
|
|
792
|
-
}
|
|
793
|
-
],
|
|
794
|
-
"total_pay": {
|
|
795
|
-
"balance": 100000000
|
|
796
|
-
}
|
|
797
|
-
},
|
|
798
|
-
"namedNewOrder": {
|
|
799
|
-
"name": "test_insurance_order_v1",
|
|
800
|
-
"replaceExistName": true
|
|
801
|
-
},
|
|
802
|
-
"namedNewAllocation": {
|
|
803
|
-
"name": "insurance_test_alloc_v1",
|
|
804
|
-
"replaceExistName": true
|
|
805
|
-
},
|
|
806
|
-
"namedNewProgress": {
|
|
807
|
-
"name": "insurance_test_progress_v1",
|
|
808
|
-
"replaceExistName": true
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
},
|
|
812
|
-
"env": {
|
|
813
|
-
"account": "insurance_provider_v1",
|
|
814
|
-
"network": "testnet"
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
```
|
|
819
|
-
|
|
820
|
-
> **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.
|
|
821
|
-
>
|
|
822
|
-
> **Optional — Query the Order**: To verify the order or obtain on-chain object IDs:
|
|
823
|
-
> ```json
|
|
824
|
-
> {
|
|
825
|
-
> "tool": "query_toolkit",
|
|
826
|
-
> "data": {
|
|
827
|
-
> "query_type": "onchain_objects",
|
|
828
|
-
> "objects": ["test_insurance_order_v1"],
|
|
829
|
-
> "network": "testnet",
|
|
830
|
-
> "no_cache": true
|
|
831
|
-
> }
|
|
832
|
-
> }
|
|
833
|
-
> ```
|
|
834
|
-
> The response includes `progress` and `allocation` fields with the on-chain object IDs.
|
|
835
|
-
|
|
836
|
-
### 10.2 Advance Progress: Initial -> Start
|
|
837
|
-
|
|
838
|
-
First, advance the progress from initial state to Start node.
|
|
839
|
-
|
|
840
|
-
**Prompt**: Advance progress to Start node.
|
|
841
|
-
|
|
842
|
-
```json
|
|
843
|
-
{
|
|
844
|
-
"tool": "onchain_operations",
|
|
845
|
-
"data": {
|
|
846
|
-
"operation_type": "order",
|
|
847
|
-
"data": {
|
|
848
|
-
"object": "test_insurance_order_v1",
|
|
849
|
-
"progress": {
|
|
850
|
-
"operation": {
|
|
851
|
-
"next_node_name": "Start",
|
|
852
|
-
"forward": "start_claim"
|
|
853
|
-
},
|
|
854
|
-
"op": "next"
|
|
855
|
-
}
|
|
856
|
-
},
|
|
857
|
-
"env": {
|
|
858
|
-
"account": "insurance_provider_v1",
|
|
859
|
-
"network": "testnet"
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
```
|
|
864
|
-
|
|
865
|
-
> **Note**:
|
|
866
|
-
> - The `progress` object requires `operation` (with both `next_node_name` and `forward` fields) plus the `op` field — use `"op": "next"` to advance the forward (other values: `"hold"`, `"unhold"`, `"adminUnhold"`)
|
|
867
|
-
> - Use simple forward name (e.g., `"start_claim"`) without node prefix. The system automatically resolves the path from current node
|
|
868
|
-
> - The Progress is advanced via the Order object's `progress` field, using the Order name as reference
|
|
869
|
-
|
|
870
|
-
### 10.3 Advance Progress: Start -> Complete
|
|
871
|
-
|
|
872
|
-
Wait at least 10 seconds after entering Start node, then advance the progress to Complete with the Order ID as submission.
|
|
873
|
-
|
|
874
|
-
> **Two-Phase Submission Loop**: When a forward has a Guard that requires user submission (`b_submission: true`), the MCP server uses a two-phase approach:
|
|
875
|
-
>
|
|
876
|
-
> **Phase 1**: Call WITHOUT the `submission` field at root level. The server will return a `submission` prompt containing the Guard addresses and submission structure that needs to be filled.
|
|
877
|
-
>
|
|
878
|
-
> **Phase 2**: Call WITH the `submission` field at root level, populated with the `value` fields from the Phase 1 prompt. The prompt shows which `identifier` expects a value of which `value_type`.
|
|
879
|
-
|
|
880
|
-
**Phase 1 Prompt**: Call progress operation WITHOUT `submission` field.
|
|
881
|
-
|
|
882
|
-
```json
|
|
883
|
-
{
|
|
884
|
-
"tool": "onchain_operations",
|
|
885
|
-
"data": {
|
|
886
|
-
"operation_type": "order",
|
|
887
|
-
"data": {
|
|
888
|
-
"object": "test_insurance_order_v1",
|
|
889
|
-
"progress": {
|
|
890
|
-
"operation": {
|
|
891
|
-
"next_node_name": "Complete",
|
|
892
|
-
"forward": "complete_claim"
|
|
893
|
-
},
|
|
894
|
-
"op": "next"
|
|
895
|
-
}
|
|
896
|
-
},
|
|
897
|
-
"env": {
|
|
898
|
-
"account": "insurance_provider_v1",
|
|
899
|
-
"network": "testnet"
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
```
|
|
904
|
-
|
|
905
|
-
The server will return a `submission` prompt (illustrative example — actual guard addresses come from your Phase 1 response):
|
|
906
|
-
|
|
907
|
-
```json
|
|
908
|
-
{
|
|
909
|
-
"result": {
|
|
910
|
-
"type": "submission",
|
|
911
|
-
"guard": [
|
|
912
|
-
{ "object": "0x1508ded8...", "impack": true }
|
|
913
|
-
],
|
|
914
|
-
"submission": [
|
|
915
|
-
{
|
|
916
|
-
"guard": "0x1508ded8...",
|
|
917
|
-
"submission": [
|
|
918
|
-
{
|
|
919
|
-
"identifier": 0,
|
|
920
|
-
"b_submission": true,
|
|
921
|
-
"value_type": "Address",
|
|
922
|
-
"name": "Order ID (submitted at runtime)",
|
|
923
|
-
"object_type": "Order"
|
|
924
|
-
}
|
|
925
|
-
]
|
|
926
|
-
}
|
|
927
|
-
]
|
|
928
|
-
},
|
|
929
|
-
"message": "Guard verification required: fill the submission array and resubmit."
|
|
930
|
-
}
|
|
931
|
-
```
|
|
932
|
-
|
|
933
|
-
> **Note**: The examples in this document use the string form of `value_type` (e.g., `"Address"`). The numeric enum ID form (e.g., `1` for Address) is also accepted as input — when filling in Phase 2, you can use either the string name (`"Address"`) or the numeric form (`1`).
|
|
934
|
-
|
|
935
|
-
**Phase 2**: Fill in the `value` field with the Order ID and resubmit. The `submission` field must be placed at the **root level** of the request (sibling to `operation_type`, `data`, and `env`).
|
|
936
|
-
|
|
937
|
-
```json
|
|
938
|
-
{
|
|
939
|
-
"tool": "onchain_operations",
|
|
940
|
-
"data": {
|
|
941
|
-
"operation_type": "order",
|
|
942
|
-
"data": {
|
|
943
|
-
"object": "test_insurance_order_v1",
|
|
944
|
-
"progress": {
|
|
945
|
-
"operation": {
|
|
946
|
-
"next_node_name": "Complete",
|
|
947
|
-
"forward": "complete_claim"
|
|
948
|
-
},
|
|
949
|
-
"op": "next"
|
|
950
|
-
}
|
|
951
|
-
},
|
|
952
|
-
"submission": {
|
|
953
|
-
"type": "submission",
|
|
954
|
-
"guard": [
|
|
955
|
-
{
|
|
956
|
-
"object": "0x1508ded8...",
|
|
957
|
-
"impack": true
|
|
958
|
-
}
|
|
959
|
-
],
|
|
960
|
-
"submission": [
|
|
961
|
-
{
|
|
962
|
-
"guard": "0x1508ded8...",
|
|
963
|
-
"submission": [
|
|
964
|
-
{
|
|
965
|
-
"identifier": 0,
|
|
966
|
-
"b_submission": true,
|
|
967
|
-
"value_type": "Address",
|
|
968
|
-
"name": "Order ID (submitted at runtime)",
|
|
969
|
-
"object_type": "Order",
|
|
970
|
-
"value": "test_insurance_order_v1"
|
|
971
|
-
}
|
|
972
|
-
]
|
|
973
|
-
}
|
|
974
|
-
]
|
|
975
|
-
},
|
|
976
|
-
"env": {
|
|
977
|
-
"account": "insurance_provider_v1",
|
|
978
|
-
"network": "testnet"
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
}
|
|
982
|
-
```
|
|
983
|
-
|
|
984
|
-
> **⚠️ Important**:
|
|
985
|
-
> - 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`.
|
|
986
|
-
> - 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.
|
|
987
|
-
> - 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.
|
|
988
|
-
> - The Order is referenced by its name (`"test_insurance_order_v1"`) in the `data.object` field.
|
|
989
|
-
> - The `progress` object requires `operation` (with both `next_node_name` and `forward` fields) plus `"op": "next"`.
|
|
990
|
-
> - Use simple forward name `"complete_claim"` without node prefix.
|
|
991
|
-
|
|
992
|
-
---
|
|
993
|
-
|
|
994
|
-
## Step 11: Withdraw Funds via Allocation
|
|
995
|
-
|
|
996
|
-
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`.
|
|
997
|
-
|
|
998
|
-
The Guard verifies:
|
|
999
|
-
1. `progress.current == "Complete"` (query 1253) via the submitted Order ID with `convert_witness: "OrderProgress"` (TypeOrderProgress)
|
|
1000
|
-
2. `order.service == insurance_service_v1` (query 1563) — project binding prevents cross-service order theft
|
|
1001
|
-
|
|
1002
|
-
The Allocation object was created automatically when the Order was placed (Step 10.1). Query the Order to obtain the Allocation object ID — it is in the `allocation` field of the Order object.
|
|
1003
|
-
|
|
1004
|
-
> **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.
|
|
1005
|
-
|
|
1006
|
-
> **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 10.3.
|
|
1007
|
-
|
|
1008
|
-
### 11.1 Phase 1: Request Submission Prompt
|
|
1009
|
-
|
|
1010
|
-
Call the allocation operation WITHOUT the `submission` field to obtain the Guard submission structure.
|
|
1011
|
-
|
|
1012
|
-
**Prompt**: Withdraw funds from allocation "insurance_test_alloc_v1" using Treasury withdraw guard.
|
|
1013
|
-
|
|
1014
|
-
```json
|
|
1015
|
-
{
|
|
1016
|
-
"tool": "onchain_operations",
|
|
1017
|
-
"data": {
|
|
1018
|
-
"operation_type": "allocation",
|
|
1019
|
-
"data": {
|
|
1020
|
-
"object": "insurance_test_alloc_v1",
|
|
1021
|
-
"alloc_by_guard": "insurance_withdraw_guard_treasury_v1"
|
|
1022
|
-
},
|
|
1023
|
-
"env": {
|
|
1024
|
-
"account": "insurance_provider_v1",
|
|
1025
|
-
"network": "testnet"
|
|
1026
|
-
}
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
```
|
|
1030
|
-
|
|
1031
|
-
The server will return a `submission` prompt (illustrative example — actual guard addresses come from your Phase 1 response):
|
|
1032
|
-
|
|
1033
|
-
```json
|
|
1034
|
-
{
|
|
1035
|
-
"result": {
|
|
1036
|
-
"type": "submission",
|
|
1037
|
-
"guard": [
|
|
1038
|
-
{ "object": "0xfb8bed2f...", "impack": true }
|
|
1039
|
-
],
|
|
1040
|
-
"submission": [
|
|
1041
|
-
{
|
|
1042
|
-
"guard": "0xfb8bed2f...",
|
|
1043
|
-
"submission": [
|
|
1044
|
-
{
|
|
1045
|
-
"identifier": 0,
|
|
1046
|
-
"b_submission": true,
|
|
1047
|
-
"value_type": "Address",
|
|
1048
|
-
"name": "order_id (Order object submitted at runtime)",
|
|
1049
|
-
"object_type": "Order"
|
|
1050
|
-
}
|
|
1051
|
-
]
|
|
1052
|
-
}
|
|
1053
|
-
]
|
|
1054
|
-
},
|
|
1055
|
-
"message": "Guard verification required: fill the submission array and resubmit."
|
|
1056
|
-
}
|
|
1057
|
-
```
|
|
1058
|
-
|
|
1059
|
-
### 11.2 Phase 2: Submit with Order ID
|
|
1060
|
-
|
|
1061
|
-
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.
|
|
1062
|
-
|
|
1063
|
-
**Prompt**: Withdraw funds from allocation with Order ID submission.
|
|
1064
|
-
|
|
1065
|
-
```json
|
|
1066
|
-
{
|
|
1067
|
-
"tool": "onchain_operations",
|
|
1068
|
-
"data": {
|
|
1069
|
-
"operation_type": "allocation",
|
|
1070
|
-
"data": {
|
|
1071
|
-
"object": "insurance_test_alloc_v1",
|
|
1072
|
-
"alloc_by_guard": "insurance_withdraw_guard_treasury_v1"
|
|
1073
|
-
},
|
|
1074
|
-
"submission": {
|
|
1075
|
-
"type": "submission",
|
|
1076
|
-
"guard": [
|
|
1077
|
-
{
|
|
1078
|
-
"object": "0xfb8bed2f...",
|
|
1079
|
-
"impack": true
|
|
1080
|
-
}
|
|
1081
|
-
],
|
|
1082
|
-
"submission": [
|
|
1083
|
-
{
|
|
1084
|
-
"guard": "0xfb8bed2f...",
|
|
1085
|
-
"submission": [
|
|
1086
|
-
{
|
|
1087
|
-
"identifier": 0,
|
|
1088
|
-
"b_submission": true,
|
|
1089
|
-
"value_type": "Address",
|
|
1090
|
-
"name": "order_id (Order object submitted at runtime)",
|
|
1091
|
-
"object_type": "Order",
|
|
1092
|
-
"value": "test_insurance_order_v1"
|
|
1093
|
-
}
|
|
1094
|
-
]
|
|
1095
|
-
}
|
|
1096
|
-
]
|
|
1097
|
-
},
|
|
1098
|
-
"env": {
|
|
1099
|
-
"account": "insurance_provider_v1",
|
|
1100
|
-
"network": "testnet"
|
|
1101
|
-
}
|
|
1102
|
-
}
|
|
1103
|
-
}
|
|
1104
|
-
```
|
|
1105
|
-
|
|
1106
|
-
> **⚠️ Important**:
|
|
1107
|
-
> - Replace `0xfb8bed2f...` with the actual `insurance_withdraw_guard_treasury_v1` address from your Phase 1 response.
|
|
1108
|
-
> - The `value` field accepts either an on-chain object ID or a named object reference (e.g., `"test_insurance_order_v1"`).
|
|
1109
|
-
> - 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.
|
|
1110
|
-
> - After a successful withdrawal, the Allocation `balance` becomes `0`, a Payment object is created as an immutable record, and the recipient receives the funds as a **CoinWrapper** object (owned but NOT yet spendable). Complete Step 12 to unwrap it into spendable balance.
|
|
1111
|
-
|
|
1112
|
-
---
|
|
1113
|
-
|
|
1114
|
-
## Step 12: Receive Funds (Unwrap CoinWrapper — Single Action)
|
|
1115
|
-
|
|
1116
|
-
After `alloc_by_guard` distributes funds, each recipient receives a `CoinWrapper<T>` object — owned but not spendable. **The tool auto-unwraps in ONE action**: no need to query CoinWrapper IDs first, and no need to specify the coin type — received CoinWrappers are auto-enumerated and their inner token type (`CoinWrapper<T>`) is auto-derived on-chain.
|
|
1117
|
-
|
|
1118
|
-
Choose the variant matching the recipient (Treasury approach → 12.1; personal approach → 12.2).
|
|
1119
|
-
|
|
1120
|
-
### 12.1 Treasury Recipient (Approach 1)
|
|
1121
|
-
|
|
1122
|
-
**Prompt**: Receive recently arrived funds into "insurance_treasury_v1".
|
|
1123
|
-
|
|
1124
|
-
```json
|
|
1125
|
-
{
|
|
1126
|
-
"tool": "onchain_operations",
|
|
1127
|
-
"data": {
|
|
1128
|
-
"operation_type": "treasury",
|
|
1129
|
-
"data": {
|
|
1130
|
-
"object": "insurance_treasury_v1",
|
|
1131
|
-
"receive": "recently"
|
|
1132
|
-
},
|
|
1133
|
-
"env": {
|
|
1134
|
-
"account": "insurance_provider_v1",
|
|
1135
|
-
"network": "testnet"
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
}
|
|
1139
|
-
```
|
|
1140
|
-
|
|
1141
|
-
> **How it works**: `receive: "recently"` auto-queries every `CoinWrapper` received by the Treasury and deposits them into the Treasury balance in a single transaction. The Treasury's token type (`0x2::wow::WOW`) must match the CoinWrapper's inner type (validated automatically).
|
|
1142
|
-
|
|
1143
|
-
### 12.2 Personal Recipient (Approach 2)
|
|
1144
|
-
|
|
1145
|
-
**Prompt**: Unwrap all CoinWrappers owned by "insurance_provider_v1" into spendable balance.
|
|
1146
|
-
|
|
1147
|
-
```json
|
|
1148
|
-
{
|
|
1149
|
-
"tool": "onchain_operations",
|
|
1150
|
-
"data": {
|
|
1151
|
-
"operation_type": "payment",
|
|
1152
|
-
"data": {
|
|
1153
|
-
"receive": true
|
|
1154
|
-
},
|
|
1155
|
-
"env": {
|
|
1156
|
-
"account": "insurance_provider_v1",
|
|
1157
|
-
"network": "testnet"
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
|
-
}
|
|
1161
|
-
```
|
|
1162
|
-
|
|
1163
|
-
> **How it works (AUTO-RECEIVE)**: with `receive: true` and `object` omitted, the tool unwraps **every** CoinWrapper currently owned by the caller via `payment::unwrap_to_myself` in a single transaction, deleting the wrappers and transferring the underlying coins to the caller. The coin type is auto-derived from each wrapper's own on-chain type — `type_parameter` is only needed if auto-derivation fails.
|
|
1164
|
-
>
|
|
1165
|
-
> **Optional — unwrap a specific wrapper only**: pass `"object": "<coinwrapper_id_or_name>"` instead of omitting it.
|
|
1166
|
-
|
|
1167
|
-
### Verify Funds Received
|
|
1168
|
-
|
|
1169
|
-
```json
|
|
1170
|
-
{
|
|
1171
|
-
"tool": "query_toolkit",
|
|
1172
|
-
"data": {
|
|
1173
|
-
"query_type": "account_balance",
|
|
1174
|
-
"name_or_address": "insurance_treasury_v1",
|
|
1175
|
-
"network": "testnet",
|
|
1176
|
-
"no_cache": true
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
```
|
|
1180
|
-
|
|
1181
|
-
The Treasury (or personal) balance should now include the withdrawn `100000000` MIST (0.1 WOW). For the personal approach, query `"insurance_provider_v1"` instead.
|
|
1182
|
-
|
|
1183
|
-
---
|
|
1184
|
-
|
|
1185
|
-
## Troubleshooting
|
|
1186
|
-
|
|
1187
|
-
### MoveAbort code: 7 (Guard Verification Failed)
|
|
1188
|
-
|
|
1189
|
-
When advancing Progress, if you get `abort code: 7 (Verify failed)`, the Guard condition was not satisfied. For the time-lock Guard:
|
|
1190
|
-
- Wait longer than the time-lock duration (10000ms = 10 seconds) before advancing to Complete
|
|
1191
|
-
- Verify the submitted Order ID is correct and corresponds to the Progress being advanced
|
|
1192
|
-
|
|
1193
|
-
For the withdraw Guard:
|
|
1194
|
-
- Verify the Order's Progress is at the "Complete" node (case-sensitive — "Complete" ≠ "complete")
|
|
1195
|
-
- Verify the Order belongs to `insurance_service_v1` (project binding check via query 1563)
|
|
1196
|
-
|
|
1197
|
-
### Forward validation failed
|
|
1198
|
-
|
|
1199
|
-
If you see `Connection from current node "" to target node "Complete" does not exist`, use simple forward names without node prefix:
|
|
1200
|
-
- ✅ Correct: `"forward": "start_claim"`
|
|
1201
|
-
- ❌ Incorrect: `"forward": "Start.start_claim"`
|
|
1202
|
-
|
|
1203
|
-
### Missing required field 'next_node_name'
|
|
1204
|
-
|
|
1205
|
-
The progress operation requires `operation` (with both `next_node_name` and `forward` fields) plus the `op` field:
|
|
1206
|
-
```json
|
|
1207
|
-
{
|
|
1208
|
-
"operation": {
|
|
1209
|
-
"next_node_name": "Start",
|
|
1210
|
-
"forward": "start_claim"
|
|
1211
|
-
},
|
|
1212
|
-
"op": "next"
|
|
1213
|
-
}
|
|
1214
|
-
```
|
|
1215
|
-
|
|
1216
|
-
### Data not found / stale data
|
|
1217
|
-
|
|
1218
|
-
If queries return old data after successful transactions:
|
|
1219
|
-
- Use `no_cache: true` parameter for critical queries
|
|
1220
|
-
- Wait for transaction confirmation before the next operation
|
|
1221
|
-
|
|
1222
|
-
### Machine modification failed
|
|
1223
|
-
|
|
1224
|
-
Published Machine nodes are immutable (`MoveAbort code: 3`). Create a new Machine with the correct configuration if changes are needed.
|
|
1225
|
-
|
|
1226
|
-
---
|
|
1227
|
-
|
|
1228
|
-
## Execution Checklist
|
|
1229
|
-
|
|
1230
|
-
- [ ] Create `insurance_provider_v1` account
|
|
1231
|
-
- [ ] Get test tokens for `insurance_provider_v1`
|
|
1232
|
-
- [ ] Step 1: Create `insurance_permission_v1` with all required indexes
|
|
1233
|
-
- [ ] Step 2: Create `insurance_treasury_v1` (same Permission as Service)
|
|
1234
|
-
- [ ] Step 3: Create `insurance_complete_guard_v1` (time-lock)
|
|
1235
|
-
- [ ] Step 4: Create `insurance_machine_v1` with nodes and publish
|
|
1236
|
-
- [ ] Step 5: Create `insurance_service_v1` unpublished (machine + sales, `publish: false` — so withdraw Guards can resolve its address)
|
|
1237
|
-
- [ ] Step 6: Create `insurance_withdraw_guard_treasury_v1` + `insurance_withdraw_guard_personal_v1` (project binding)
|
|
1238
|
-
- [ ] Step 7: Add 2 Entity-sharing order_allocators to `insurance_service_v1` and publish
|
|
1239
|
-
- [ ] Step 8: Unpause Service (Optional — skip if service was never paused)
|
|
1240
|
-
- [ ] Step 9: Verify Service configuration
|
|
1241
|
-
- [ ] Step 10.1: Create test insurance order
|
|
1242
|
-
- [ ] Step 10.2: Advance progress Initial -> Start
|
|
1243
|
-
- [ ] Step 10.3: Advance progress Start -> Complete with submission (wait 10s after Step 10.2)
|
|
1244
|
-
- [ ] Step 11: Withdraw funds via Allocation (alloc_by_guard with Treasury or personal withdraw guard)
|
|
1245
|
-
- [ ] Step 12: Receive funds (Treasury: `receive: "recently"` / Personal: `payment {receive: true}`) and verify balance
|