@wowok/skills 1.1.12 → 1.1.13
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/examples/Insurance/Insurance.md +142 -23
- package/examples/MyShop/MyShop.md +180 -189
- package/examples/MyShop/myshop_machine_nodes.json +14 -8
- package/examples/MyShop_Advanced/MyShop_Advanced.md +57 -56
- package/examples/ThreeBody_Signature/ThreeBody_Signature.md +431 -111
- package/examples/Travel/Travel.md +64 -18
- package/package.json +1 -1
- package/wowok-guard/SKILL.md +125 -19
|
@@ -90,6 +90,21 @@ Before running this example, ensure you have:
|
|
|
90
90
|
|
|
91
91
|
---
|
|
92
92
|
|
|
93
|
+
## Environment Parameters
|
|
94
|
+
|
|
95
|
+
All on-chain operations in this example use the following `env` fields:
|
|
96
|
+
|
|
97
|
+
| Field | Value | Purpose |
|
|
98
|
+
|-------|-------|---------|
|
|
99
|
+
| `network` | `"testnet"` | Target network |
|
|
100
|
+
| `account` | Account name | Signer account for the transaction |
|
|
101
|
+
| `no_cache` | `true` | Bypass local cache to avoid stale reads during sequential object creation. Without this, operations that depend on recently created objects may fail with "object not found". |
|
|
102
|
+
| `confirmed` | `true` | Explicitly confirm the on-chain transaction (MCP ConfirmGate). Required for all write operations. |
|
|
103
|
+
|
|
104
|
+
Additionally, `onChain: true` is required when an object's name needs to be resolved across different accounts (see Step 0.3).
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
93
108
|
## Step 0: Setup Weather Data
|
|
94
109
|
|
|
95
110
|
Before creating the travel service, set up the weather Repository with the next 5 days of weather data. The weather data is keyed by timestamp, and the `weather_check_guard` (Step 3.1) will query this repository at runtime when the customer enters the "Ice Scooting" node (Step 7.3). You must use timestamps that are valid at the time you run this example.
|
|
@@ -139,7 +154,9 @@ Day 5: 1783900800000 (2026-07-13T00:00:00.000Z)
|
|
|
139
154
|
},
|
|
140
155
|
"env": {
|
|
141
156
|
"account": "weather_provider",
|
|
142
|
-
"network": "testnet"
|
|
157
|
+
"network": "testnet",
|
|
158
|
+
"no_cache": true,
|
|
159
|
+
"confirmed": true
|
|
143
160
|
}
|
|
144
161
|
}
|
|
145
162
|
```
|
|
@@ -155,7 +172,8 @@ Day 5: 1783900800000 (2026-07-13T00:00:00.000Z)
|
|
|
155
172
|
"object": {
|
|
156
173
|
"name": "weather_repo",
|
|
157
174
|
"permission": "weather_permission",
|
|
158
|
-
"replaceExistName": true
|
|
175
|
+
"replaceExistName": true,
|
|
176
|
+
"onChain": true
|
|
159
177
|
},
|
|
160
178
|
"description": "Weather data repository for Iceland travel activities",
|
|
161
179
|
"policies": {
|
|
@@ -173,11 +191,15 @@ Day 5: 1783900800000 (2026-07-13T00:00:00.000Z)
|
|
|
173
191
|
},
|
|
174
192
|
"env": {
|
|
175
193
|
"account": "weather_provider",
|
|
176
|
-
"network": "testnet"
|
|
194
|
+
"network": "testnet",
|
|
195
|
+
"no_cache": true,
|
|
196
|
+
"confirmed": true
|
|
177
197
|
}
|
|
178
198
|
}
|
|
179
199
|
```
|
|
180
200
|
|
|
201
|
+
> **Note**: `onChain: true` is required here because `weather_repo` is created by the `weather_provider` account, but its name will be referenced in the Guard table (Step 3.1) by the `travel_provider` account. Without `onChain: true`, the name is stored locally only on `weather_provider`'s device and cannot be resolved by `travel_provider`. When `onChain: true` is set, the name is published on-chain and becomes publicly visible, allowing cross-account name resolution.
|
|
202
|
+
|
|
181
203
|
### 0.4 Add Weather Data
|
|
182
204
|
|
|
183
205
|
Add 5 days of weather data. The `weather_check_guard` (Step 3.1) only verifies that a record **exists** for the activity date (via `repository.data has`), so all 5 days will pass the Guard regardless of the condition value. The "rainy" value on Day 5 is informational only — to actually reject based on weather condition, you would need a Guard that queries `repository.data` and compares the value, which is more complex and not used in this example.
|
|
@@ -206,7 +228,9 @@ Add 5 days of weather data. The `weather_check_guard` (Step 3.1) only verifies t
|
|
|
206
228
|
},
|
|
207
229
|
"env": {
|
|
208
230
|
"account": "weather_provider",
|
|
209
|
-
"network": "testnet"
|
|
231
|
+
"network": "testnet",
|
|
232
|
+
"no_cache": true,
|
|
233
|
+
"confirmed": true
|
|
210
234
|
}
|
|
211
235
|
}
|
|
212
236
|
```
|
|
@@ -239,7 +263,9 @@ Create a Permission object to manage access control for the travel service. Add
|
|
|
239
263
|
},
|
|
240
264
|
"env": {
|
|
241
265
|
"account": "travel_provider",
|
|
242
|
-
"network": "testnet"
|
|
266
|
+
"network": "testnet",
|
|
267
|
+
"no_cache": true,
|
|
268
|
+
"confirmed": true
|
|
243
269
|
}
|
|
244
270
|
}
|
|
245
271
|
```
|
|
@@ -267,7 +293,9 @@ Create an Arbitration object for dispute resolution.
|
|
|
267
293
|
},
|
|
268
294
|
"env": {
|
|
269
295
|
"account": "travel_provider",
|
|
270
|
-
"network": "testnet"
|
|
296
|
+
"network": "testnet",
|
|
297
|
+
"no_cache": true,
|
|
298
|
+
"confirmed": true
|
|
271
299
|
}
|
|
272
300
|
}
|
|
273
301
|
```
|
|
@@ -337,7 +365,9 @@ repository.data has("Condition", convert_number_address(activity_date))
|
|
|
337
365
|
},
|
|
338
366
|
"env": {
|
|
339
367
|
"account": "travel_provider",
|
|
340
|
-
"network": "testnet"
|
|
368
|
+
"network": "testnet",
|
|
369
|
+
"no_cache": true,
|
|
370
|
+
"confirmed": true
|
|
341
371
|
}
|
|
342
372
|
}
|
|
343
373
|
```
|
|
@@ -409,7 +439,9 @@ clock > progress.current_time + 1000
|
|
|
409
439
|
},
|
|
410
440
|
"env": {
|
|
411
441
|
"account": "travel_provider",
|
|
412
|
-
"network": "testnet"
|
|
442
|
+
"network": "testnet",
|
|
443
|
+
"no_cache": true,
|
|
444
|
+
"confirmed": true
|
|
413
445
|
}
|
|
414
446
|
}
|
|
415
447
|
```
|
|
@@ -455,7 +487,9 @@ Creates a Guard that allows order cancellation. This Guard always passes (return
|
|
|
455
487
|
},
|
|
456
488
|
"env": {
|
|
457
489
|
"account": "travel_provider",
|
|
458
|
-
"network": "testnet"
|
|
490
|
+
"network": "testnet",
|
|
491
|
+
"no_cache": true,
|
|
492
|
+
"confirmed": true
|
|
459
493
|
}
|
|
460
494
|
}
|
|
461
495
|
```
|
|
@@ -507,7 +541,9 @@ Checks if order progress current node is "Complete". If passed, merchant receive
|
|
|
507
541
|
},
|
|
508
542
|
"env": {
|
|
509
543
|
"account": "travel_provider",
|
|
510
|
-
"network": "testnet"
|
|
544
|
+
"network": "testnet",
|
|
545
|
+
"no_cache": true,
|
|
546
|
+
"confirmed": true
|
|
511
547
|
}
|
|
512
548
|
}
|
|
513
549
|
```
|
|
@@ -583,7 +619,9 @@ Checks if progress current is "Cancel" or "Ice Scooting". If passed, merchant ge
|
|
|
583
619
|
},
|
|
584
620
|
"env": {
|
|
585
621
|
"account": "travel_provider",
|
|
586
|
-
"network": "testnet"
|
|
622
|
+
"network": "testnet",
|
|
623
|
+
"no_cache": true,
|
|
624
|
+
"confirmed": true
|
|
587
625
|
}
|
|
588
626
|
}
|
|
589
627
|
```
|
|
@@ -635,7 +673,9 @@ Checks if progress current is "SPA". If passed, merchant gets 5%, user gets 95%
|
|
|
635
673
|
},
|
|
636
674
|
"env": {
|
|
637
675
|
"account": "travel_provider",
|
|
638
|
-
"network": "testnet"
|
|
676
|
+
"network": "testnet",
|
|
677
|
+
"no_cache": true,
|
|
678
|
+
"confirmed": true
|
|
639
679
|
}
|
|
640
680
|
}
|
|
641
681
|
```
|
|
@@ -762,7 +802,9 @@ Create a Machine to define the travel service workflow with all nodes and forwar
|
|
|
762
802
|
},
|
|
763
803
|
"env": {
|
|
764
804
|
"account": "travel_provider",
|
|
765
|
-
"network": "testnet"
|
|
805
|
+
"network": "testnet",
|
|
806
|
+
"no_cache": true,
|
|
807
|
+
"confirmed": true
|
|
766
808
|
}
|
|
767
809
|
}
|
|
768
810
|
```
|
|
@@ -883,7 +925,9 @@ Create the travel service with all configurations and publish it in one operatio
|
|
|
883
925
|
},
|
|
884
926
|
"env": {
|
|
885
927
|
"account": "travel_provider",
|
|
886
|
-
"network": "testnet"
|
|
928
|
+
"network": "testnet",
|
|
929
|
+
"no_cache": true,
|
|
930
|
+
"confirmed": true
|
|
887
931
|
}
|
|
888
932
|
}
|
|
889
933
|
```
|
|
@@ -960,7 +1004,9 @@ The customer (Alice) purchases the travel package. This creates an Order, a Prog
|
|
|
960
1004
|
},
|
|
961
1005
|
"env": {
|
|
962
1006
|
"account": "alice",
|
|
963
|
-
"network": "testnet"
|
|
1007
|
+
"network": "testnet",
|
|
1008
|
+
"no_cache": true,
|
|
1009
|
+
"confirmed": true
|
|
964
1010
|
}
|
|
965
1011
|
}
|
|
966
1012
|
```
|
|
@@ -1284,7 +1330,7 @@ For refund scenarios (Cancel or SPA), use the corresponding Guard. The same subm
|
|
|
1284
1330
|
"submission": [{"identifier": 0, "b_submission": true, "value_type": "Address", "value": "<ORDER_OBJECT_ID>", "name": "Order ID"}]
|
|
1285
1331
|
}]
|
|
1286
1332
|
},
|
|
1287
|
-
"env": {"account": "travel_provider", "network": "testnet", "no_cache": true}
|
|
1333
|
+
"env": {"account": "travel_provider", "network": "testnet", "no_cache": true, "confirmed": true}
|
|
1288
1334
|
}
|
|
1289
1335
|
```
|
|
1290
1336
|
|
|
@@ -1305,7 +1351,7 @@ For refund scenarios (Cancel or SPA), use the corresponding Guard. The same subm
|
|
|
1305
1351
|
"submission": [{"identifier": 0, "b_submission": true, "value_type": "Address", "value": "<ORDER_OBJECT_ID>", "name": "Order ID"}]
|
|
1306
1352
|
}]
|
|
1307
1353
|
},
|
|
1308
|
-
"env": {"account": "travel_provider", "network": "testnet", "no_cache": true}
|
|
1354
|
+
"env": {"account": "travel_provider", "network": "testnet", "no_cache": true, "confirmed": true}
|
|
1309
1355
|
}
|
|
1310
1356
|
```
|
|
1311
1357
|
|
|
@@ -1440,6 +1486,6 @@ Customers place orders using the `order_new` field in the Service operation. Thi
|
|
|
1440
1486
|
"namedNewAllocation": {"name": "allocation_name", "replaceExistName": true}
|
|
1441
1487
|
}
|
|
1442
1488
|
},
|
|
1443
|
-
"env": {"account": "customer", "network": "testnet"}
|
|
1489
|
+
"env": {"account": "customer", "network": "testnet", "no_cache": true, "confirmed": true}
|
|
1444
1490
|
}
|
|
1445
1491
|
```
|
package/package.json
CHANGED
package/wowok-guard/SKILL.md
CHANGED
|
@@ -53,7 +53,30 @@ Every Guard is built from three layers, each with a distinct role:
|
|
|
53
53
|
|
|
54
54
|
**The root is the question**: It must return Bool. Intermediate nodes return numbers, strings, addresses, or vectors. Guard is **strongly typed** — the type system is strictly enforced at creation time. Type mismatches (e.g., passing a string to a numeric comparison node) will cause validation errors and prevent Guard creation.
|
|
55
55
|
|
|
56
|
-
**The rely is composition**: Up to 4 dependent Guards. When `rely.logic_or` is false (default), all dependencies must pass (AND). When true, any passing is sufficient (OR). A Guard can only depend on Guards with `rep: true` — `rep`
|
|
56
|
+
**The rely is composition**: Up to 4 dependent Guards. When `rely.logic_or` is false (default), all dependencies must pass (AND). When true, any passing is sufficient (OR). A Guard can only depend on Guards with `rep: true` — `rep` indicates the Guard's `repository.data` queries (query 1167) do not depend on runtime submissions, so results are deterministic and the Guard can serve as a dependency. Guards with `rep: false` cannot appear in `rely` lists. Violations are caught by the contract layer at creation time.
|
|
57
|
+
|
|
58
|
+
### Data Source 4 Classification — The Foundation of Guard Semantics
|
|
59
|
+
|
|
60
|
+
A Guard is fundamentally a **data computation tree**: deterministic data (on-chain constants + system context) + submitted data (runtime, semi-open) → derived through finite operation rules → a single boolean result. Every leaf node in the computation tree draws data from one of **4 data source classifications**. Understanding these 4 classifications is essential for designing and interpreting Guards.
|
|
61
|
+
|
|
62
|
+
| Type | Name | SDK Manifestation | Native Opcode | Trust Level | Typical Scenario |
|
|
63
|
+
|------|------|-------------------|---------------|-------------|------------------|
|
|
64
|
+
| **Type 1** | OnChainConstant | `query` + `identifier` (`b_submission: false`, no witness) | TYPE_QUERY + TYPE_CONSTANT | Highest | Query fields of already-published Service/Machine/Reward objects |
|
|
65
|
+
| **Type 2** | WitnessDerived | `query` + `identifier` + `convert_witness` (100-108) | TYPE_QUERY + witness_byte | High (source trusted + deterministic derivation) | Order → Progress query via witness=100 |
|
|
66
|
+
| **Type 3** | SubmittedObject | `query` + `identifier` (`b_submission: true`, no witness) | TYPE_QUERY + TYPE_CONSTANT | Medium (requires constraint rules) | User submits Order address for field query |
|
|
67
|
+
| **Type 4** | SystemContext | `context` (Signer/Clock/Guard) | TYPE_SIGNER / TYPE_CLOCK / TYPE_GUARD | Highest | Identity verification, time-locks |
|
|
68
|
+
|
|
69
|
+
**Key insights**:
|
|
70
|
+
1. **Type 1 and Type 3 are isomorphic at the native layer** — both use TYPE_QUERY+TYPE_CONSTANT; the only difference is the `b_submission` flag (false vs true)
|
|
71
|
+
2. **Type 2 can overlay on Type 1 or Type 3** — the source object can be a constant (Type 1) or a submission (Type 3), then witness derives the target object
|
|
72
|
+
3. **Type 4 is fully independent** — does not depend on the table
|
|
73
|
+
4. **Except for Type 4, all data must be declared in the table** — the table is the complete data contract between Guard and caller
|
|
74
|
+
|
|
75
|
+
**The table as data contract**: The table declares:
|
|
76
|
+
- **Deterministic data** (`b_submission: false`): type + value, baked at creation, immutable
|
|
77
|
+
- **Submitted data** (`b_submission: true`): type only (1-byte placeholder), value provided by caller at runtime — **must have constraint rules designed, otherwise empty data is meaningless**
|
|
78
|
+
|
|
79
|
+
**Guard essence**: A deterministic data set (Type 1 + Type 4) + submitted data (Type 3, must have constraint rules and defined types) → derived through finite operation rules → a single boolean result. The semantics are deterministic — you only need to fill in the "data object source meaning" and "field meaning" (e.g., "the permission address of service A", "the current node time of workflow B").
|
|
57
80
|
|
|
58
81
|
### Where Guards Attach in the Ecosystem
|
|
59
82
|
|
|
@@ -148,26 +171,43 @@ The Guard table is the **complete declaration of information** the Guard consume
|
|
|
148
171
|
- **No duplicate identifiers.** Each index number must appear exactly once.
|
|
149
172
|
- **Non-submission entries must have a value.** These are baked into the Guard immutably.
|
|
150
173
|
- **Submission entries use placeholder values.** The actual value is provided by the caller at runtime.
|
|
151
|
-
- **Query target objects must be of type Address in the table.**
|
|
174
|
+
- **Query target objects must be of type Address in the table.** The `object_type` field is **automatically filled by the SDK** based on the first query node referencing this identifier (it is NOT a user-provided field). The SDK infers the object type from the query instruction's target object type (Progress, Order, Machine, Reward, etc.).
|
|
152
175
|
- **Querying EntityRegistrar or EntityLinker requires system address table entries.** Add entries for `ENTITY_REGISTRAR_ADDRESS` (`0xaab`) or `ENTITY_LINKER_ADDRESS` (`0xaaa`) to the table as Address-type constants when your query instruction targets these global registries. Without them, creation fails.
|
|
153
176
|
- **Maximum 256 table entries** (identifiers 0–255). The total serialized table size must not exceed 40000 bytes.
|
|
154
177
|
- **Submission entries must have descriptive `name` values.** For `b_submission: true` entries, `name` is the contract between Guard and caller — it tells callers what data they must provide. Use natural language that explains the purpose and necessity: "The order ID that identifies the target Order for verification" not `"order_id"`, "The signer's account address that will be compared against the authorized list" not `"addr"`. This is critical because callers see only this name when submitting data.
|
|
155
178
|
|
|
156
179
|
### The convert_witness Mechanism
|
|
157
180
|
|
|
158
|
-
`convert_witness` transforms a
|
|
181
|
+
`convert_witness` transforms a source object ID into its associated target object — enabling queries across object relationships without requiring the caller to submit multiple IDs. This is the **Type 2 (WitnessDerived)** data source.
|
|
159
182
|
|
|
160
|
-
**Core principle**: Caller submits what they have (e.g., Order ID); Guard queries what it needs (e.g., Progress state) via witness conversion.
|
|
183
|
+
**Core principle**: Witness is a "read the source object's associated field" mechanism (not a lookup table, not an independent index). It is a one-to-one deterministic derivation of object relationships with only 9 derivation types. Caller submits what they have (e.g., Order ID); Guard queries what it needs (e.g., Progress state) via witness conversion.
|
|
161
184
|
|
|
162
185
|
**Rules**:
|
|
163
186
|
- Witness type encodes source→target transformation
|
|
164
|
-
- Table entry's `object_type` must match witness source type
|
|
187
|
+
- Table entry's `object_type` (auto-filled by SDK) must match witness source type
|
|
165
188
|
- Query instruction's object type must match witness target type
|
|
166
189
|
- Type mismatches cause Guard creation to fail
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
190
|
+
- Multi-hop witnesses (106-108) require intermediate objects to exist
|
|
191
|
+
|
|
192
|
+
**Complete 9 witness types** (defined in `guard.rs#L34-L65`):
|
|
193
|
+
|
|
194
|
+
| Code | Name | Source → Target | Derivation | Hops |
|
|
195
|
+
|------|------|-----------------|------------|------|
|
|
196
|
+
| 100 | TypeOrderProgress | Order → Progress | read order.progress field | 1 |
|
|
197
|
+
| 101 | TypeOrderMachine | Order → Machine | read order.machine field | 1 |
|
|
198
|
+
| 102 | TypeOrderService | Order → Service | read order.service field | 1 |
|
|
199
|
+
| 103 | TypeProgressMachine | Progress → Machine | read progress.machine field | 1 |
|
|
200
|
+
| 104 | TypeArbOrder | Arb → Order | read arb.order field | 1 |
|
|
201
|
+
| 105 | TypeArbArbitration | Arb → Arbitration | read arb.arbitration field | 1 |
|
|
202
|
+
| 106 | TypeArbProgress | Arb → Progress | arb.order → order.progress | 2 (multi-hop) |
|
|
203
|
+
| 107 | TypeArbMachine | Arb → Machine | arb.order → order.machine | 2 (multi-hop) |
|
|
204
|
+
| 108 | TypeArbService | Arb → Service | arb.order → order.service | 2 (multi-hop) |
|
|
205
|
+
|
|
206
|
+
**Key notes**:
|
|
207
|
+
- **Type 2 can overlay on Type 1 or Type 3**: The source object can be a constant (Type 1, `b_submission: false`) or a submission (Type 3, `b_submission: true`). The witness then derives the target object.
|
|
208
|
+
- **Multi-hop witnesses (106-108)**: Arb → Progress/Machine/Service uses two hops (Arb → Order → target). The intermediate Order object must exist for the derivation to succeed.
|
|
209
|
+
- **TypeArbArbitration (105)**: Arb and Arbitration are **different on-chain objects**. The witness queries the Arbitration (parent service) from an Arb (case) address — the binding is set when Arbitration creates the Arb.
|
|
210
|
+
- **Available witness types** are also discoverable via `wowok_buildin_info` with info `"guard instructions"`.
|
|
171
211
|
|
|
172
212
|
---
|
|
173
213
|
|
|
@@ -281,6 +321,8 @@ Machine's forward `guard` validates state transitions. If `retained_submission`
|
|
|
281
321
|
|
|
282
322
|
Repository's `write_guard` validates writes. If `id_from_submission` is set, reads entity ID from that submission index — **the index must be Address type**. If `data_from_submission` is set, reads data value from that index — **the value type must match the Repository's declared value_type**. Guard table must include entries for the data being extracted.
|
|
283
323
|
|
|
324
|
+
**Important — impack_list semantics in verify phase**: When a Guard queries Repository data (query 1167 `repository.data`) with a policy that has a `quote_guard` set, the verification checks whether the quote_guard address is in the `impack_list`. However, `impack_list` is **always empty during the `verify_guard` phase** — `Passport.new()` initializes `impack:vector[]` and the verify loop never modifies it; `impack` is only populated in `result_for_permission` (after verify completes). This means a Repository query with `quote_guard = Some(addr)` will always fail with `IMPACK_GUARD_NOT_FOUND` in the gen_passport flow; only `quote_guard = None` passes. Verify the quote_guard mechanism's design intent before relying on it.
|
|
325
|
+
|
|
284
326
|
---
|
|
285
327
|
|
|
286
328
|
**Key Principle**: Design your Guard table based on what data the target object needs to read. Objects don't just validate — they consume Guard submissions as structured data inputs.
|
|
@@ -303,25 +345,89 @@ Each object extracts Guard data with precise type expectations. Mismatches cause
|
|
|
303
345
|
|
|
304
346
|
### Common Pitfalls
|
|
305
347
|
|
|
306
|
-
|
|
348
|
+
> The full constraint system has **33 rules: 22 creation-phase + 11 runtime-phase**. The 22 creation-phase constraints below are all enforced by SDK + native `validate_guard_data`; runtime constraints are enforced by native `verify_guard`.
|
|
349
|
+
|
|
350
|
+
#### Creation-Phase Constraints (22 items, enforced by SDK + native `validate_guard_data`)
|
|
351
|
+
|
|
352
|
+
**Root (1 item)**
|
|
353
|
+
|
|
354
|
+
1. **ROOT_01 — Root must return Bool**: The outermost node of the tree must produce Bool. Logic and comparison nodes return Bool; arithmetic, conversion, and string operation nodes do not. Ensure your tree terminates at a logic or comparison node — the creation validation will reject non-Bool roots.
|
|
355
|
+
|
|
356
|
+
**Table (5 items)**
|
|
357
|
+
|
|
358
|
+
2. **TABLE_01 — Identifier uniqueness**: Every `identifier` in the table must be unique (0–255). Duplicate identifiers cause creation failure. SDK uses `lodash.groupBy` to detect duplicates.
|
|
359
|
+
|
|
360
|
+
3. **TABLE_02 — Identifier referential integrity**: Every `identifier` node in the computation tree must match an entry in the table. Missing entries cause creation failure — validate your tree against your table before submitting.
|
|
361
|
+
|
|
362
|
+
4. **TABLE_03 — Constant value non-empty**: When `b_submission=false`, the `value` field must be non-empty. These values are baked into the Guard immutably at creation time.
|
|
363
|
+
|
|
364
|
+
5. **TABLE_04 — Table size limits**: Maximum 256 table entries (identifiers 0–255), and the total serialized table size must not exceed 40000 bytes (BCS). Enforced by Move `guard::new`.
|
|
365
|
+
|
|
366
|
+
6. **TABLE_05 — Submission value is 1-byte type code**: When `b_submission=true`, the `value` field is only a 1-byte type code placeholder (the actual value is provided at runtime). Enforced by native `deserialize_constants`.
|
|
367
|
+
|
|
368
|
+
**Query (4 items)**
|
|
369
|
+
|
|
370
|
+
7. **QUERY_01 — Query instruction ID valid**: Query instruction IDs are system-defined. Always discover them through `wowok_buildin_info` with info `"guard instructions"`. Invalid IDs cause creation failure.
|
|
371
|
+
|
|
372
|
+
8. **QUERY_02 — Parameter count matches**: The parameter count and types in your query node must match the instruction exactly — off-by-one parameter counts are a common failure.
|
|
373
|
+
|
|
374
|
+
9. **QUERY_03 — Return type compatible**: The query node's return type must be compatible with the parent node's expected input. A `logic_equal` comparing a String to a U64 fails validation. Use explicit conversion nodes (`convert_string_number`, `convert_number_string`) when types differ. Numeric comparisons use `logic_as_u256_*` variants which auto-widen to U256.
|
|
375
|
+
|
|
376
|
+
10. **QUERY_04 — Object identifier is Address type**: The table entry referenced by a query node's `object.identifier` must have `value_type: Address`. SDK `buildNode` validates this at L603-609.
|
|
377
|
+
|
|
378
|
+
**Witness (3 items)**
|
|
379
|
+
|
|
380
|
+
11. **WITNESS_01 — Witness type valid (100-108)**: The `convert_witness` value must be one of the 9 valid witness types (100-108). Invalid witness types cause creation failure.
|
|
381
|
+
|
|
382
|
+
12. **WITNESS_02 — Witness target matches query objectType**: The witness's target object type must match the query instruction's expected object type. For example, `TypeOrderProgress` (100) derives a Progress, so the query must target a Progress object. SDK `buildNode` validates this at L613-619.
|
|
383
|
+
|
|
384
|
+
13. **WITNESS_03 — Witness source matches table object_type**: If the table entry has an `object_type` declared (auto-filled by SDK), it must match the witness's source object type. For example, `TypeOrderProgress` (100) expects an Order source, so the table entry's `object_type` must be Order. SDK `buildNode` validates this at L622-631. **Missing convert_witness** is a related failure: when accessing Progress data from an Order ID, the query node needs `convert_witness` with the appropriate witness type. Without it, the runtime looks for a Progress at the Order's address — which does not exist as a Progress object.
|
|
385
|
+
|
|
386
|
+
**Rely (3 items)**
|
|
387
|
+
|
|
388
|
+
14. **RELY_01 — Dependency count ≤ 4**: A Guard can depend on at most 4 other Guards (`MAX_DEPENDED_COUNT`). SDK `reliesAdd` enforces this limit.
|
|
389
|
+
|
|
390
|
+
15. **RELY_02 — Dependencies must have rep=true**: A Guard's `rely` entries must reference Guards with `rep: true` — meaning their `repository.data` queries do not depend on runtime submissions. Guards that depend on a Repository via submitted addresses (`rep: false`) cannot serve as dependencies. Move `guard::relies_add` catches violations at creation time.
|
|
391
|
+
|
|
392
|
+
16. **RELY_03 — No self-reference**: A Guard cannot depend on itself. SDK `reliesAdd` prevents self-referential rely entries.
|
|
393
|
+
|
|
394
|
+
**Binding (3 items)**
|
|
395
|
+
|
|
396
|
+
17. **BINDING_01 — voting_guard GuardIdentifier must be numeric**: When using `GuardIdentifier` for Arbitration `voting_guard`, the referenced table entry must have a numeric `value_type` (U8–U256). The system checks this when the VotingGuard is added to the Arbitration — if the identifier does not exist or is non-numeric, the operation reverts with `E_GUARD_IDENTIFIER_NOT_NUMBER`.
|
|
397
|
+
|
|
398
|
+
18. **BINDING_02 — Repository id_from_submission must be Address**: When a Repository `write_guard` uses `id_from_submission`, the referenced table entry must have `value_type: Address`. Move Repository enforces this at binding time.
|
|
399
|
+
|
|
400
|
+
19. **BINDING_03 — Repository data_from_submission type must match**: When a Repository `write_guard` uses `data_from_submission`, the referenced table entry's `value_type` must match the Repository's declared `value_type`. Move Repository enforces this at binding time.
|
|
401
|
+
|
|
402
|
+
**Input (2 items)**
|
|
307
403
|
|
|
308
|
-
|
|
404
|
+
20. **INPUT_01 — Root bytecode non-empty**: The serialized root computation tree must not be empty. SDK `newGuard` validates this before submission.
|
|
309
405
|
|
|
310
|
-
|
|
406
|
+
21. **INPUT_02 — Root bytecode size ≤ MAX_INPUT_SIZE**: The serialized root computation tree must not exceed `MAX_INPUT_SIZE`. SDK `newGuard` validates this before submission.
|
|
311
407
|
|
|
312
|
-
|
|
408
|
+
**Immutable (1 item)**
|
|
313
409
|
|
|
314
|
-
|
|
410
|
+
22. **IMMUTABLE_01 — Guard becomes immutable after creation**: Once `guard::create` is called, the Guard's `immutable` flag is set to `true` and no further modifications are possible. This is the foundation of the immutability contract — to change a Guard, export via `guard2file`, create a new Guard, and update all references.
|
|
315
411
|
|
|
316
|
-
|
|
412
|
+
#### Practical Tips (not strict constraints, but strongly recommended)
|
|
317
413
|
|
|
318
|
-
|
|
414
|
+
- **Testing with production durations**: Set time-lock durations to small values (e.g., 1000 milliseconds) during testing. Increase to production values only after verifying the logic works correctly. A Guard with a 30-day lock tested with real durations cannot produce results for a month.
|
|
415
|
+
- **Forgetting to export before recreating**: Guards are immutable. If you need to change one, export it first with `guard2file` so you have the exact on-chain definition as a reference. Then create a new Guard with a versioned name and update all references.
|
|
416
|
+
- **Not checking Arbitration pause state**: Even with a valid usage_guard Passport, the dispute fails if the Arbitration is paused (`bPaused: true`). The pause check happens before the guard check — advise customers to verify the Arbitration is active before generating Passports.
|
|
319
417
|
|
|
320
|
-
|
|
418
|
+
#### Runtime-Phase Constraints (enforced by native `verify_guard`)
|
|
321
419
|
|
|
322
|
-
|
|
420
|
+
These constraints are checked at Guard verification time (gen_passport or actual usage), not at creation. They are often overlooked because creation succeeds but runtime fails:
|
|
323
421
|
|
|
324
|
-
|
|
422
|
+
- **RUN_IMMUTABLE_01**: Guard must have `immutable=true` to be verified. A Guard that hasn't been finalized via `guard::create` cannot be used.
|
|
423
|
+
- **RUN_SUB_01**: The submission's `value[0]` (type byte) must match the table declaration. A submission with the wrong type byte is rejected.
|
|
424
|
+
- **RUN_SUB_02**: Every table entry with `b_submission=true` must have a corresponding submission value. Missing submissions cause failure.
|
|
425
|
+
- **RUN_SUB_03**: Total submission bytes must be ≤ `MAX_SUBMISSION_SIZE` (256).
|
|
426
|
+
- **RUN_WITNESS_01/02**: When witness conversion runs, the source object must have the associated field, and the derived target object must exist. Multi-hop witnesses (106-108) require the intermediate Order object to exist.
|
|
427
|
+
- **RUN_QUERY_01**: The query target object must exist and its type must match.
|
|
428
|
+
- **RUN_IMPACK_01/02**: At least one impack guard is required; an impack guard failure fails the entire passport. **Note**: `impack_list` is always empty during verify (see Repository section above), so quote_guard queries will fail unless `quote_guard = None`.
|
|
429
|
+
- **RUN_TX_01**: The Passport's `tx_hash` must match the current transaction.
|
|
430
|
+
- **RUN_RELY_01**: Rely guards must have been added to the passport.
|
|
325
431
|
|
|
326
432
|
---
|
|
327
433
|
|