@wowok/agent-mcp 3.4.4 → 3.4.5

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.
Files changed (191) hide show
  1. package/dist/.build-stamp.json +3 -3
  2. package/dist/chain-semantics/composition-truth.js +1 -1
  3. package/dist/composition/audit.js +1 -1
  4. package/dist/composition/compile.js +1 -1
  5. package/dist/composition/emit-phases.js +1 -1
  6. package/dist/composition/guard-fill.js +1 -1
  7. package/dist/composition/input-normalize.js +1 -1
  8. package/dist/composition/materialize.js +1 -1
  9. package/dist/composition/mode-gates.js +1 -1
  10. package/dist/composition/param-disclosure.js +1 -1
  11. package/dist/composition/plan-run-store.js +1 -0
  12. package/dist/composition/reflux.js +1 -1
  13. package/dist/composition/role-bindings.js +1 -0
  14. package/dist/composition/shape-expand.js +1 -1
  15. package/dist/composition/supply-chain-emit.js +1 -1
  16. package/dist/config/judgment.d.ts +13 -25
  17. package/dist/config/judgment.js +1 -1
  18. package/dist/config/match-policy-file.js +1 -1
  19. package/dist/config/rule-engine.d.ts +4 -10
  20. package/dist/config/rule-engine.js +1 -1
  21. package/dist/config/template-params.js +1 -1
  22. package/dist/evaluation/engine.js +1 -1
  23. package/dist/experience/realtime-feedback.js +1 -1
  24. package/dist/extensions/capability.js +1 -1
  25. package/dist/graph/onchain/expand.js +1 -1
  26. package/dist/graph/onchain/exposure.js +1 -1
  27. package/dist/harness/forward-roster-preflight.js +1 -0
  28. package/dist/keeper/detectors.js +1 -1
  29. package/dist/knowledge/allocator-rail-verifier.js +1 -1
  30. package/dist/knowledge/arb-operation-face.js +1 -1
  31. package/dist/knowledge/arbitration-rail-verifier.js +1 -1
  32. package/dist/knowledge/audit-rules.d.ts +17 -1
  33. package/dist/knowledge/audit-rules.js +1 -1
  34. package/dist/knowledge/baselines/rules/alloc_audit.json.good.sha256 +1 -0
  35. package/dist/knowledge/baselines/rules/allocation.json.good.sha256 +1 -0
  36. package/dist/knowledge/baselines/rules/arb.json.good.sha256 +1 -0
  37. package/dist/knowledge/baselines/rules/arbitration.json.good.sha256 +1 -0
  38. package/dist/knowledge/baselines/rules/bridge.json.good.sha256 +1 -0
  39. package/dist/knowledge/baselines/rules/contact.json.good.sha256 +1 -0
  40. package/dist/knowledge/baselines/rules/demand.json.good.sha256 +1 -0
  41. package/dist/knowledge/baselines/rules/graph.json.good.sha256 +1 -0
  42. package/dist/knowledge/baselines/rules/guard.json.good.sha256 +1 -0
  43. package/dist/knowledge/baselines/rules/machine.json.good.sha256 +1 -0
  44. package/dist/knowledge/baselines/rules/oracle.json.good.sha256 +1 -0
  45. package/dist/knowledge/baselines/rules/order.json.good.sha256 +1 -0
  46. package/dist/knowledge/baselines/rules/payment.json.good.sha256 +1 -0
  47. package/dist/knowledge/baselines/rules/permission.json.good.sha256 +1 -0
  48. package/dist/knowledge/baselines/rules/personal.json.good.sha256 +1 -0
  49. package/dist/knowledge/baselines/rules/plan.json +153 -33
  50. package/dist/knowledge/baselines/rules/plan.json.good +153 -33
  51. package/dist/knowledge/baselines/rules/plan.json.good.sha256 +1 -0
  52. package/dist/knowledge/baselines/rules/progress.json.good.sha256 +1 -0
  53. package/dist/knowledge/baselines/rules/proof.json.good.sha256 +1 -0
  54. package/dist/knowledge/baselines/rules/registrar.json.good.sha256 +1 -0
  55. package/dist/knowledge/baselines/rules/repository.json.good.sha256 +1 -0
  56. package/dist/knowledge/baselines/rules/resource.json.good.sha256 +1 -0
  57. package/dist/knowledge/baselines/rules/reward.json.good.sha256 +1 -0
  58. package/dist/knowledge/baselines/rules/service.json.good.sha256 +1 -0
  59. package/dist/knowledge/baselines/rules/treasury.json.good.sha256 +1 -0
  60. package/dist/knowledge/baselines/rules/util.json.good.sha256 +1 -0
  61. package/dist/knowledge/builtin-templates.d.ts +1 -1
  62. package/dist/knowledge/builtin-templates.js +1 -1
  63. package/dist/knowledge/discount-threshold.js +1 -1
  64. package/dist/knowledge/fee-param-bindings.js +1 -1
  65. package/dist/knowledge/getting-started.js +1 -1
  66. package/dist/knowledge/guard-binding-table.js +1 -1
  67. package/dist/knowledge/guard-design-patterns.js +1 -1
  68. package/dist/knowledge/guard-templates.d.ts +3 -2
  69. package/dist/knowledge/guard-templates.js +1 -1
  70. package/dist/knowledge/index.js +1 -1
  71. package/dist/knowledge/industry-registry.js +1 -1
  72. package/dist/knowledge/jsonrpc-enum.js +1 -1
  73. package/dist/knowledge/knob-docs.js +1 -1
  74. package/dist/knowledge/machine-topology.js +1 -1
  75. package/dist/knowledge/param-schema.js +1 -1
  76. package/dist/knowledge/param-tiers.js +1 -1
  77. package/dist/knowledge/path-oracle/products/alibaba-1688.js +1 -1
  78. package/dist/knowledge/path-oracle/products/amazon.js +1 -1
  79. package/dist/knowledge/path-oracle/products/booking-com.js +1 -1
  80. package/dist/knowledge/path-oracle/products/contra.js +1 -1
  81. package/dist/knowledge/path-oracle/products/costco.js +1 -1
  82. package/dist/knowledge/path-oracle/products/duoduo-maicai.js +1 -1
  83. package/dist/knowledge/path-oracle/products/etsy.js +1 -1
  84. package/dist/knowledge/path-oracle/products/gamefound.js +1 -1
  85. package/dist/knowledge/path-oracle/products/gofundme.js +1 -1
  86. package/dist/knowledge/path-oracle/products/klook.js +1 -1
  87. package/dist/knowledge/path-oracle/products/ninety-nine-designs.js +1 -1
  88. package/dist/knowledge/path-oracle/products/pinduoduo-kuaituantuan.js +1 -1
  89. package/dist/knowledge/path-oracle/products/shansong.js +1 -1
  90. package/dist/knowledge/path-oracle/products/taobao-presale.js +1 -1
  91. package/dist/knowledge/path-oracle/products/upwork-catalog.js +1 -1
  92. package/dist/knowledge/path-oracle/products/upwork.js +1 -1
  93. package/dist/knowledge/pattern-resolutions.js +1 -1
  94. package/dist/knowledge/protocol-facts.js +1 -1
  95. package/dist/knowledge/publish-gate.js +1 -1
  96. package/dist/knowledge/publish-surface-contract.js +1 -1
  97. package/dist/knowledge/template-loader.js +1 -1
  98. package/dist/knowledge/template-registry.js +1 -1
  99. package/dist/knowledge/template-scanner.js +1 -1
  100. package/dist/knowledge/time-units.js +1 -0
  101. package/dist/knowledge/tools-reference.js +1 -1
  102. package/dist/knowledge/workflow-guidance.js +1 -1
  103. package/dist/monitor/MonitorLoop.js +1 -1
  104. package/dist/participation/radar-core.js +1 -1
  105. package/dist/playbooks/service-build/business-puzzle.js +1 -1
  106. package/dist/playbooks/service-build/machine-panorama.js +1 -1
  107. package/dist/playbooks/service-build/merchant-guide.js +1 -1
  108. package/dist/playbooks/service-build/migration-planner.js +1 -1
  109. package/dist/playbooks/service-build/object-panorama.js +1 -1
  110. package/dist/playbooks/service-build/participation-radar.js +1 -1
  111. package/dist/playbooks/service-build/relationship-profile.js +1 -1
  112. package/dist/playbooks/service-build/service-panorama.js +1 -1
  113. package/dist/playbooks/service-build/service-quote.js +1 -1
  114. package/dist/review/index.js +1 -1
  115. package/dist/safety/confirm-gate.js +1 -1
  116. package/dist/schema/benchmark-migration/index.d.ts +110 -2
  117. package/dist/schema/benchmark-migration/index.js +1 -1
  118. package/dist/schema/boundary-coercion.js +1 -0
  119. package/dist/schema/call/arbitration.js +1 -1
  120. package/dist/schema/call/base.js +1 -1
  121. package/dist/schema/call/handler.js +1 -1
  122. package/dist/schema/call/machine.d.ts +56 -8
  123. package/dist/schema/call/order.d.ts +37 -10
  124. package/dist/schema/call/order.js +1 -1
  125. package/dist/schema/call/permission.d.ts +210 -30
  126. package/dist/schema/call/personal.d.ts +56 -8
  127. package/dist/schema/call/progress.d.ts +28 -4
  128. package/dist/schema/call/semantic.js +1 -1
  129. package/dist/schema/call/service.d.ts +84 -12
  130. package/dist/schema/common/index.d.ts +14 -2
  131. package/dist/schema/common/index.js +1 -1
  132. package/dist/schema/evaluation/index.js +1 -1
  133. package/dist/schema/goal/index.d.ts +1 -1
  134. package/dist/schema/goal/planning.js +1 -1
  135. package/dist/schema/local/index.js +1 -1
  136. package/dist/schema/messenger/index.d.ts +168 -24
  137. package/dist/schema/messenger/index.js +1 -1
  138. package/dist/schema/operations.d.ts +655 -22
  139. package/dist/schema/operations.js +1 -1
  140. package/dist/schema/persona/index.d.ts +22 -110
  141. package/dist/schema/query/index.js +1 -1
  142. package/dist/schema/schema-version.js +1 -1
  143. package/dist/schema/workflow/index.d.ts +4 -0
  144. package/dist/schema/workflow/index.js +1 -1
  145. package/dist/schema-query-impl/index.js +1 -1
  146. package/dist/schemas/benchmark_migration_operation.schema.json +1 -1
  147. package/dist/schemas/evaluation_operation.schema.json +1 -1
  148. package/dist/schemas/goal_operation.schema.json +1 -1
  149. package/dist/schemas/guard_rebind_replacement.schema.json +1 -0
  150. package/dist/schemas/index.json +1 -1
  151. package/dist/schemas/messenger_operation.schema.json +1 -1
  152. package/dist/schemas/onchain_operations.schema.json +1 -1
  153. package/dist/schemas/onchain_operations_allocation.schema.json +1 -1
  154. package/dist/schemas/onchain_operations_arbitration.schema.json +1 -1
  155. package/dist/schemas/onchain_operations_contact.schema.json +1 -1
  156. package/dist/schemas/onchain_operations_demand.schema.json +1 -1
  157. package/dist/schemas/onchain_operations_gen_passport.schema.json +1 -1
  158. package/dist/schemas/onchain_operations_machine.schema.json +1 -1
  159. package/dist/schemas/onchain_operations_order.schema.json +1 -1
  160. package/dist/schemas/onchain_operations_permission.schema.json +1 -1
  161. package/dist/schemas/onchain_operations_personal.schema.json +1 -1
  162. package/dist/schemas/onchain_operations_progress.schema.json +1 -1
  163. package/dist/schemas/onchain_operations_proof.schema.json +1 -1
  164. package/dist/schemas/onchain_operations_repository.schema.json +1 -1
  165. package/dist/schemas/onchain_operations_reward.schema.json +1 -1
  166. package/dist/schemas/onchain_operations_service.schema.json +1 -1
  167. package/dist/schemas/onchain_operations_treasury.schema.json +1 -1
  168. package/dist/schemas/persona_operation.schema.json +1 -1
  169. package/dist/schemas/time_convert.schema.json +1 -0
  170. package/dist/schemas/wip_file.schema.json +1 -1
  171. package/dist/schemas/workflow_operation.schema.json +1 -1
  172. package/dist/tools/handlers/benchmark-migration.js +1 -1
  173. package/dist/tools/handlers/config.js +1 -1
  174. package/dist/tools/handlers/fund-rail-recipe.js +1 -1
  175. package/dist/tools/handlers/guard-rebind-replacement.js +1 -0
  176. package/dist/tools/handlers/local.js +1 -1
  177. package/dist/tools/handlers/mark-namespace.js +1 -1
  178. package/dist/tools/handlers/onchain.js +1 -1
  179. package/dist/tools/handlers/query.js +1 -1
  180. package/dist/tools/handlers/settle-sweep.js +1 -1
  181. package/dist/tools/handlers/time-convert.js +1 -0
  182. package/dist/tools/handlers/wip.js +1 -1
  183. package/dist/tools/handlers/workflow.js +1 -1
  184. package/dist/tools/index.d.ts +1 -0
  185. package/dist/tools/index.js +1 -1
  186. package/dist/tools/registry/business.js +1 -1
  187. package/dist/tools/registry/local.js +1 -1
  188. package/dist/tools/registry/onchain.js +1 -1
  189. package/dist/tools/wip-verify-ledger.js +1 -1
  190. package/dist/tools/wrap.js +1 -1
  191. package/package.json +6 -5
@@ -1 +1 @@
1
- {"$schema":"http://json-schema.org/draft-07/schema#","$id":"https://wowok.net/schemas/onchain_operations_service.json","title":"Service Operation","description":"🏪 Service Object: Create and manage product/service listings with transparent promises, bind workflow templates to order processing, set pricing, issue discount coupons to customers, and establish quality standards, etc..","type":"object","properties":{"operation_type":{"type":"string","const":"service"},"data":{"type":"object","properties":{"object":{"anyOf":[{"type":"string","description":"String format: Reference an EXISTING object by its name (local mark) or on-chain object ID. Use this when the object already exists and you want to reference it."},{"type":"object","properties":{"name":{"description":"The name of the object","type":"string"},"tags":{"description":"The tags of the object","type":"array","items":{"type":"string"}},"onChain":{"description":"CRITICAL: Whether to sync the name to the blockchain. DEFAULT (undefined/false): The name is stored LOCALLY ONLY on your device (PRIVATE). If set to true: The name is published ON-CHAIN and becomes PUBLICLY VISIBLE to everyone. Only set to true for displaying the relationships you are willing to make public on the chain.","type":"boolean"},"replaceExistName":{"description":"FORCE CLAIM: Set to true ONLY when the user explicitly expresses a STRONG INTENTION to forcefully take over an existing name (e.g., 'I must use this name', 'force rename', 'replace the existing one'). WARNING: This will UNBIND the name from its original object and rebind it to the new one, potentially breaking existing references. If not specified or false: the operation will FAIL with an error when the name is already in use (safe default behavior).","type":"boolean"},"permission":{"anyOf":[{"type":"string","description":"String format: Reference an EXISTING object by its name (local mark) or on-chain object ID. Example: 'my-object' or '0x1234...'"},{"type":"object","properties":{"name":{"description":"The name of the object","type":"string"},"tags":{"description":"The tags of the object","type":"array","items":{"type":"string"}},"onChain":{"description":"CRITICAL: Whether to sync the name to the blockchain. DEFAULT (undefined/false): The name is stored LOCALLY ONLY on your device (PRIVATE). If set to true: The name is published ON-CHAIN and becomes PUBLICLY VISIBLE to everyone. Only set to true for displaying the relationships you are willing to make public on the chain.","type":"boolean"},"replaceExistName":{"description":"FORCE CLAIM: Set to true ONLY when the user explicitly expresses a STRONG INTENTION to forcefully take over an existing name (e.g., 'I must use this name', 'force rename', 'replace the existing one'). WARNING: This will UNBIND the name from its original object and rebind it to the new one, potentially breaking existing references. If not specified or false: the operation will FAIL with an error when the name is already in use (safe default behavior).","type":"boolean"},"description":{"description":"The description of the object","type":"string"}},"additionalProperties":false,"description":"Object format: CREATE a NEW object with name, optional description, and visibility settings. Extends NamedObjectSchema with an additional 'description' field for detailed object information."}],"description":"Two ways to specify an object: (1) STRING - Reference an EXISTING object by name or ID; (2) OBJECT - CREATE a NEW object with full configuration including optional name, tags, description, and visibility settings (local private by default, or public on-chain with onChain:true)."},"type_parameter":{"default":"0x2::wow::WOW","description":"Payment token type for this object (format: {address}::{module}::{struct}). e.g. ALWAYS the FULL type string `{address}::{module}::{struct}` e.g. '0x2::wow::WOW'. ⚠️ The bare names 'WOW' / 'USDT' / 'ETH' are REJECTED (the validator requires all three parts) — write '0x2::wow::WOW', not 'WOW'. The field may be OMITTED entirely: it then defaults to WOW ('0x2::wow::WOW'). This token is what the object accepts for payments and is fixed at creation. To discover other available tokens, call wowok_buildin_info with info 'mainnet bridge tokens' and use the returned `wowTypeTag` value here. NOTE: testnet/localnet carry WOW only — USDT/ETH are a mainnet capability.","type":"string"}},"required":["type_parameter"],"additionalProperties":false,"description":"Object format: CREATE a NEW object with COMPLETE configuration including: optional name, tags, description, token type for payments (e.g., '0x2::wow::WOW'), AND Permission-based access control. Use this for creating sophisticated objects with both payment token specification and permission management."}],"description":"Two ways to specify an object: (1) STRING - Reference an EXISTING object by name or ID; (2) OBJECT - CREATE a NEW object with full configuration including name, tags, description, token type for payments, and Permission-based access control. The object format is used when you need both token specification AND permission management."},"order_new":{"description":"Create new order. RETRY DISCIPLINE: the order creation is atomic on-chain but NOT in observability — a transport drop after submit leaves the commit state UNKNOWN, and a blind resubmit creates a second order with a second full escrow (live mainnet incident). On any failure/timeout, verify whether an order with this exact signature (service + buyer + items) already landed — via the in-flight marker in the failure envelope, the sender's recent on-chain objects, or onchain_events — and adopt it if present; resubmit only if confirmed absent.","type":"object","properties":{"buy":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"name":{"description":"Name of the product or service to purchase. Must match a listed sale name EXACTLY (the buy path resolves each item by exact name match) and MUST be ≤ 64 bytes (UTF-8): the on-chain buy path caps buyer-sent item names at 64 bytes even though the merchant side lists names up to 256 bytes — a longer name aborts E_NAME_LENGTH_EXCEEDED (abort 1) before anything else runs (F-RQ-01). When the exact name is impractical (long/CJK names that risk transport corruption), OMIT it and use sale_id or sale_name instead — the handler resolves the reference against the Service's LIVE sales list and fills this name for you (CHAN-P1-16).","type":"string"},"sale_id":{"description":"CHAN-P1-16: buy by the SKU's 0-based INDEX in the Service's live sales list (the order the service_quote / query lists them). The handler resolves the index to the live sale (name + price), rewrites item.name on your behalf, and echoes `sale_index + sale_name + price` in the response — the exact name never crosses the wire. Out-of-range index → refused with the full live index table (index + name + price) so one retry lands. Consumed by the MCP gate, never reaches the chain.","type":"integer","minimum":0,"maximum":9007199254740991},"sale_name":{"description":"CHAN-P1-16: buy by SKU NAME matched against the Service's LIVE sales list (exact match first; whitespace/case-tolerant, then containment when the name was corrupted in transport). Exactly one live match → the handler fills item.name and echoes `sale_index + sale_name + price`; several candidates → refused with every candidate's index; none → refused with the full live index table. Consumed by the MCP gate, never reaches the chain.","type":"string","minLength":1},"quantity":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"⚠️ PURCHASE QUANTITY, NOT inventory. This is the number of units you are buying; the on-chain order total = sale.price x this value. Do NOT put the product's available stock here — inventory is the separate `stock` field on the Service's sales list. To buy one unit, set quantity: 1. (Legacy callers may still send this as `stock`; it is accepted and treated identically as the purchase quantity.)"},"wip_hash":{"default":"","description":"WIP pin hash. HARD RULE (h1z9 card 13 #17, unified doctrine): when the product's wip_hash is NON-EMPTY, the buyer MUST pass this exact value — NEVER \"\". The chain quote aborts (E_WIP_HASH_NOT_MATCH) when the pin mismatches, which is the delivery-integrity guarantee. To skip copying the hash, set derive_wip_from_listing:true on the order_new object instead (explicit opt-in; the response then warns 'wip_pin: auto-filled — no WYSIWYG guarantee'). Only pass an explicit hash when pinning a value seen earlier: that protects against a legitimate merchant WIP update between viewing the product and placing the order.","type":"string"}},"required":["quantity","wip_hash"],"additionalProperties":false},"description":"List of products or services to purchase"},"total_pay":{"description":"Actual payment amount. FORMAT: {balance: <amount_in_smallest_unit>} or {coin: <coin_object_id>}. The token type and precision are determined by the Service object's type_parameter (the generic type set when the Service was created). For WOW (9 decimals): {balance: 1000000000} = 1 WOW. OPTIONAL without a discount (M-K17): omit it and the handler derives the EXACT total Σ(sale price × quantity) from the Service's on-chain sales list and discloses the derived value — no transcription, no drift. REQUIRED when 'discount' is set (the discounted total depends on the coupon's live value: run query_toolkit query_type='service_quote' and pass total_pay.balance = the quoted final_total). An explicit value is always honored as-is. AMOUNT GATE (M-K11-a): a total that EXACTLY equals Σ published sale price × quantity (catalog-priced buy, in the Service's own payment coin — WOW or bridged USDT/USDC/ETH/BTC) bypasses the harness pre-sign amount gate; any other amount above the threshold is blocked until WOWOK_AMOUNT_THRESHOLD is raised after explicit user confirmation.","anyOf":[{"type":"object","properties":{"balance":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"A coin/balance amount. Accepts three formats: (1) DISPLAY FORMAT with token symbol: \"2.5WOW\", \"10USDC\", \"0.05WOW\" — auto-converted to smallest units via the Fund Processing Layer (token precision resolved from official registry → cache → on-chain). The symbol MUST match the token's type_parameter. (2) SMALLEST UNIT (numeric string): \"10000000000\" — used as-is, no conversion. (3) SMALLEST UNIT (number): 10000000000 — used as-is only within the safe integer range (±2^53); numbers outside it are REJECTED, use a numeric string instead. PRECISION RULE: for values exceeding 2^53 (9007199254740991), ALWAYS use format (1) or (2) — JS numbers lose integer precision silently and such inputs are blocked. Raw amounts must be plain non-negative integers; a decimal value without a token symbol (e.g. \"2.5\") is rejected — append the symbol (\"2.5WOW\") so the Fund Processing Layer converts it. WARNING — BARE INTEGER MEANS SMALLEST UNIT, NOT TOKENS: formats (2)/(3) are NEVER interpreted as display tokens. For example amount=\"5\" or 5 means 5 raw units = 0.000000005 WOW (9 decimals) — NOT 5 WOW. When the user asks for a token amount, you MUST use display format (\"5WOW\", \"2USDC\"); a bare integer is only correct for unitless counts (e.g. stock quantity) or when you computed exact raw units yourself. Default token: WOW (9 decimals, 1 WOW = 10^9 MIST). For custom tokens: use display format with the token's symbol, or pass smallest units directly. MONEY CONFIRMATION: all monetary fields trigger user confirmation via the Fund Processing Layer, where the token's FULL type, decimals and raw amount are always visible. MULTIPLE ISSUERS: several on-chain tokens may legally share the same symbol (e.g. multiple \"USDT\" coins). When a bare symbol matches more than one token, the operation is BLOCKED and every candidate is listed with full details (type, name, decimals, verified tag) — present the list to the USER and let them choose (they may answer by number), then re-issue with the chosen token's FULL type string in type_parameter; never guess an issuer from the bare symbol. MISSING TOKEN INFO: when a token's precision cannot be resolved, the operation is REFUSED (raw u64 included — amount magnitude could not be verified). Recovery: provide the token's FULL type in package::module::Name form in type_parameter (a bare symbol like \"USDT\" cannot be resolved), and verify the WOW network is correct. Examples: \"2.5WOW\" (display → 2500000000), 10000000000 (number, smallest unit), \"50000000000\" (string, smallest unit). Used for: service sale prices, compensation fund balances, Treasury deposits, arbitration fees, reward amounts, stock quantities."}},"required":["balance"],"additionalProperties":false,"description":"Specify an amount value."},{"type":"object","properties":{"coin":{"type":"string","description":"Coin object ID or name(local mark). WHOLE-COIN TRANSFER: the ENTIRE Coin object is moved to the recipient — the 'amount' is NOT taken from it (testnet lesson: passing your main gas coin transfers its full balance, leaving you unable to pay for anything). Use only for coins whose whole balance is exactly what you intend to send; prefer {balance: <smallest-unit number>} for partial amounts."}},"required":["coin"],"additionalProperties":false}]},"discount":{"description":"Discount object ID or name. ⚠️ COUPON OWNERSHIP RULE (KB-02, disclose BEFORE checkout): a coupon held by another address cannot be applied to your order — only the coupon's current holder can redeem it, and the buy is signed by the buyer, so have the owner transfer the coupon to the buyer first (call service discount_send), then attach it here. Attaching the coupon BURNS it (every coupon is single-use), and any later refund settles the POST-coupon amount only (the escrowed discounted total) — the coupon's face value is never restored.","type":"string"},"payment_remark":{"description":"Payment remark","type":"string"},"payment_index":{"description":"Payment index","type":"number"},"derive_wip_from_listing":{"description":"EXPLICIT OPT-IN to wip-hash auto-fill (h1z9 card 13 #17: the ONLY sanctioned auto-fill path). true = for every item whose wip_hash is empty, the CURRENT listing hash is injected at order time and the response warns 'wip_pin: auto-filled — no WYSIWYG guarantee': the merchant may rebind the .wip file later, and an injected hash follows the listing while an explicitly passed hash stays pinned. Absent/false = the hard rule applies: pass each product's wip_hash EXACTLY (NEVER \"\" when the product has a pin) or the order is refused before send. This flag is consumed by the MCP gate and never reaches the chain.","type":"boolean"}},"required":["items"],"additionalProperties":false},"agents":{"description":"Order agents. Agents can operate the order, such as canceling the order, modifying the order status, etc.; but cannot receive the funds received by the order.","anyOf":[{"description":"Array of account names, addresses, or mark names. Local marks are searched first for each entry. EXAMPLE: ['alice', '0x2...', 'bob']"},{"type":"object","properties":{"entities":{"minItems":1,"type":"array","items":{"type":"object","properties":{"name_or_address":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"local_mark_first":{"description":"Whether to prioritize local marks, if true, prioritize local marks, otherwise prioritize global marks","type":"boolean"}},"additionalProperties":false,"description":"Account or address lookup object. Use this to specify which account to use for an operation. EXAMPLE: { name_or_address: 'testor2' } - looks up account by name; EXAMPLE: { name_or_address: '0x1234...' } - uses address directly; If name_or_address is empty string '', uses the default local account. name_or_address is REQUIRED — {} resolves to nothing useful and is rejected."}},"check_all_founded":{"default":true,"description":"Whether to check all entities are found. Defaults to true: abort and throw if ANY entity cannot be resolved. Set false only when partial resolution is explicitly intended (only found IDs are returned)","type":"boolean"}},"required":["entities","check_all_founded"],"additionalProperties":false,"description":"Used to batch find account or object IDs by name"}]},"order_required_info":{"description":"Contact object ID or WTS Proof object, RECORDED on the Order as evidence that the order holder delivered the private information the Service declares in customer_required (e.g. phone/email/shipping_address). ACCEPTED FORMS (upwc-cat-261017 T10 live probe): an on-chain object ADDRESS (0x…), a REGISTERED mark name, or the Contact/Proof object itself — a bare account name is NOT an object reference and fails with 'not found'; RECORD-ONLY, NOT ENFORCED: nothing on-chain reads this field — the purchase entry never requires it, and an order supplying none of the declared fields is still created. FLOW: the order holder sends the information to the Service's Contact (um) via end-to-end encrypted Messenger, then passes the Contact object ID or the generated WTS Proof here. To ENFORCE delivery on-chain, mount the pattern.required_info_evidence_gate Guard on the forward that hands over goods or funds, asserting order.required_info is some (presence-only — the recorded address value is never a guard condition; accepting the delivered information is the merchant's confirming forward). ATTESTATION-ONLY: the recorded value is self-attested, has no on-chain readback, and MUST NOT be used as a gate condition. PER-ORDER BINDING: when the listing genuinely promises a per-order credential, use the dedicated controlled bind operation (order_required_info_bind) with a Proof whose about is THIS order and whose creator is the order holder — the chain verifies both at write time and rejects a mismatch without writing anything. The reuse model (one Contact Proof across orders) stays the default for this plain record field; pick per listing promise, not per habit. BOUNDARY: that binding proves the credential AUTHOR only, never its content or any rating — do not mirror it onto review/reward claims; public reviews are Repository rows whose values are enforced guard-side via data-value probes, not through Proof objects.","type":"string"},"transfer":{"description":"Set the new owner of the order. Requires order owner permission to set.","anyOf":[{"description":"Account name, address (0x...), or mark name. When using string format, local marks are searched first. EXAMPLE: 'alice' - searches local marks first, then global; EXAMPLE: '0x2...' (64 hex chars) - uses address directly; EXAMPLE: '' - uses the default local account"},{"type":"object","properties":{"name_or_address":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"local_mark_first":{"description":"Whether to prioritize local marks, if true, prioritize local marks, otherwise prioritize global marks","type":"boolean"}},"additionalProperties":false,"description":"Account or address lookup object. Use this to specify which account to use for an operation. EXAMPLE: { name_or_address: 'testor2' } - looks up account by name; EXAMPLE: { name_or_address: '0x1234...' } - uses address directly; If name_or_address is empty string '', uses the default local account. name_or_address is REQUIRED — {} resolves to nothing useful and is rejected."}]},"namedNewOrder":{"description":"RECOMMENDED: Set a local name for the newly created Order object. Without this, the Order is only referenceable by its on-chain address. Example: {name: 'my_order_v1'} allows subsequent operations to use 'my_order_v1' instead of the address. PLACEMENT: this field MUST be inside data.order_new (it is an OrderNew field) — putting namedNewOrder at the data root fails schema validation with 'Unrecognized key'. MIGRATION TIP: for batch/migration order creation, always auto-generate readable names (e.g. '<source>_<service>_<seq>' like 'my_shop_svc_v1_0001') — unnamed orders (head.name = null) are only address-referenceable, which breaks downstream queries, displays and audits (E-8).","type":"object","properties":{"name":{"description":"The name of the object","type":"string"},"tags":{"description":"The tags of the object","type":"array","items":{"type":"string"}},"onChain":{"description":"CRITICAL: Whether to sync the name to the blockchain. DEFAULT (undefined/false): The name is stored LOCALLY ONLY on your device (PRIVATE). If set to true: The name is published ON-CHAIN and becomes PUBLICLY VISIBLE to everyone. Only set to true for displaying the relationships you are willing to make public on the chain.","type":"boolean"},"replaceExistName":{"description":"FORCE CLAIM: Set to true ONLY when the user explicitly expresses a STRONG INTENTION to forcefully take over an existing name (e.g., 'I must use this name', 'force rename', 'replace the existing one'). WARNING: This will UNBIND the name from its original object and rebind it to the new one, potentially breaking existing references. If not specified or false: the operation will FAIL with an error when the name is already in use (safe default behavior).","type":"boolean"}},"additionalProperties":false},"namedNewAllocation":{"description":"RECOMMENDED: Set a local name for the order's Allocation object. Without this, the Allocation is only referenceable by its address. Example: {name: 'my_allocation_v1'} allows alloc_by_guard to reference 'my_allocation_v1'.","type":"object","properties":{"name":{"description":"The name of the object","type":"string"},"tags":{"description":"The tags of the object","type":"array","items":{"type":"string"}},"onChain":{"description":"CRITICAL: Whether to sync the name to the blockchain. DEFAULT (undefined/false): The name is stored LOCALLY ONLY on your device (PRIVATE). If set to true: The name is published ON-CHAIN and becomes PUBLICLY VISIBLE to everyone. Only set to true for displaying the relationships you are willing to make public on the chain.","type":"boolean"},"replaceExistName":{"description":"FORCE CLAIM: Set to true ONLY when the user explicitly expresses a STRONG INTENTION to forcefully take over an existing name (e.g., 'I must use this name', 'force rename', 'replace the existing one'). WARNING: This will UNBIND the name from its original object and rebind it to the new one, potentially breaking existing references. If not specified or false: the operation will FAIL with an error when the name is already in use (safe default behavior).","type":"boolean"}},"additionalProperties":false},"namedNewProgress":{"description":"RECOMMENDED: Set a local name for the order's Progress object. Without this, the Progress is only referenceable by its address. Example: {name: 'my_progress_v1'} allows progress operations to use 'my_progress_v1'.","type":"object","properties":{"name":{"description":"The name of the object","type":"string"},"tags":{"description":"The tags of the object","type":"array","items":{"type":"string"}},"onChain":{"description":"CRITICAL: Whether to sync the name to the blockchain. DEFAULT (undefined/false): The name is stored LOCALLY ONLY on your device (PRIVATE). If set to true: The name is published ON-CHAIN and becomes PUBLICLY VISIBLE to everyone. Only set to true for displaying the relationships you are willing to make public on the chain.","type":"boolean"},"replaceExistName":{"description":"FORCE CLAIM: Set to true ONLY when the user explicitly expresses a STRONG INTENTION to forcefully take over an existing name (e.g., 'I must use this name', 'force rename', 'replace the existing one'). WARNING: This will UNBIND the name from its original object and rebind it to the new one, potentially breaking existing references. If not specified or false: the operation will FAIL with an error when the name is already in use (safe default behavior).","type":"boolean"}},"additionalProperties":false}},"required":["buy"],"additionalProperties":false},"description":{"type":"string","description":"Description string (max 4000 bcs characters)"},"location":{"description":"The service area and scope as stated by the merchant. IMPORTANT: If the service has a geographic scope, ALWAYS specify this field. Use a complete hierarchical address (e.g. 'US → California → Los Angeles → Koreatown'). If only a partial location is known, EXPAND it to the full standardized form (country → province/state → city → district, worldwide) — when ambiguous, offer 2-4 candidate completions and let the user pick.","type":"string"},"sales":{"description":"Service sales products or services list. ⚠️ WIP (PRODUCT-DETAIL FILE) — HOW TO PROVIDE IT: (1) EASIEST — official free hosting: upload the detail file with the wip_file tool; the default endpoint is https://wip.store.wowok.net (free: 10 files per account, 180-day retention, 12MB per file, rate-limited; files stay until you purge them). Put the returned URL into sale.wip. (2) Your own hosting: any publicly reachable URL (GitHub Pages / IPFS / your own website) — pass customBaseUrl to wip_file when uploading to a non-default endpoint, or host the file yourself and put that URL into sale.wip. For long-lived MAINNET listings prefer your own endpoint so the detail page outlives the free retention window. ⚠️ REACHABILITY RULE: a non-empty sale.wip MUST be a publicly reachable URL. The URL is stored ON-CHAIN and every customer fetches it at order time — a local file path, localhost/loopback URL, or LAN private-IP URL is unreachable by customers on other machines and aborts order_new 100%. Local-network URLs are INTERNAL TEST USE ONLY (env.network = localnet). ⚠️ SCORING: on mainnet, a sale item without a product-detail file is an incomplete listing — it hurts the service's market completeness score. Leave sale.wip empty (\"\") only for quick local testing.","oneOf":[{"type":"object","properties":{"op":{"type":"string","const":"add"},"sales":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the product or service for sale. ⚠️ 64-BYTE BUY LIMIT (F-RQ-01): the chain lists this name up to 256 bytes but validates the BUYER-SENT item name at only 64 bytes at buy time. A name of 65–256 bytes lists fine yet makes the SKU PERMANENTLY unbuyable — every order aborts E_NAME_LENGTH_EXCEEDED (abort 1). Keep SKU names ≤ 64 bytes (UTF-8); renaming cannot fix a dead SKU (the buy path matches items by EXACT name — a new name is a NEW SKU). service_quote.buyable reports this per item."},"price":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Price of the product or service"},"stock":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Current REMAINING stock of the product or service. Each order DECREMENTS it by the ordered quantity (a buy aborts when the remaining stock is lower than the ordered quantity). Writing this field SETS the remaining stock to the given value — it is NOT added to it. To change one product without resending the whole list, use the per-item sales ops on onchain_operations service: stock_add / stock_reduce (deltas), price_add / price_reduce (deltas), sale_suspension (suspend/resume one product)."},"suspension":{"type":"boolean","description":"Whether sale is suspended"},"wip":{"type":"string","description":"WIP file URL. EMPTY string \"\" skips verification (TESTING ONLY). Production MUST use a real HTTP URL pointing to a .wip file generated by the wip_file tool. ⚠️ NETWORK DEPLOYMENT REQUIRED: the URL is stored ON-CHAIN and every customer fetches it when placing an order. A local file path (C:\\..., /path/file.wip), a localhost/loopback URL or a LAN private-IP URL is unreachable by customers on other machines — it passes the merchant-side set-time verification but makes order_new abort 100% for customers. Either deploy the .wip file to a public endpoint (GitHub Pages / IPFS / your own website) and set this to the public URL, or leave it empty (\"\") to skip WIP verification (TESTING ONLY). Example: \"https://cdn.example.com/products/phone_v1.wip\""},"wip_hash":{"default":"","description":"The 'meta.hash' field INSIDE the sale's WIP file (a content hash of the file's JSON payload), committed on-chain by the merchant. NOT the SHA-256 of the .wip file bytes — hashing the downloaded file (shasum -a 256) yields a DIFFERENT value and fails verification; use the hash embedded in the file's meta section (wip_file verify reports it). BUY RULE: if this is NON-EMPTY, the buyer MUST pass this exact value as wip_hash when creating an order (ServiceBuyItem.wip_hash) — NEVER use \"\". Pinning the on-chain hash prevents the merchant from replacing the WIP file (a legitimate update) between the buyer's view and order placement, ensuring 'what you see is what you get'. EMPTY means no hash was committed (TESTING ONLY, no delivery-integrity guarantee). PUBLISH PREFLIGHT (TPL-21, ptrn8-mn-261108): this field is INPUT-optional (defaults to \"\") but PUBLISH-required — once the service's WIP verification face is on, the publish preflight hard-requires a committed wip_hash for every sale and flags an empty one. The optionality is a testing affordance, not a production-legal state.","type":"string"}},"required":["name","price","stock","suspension","wip","wip_hash"],"additionalProperties":false,"description":"Service sale"}}},"required":["op","sales"],"additionalProperties":false,"description":"Add new sales products or services."},{"type":"object","properties":{"op":{"type":"string","const":"set"},"sales":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the product or service for sale. ⚠️ 64-BYTE BUY LIMIT (F-RQ-01): the chain lists this name up to 256 bytes but validates the BUYER-SENT item name at only 64 bytes at buy time. A name of 65–256 bytes lists fine yet makes the SKU PERMANENTLY unbuyable — every order aborts E_NAME_LENGTH_EXCEEDED (abort 1). Keep SKU names ≤ 64 bytes (UTF-8); renaming cannot fix a dead SKU (the buy path matches items by EXACT name — a new name is a NEW SKU). service_quote.buyable reports this per item."},"price":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Price of the product or service"},"stock":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Current REMAINING stock of the product or service. Each order DECREMENTS it by the ordered quantity (a buy aborts when the remaining stock is lower than the ordered quantity). Writing this field SETS the remaining stock to the given value — it is NOT added to it. To change one product without resending the whole list, use the per-item sales ops on onchain_operations service: stock_add / stock_reduce (deltas), price_add / price_reduce (deltas), sale_suspension (suspend/resume one product)."},"suspension":{"type":"boolean","description":"Whether sale is suspended"},"wip":{"type":"string","description":"WIP file URL. EMPTY string \"\" skips verification (TESTING ONLY). Production MUST use a real HTTP URL pointing to a .wip file generated by the wip_file tool. ⚠️ NETWORK DEPLOYMENT REQUIRED: the URL is stored ON-CHAIN and every customer fetches it when placing an order. A local file path (C:\\..., /path/file.wip), a localhost/loopback URL or a LAN private-IP URL is unreachable by customers on other machines — it passes the merchant-side set-time verification but makes order_new abort 100% for customers. Either deploy the .wip file to a public endpoint (GitHub Pages / IPFS / your own website) and set this to the public URL, or leave it empty (\"\") to skip WIP verification (TESTING ONLY). Example: \"https://cdn.example.com/products/phone_v1.wip\""},"wip_hash":{"default":"","description":"The 'meta.hash' field INSIDE the sale's WIP file (a content hash of the file's JSON payload), committed on-chain by the merchant. NOT the SHA-256 of the .wip file bytes — hashing the downloaded file (shasum -a 256) yields a DIFFERENT value and fails verification; use the hash embedded in the file's meta section (wip_file verify reports it). BUY RULE: if this is NON-EMPTY, the buyer MUST pass this exact value as wip_hash when creating an order (ServiceBuyItem.wip_hash) — NEVER use \"\". Pinning the on-chain hash prevents the merchant from replacing the WIP file (a legitimate update) between the buyer's view and order placement, ensuring 'what you see is what you get'. EMPTY means no hash was committed (TESTING ONLY, no delivery-integrity guarantee). PUBLISH PREFLIGHT (TPL-21, ptrn8-mn-261108): this field is INPUT-optional (defaults to \"\") but PUBLISH-required — once the service's WIP verification face is on, the publish preflight hard-requires a committed wip_hash for every sale and flags an empty one. The optionality is a testing affordance, not a production-legal state.","type":"string"}},"required":["name","price","stock","suspension","wip","wip_hash"],"additionalProperties":false,"description":"Service sale"}}},"required":["op","sales"],"additionalProperties":false,"description":"Replaces the ENTIRE sales list: every product NOT included is REMOVED from the Service (its stock and wip binding go with it). To change ONE product, prefer the per-item ops (price_add / price_reduce / stock_add / stock_reduce / sale_suspension) over re-sending the full list; with op:set you MUST resend ALL unchanged products too. Removal is immediate and cannot be undone."},{"type":"object","properties":{"op":{"type":"string","const":"remove"},"sales_name":{"type":"array","items":{"type":"string","description":"Sales name"}}},"required":["op","sales_name"],"additionalProperties":false,"description":"Remove existing sales products or services."},{"type":"object","properties":{"op":{"type":"string","const":"clear"}},"required":["op"],"additionalProperties":false,"description":"Clear all sales products or services."},{"type":"object","properties":{"op":{"type":"string","const":"price_add"},"sale_name":{"type":"string","description":"Name of the product to update"},"value":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Price INCREASE delta in the Service token's smallest units (e.g. 100000000 = +0.1 WOW). Added to the current price (on-chain saturating add). NOT the new absolute price."}},"required":["op","sale_name","value"],"additionalProperties":false,"description":"Raise one product's price by a delta. Only the named product is touched; an unknown sale_name aborts on chain (code 32) — the MCP pre-gate resolves the name against the live sales list and refuses the call before send, and the response carries a {field, before, after} read-back delta."},{"type":"object","properties":{"op":{"type":"string","const":"price_reduce"},"sale_name":{"type":"string","description":"Name of the product to update"},"value":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Price DECREASE delta in the Service token's smallest units (e.g. 100000000 = -0.1 WOW). Must not exceed the current price: an oversized reduce ABORTS on chain (code 41) and does NOT clamp. NOT the new absolute price."}},"required":["op","sale_name","value"],"additionalProperties":false,"description":"Lower one product's price by a delta. Only the named product is touched; an unknown sale_name aborts on chain (code 32) — the MCP pre-gate refuses unknown names before send; an oversized delta is refused by the chain (code 41) instead of clamping; the response carries a {field, before, after} read-back delta."},{"type":"object","properties":{"op":{"type":"string","const":"stock_add"},"sale_name":{"type":"string","description":"Name of the product to update"},"value":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Stock INCREASE delta (a unit COUNT, not money), e.g. 50 = +50 units."}},"required":["op","sale_name","value"],"additionalProperties":false,"description":"Restock one product by a delta. Only the named product is touched; an unknown sale_name aborts on chain (code 32) — the MCP pre-gate refuses unknown names before send; the response carries a {field, before, after} read-back delta."},{"type":"object","properties":{"op":{"type":"string","const":"stock_reduce"},"sale_name":{"type":"string","description":"Name of the product to update"},"value":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Stock DECREASE delta (a unit COUNT, not money), e.g. 10 = -10 units. If the delta exceeds current stock, the stock clamps to 0 (product becomes unsellable)."}},"required":["op","sale_name","value"],"additionalProperties":false,"description":"Reduce one product's stock by a delta (e.g. write-off damaged units). Only the named product is touched; an unknown sale_name aborts on chain (code 32) — the MCP pre-gate refuses unknown names before send."},{"type":"object","properties":{"op":{"type":"string","const":"sale_suspension"},"sale_name":{"type":"string","description":"Name of the product to suspend or resume"},"suspension":{"type":"boolean","description":"true = suspend the product (buy/quote abort with E_SALE_SUSPENDED); false = resume selling."}},"required":["op","sale_name","suspension"],"additionalProperties":false,"description":"Suspend or resume ONE product without removing it (keeps price/stock/WIP binding). The retail-style 'out of stock / listing inactive' state. Only the named product is touched; an unknown sale_name aborts on chain (code 32) — the MCP pre-gate refuses unknown names before send; the response carries a {field, before, after} read-back delta."},{"type":"object","properties":{"op":{"type":"string","const":"wip_set"},"sale_name":{"type":"string","description":"Name of the product whose WIP file is (re)bound"},"wip":{"type":"string","description":"New WIP file URL for the product. Same network-deployment rule as the add/set wip field: production MUST use a public HTTP URL to a .wip file (a local path, localhost/loopback or LAN URL passes the merchant-side set-time verification but aborts order_new for every customer). \"\" clears WIP verification (TESTING ONLY — the product then has no pin)."},"wip_hash":{"description":"Expected meta.hash embedded in the new WIP file — when provided it is VERIFIED against the file before send (mismatch aborts pre-send); the on-chain pin is always derived from the file's own meta.hash. Pass it whenever the value is known: after the rebind, buyers pinning the OLD hash abort at quote (E_WIP_HASH_NOT_MATCH) until they re-copy the NEW hash.","type":"string"}},"required":["op","sale_name","wip"],"additionalProperties":false,"description":"Rebind ONE product's WIP file (and pin) without touching its price, stock or suspension — fields not supplied here keep the live on-chain values. An unknown sale_name aborts on chain (code 32) — the MCP pre-gate resolves the name against the live sales list and refuses the call before send. Executed as read-merge-rewrite: the handler reads the live sales list, changes only the named product's wip/wip_hash, and replays the full table as an op:set — a concurrent catalog edit between read and rewrite would be overwritten, so run this when no other catalog change is in flight. Announce the new pin hash to holders of the old one: their orders abort E_WIP_HASH_NOT_MATCH after the rebind until they re-copy it."}]},"restock":{"description":"Refund restocking (permission 305 SERVICE_SALES). op:'flag' opts ONE live product into restock-on-refund; op:'order' puts the units a REFUNDED order purchased back on shelf. The order path is all-or-nothing: every purchased line must be flagged and still live before any unit moves (otherwise the chain aborts 46/32), so half a restock is impossible. The order path is once-per-order (replay aborts 49) and bound to THIS service (foreign order aborts 26). Do NOT fake a restock with stock_add when the order carries several lines — use op:'order' so quantities come from the order itself. DISCLOSURE: restock reopens sales — if the machine (or its template) has no refund-terminal gate, orders inside their refund window may lose refund eligibility or create fund-accounting ambiguity once restocked units are resold; confirm the machine's refund rail remains reachable after restocking.","oneOf":[{"type":"object","properties":{"op":{"type":"string","const":"flag"},"sale_name":{"type":"string","description":"Name of the LIVE product whose restock-on-refund flag is set"},"flagged":{"type":"boolean","description":"true = refunded orders of this SKU put their purchased units back on shelf; false = opt out."}},"required":["op","sale_name","flagged"],"additionalProperties":false,"description":"Opt ONE live product in/out of restock-on-refund. An unknown sale_name aborts on chain (code 32); delisting the product is the kill switch. Without the flag, the order-level restock op refuses that line (code 46). Flagging a SKU does not itself touch stock — the order-level op below does the restoration, and it is once-per-order per order (code 49) and bound to orders of THIS service (foreign orders abort code 26)."},{"type":"object","properties":{"op":{"type":"string","const":"order"},"order":{"type":"string","minLength":1,"description":"Address or local name of the REFUNDED order whose purchased units go back on shelf. Must be an order of THIS service (a foreign order aborts code 26), and each order can be restocked exactly once — a second call for the same order aborts code 49 (no retry succeeds; the restoration is already complete)."}},"required":["op","order"],"additionalProperties":false,"description":"Put back the units one refunded order purchased, read from the order's own purchase lines (the caller cannot add extra units). Two-pass all-or-nothing on chain: every line must be restock-flagged and still live before the first unit moves (unflagged → code 46, delisted → code 32), so a partial restock is impossible. Once-per-order (code 49 on replay) and ownership-bound (a foreign order aborts code 26); the applied state lives in a RestockStamp dynamic field on the service (no public query primitive) — the MCP pre-gate reads that stamp before send and refuses a replay (restock_order_already_applied) so no gas is burned. Emits one stock-restocked event per line."}]},"repositories":{"description":"Service Repository object list.","anyOf":[{"type":"object","properties":{"op":{"anyOf":[{"type":"string","const":"add"},{"type":"string","const":"set"}]},"objects":{"type":"array","items":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"description":"List of object IDs or names to add or set"}},"required":["op","objects"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"remove"},"objects":{"type":"array","items":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"description":"List of object IDs or names to remove"}},"required":["op","objects"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"clear"}},"required":["op"],"additionalProperties":false}]},"rewards":{"description":"Service Reward object list. May share the Service's Permission (no conflict check — intentional: rewards are the provider's own incentive tool; only Arbitration requires a different Permission for neutrality). ⚠️ OP SEMANTICS (SDK translation, etm-mn-261013 E-06): op:'set' executes as clear + add — and reward clear is TIME-LOCKED after publish (E_LOCKED_TIME_NOT_ENOUGH = abort 24: requires pause + setting_lock_duration elapsed, default 30 days). BEFORE publish op:'set' is fine; AFTER publish attach rewards with op:'add' ONLY (add has no lock).","anyOf":[{"type":"object","properties":{"op":{"anyOf":[{"type":"string","const":"add"},{"type":"string","const":"set"}]},"objects":{"type":"array","items":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"description":"List of object IDs or names to add or set"}},"required":["op","objects"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"remove"},"objects":{"type":"array","items":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"description":"List of object IDs or names to remove"}},"required":["op","objects"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"clear"}},"required":["op"],"additionalProperties":false}]},"arbitrations":{"description":"Service Arbitration object list. FORMAT: same as repositories — use the `objects` field name inside the operation data. Example: {arbitrations: {op: 'add', objects: [{name: 'my_arb_1'}]}}. Each item is a NameOrAddress (object ID or local mark name). ⚠️ OP SEMANTICS (SDK translation, etm-mn-261013 E-06 + crs P3-1): op:'add' appends and is the ONLY unlocked path after publish (add has no publish assert on-chain). op:'set' executes as clear + add and REPLACES the entire allowlist (pass EVERY Arbitration that must remain bound) — clear is TIME-LOCKED after publish (E_LOCKED_TIME_NOT_ENOUGH = abort 24: requires pause + setting_lock_duration elapsed, default 30 days), so use op:'set' BEFORE publish only. (The 2026-10-08 op:'add' disable was lifted: the unparseable-success-response SDK bug it responded to is fixed — safeTextJson + big-int conversion.) ⚠️ PERMISSION RULE (contract-enforced): every Arbitration bound here MUST use a Permission object DIFFERENT from THIS Service's permission — binding an Arbitration that shares the Service's Permission aborts with E_ARBITRATION_PERMISSION_CONFLICT (error 33). Create a dedicated Permission for each Arbitration BEFORE binding. DESIGN RATIONALE (confirmed intentional): dispute resolution requires NEUTRALITY — an Arbitration controlled by the same Permission admins as the Service it judges would be a conflict of interest. ONLY Arbitration has this check: Reward and Treasury objects MAY share the Service's Permission (they are the provider's own tools).","anyOf":[{"type":"object","properties":{"op":{"anyOf":[{"type":"string","const":"add"},{"type":"string","const":"set"}]},"objects":{"type":"array","items":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"description":"List of object IDs or names to add or set"}},"required":["op","objects"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"remove"},"objects":{"type":"array","items":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"description":"List of object IDs or names to remove"}},"required":["op","objects"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"clear"}},"required":["op"],"additionalProperties":false}]},"machine":{"description":"Service Machine object ID or name. The Machine object must be in published state.","anyOf":[{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},{"type":"null"}]},"discount":{"description":"Issue discount (mint coupons bound to this Service). ⚠️ ISSUANCE PRESCRIPTION (KB-02): issuing = MINT then TRANSFER. This field mints the coupon objects under THIS account — its `recipient` field delivers them directly when you know the recipients; for pre-minted campaign coupons held for later handout, the handout itself is discount_send (mint first, transfer to the recipient at distribution time). COUPON SEMANTICS to disclose: HOLDING IS THE CREDENTIAL — the coupon belongs to whoever HOLDS it, only the holder's own signature can spend it, and sharing the coupon's object ID confers nothing; ONE COUPON, ONE BURN — every coupon is single-use and is destroyed on first spend; REFUNDS SETTLE THE POST-COUPON AMOUNT — refund rails pay back the escrowed discounted total only, a cancelled order never restores the coupon's face value. A coupon held by another address cannot be applied to a buyer's order — the owner must discount_send it to the buyer first. NO AUTO-REISSUE (sso7-mn F-37, ruling 2026-11-05): a burned coupon is never restored and never re-minted automatically — making the buyer whole on the coupon value is the merchant's OFF-CHAIN duty (issue a fresh coupon yourself).","type":"object","properties":{"name":{"type":"string","description":"Discount name. MUST be ≤ 64 bytes (UTF-8): the chain applies the same 64-byte name cap to discount rows as to SKU names, at listing time — a longer name aborts E_NAME_LENGTH_EXCEEDED (abort 1) at creation (F-RQ-01)."},"discount_type":{"anyOf":[{"type":"integer","minimum":0,"maximum":1},{}],"description":"Discount type — 0=RATES (proportional off, per-10000: e.g. 1000 means 10% off), 1=FIXED (fixed deduction of the product amount, base units: e.g. 100 means 100 deducted). Accepts the number (0/1) or the string ('RATES'/'FIXED'); the value is always stored as the number on-chain."},"discount_value":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Discount magnitude, meaning depends on discount_type. RATES (0): per-10000 off rate — 10 = 0.1% off, 1000 = 10% off, 10000 = 100% off; values above 10000 are rejected. FIXED (1): fixed deduction from the order total in the Service token's smallest units (e.g. 1000000000 = 1 WOW at 9 decimals)."},"benchmark":{"description":"Minimum order total (in the Service token's smallest units) for the discount to apply — when set, the discount is applied only if the PRE-discount order total is GREATER THAN OR EQUAL TO this value. ✅ OMITTING this field (or passing null, or 0) means NO threshold — the discount applies UNCONDITIONALLY, and that is the common, correct case. This is the on-chain behaviour: benchmark_met = if (option::is_some(&discount.benchmark)) { total >= benchmark } else { true } (inside the on-chain discount-application step). ⚠️ SHARP EDGE when you DO set a threshold: an order below the threshold CANNOT use the coupon — attaching it at buy aborts (error 38: the transaction rolls back, nothing is paid, and the coupon is preserved); dropping it means the buyer pays FULL price and keeps the coupon for a future order. Keep thresholds low enough that your typical basket clears them. If the order total is below the discounted price the payment aborts — pay the list price; the excess is returned as a new Coin.","anyOf":[{"type":"number"},{"type":"string"}]},"time_ms_start":{"description":"Discount start time (milliseconds). ⚠️ A FUTURE start mints a coupon that is listed as usable but CANNOT be spent until the window opens (every spend aborts E_DISCOUNT_TIME_INVALID / buy code 35). Legitimate for scheduled campaigns — the mint carries a loud warning; do not distribute the coupon to recipients before the window opens.","type":"number"},"allow_zero_total":{"description":"NO EFFECT — DO NOT SET (BSX-F07: the former escape hatch is removed). This flag has no on-chain field (the on-chain Discount struct never carried it; a coupon minted with it is byte-identical to one without), and it NO LONGER downgrades the MCP issuance block for a coupon that zeroes the cheapest SKU — the block is unconditional: a zeroing coupon can only dead-end at the buyer's checkout (order_new_zero_total_dead_order client-side, abort 42 on-chain). For a deliberate free tier: price the SKU at 1 smallest unit (never 0 — a zero-priced sale is permanently unbuyable) or deliver it outside the sales rails (e.g. a Demand with Signature fulfillment). Omit this field.","type":"boolean"},"time_ms_end":{"type":"number","description":"Discount end time (milliseconds)"},"count":{"type":"number","description":"Number of SEPARATE Discount (coupon) objects minted — total delivered = count × number of recipients. Each coupon object is SINGLE-USE (consumed on first use). This is NOT a per-coupon reuse count: count:2 creates 2 independent one-time coupons, not 1 coupon usable twice."},"recipient":{"anyOf":[{"description":"Array of account names, addresses, or mark names. Local marks are searched first for each entry. EXAMPLE: ['alice', '0x2...', 'bob']"},{"type":"object","properties":{"entities":{"minItems":1,"type":"array","items":{"type":"object","properties":{"name_or_address":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"local_mark_first":{"description":"Whether to prioritize local marks, if true, prioritize local marks, otherwise prioritize global marks","type":"boolean"}},"additionalProperties":false,"description":"Account or address lookup object. Use this to specify which account to use for an operation. EXAMPLE: { name_or_address: 'testor2' } - looks up account by name; EXAMPLE: { name_or_address: '0x1234...' } - uses address directly; If name_or_address is empty string '', uses the default local account. name_or_address is REQUIRED — {} resolves to nothing useful and is rejected."}},"check_all_founded":{"default":true,"description":"Whether to check all entities are found. Defaults to true: abort and throw if ANY entity cannot be resolved. Set false only when partial resolution is explicitly intended (only found IDs are returned)","type":"boolean"}},"required":["entities","check_all_founded"],"additionalProperties":false,"description":"Used to batch find account or object IDs by name"}],"description":"Discount recipient. OBJECT FORM REQUIRED (T9 az3-mn-261013): a bare string is REJECTED here — pass {entities: [{name_or_address: '<account_name_or_0x_address>'}]} (example: {entities: [{name_or_address: 'buyer1'}]}). Total coupons delivered = count × number of recipients."},"transferable":{"type":"boolean","description":"Whether the discount object recipient can transfer the discount object"}},"required":["name","discount_type","discount_value","time_ms_end","count","recipient","transferable"],"additionalProperties":false},"discount_destroy":{"description":"Destroy existing discount object ID list.","type":"array","items":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."}},"discount_send":{"description":"Transfer ALREADY-MINTED coupons you own to another address, instead of destroying them (discount_destroy) or minting new ones (discount). This is a pure ownership handover: the on-chain entry points are public funs with NO Service permission requirement — the only preconditions are that the sender owns each coupon and each was minted transferable:true. Typical use: hand out pre-minted campaign coupons, or move coupons between your own accounts. KB-02 COUPON SEMANTICS: this transfer is the second half of coupon ISSUANCE (mint via `discount`, then transfer here at distribution time). HOLDING IS THE CREDENTIAL: the coupon belongs to whoever HOLDS it — only the holder's own signature can spend it, and sharing the object ID confers nothing. ONE COUPON, ONE BURN: each coupon stays single-use and is destroyed on first spend — transfer does not reset that. REFUNDS SETTLE THE POST-COUPON AMOUNT: refund rails pay the escrowed discounted total only, never the coupon's face value. Until you transfer a gifted coupon, the recipient CANNOT use it on their own orders — a coupon held by another address cannot be applied to their buy.","type":"object","properties":{"discounts":{"minItems":1,"type":"array","items":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"description":"Coupon object IDs or local names to transfer. You MUST own these Discount objects. Each coupon must have been minted with transferable:true — otherwise the chain aborts with E_DISCOUNT_NOT_TRANSFERABLE (semantic code service:10). Coupons stay single-use; the transfer does not change that. There is NO batch entry on-chain — each coupon is delivered by its own singleton call (fanned out automatically); prefer ONE coupon per transaction for coupon migrations (SDK cap MAX_DISCOUNT_COUNT_ONCE still applies)."},"recipient":{"anyOf":[{"description":"Account name, address (0x...), or mark name. When using string format, local marks are searched first. EXAMPLE: 'alice' - searches local marks first, then global; EXAMPLE: '0x2...' (64 hex chars) - uses address directly; EXAMPLE: '' - uses the default local account"},{"type":"object","properties":{"name_or_address":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"local_mark_first":{"description":"Whether to prioritize local marks, if true, prioritize local marks, otherwise prioritize global marks","type":"boolean"}},"additionalProperties":false,"description":"Account or address lookup object. Use this to specify which account to use for an operation. EXAMPLE: { name_or_address: 'testor2' } - looks up account by name; EXAMPLE: { name_or_address: '0x1234...' } - uses address directly; If name_or_address is empty string '', uses the default local account. name_or_address is REQUIRED — {} resolves to nothing useful and is rejected."}],"description":"Destination address (or account/local mark resolvable to one). ALL listed coupons are moved to this single address in one call."}},"required":["discounts","recipient"],"additionalProperties":false},"customer_required":{"description":"Customer required information labels. Such as phone, email, shipping_address, etc. DECLARATIVE ONLY: nothing on-chain or in the SDK reads this field — it is a pure listing declaration of what the customer will be asked to provide. It is NOT enforced against order_new and NOT linked to any delivery path by the SDK. OPERATIONAL PAIRING (convention, not enforcement): deliver the actual private information via end-to-end encrypted Messenger to the Service's Contact bound as `um` — bind `um` when you use customer_required, or the customer has no encrypted channel to send it through. To ENFORCE delivery on-chain, mount the pattern.required_info_evidence_gate Guard on the goods/funds forward (see order_new.order_required_info).","type":"array","items":{"type":"string","minLength":1}},"order_allocators":{"description":"Order fund allocator. Max 100 allocators (MAX_ALLOCATOR_COUNT). ✅ EACH allocator has a guard, and EVERY allocator whose guard address matches the supplied guard RUNS — they are NOT mutually exclusive and NOT first-match-wins. One guard may legitimately authorize several distribution rules (different fix / rate / cap); each contributes its own Payment and consumes its own once-slot (keyed by the allocator index). Allocators are evaluated in vector order against the SHRINKING pool, so a later allocator only sees the balance left by the earlier ones — which is exactly how a waterfall (e.g. Amount fee + net Rate split) is built. On-chain truth: the allocation module runs a while loop over all allocators, firing those whose guard address matches the submitted one. ⚠️ If you WANT mutual exclusion you must express it inside the Guard itself (make the conditions logically exclusive). Set to null to clear. ⚠️ IMMUTABLE after publish except APPEND: order_allocators full replacement can ONLY be done BEFORE publish=true (on-chain check rejects after publish — E_ALREADY_PUBLISHED). After publish, the ONLY mutation is order_allocators_append (prefix-frozen extension — see that field). There is NO pause+lock exception for order_allocators (unlike arbitrations/rewards which have time-lock removal). PRE-PUBLISH CHECKLIST: verify all guard names resolve, all sharing amounts are correct, threshold is set, and recipient types (Entity/Signer/GuardIdentifier) are intended before calling publish=true. GuardIdentifier sharing mode: {who: {GuardIdentifier: <u8>}, sharing: <rate>, mode: 'Rate'} — resolves recipient from the Guard table submission at allocation time. BINDING SEMANTICS (contract-enforced, abort code 15): in a Service-created Allocation EVERY GuardIdentifier submission must equal the PAYING order — it is always 'the order', never a third party whose address is supplied at trigger time; use {who:{Entity:...}} for named parties. Canonical order pattern: the recipient slot is the single submitted Order (constrained by the Guard — service binding, qualifying node, signer==order.owner); funds land at that order object and are receivable only by its owner (object receipt = owner receipt). Safety is determined by constraint sufficiency — run the recipient constraint audit before publish. Fixed recipients should use {who:{Entity:...}}; unbound Signer recipients are a CRITICAL theft risk. MULTI-CALL ALLOCATION: an allocation can be executed MULTIPLE times (no consumed flag in contract). Use Amount mode (not Surplus) for recurring allocations — an uncapped Surplus sweeps the entire remaining balance on first run. For monthly payment scenarios, create multiple Allocators with time-based Guards + Amount mode sharing items.","anyOf":[{"type":"object","properties":{"description":{"type":"string","description":"Description of fund allocator list"},"threshold":{"default":0,"description":"Minimum balance required for allocation to fire. When the Allocation object's balance < threshold, allocation aborts with EINSUFFICIENT_BALANCE=7. Also: when an Allocator has only Amount items (no Rate, no Surplus), the sum of Amount items must be >= threshold (EAMOUNT_BELOW_THRESHOLD=12). Set to 0 (default) to allow any balance.","anyOf":[{"type":"number"},{"type":"string"}]},"allocators":{"type":"array","items":{"type":"object","properties":{"guard":{"type":"string","description":"Guard object ID or name. A distribution call submits ONE guard; EVERY Allocator bound to that guard fires — in vector order, each against the balance left by the previous (the distribution loop matches the submitted guard address, it does NOT evaluate guards competitively). NOT first-match-wins: Allocators with different guards are alternative distribution paths selected by the caller's choice of guard (e.g., a refund guard vs a damage guard), and mutual exclusion must be expressed inside the Guard conditions themselves, never assumed from ordering."},"sharing":{"type":"array","items":{"type":"object","properties":{"who":{"anyOf":[{"type":"object","properties":{"GuardIdentifier":{"type":"integer","minimum":0,"maximum":255,"description":"Identifier (0-255) for data lookup in Guard table. Slot consensus (enforced on-chain at guard table construction): 0-220 = user slots (free for business guards); 221-253 = PROTOCOL-RESERVED (rejected on-chain — reserved so future protocol features get fixed slots without colliding with published guards); 255 = ONCE replay-protection slot on Allocation (byte-keyed, the submitted bytes are the once-key — use for per-period keys like period-<N>); 254 = ONCE-FOR-OBJECT slot on Allocation (chain-derived key = bcs(the Allocation's payment_info.for_object); the submitted bytes are ignored and the submission only arms the slot — use for one-shot per-order rails whose payee is NOT the order itself, such as settlement releases and incentive/bounty claims). NEVER arm 254 on a refund rail: a refund pays the submitted Order through user slot 0, and a refund leg re-entered in a later renewal period would abort E_ONCE_TRIGGERED (16) forever — refund once-ness comes from the terminal-node topology, never from a once slot. SLOT 0 SEMANTICS: slot 0 carries the transacted Order address by convention. As a submission slot it is legal on order/allocation/machine rails (the order exists when those verify), but FORBIDDEN on a Service buy_guard — the order does not exist when the buy-time passport is verified, so the mount is refused (service abort 43)."}},"required":["GuardIdentifier"],"additionalProperties":false,"description":"Guard verified recipient ID. Get recipient ID from specified data index in Guard table. The ID must be of address type. ALLOCATION rails only — the REWARD claim rail requires recipient == the transaction sender (abort 14), so a GuardIdentifier recipient on reward.guard_add resolves to the submitted Order and is structurally unpayable; the tool gate rejects it (crs-mn-261015 F-12)."},{"type":"object","properties":{"Entity":{"anyOf":[{"description":"Account name, address (0x...), or mark name. When using string format, local marks are searched first. EXAMPLE: 'alice' - searches local marks first, then global; EXAMPLE: '0x2...' (64 hex chars) - uses address directly; EXAMPLE: '' - uses the default local account"},{"type":"object","properties":{"name_or_address":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"local_mark_first":{"description":"Whether to prioritize local marks, if true, prioritize local marks, otherwise prioritize global marks","type":"boolean"}},"additionalProperties":false,"description":"Account or address lookup object. Use this to specify which account to use for an operation. EXAMPLE: { name_or_address: 'testor2' } - looks up account by name; EXAMPLE: { name_or_address: '0x1234...' } - uses address directly; If name_or_address is empty string '', uses the default local account. name_or_address is REQUIRED — {} resolves to nothing useful and is rejected."}],"description":"Account or address lookup. Can be a simple string (recommended for AI) or full object with explicit local_mark_first control. String form auto-converts to { name_or_address: <string>, local_mark_first: true }."}},"required":["Entity"],"additionalProperties":false,"description":"Static address resolved via LocalMark. Format: {Entity: 'mark_name'} (string shorthand) or {Entity: {name_or_address: 'mark_name'}} (full object).F-RQ-11 (rq2 promotion): string shorthand accepted — the FIX-005 transform resolves local marks first."},{"type":"object","properties":{"Signer":{"type":"string","const":"signer"}},"required":["Signer"],"additionalProperties":false,"description":"Current transaction signer (tx_context::sender) at the time of the alloc() call. For refunds, the Order owner must call alloc_by_guard themselves to receive the funds. On the REWARD claim rail this is the CANONICAL recipient (the claim entry requires recipient == the tx sender)."}],"description":"Recipient of this allocation. Three forms — each resolves the address at a DIFFERENT time:\n• { GuardIdentifier: u8 } — DYNAMIC address resolved from Passport at alloc() time (from the passport's submission record). Use 0 for Order owner in Service-integrated mode (Customer who created the Order). The identifier must match a Guard table entry with b_submission=true. If Passport has no matching submission, contract aborts with E_VERIFY_FAILED. Use when the recipient address is not known at config time and must be supplied via Guard submission data.\n• { Entity: { name_or_address: '...' } } — FIXED address resolved via LocalMark at SDK build time (passed to contract as a literal address). Use for known recipients (e.g., 'turo_host', or a Treasury object address). Use when the recipient is a stable, known address (e.g., operator receives rent, platform fee to treasury).\n• 'Signer' — the transaction sender at the time of the alloc() call (tx_context::sender). RESOLVED AT EXECUTION TIME, not at config time. For refunds: the customer (Order owner) must call alloc_by_guard THEMSELVES so that tx_context::sender resolves to THEIR address — if the operator calls alloc_by_guard, the operator becomes the recipient (Signer = operator), NOT the customer. Use when the recipient is whoever submits the allocation transaction (e.g., customer receives refund)."},"sharing":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Allocation value. SEMANTICS DEPEND ON `mode`:\n• mode='Amount': absolute amount in smallest unit (e.g., '750000000' for 0.75 WOW, '250000000' for 0.25 WOW). Allocated first; sum of Amount items cached as `fix`.\n• mode='Rate' (NET): basis-points rate off the post-fix base (balance - fix, or max - fix), 10000 = 100% (e.g., '7500' for 75%, '2500' for 25%). When no Surplus in same Allocator, sum MUST == 10000; when Surplus present, sum MUST <= 10000.\n• mode='RateGross': basis-points rate off the FULL pool (balance) or the `max` cap — the fixed Amount total is NOT subtracted, 10000 = 100%. sum MUST <= 10000 (and, with `max` set, fix×10000 + sum×max <= max×10000). Cannot be mixed with mode='Rate' in the same Allocator while a fixed Amount total is present.\n• mode='Surplus': IGNORED (contract forces to 0). Set to '0' for clarity. Receives remaining balance after Amount + Rate/RateGross allocations.\n• mode='Formula': basis-points COEFFICIENT (MUST be <= 10000) of a RUNTIME repository scalar — payout = clamp(coefficient × scalar / 10000, 0, headroom). Does NOT join any rate sum (its base is the queried scalar, not the pool) and skips the Amount>=threshold declaration check. Bind the slot's data source via allocation formula_spec_set, else the scalar reads 0.\n⚠️ T1 LOSSY POINT (B-2): Amount/Rate/RateGross/Surplus values are PRE-CONFIGURED and STATIC — a free-form continuous amount still cannot be expressed with them. Formula mode covers the bounded case: a coefficient (<= 10000 bps) of an attested repository aggregate (record count / value sum) — use it for runtime-proportional payouts; for anything richer, model (a) a fixed-tier Allocator list guarded by distinct Guards, or (b) an Amount with a `max` cap — both are finite configurations."},"mode":{"anyOf":[{"type":"string","enum":["Amount","Rate","Surplus","RateGross","Formula"]},{}],"description":"Allocation mode — determines how the `sharing` field is interpreted. Modes can be used individually OR combined within a single Allocator; when combined, allocation order is strictly: Amount first, then Rate/RateGross, then Formula scalar legs, then Surplus. Understanding these modes allows modeling almost any fund distribution pattern.\n• Amount (0): `sharing` is a FIXED amount in smallest unit (e.g., '750000000' = 0.75 WOW). Allocated FIRST; sum of all Amount items is cached as `fix` by the contract. Validation: when no Rate and no Surplus items exist, sum of Amount items must be >= allocators.threshold (EAMOUNT_BELOW_THRESHOLD=12); when `max` is set, sum of Amount items must be <= max (EAMOUNT_EXCEEDS_MAX=13).\n• Rate (1): `sharing` is a NET basis-points rate (10000 = 100%). Allocated AFTER Amount; formula: allocated = (sharing × total_rates) / 10000, where total_rates = balance - fix (or max - fix if `max` is set) — the cached fixed Amount total IS subtracted. Validation: when no Surplus items exist, sum of all Rate items must be EXACTLY 10000 (ERATE_NOT_10000=4); when Surplus items exist, sum of all Rate items must be <= 10000 (ERATE_EXCEEDS_10000=6).\n• RateGross (3): `sharing` is a GROSS basis-points rate (10000 = 100%). Allocated AFTER Amount; formula: allocated = (sharing × total_rates) / 10000, where total_rates = balance (the full pool) or the `max` cap when set — the fixed Amount total is NOT subtracted, so fixed Amount entries and percentage-of-total rates coexist exactly. Validation: sum of all RateGross items must be <= 10000 (ERATE_EXCEEDS_10000=6); when `max` is set, fix×10000 + sum(rate)×max <= max×10000 must hold (6); with no `max` and a fixed total > 0, sum of RateGross items must be < 10000 (6). RateGross cannot be mixed with NET Rate entries in the same Allocator while a fixed Amount total is present (EMIXED_RATE_BASES=17).\n• Surplus (2): `sharing` is IGNORED (contract forces it to 0). Allocated LAST; receives the remaining balance after Amount + Rate allocations. Validation: MAX ONE Surplus item per Allocator (EMULTIPLE_SURPLUS=5). When Surplus exists, Rate sum constraint relaxes from == 10000 to <= 10000.\n• Formula (4): `sharing` is a basis-points COEFFICIENT (<= 10000, ERATE_EXCEEDS_10000=6) applied to a RUNTIME scalar queried from a Repository at alloc() time — amount = clamp(coefficient × scalar / 10000, 0, headroom). The scalar comes from the slot's bound FormulaSpec (record-count or value-sum over a repository policy key, predicate wire identical to the 1173/1174 count/sum-where guard queries; explicit candidate ids, max 100, empty list = zero hits = scalar 0). A Formula leg does NOT join total_rate (its base is the queried scalar, not the pool) and its presence SKIPS the Amount-sum >= threshold declaration check (payout is runtime-defined). Requires a spec bound via allocation formula_spec_set — an unbound Formula slot prices its scalar as 0. binding a malformed spec aborts (EFORMULA_SPEC_INVALID=24).\nALLOCATION ORDER (strict): Amount items (fixed, cached as fix) → Rate/RateGross items → Formula scalar legs → Surplus item (remaining).\nRECOMMENDATION: Use Amount mode for known fixed amounts (clearer, no sum constraint). Use Rate mode for proportional splits off the post-fix remainder (requires sum == 10000 unless Surplus present). Use RateGross mode for a percentage of the FULL pool/`max` that must coexist with fixed Amount entries. Use Surplus to capture remainder (e.g., platform fee + host gets rest). Use Formula for payouts proportional to an attested on-chain aggregate (e.g. N records served, total value logged in a Repository) that cannot be known at configuration time. Accepts string ('Amount'/'Rate'/'Surplus'/'RateGross'/'Formula', recommended) or number (0/1/2/3/4)."}},"required":["who","sharing","mode"],"additionalProperties":false,"description":"Fund allocation item — one recipient's share of the Allocation balance. The `sharing` value's meaning depends on `mode` (see AllocationModeSchema). Multiple items in the same Allocator are evaluated together: Amount items first, Rate/RateGross items second, Surplus last."},"description":"Fund allocation item list. Each item specifies a recipient (who), a value (sharing), and a mode. Items can mix modes (Amount + Rate/RateGross + Formula + Surplus) within the same Allocator. RECIPIENT SEMANTICS: the Guard constrains what each submission slot may be; a recipient's safety follows from the sufficiency of those constraints (run the recipient constraint audit). Canonical order pattern: recipient = the single submitted Order — funds land at that object and are receivable only by its owner. ALLOCATION ORDER: Amount items first (cached as fix) → Rate items (proportional to balance - fix; RateGross proportional to the full pool) → Formula legs (coefficient of the runtime repository scalar) → Surplus item (remaining). CONSTRAINTS: max ONE Surplus item per Allocator; NET Rate sum must == 10000 (no Surplus) or <= 10000 (with Surplus); RateGross sum must <= 10000 (never mixed with NET Rate while a fixed total is present); each Formula leg's coefficient must <= 10000 but does NOT count into any rate sum; Amount sum must >= threshold (no Rate, no RateGross and no Formula present — a Formula leg skips this floor since its payout is runtime-defined) and <= max (if max set)."},"fix":{"description":"OUTPUT-ONLY (query result). Cached sum of all Amount-mode `sharing` values in this Allocator. Computed by the contract when the allocator is added — DO NOT set this field at creation. Used internally to compute `total_rates = balance - fix` for NET Rate allocation (RateGross ignores fix and uses the full pool/`max`).","anyOf":[{"type":"number"},{"type":"string"}]},"max":{"description":"Maximum allocation cap (OPTIONAL — omit the field or set to null to disable the cap; do NOT set to 0 as that means a cap of zero). Passed through to the contract as Option<u64> when the allocator is added: when null/omitted the contract treats it as `none` (no cap); when set, the contract enforces it. Has THREE effects when set:\n1. Construction: sum of Amount items must be <= max (EAMOUNT_EXCEEDS_MAX=13)\n2. Rate execution: NET Rate total_rates = max - fix; RateGross total_rates = max (fix NOT subtracted)\n3. Surplus execution: surplus_amount = max - alloced_amount (instead of balance - alloced_amount)\nUse when you want to cap total allocation regardless of Order balance (e.g., cap payout to declared amount). SDK pre-validates Amount sum <= max at build time to give actionable error messages before on-chain abort.","anyOf":[{"anyOf":[{"type":"number"},{"type":"string"}],"description":"A coin/balance amount. Accepts three formats: (1) DISPLAY FORMAT with token symbol: \"2.5WOW\", \"10USDC\", \"0.05WOW\" — auto-converted to smallest units via the Fund Processing Layer (token precision resolved from official registry → cache → on-chain). The symbol MUST match the token's type_parameter. (2) SMALLEST UNIT (numeric string): \"10000000000\" — used as-is, no conversion. (3) SMALLEST UNIT (number): 10000000000 — used as-is only within the safe integer range (±2^53); numbers outside it are REJECTED, use a numeric string instead. PRECISION RULE: for values exceeding 2^53 (9007199254740991), ALWAYS use format (1) or (2) — JS numbers lose integer precision silently and such inputs are blocked. Raw amounts must be plain non-negative integers; a decimal value without a token symbol (e.g. \"2.5\") is rejected — append the symbol (\"2.5WOW\") so the Fund Processing Layer converts it. WARNING — BARE INTEGER MEANS SMALLEST UNIT, NOT TOKENS: formats (2)/(3) are NEVER interpreted as display tokens. For example amount=\"5\" or 5 means 5 raw units = 0.000000005 WOW (9 decimals) — NOT 5 WOW. When the user asks for a token amount, you MUST use display format (\"5WOW\", \"2USDC\"); a bare integer is only correct for unitless counts (e.g. stock quantity) or when you computed exact raw units yourself. Default token: WOW (9 decimals, 1 WOW = 10^9 MIST). For custom tokens: use display format with the token's symbol, or pass smallest units directly. MONEY CONFIRMATION: all monetary fields trigger user confirmation via the Fund Processing Layer, where the token's FULL type, decimals and raw amount are always visible. MULTIPLE ISSUERS: several on-chain tokens may legally share the same symbol (e.g. multiple \"USDT\" coins). When a bare symbol matches more than one token, the operation is BLOCKED and every candidate is listed with full details (type, name, decimals, verified tag) — present the list to the USER and let them choose (they may answer by number), then re-issue with the chosen token's FULL type string in type_parameter; never guess an issuer from the bare symbol. MISSING TOKEN INFO: when a token's precision cannot be resolved, the operation is REFUSED (raw u64 included — amount magnitude could not be verified). Recovery: provide the token's FULL type in package::module::Name form in type_parameter (a bare symbol like \"USDT\" cannot be resolved), and verify the WOW network is correct. Examples: \"2.5WOW\" (display → 2500000000), 10000000000 (number, smallest unit), \"50000000000\" (string, smallest unit). Used for: service sale prices, compensation fund balances, Treasury deposits, arbitration fees, reward amounts, stock quantities."},{"type":"null"}]}},"required":["guard","sharing"],"additionalProperties":false,"description":"Fund allocator — a complete allocation strategy triggered by a Guard. Contains a sharing[] array where items can mix Amount/Rate/RateGross/Surplus modes. When the Guard passes, the contract allocates funds in strict order: Amount → Rate/RateGross → Surplus."},"description":"Fund allocator list. NOT first-match-wins: a distribution call submits ONE guard and EVERY allocator bound to that guard fires, in vector order, each against the shrinking pool left by the previous (this is how a waterfall like Amount fee + net Rate split is built). Alternative paths (e.g., refund / damage-deduct / arbitrate) are expressed as allocators bound to DIFFERENT guards; the caller's submitted guard selects the path."}},"required":["description","threshold","allocators"],"additionalProperties":false,"description":"Fund allocator list — the top-level allocation configuration attached to an Order. Contains a threshold and a list of Allocators. A distribution call submits ONE guard; every Allocator bound to that guard executes its sharing[] in strict order (Amount → Rate/RateGross → Surplus) against the shrinking pool. MULTI-TIER ALLOCATION (DOC-04): Each Order binds ONE Allocators template (set on Service.order_allocators before publish). For multi-tier distribution (e.g., customer→agency→suppliers), use a two-phase approach: (1) Tier-1 Allocators on the customer's Order (allocates to agency + refund fund); (2) Tier-2 Allocators on a NEW Order created by the agency (allocates agency's received funds to suppliers). Each tier's NET Rate-mode sharing[] must independently sum to 10000 (or <= 10000 with Surplus); RateGross-mode sharing[] must sum to <= 10000."},{"type":"null"}]},"order_allocators_append":{"description":"Append-only correction window for order_allocators — the ONLY allocator mutation allowed AFTER publish (J1). REQUIREMENTS (chain-enforced, allocation abort code 20 EALLOCATORS_NOT_EXTENSION): the supplied Allocators must be a pure EXTENSION of the current on-chain plan — every existing allocator appears VERBATIM as a prefix (same guard, same sharing, same fix/max), threshold must be UNCHANGED; only description may change freely. New allocators are appended after the prefix. WHY: rewriting an existing allocator or changing the threshold would retroactively alter payout rules for orders already escrowed against the old plan. Clearing the plan (null) is NOT possible here — that would strand in-flight orders. Permission: same index 313 as order_allocators. USE CASE: you forgot one allocator guard (e.g. the refund exit for a review node) and the Service is already published — instead of abandoning the Service, append the missing allocator. ⚠️ SCOPE — NEW ORDERS ONLY: each order instantiates its own Allocation from this plan AT BUY TIME, so appending changes the template for FUTURE orders only. Orders already escrowed under the previous plan do NOT gain the appended allocator — their Allocation (and its fund exits) is frozen as originally instantiated; if in-flight orders are already stranded, this append does NOT rescue them. ⚠️ Appended allocators are evaluated AFTER the existing ones against the shrinking pool (vector order), so they see the balance left by earlier allocators — design appended waterfall tails accordingly. ⚠️ Once appended, an allocator can NEVER be edited or removed — same permanence as the original plan.","type":"object","properties":{"description":{"type":"string","description":"Description of fund allocator list"},"threshold":{"default":0,"description":"Minimum balance required for allocation to fire. When the Allocation object's balance < threshold, allocation aborts with EINSUFFICIENT_BALANCE=7. Also: when an Allocator has only Amount items (no Rate, no Surplus), the sum of Amount items must be >= threshold (EAMOUNT_BELOW_THRESHOLD=12). Set to 0 (default) to allow any balance.","anyOf":[{"type":"number"},{"type":"string"}]},"allocators":{"type":"array","items":{"type":"object","properties":{"guard":{"type":"string","description":"Guard object ID or name. A distribution call submits ONE guard; EVERY Allocator bound to that guard fires — in vector order, each against the balance left by the previous (the distribution loop matches the submitted guard address, it does NOT evaluate guards competitively). NOT first-match-wins: Allocators with different guards are alternative distribution paths selected by the caller's choice of guard (e.g., a refund guard vs a damage guard), and mutual exclusion must be expressed inside the Guard conditions themselves, never assumed from ordering."},"sharing":{"type":"array","items":{"type":"object","properties":{"who":{"anyOf":[{"type":"object","properties":{"GuardIdentifier":{"type":"integer","minimum":0,"maximum":255,"description":"Identifier (0-255) for data lookup in Guard table. Slot consensus (enforced on-chain at guard table construction): 0-220 = user slots (free for business guards); 221-253 = PROTOCOL-RESERVED (rejected on-chain — reserved so future protocol features get fixed slots without colliding with published guards); 255 = ONCE replay-protection slot on Allocation (byte-keyed, the submitted bytes are the once-key — use for per-period keys like period-<N>); 254 = ONCE-FOR-OBJECT slot on Allocation (chain-derived key = bcs(the Allocation's payment_info.for_object); the submitted bytes are ignored and the submission only arms the slot — use for one-shot per-order rails whose payee is NOT the order itself, such as settlement releases and incentive/bounty claims). NEVER arm 254 on a refund rail: a refund pays the submitted Order through user slot 0, and a refund leg re-entered in a later renewal period would abort E_ONCE_TRIGGERED (16) forever — refund once-ness comes from the terminal-node topology, never from a once slot. SLOT 0 SEMANTICS: slot 0 carries the transacted Order address by convention. As a submission slot it is legal on order/allocation/machine rails (the order exists when those verify), but FORBIDDEN on a Service buy_guard — the order does not exist when the buy-time passport is verified, so the mount is refused (service abort 43)."}},"required":["GuardIdentifier"],"additionalProperties":false,"description":"Guard verified recipient ID. Get recipient ID from specified data index in Guard table. The ID must be of address type. ALLOCATION rails only — the REWARD claim rail requires recipient == the transaction sender (abort 14), so a GuardIdentifier recipient on reward.guard_add resolves to the submitted Order and is structurally unpayable; the tool gate rejects it (crs-mn-261015 F-12)."},{"type":"object","properties":{"Entity":{"anyOf":[{"description":"Account name, address (0x...), or mark name. When using string format, local marks are searched first. EXAMPLE: 'alice' - searches local marks first, then global; EXAMPLE: '0x2...' (64 hex chars) - uses address directly; EXAMPLE: '' - uses the default local account"},{"type":"object","properties":{"name_or_address":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"local_mark_first":{"description":"Whether to prioritize local marks, if true, prioritize local marks, otherwise prioritize global marks","type":"boolean"}},"additionalProperties":false,"description":"Account or address lookup object. Use this to specify which account to use for an operation. EXAMPLE: { name_or_address: 'testor2' } - looks up account by name; EXAMPLE: { name_or_address: '0x1234...' } - uses address directly; If name_or_address is empty string '', uses the default local account. name_or_address is REQUIRED — {} resolves to nothing useful and is rejected."}],"description":"Account or address lookup. Can be a simple string (recommended for AI) or full object with explicit local_mark_first control. String form auto-converts to { name_or_address: <string>, local_mark_first: true }."}},"required":["Entity"],"additionalProperties":false,"description":"Static address resolved via LocalMark. Format: {Entity: 'mark_name'} (string shorthand) or {Entity: {name_or_address: 'mark_name'}} (full object).F-RQ-11 (rq2 promotion): string shorthand accepted — the FIX-005 transform resolves local marks first."},{"type":"object","properties":{"Signer":{"type":"string","const":"signer"}},"required":["Signer"],"additionalProperties":false,"description":"Current transaction signer (tx_context::sender) at the time of the alloc() call. For refunds, the Order owner must call alloc_by_guard themselves to receive the funds. On the REWARD claim rail this is the CANONICAL recipient (the claim entry requires recipient == the tx sender)."}],"description":"Recipient of this allocation. Three forms — each resolves the address at a DIFFERENT time:\n• { GuardIdentifier: u8 } — DYNAMIC address resolved from Passport at alloc() time (from the passport's submission record). Use 0 for Order owner in Service-integrated mode (Customer who created the Order). The identifier must match a Guard table entry with b_submission=true. If Passport has no matching submission, contract aborts with E_VERIFY_FAILED. Use when the recipient address is not known at config time and must be supplied via Guard submission data.\n• { Entity: { name_or_address: '...' } } — FIXED address resolved via LocalMark at SDK build time (passed to contract as a literal address). Use for known recipients (e.g., 'turo_host', or a Treasury object address). Use when the recipient is a stable, known address (e.g., operator receives rent, platform fee to treasury).\n• 'Signer' — the transaction sender at the time of the alloc() call (tx_context::sender). RESOLVED AT EXECUTION TIME, not at config time. For refunds: the customer (Order owner) must call alloc_by_guard THEMSELVES so that tx_context::sender resolves to THEIR address — if the operator calls alloc_by_guard, the operator becomes the recipient (Signer = operator), NOT the customer. Use when the recipient is whoever submits the allocation transaction (e.g., customer receives refund)."},"sharing":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Allocation value. SEMANTICS DEPEND ON `mode`:\n• mode='Amount': absolute amount in smallest unit (e.g., '750000000' for 0.75 WOW, '250000000' for 0.25 WOW). Allocated first; sum of Amount items cached as `fix`.\n• mode='Rate' (NET): basis-points rate off the post-fix base (balance - fix, or max - fix), 10000 = 100% (e.g., '7500' for 75%, '2500' for 25%). When no Surplus in same Allocator, sum MUST == 10000; when Surplus present, sum MUST <= 10000.\n• mode='RateGross': basis-points rate off the FULL pool (balance) or the `max` cap — the fixed Amount total is NOT subtracted, 10000 = 100%. sum MUST <= 10000 (and, with `max` set, fix×10000 + sum×max <= max×10000). Cannot be mixed with mode='Rate' in the same Allocator while a fixed Amount total is present.\n• mode='Surplus': IGNORED (contract forces to 0). Set to '0' for clarity. Receives remaining balance after Amount + Rate/RateGross allocations.\n• mode='Formula': basis-points COEFFICIENT (MUST be <= 10000) of a RUNTIME repository scalar — payout = clamp(coefficient × scalar / 10000, 0, headroom). Does NOT join any rate sum (its base is the queried scalar, not the pool) and skips the Amount>=threshold declaration check. Bind the slot's data source via allocation formula_spec_set, else the scalar reads 0.\n⚠️ T1 LOSSY POINT (B-2): Amount/Rate/RateGross/Surplus values are PRE-CONFIGURED and STATIC — a free-form continuous amount still cannot be expressed with them. Formula mode covers the bounded case: a coefficient (<= 10000 bps) of an attested repository aggregate (record count / value sum) — use it for runtime-proportional payouts; for anything richer, model (a) a fixed-tier Allocator list guarded by distinct Guards, or (b) an Amount with a `max` cap — both are finite configurations."},"mode":{"anyOf":[{"type":"string","enum":["Amount","Rate","Surplus","RateGross","Formula"]},{}],"description":"Allocation mode — determines how the `sharing` field is interpreted. Modes can be used individually OR combined within a single Allocator; when combined, allocation order is strictly: Amount first, then Rate/RateGross, then Formula scalar legs, then Surplus. Understanding these modes allows modeling almost any fund distribution pattern.\n• Amount (0): `sharing` is a FIXED amount in smallest unit (e.g., '750000000' = 0.75 WOW). Allocated FIRST; sum of all Amount items is cached as `fix` by the contract. Validation: when no Rate and no Surplus items exist, sum of Amount items must be >= allocators.threshold (EAMOUNT_BELOW_THRESHOLD=12); when `max` is set, sum of Amount items must be <= max (EAMOUNT_EXCEEDS_MAX=13).\n• Rate (1): `sharing` is a NET basis-points rate (10000 = 100%). Allocated AFTER Amount; formula: allocated = (sharing × total_rates) / 10000, where total_rates = balance - fix (or max - fix if `max` is set) — the cached fixed Amount total IS subtracted. Validation: when no Surplus items exist, sum of all Rate items must be EXACTLY 10000 (ERATE_NOT_10000=4); when Surplus items exist, sum of all Rate items must be <= 10000 (ERATE_EXCEEDS_10000=6).\n• RateGross (3): `sharing` is a GROSS basis-points rate (10000 = 100%). Allocated AFTER Amount; formula: allocated = (sharing × total_rates) / 10000, where total_rates = balance (the full pool) or the `max` cap when set — the fixed Amount total is NOT subtracted, so fixed Amount entries and percentage-of-total rates coexist exactly. Validation: sum of all RateGross items must be <= 10000 (ERATE_EXCEEDS_10000=6); when `max` is set, fix×10000 + sum(rate)×max <= max×10000 must hold (6); with no `max` and a fixed total > 0, sum of RateGross items must be < 10000 (6). RateGross cannot be mixed with NET Rate entries in the same Allocator while a fixed Amount total is present (EMIXED_RATE_BASES=17).\n• Surplus (2): `sharing` is IGNORED (contract forces it to 0). Allocated LAST; receives the remaining balance after Amount + Rate allocations. Validation: MAX ONE Surplus item per Allocator (EMULTIPLE_SURPLUS=5). When Surplus exists, Rate sum constraint relaxes from == 10000 to <= 10000.\n• Formula (4): `sharing` is a basis-points COEFFICIENT (<= 10000, ERATE_EXCEEDS_10000=6) applied to a RUNTIME scalar queried from a Repository at alloc() time — amount = clamp(coefficient × scalar / 10000, 0, headroom). The scalar comes from the slot's bound FormulaSpec (record-count or value-sum over a repository policy key, predicate wire identical to the 1173/1174 count/sum-where guard queries; explicit candidate ids, max 100, empty list = zero hits = scalar 0). A Formula leg does NOT join total_rate (its base is the queried scalar, not the pool) and its presence SKIPS the Amount-sum >= threshold declaration check (payout is runtime-defined). Requires a spec bound via allocation formula_spec_set — an unbound Formula slot prices its scalar as 0. binding a malformed spec aborts (EFORMULA_SPEC_INVALID=24).\nALLOCATION ORDER (strict): Amount items (fixed, cached as fix) → Rate/RateGross items → Formula scalar legs → Surplus item (remaining).\nRECOMMENDATION: Use Amount mode for known fixed amounts (clearer, no sum constraint). Use Rate mode for proportional splits off the post-fix remainder (requires sum == 10000 unless Surplus present). Use RateGross mode for a percentage of the FULL pool/`max` that must coexist with fixed Amount entries. Use Surplus to capture remainder (e.g., platform fee + host gets rest). Use Formula for payouts proportional to an attested on-chain aggregate (e.g. N records served, total value logged in a Repository) that cannot be known at configuration time. Accepts string ('Amount'/'Rate'/'Surplus'/'RateGross'/'Formula', recommended) or number (0/1/2/3/4)."}},"required":["who","sharing","mode"],"additionalProperties":false,"description":"Fund allocation item — one recipient's share of the Allocation balance. The `sharing` value's meaning depends on `mode` (see AllocationModeSchema). Multiple items in the same Allocator are evaluated together: Amount items first, Rate/RateGross items second, Surplus last."},"description":"Fund allocation item list. Each item specifies a recipient (who), a value (sharing), and a mode. Items can mix modes (Amount + Rate/RateGross + Formula + Surplus) within the same Allocator. RECIPIENT SEMANTICS: the Guard constrains what each submission slot may be; a recipient's safety follows from the sufficiency of those constraints (run the recipient constraint audit). Canonical order pattern: recipient = the single submitted Order — funds land at that object and are receivable only by its owner. ALLOCATION ORDER: Amount items first (cached as fix) → Rate items (proportional to balance - fix; RateGross proportional to the full pool) → Formula legs (coefficient of the runtime repository scalar) → Surplus item (remaining). CONSTRAINTS: max ONE Surplus item per Allocator; NET Rate sum must == 10000 (no Surplus) or <= 10000 (with Surplus); RateGross sum must <= 10000 (never mixed with NET Rate while a fixed total is present); each Formula leg's coefficient must <= 10000 but does NOT count into any rate sum; Amount sum must >= threshold (no Rate, no RateGross and no Formula present — a Formula leg skips this floor since its payout is runtime-defined) and <= max (if max set)."},"fix":{"description":"OUTPUT-ONLY (query result). Cached sum of all Amount-mode `sharing` values in this Allocator. Computed by the contract when the allocator is added — DO NOT set this field at creation. Used internally to compute `total_rates = balance - fix` for NET Rate allocation (RateGross ignores fix and uses the full pool/`max`).","anyOf":[{"type":"number"},{"type":"string"}]},"max":{"description":"Maximum allocation cap (OPTIONAL — omit the field or set to null to disable the cap; do NOT set to 0 as that means a cap of zero). Passed through to the contract as Option<u64> when the allocator is added: when null/omitted the contract treats it as `none` (no cap); when set, the contract enforces it. Has THREE effects when set:\n1. Construction: sum of Amount items must be <= max (EAMOUNT_EXCEEDS_MAX=13)\n2. Rate execution: NET Rate total_rates = max - fix; RateGross total_rates = max (fix NOT subtracted)\n3. Surplus execution: surplus_amount = max - alloced_amount (instead of balance - alloced_amount)\nUse when you want to cap total allocation regardless of Order balance (e.g., cap payout to declared amount). SDK pre-validates Amount sum <= max at build time to give actionable error messages before on-chain abort.","anyOf":[{"anyOf":[{"type":"number"},{"type":"string"}],"description":"A coin/balance amount. Accepts three formats: (1) DISPLAY FORMAT with token symbol: \"2.5WOW\", \"10USDC\", \"0.05WOW\" — auto-converted to smallest units via the Fund Processing Layer (token precision resolved from official registry → cache → on-chain). The symbol MUST match the token's type_parameter. (2) SMALLEST UNIT (numeric string): \"10000000000\" — used as-is, no conversion. (3) SMALLEST UNIT (number): 10000000000 — used as-is only within the safe integer range (±2^53); numbers outside it are REJECTED, use a numeric string instead. PRECISION RULE: for values exceeding 2^53 (9007199254740991), ALWAYS use format (1) or (2) — JS numbers lose integer precision silently and such inputs are blocked. Raw amounts must be plain non-negative integers; a decimal value without a token symbol (e.g. \"2.5\") is rejected — append the symbol (\"2.5WOW\") so the Fund Processing Layer converts it. WARNING — BARE INTEGER MEANS SMALLEST UNIT, NOT TOKENS: formats (2)/(3) are NEVER interpreted as display tokens. For example amount=\"5\" or 5 means 5 raw units = 0.000000005 WOW (9 decimals) — NOT 5 WOW. When the user asks for a token amount, you MUST use display format (\"5WOW\", \"2USDC\"); a bare integer is only correct for unitless counts (e.g. stock quantity) or when you computed exact raw units yourself. Default token: WOW (9 decimals, 1 WOW = 10^9 MIST). For custom tokens: use display format with the token's symbol, or pass smallest units directly. MONEY CONFIRMATION: all monetary fields trigger user confirmation via the Fund Processing Layer, where the token's FULL type, decimals and raw amount are always visible. MULTIPLE ISSUERS: several on-chain tokens may legally share the same symbol (e.g. multiple \"USDT\" coins). When a bare symbol matches more than one token, the operation is BLOCKED and every candidate is listed with full details (type, name, decimals, verified tag) — present the list to the USER and let them choose (they may answer by number), then re-issue with the chosen token's FULL type string in type_parameter; never guess an issuer from the bare symbol. MISSING TOKEN INFO: when a token's precision cannot be resolved, the operation is REFUSED (raw u64 included — amount magnitude could not be verified). Recovery: provide the token's FULL type in package::module::Name form in type_parameter (a bare symbol like \"USDT\" cannot be resolved), and verify the WOW network is correct. Examples: \"2.5WOW\" (display → 2500000000), 10000000000 (number, smallest unit), \"50000000000\" (string, smallest unit). Used for: service sale prices, compensation fund balances, Treasury deposits, arbitration fees, reward amounts, stock quantities."},{"type":"null"}]}},"required":["guard","sharing"],"additionalProperties":false,"description":"Fund allocator — a complete allocation strategy triggered by a Guard. Contains a sharing[] array where items can mix Amount/Rate/RateGross/Surplus modes. When the Guard passes, the contract allocates funds in strict order: Amount → Rate/RateGross → Surplus."},"description":"Fund allocator list. NOT first-match-wins: a distribution call submits ONE guard and EVERY allocator bound to that guard fires, in vector order, each against the shrinking pool left by the previous (this is how a waterfall like Amount fee + net Rate split is built). Alternative paths (e.g., refund / damage-deduct / arbitrate) are expressed as allocators bound to DIFFERENT guards; the caller's submitted guard selects the path."}},"required":["description","threshold","allocators"],"additionalProperties":false},"buy_guard":{"description":"Buy guard object ID or name (null CLEARS the mount). RUNTIME SWITCH (permission 307 SERVICE_BUY_GUARD — the guard OBJECT is immutable but its MOUNT on the Service is mutable at any time). ROUND-ROTATION DUTY (拍板② dm-mtw-261027): for daily/group rounds whose cutoff is an absolute timestamp, the precise batch boundary is THIS mount, not the time guard — at the cutoff instant the keeper cron SETS the buy_guard (new entrants refused at BUY time) and CLEARs/re-arms it when the next round opens; the on-chain Clock >= cutoff comparison stays the settlement/advance authority. Disclose the publisher's time source the cron fires on. Full Machine reuse across rounds (advance gate re-reading a repository cutoff row) is filed for a protocol window.","anyOf":[{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},{"type":"null"}]},"compensation_fund_add":{"description":"Deposit funds into the Service compensation_fund. Used to pay indemnity when arbitration resolves in customer's favor. FORMAT: {balance: <amount_in_smallest_unit>} — the field name is 'balance' (NOT 'amount'). The token type and precision are determined by the Service object's type_parameter (the generic type set when the Service was created). For WOW (9 decimals): {balance: 1000000000} = 1 WOW. For tokens with different decimals, adjust accordingly (e.g. USDC has 6 decimals, so {balance: 1000000} = 1 USDC). REQUIRES: Permission index 315 (SERVICE_COMPENSATION_FUND_DEPOSIT) for NON-ADMIN callers. The Permission owner and admin short-circuit every builtin index check (no grant needed); only non-admin callers must be granted 315 first. COMMON MISTAKE: using {amount: ...} or {amount: ..., type: 'WOW'} — these will fail. The correct field is 'balance'.","anyOf":[{"type":"object","properties":{"balance":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"A coin/balance amount. Accepts three formats: (1) DISPLAY FORMAT with token symbol: \"2.5WOW\", \"10USDC\", \"0.05WOW\" — auto-converted to smallest units via the Fund Processing Layer (token precision resolved from official registry → cache → on-chain). The symbol MUST match the token's type_parameter. (2) SMALLEST UNIT (numeric string): \"10000000000\" — used as-is, no conversion. (3) SMALLEST UNIT (number): 10000000000 — used as-is only within the safe integer range (±2^53); numbers outside it are REJECTED, use a numeric string instead. PRECISION RULE: for values exceeding 2^53 (9007199254740991), ALWAYS use format (1) or (2) — JS numbers lose integer precision silently and such inputs are blocked. Raw amounts must be plain non-negative integers; a decimal value without a token symbol (e.g. \"2.5\") is rejected — append the symbol (\"2.5WOW\") so the Fund Processing Layer converts it. WARNING — BARE INTEGER MEANS SMALLEST UNIT, NOT TOKENS: formats (2)/(3) are NEVER interpreted as display tokens. For example amount=\"5\" or 5 means 5 raw units = 0.000000005 WOW (9 decimals) — NOT 5 WOW. When the user asks for a token amount, you MUST use display format (\"5WOW\", \"2USDC\"); a bare integer is only correct for unitless counts (e.g. stock quantity) or when you computed exact raw units yourself. Default token: WOW (9 decimals, 1 WOW = 10^9 MIST). For custom tokens: use display format with the token's symbol, or pass smallest units directly. MONEY CONFIRMATION: all monetary fields trigger user confirmation via the Fund Processing Layer, where the token's FULL type, decimals and raw amount are always visible. MULTIPLE ISSUERS: several on-chain tokens may legally share the same symbol (e.g. multiple \"USDT\" coins). When a bare symbol matches more than one token, the operation is BLOCKED and every candidate is listed with full details (type, name, decimals, verified tag) — present the list to the USER and let them choose (they may answer by number), then re-issue with the chosen token's FULL type string in type_parameter; never guess an issuer from the bare symbol. MISSING TOKEN INFO: when a token's precision cannot be resolved, the operation is REFUSED (raw u64 included — amount magnitude could not be verified). Recovery: provide the token's FULL type in package::module::Name form in type_parameter (a bare symbol like \"USDT\" cannot be resolved), and verify the WOW network is correct. Examples: \"2.5WOW\" (display → 2500000000), 10000000000 (number, smallest unit), \"50000000000\" (string, smallest unit). Used for: service sale prices, compensation fund balances, Treasury deposits, arbitration fees, reward amounts, stock quantities."}},"required":["balance"],"additionalProperties":false,"description":"Specify an amount value."},{"type":"object","properties":{"coin":{"type":"string","description":"Coin object ID or name(local mark). WHOLE-COIN TRANSFER: the ENTIRE Coin object is moved to the recipient — the 'amount' is NOT taken from it (testnet lesson: passing your main gas coin transfers its full balance, leaving you unable to pay for anything). Use only for coins whose whole balance is exactly what you intend to send; prefer {balance: <smallest-unit number>} for partial amounts."}},"required":["coin"],"additionalProperties":false}]},"compensation_fund_withdraw":{"description":"Withdraw ALL funds from the compensation_fund to a new Payment object owned by `receipt`. REQUIRES: Service must be paused AND setting_lock_duration must have elapsed since pause (the unpublished-state check). Withdraws the ENTIRE compensation_fund balance via balance::withdraw_all. DIFFERENT from the order-side compensation claim (for arbitration-winning users, no pause+lock required).","type":"object","properties":{"receipt":{"anyOf":[{"description":"Account name, address (0x...), or mark name. When using string format, local marks are searched first. EXAMPLE: 'alice' - searches local marks first, then global; EXAMPLE: '0x2...' (64 hex chars) - uses address directly; EXAMPLE: '' - uses the default local account"},{"type":"object","properties":{"name_or_address":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"local_mark_first":{"description":"Whether to prioritize local marks, if true, prioritize local marks, otherwise prioritize global marks","type":"boolean"}},"additionalProperties":false,"description":"Account or address lookup object. Use this to specify which account to use for an operation. EXAMPLE: { name_or_address: 'testor2' } - looks up account by name; EXAMPLE: { name_or_address: '0x1234...' } - uses address directly; If name_or_address is empty string '', uses the default local account. name_or_address is REQUIRED — {} resolves to nothing useful and is rejected."}],"description":"Receipt address that will receive the withdrawn funds (as a new Payment object)"},"payment_info":{"type":"object","properties":{"for_object":{"description":"Binding anchor for this distribution. On an Allocation a SET for_object is ENFORCED at alloc(): every GuardIdentifier recipient submission must equal this address or the whole tx aborts (ERECIPIENT_NOT_FOR_OBJECT, code 15) — verify the anchor matches the intended recipient flow BEFORE create; payment_info is immutable afterwards. NULL/omitted = no anchor: nothing is enforced on-chain, recipient routing is entirely the creator's design. Also recorded at creation for auditors to query the distribution's business context.","anyOf":[{"type":"string"},{"type":"null"}]},"for_guard":{"description":"Payment to satisfy verification of a Guard object","anyOf":[{"type":"string"},{"type":"null"}]},"remark":{"type":"string","description":"Payment record remark"},"index":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Payment record index (non-negative integer)"}},"required":["remark","index"],"additionalProperties":false,"description":"Payment info for the new Payment object created to hold the withdrawn funds"}},"required":["receipt","payment_info"],"additionalProperties":false},"setting_lock_duration_add":{"description":"Additional lock duration to ADD to 'setting_lock_duration' (Move field name). UNIT: milliseconds (ms). Example: 2592000000 = 30 days, 7776000000 = 90 days, 86400000 = 1 day. DEFAULT: 2592000000 (30 days, DEFAULT_LOCK_DURATION). This is the initial value when a Service is created. Behavior: additive (safe_add) — only increases, never decreases. Can be called BEFORE or AFTER publish (no publish check). Affects the waiting time required by: compensation_fund_withdraw, arbitrations remove/clear, rewards remove/clear (all require pause + setting_lock_duration elapsed since pause).","type":"number"},"compensation_fund_receive":{"description":"Receive order compensation funds from this Service object.\n\nACCEPTED FORMATS (F-06 unified receive operation block):\n• 'recently' (string literal) — auto-query and receive ALL recently received balance.\n Use this for the common case: \"deposit all recently received coins into pending balance.\"\n Example: receive: 'recently'\n REWARD-OBJECT TRAP (F55 gf32-mn-261103): on a REWARD object, 'recently' resolves through\n the Payment-derived ReceivedBalance primitive — a Reward that holds plain CoinWrapper\n sweeps (query_received answers ReceivedNormal[]) aborts with 'received is ReceivedNormal[]\n (expected ReceivedBalance)'. For a plain coin sweep on a Reward use owner_receive:'recently'\n (same call — it unwraps received objects to the Permission owner) instead of receive.\n• ReceivedBalance ({token_type, balance, received: [{id, balance, payment}]}) —\n receive a specific balance record from a Payment/payer.\n Use this when targeting a specific received balance (advanced).\n Example: receive: {token_type: '0x2::wow::WOW', balance: 1000000, received: [{id: '0xrec1', balance: 1000000, payment: '0xpay1'}]}\nANTI-PATTERN: do NOT wrap in {result: ...} — pass the value directly.","anyOf":[{"type":"object","properties":{"balance":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"A coin/balance amount. Accepts three formats: (1) DISPLAY FORMAT with token symbol: \"2.5WOW\", \"10USDC\", \"0.05WOW\" — auto-converted to smallest units via the Fund Processing Layer (token precision resolved from official registry → cache → on-chain). The symbol MUST match the token's type_parameter. (2) SMALLEST UNIT (numeric string): \"10000000000\" — used as-is, no conversion. (3) SMALLEST UNIT (number): 10000000000 — used as-is only within the safe integer range (±2^53); numbers outside it are REJECTED, use a numeric string instead. PRECISION RULE: for values exceeding 2^53 (9007199254740991), ALWAYS use format (1) or (2) — JS numbers lose integer precision silently and such inputs are blocked. Raw amounts must be plain non-negative integers; a decimal value without a token symbol (e.g. \"2.5\") is rejected — append the symbol (\"2.5WOW\") so the Fund Processing Layer converts it. WARNING — BARE INTEGER MEANS SMALLEST UNIT, NOT TOKENS: formats (2)/(3) are NEVER interpreted as display tokens. For example amount=\"5\" or 5 means 5 raw units = 0.000000005 WOW (9 decimals) — NOT 5 WOW. When the user asks for a token amount, you MUST use display format (\"5WOW\", \"2USDC\"); a bare integer is only correct for unitless counts (e.g. stock quantity) or when you computed exact raw units yourself. Default token: WOW (9 decimals, 1 WOW = 10^9 MIST). For custom tokens: use display format with the token's symbol, or pass smallest units directly. MONEY CONFIRMATION: all monetary fields trigger user confirmation via the Fund Processing Layer, where the token's FULL type, decimals and raw amount are always visible. MULTIPLE ISSUERS: several on-chain tokens may legally share the same symbol (e.g. multiple \"USDT\" coins). When a bare symbol matches more than one token, the operation is BLOCKED and every candidate is listed with full details (type, name, decimals, verified tag) — present the list to the USER and let them choose (they may answer by number), then re-issue with the chosen token's FULL type string in type_parameter; never guess an issuer from the bare symbol. MISSING TOKEN INFO: when a token's precision cannot be resolved, the operation is REFUSED (raw u64 included — amount magnitude could not be verified). Recovery: provide the token's FULL type in package::module::Name form in type_parameter (a bare symbol like \"USDT\" cannot be resolved), and verify the WOW network is correct. Examples: \"2.5WOW\" (display → 2500000000), 10000000000 (number, smallest unit), \"50000000000\" (string, smallest unit). Used for: service sale prices, compensation fund balances, Treasury deposits, arbitration fees, reward amounts, stock quantities."},"token_type":{"type":"string","description":"Asset type of Coin objects. Supports CoinWrapper<...> format for order receive operations."},"received":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Received CoinWrapper object ID"},"balance":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"A coin/balance amount. Accepts three formats: (1) DISPLAY FORMAT with token symbol: \"2.5WOW\", \"10USDC\", \"0.05WOW\" — auto-converted to smallest units via the Fund Processing Layer (token precision resolved from official registry → cache → on-chain). The symbol MUST match the token's type_parameter. (2) SMALLEST UNIT (numeric string): \"10000000000\" — used as-is, no conversion. (3) SMALLEST UNIT (number): 10000000000 — used as-is only within the safe integer range (±2^53); numbers outside it are REJECTED, use a numeric string instead. PRECISION RULE: for values exceeding 2^53 (9007199254740991), ALWAYS use format (1) or (2) — JS numbers lose integer precision silently and such inputs are blocked. Raw amounts must be plain non-negative integers; a decimal value without a token symbol (e.g. \"2.5\") is rejected — append the symbol (\"2.5WOW\") so the Fund Processing Layer converts it. WARNING — BARE INTEGER MEANS SMALLEST UNIT, NOT TOKENS: formats (2)/(3) are NEVER interpreted as display tokens. For example amount=\"5\" or 5 means 5 raw units = 0.000000005 WOW (9 decimals) — NOT 5 WOW. When the user asks for a token amount, you MUST use display format (\"5WOW\", \"2USDC\"); a bare integer is only correct for unitless counts (e.g. stock quantity) or when you computed exact raw units yourself. Default token: WOW (9 decimals, 1 WOW = 10^9 MIST). For custom tokens: use display format with the token's symbol, or pass smallest units directly. MONEY CONFIRMATION: all monetary fields trigger user confirmation via the Fund Processing Layer, where the token's FULL type, decimals and raw amount are always visible. MULTIPLE ISSUERS: several on-chain tokens may legally share the same symbol (e.g. multiple \"USDT\" coins). When a bare symbol matches more than one token, the operation is BLOCKED and every candidate is listed with full details (type, name, decimals, verified tag) — present the list to the USER and let them choose (they may answer by number), then re-issue with the chosen token's FULL type string in type_parameter; never guess an issuer from the bare symbol. MISSING TOKEN INFO: when a token's precision cannot be resolved, the operation is REFUSED (raw u64 included — amount magnitude could not be verified). Recovery: provide the token's FULL type in package::module::Name form in type_parameter (a bare symbol like \"USDT\" cannot be resolved), and verify the WOW network is correct. Examples: \"2.5WOW\" (display → 2500000000), 10000000000 (number, smallest unit), \"50000000000\" (string, smallest unit). Used for: service sale prices, compensation fund balances, Treasury deposits, arbitration fees, reward amounts, stock quantities."},"payment":{"type":"string","description":"Payment object ID"},"type":{"description":"Type of the received object (or inner coin type); used for token_type detection","type":"string"},"version":{"description":"Object version, required to build a Receiving<T> argument for owner_receive","type":"string"},"digest":{"description":"Object digest, required to build a Receiving<T> argument for owner_receive","type":"string"}},"required":["id","balance","payment"],"additionalProperties":false,"description":"Received CoinWrapper object record"},"description":"Received records of Coin objects"}},"required":["balance","token_type","received"],"additionalProperties":false,"description":"Received record of Coin objects"},{"type":"string","const":"recently"}]},"owner_receive":{"description":"Unwrap CoinWrapper objects and other objects received by this Service object and send them to the owner of its Permission object.\n\nACCEPTED FORMATS (F-06 unified receive operation block):\n• 'recently' (string literal) — auto-query and receive ALL recently received objects.\n Use this for the common case: \"withdraw everything the object has received\" — for\n order.receive this is the correct default for \"the buyer got their refund\".\n Example: receive: 'recently'\n• bare object id (string, 0x-prefixed) — one-object form, auto-expanded (F-15):\n pass the id of the single received object you want to unwrap (e.g. a CoinWrapper id).\n Example: receive: '0xabc...'\n• ReceivedNormal[] (array) — explicit list of received objects to unwrap.\n Use this when you want to receive specific objects only (not all).\n Example: receive: [{id: '0xobj1', type: '0x2::coin::Coin<0x2::wow::WOW>'}]\n• ReceivedBalance ({token_type, balance, received: [{id, balance, payment}]}) —\n receive a balance record from a specific Payment/payer.\n Use this for precise balance targeting (advanced — usually after querying\n the object's received history via query_received).\n Example: receive: {token_type: '0x2::wow::WOW', balance: 1000000, received: [{id: '0xrec1', balance: 1000000, payment: '0xpay1'}]}\nANTI-PATTERN: do NOT wrap in {result: ...} — pass the value directly.","anyOf":[{"type":"string","const":"recently"},{"type":"string","pattern":"^0x[0-9a-fA-F]{8,}$"},{"minItems":1,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1,"description":"Received object ID"},"type":{"type":"string","minLength":1,"description":"Object type"},"content_raw":{"description":"Raw content data"},"version":{"description":"Object version, required to build a Receiving<T> argument for owner_receive","type":"string"},"digest":{"description":"Object digest, required to build a Receiving<T> argument for owner_receive","type":"string"}},"required":["id","type"],"additionalProperties":false,"description":"Received normal object record"}},{"type":"object","properties":{"balance":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"A coin/balance amount. Accepts three formats: (1) DISPLAY FORMAT with token symbol: \"2.5WOW\", \"10USDC\", \"0.05WOW\" — auto-converted to smallest units via the Fund Processing Layer (token precision resolved from official registry → cache → on-chain). The symbol MUST match the token's type_parameter. (2) SMALLEST UNIT (numeric string): \"10000000000\" — used as-is, no conversion. (3) SMALLEST UNIT (number): 10000000000 — used as-is only within the safe integer range (±2^53); numbers outside it are REJECTED, use a numeric string instead. PRECISION RULE: for values exceeding 2^53 (9007199254740991), ALWAYS use format (1) or (2) — JS numbers lose integer precision silently and such inputs are blocked. Raw amounts must be plain non-negative integers; a decimal value without a token symbol (e.g. \"2.5\") is rejected — append the symbol (\"2.5WOW\") so the Fund Processing Layer converts it. WARNING — BARE INTEGER MEANS SMALLEST UNIT, NOT TOKENS: formats (2)/(3) are NEVER interpreted as display tokens. For example amount=\"5\" or 5 means 5 raw units = 0.000000005 WOW (9 decimals) — NOT 5 WOW. When the user asks for a token amount, you MUST use display format (\"5WOW\", \"2USDC\"); a bare integer is only correct for unitless counts (e.g. stock quantity) or when you computed exact raw units yourself. Default token: WOW (9 decimals, 1 WOW = 10^9 MIST). For custom tokens: use display format with the token's symbol, or pass smallest units directly. MONEY CONFIRMATION: all monetary fields trigger user confirmation via the Fund Processing Layer, where the token's FULL type, decimals and raw amount are always visible. MULTIPLE ISSUERS: several on-chain tokens may legally share the same symbol (e.g. multiple \"USDT\" coins). When a bare symbol matches more than one token, the operation is BLOCKED and every candidate is listed with full details (type, name, decimals, verified tag) — present the list to the USER and let them choose (they may answer by number), then re-issue with the chosen token's FULL type string in type_parameter; never guess an issuer from the bare symbol. MISSING TOKEN INFO: when a token's precision cannot be resolved, the operation is REFUSED (raw u64 included — amount magnitude could not be verified). Recovery: provide the token's FULL type in package::module::Name form in type_parameter (a bare symbol like \"USDT\" cannot be resolved), and verify the WOW network is correct. Examples: \"2.5WOW\" (display → 2500000000), 10000000000 (number, smallest unit), \"50000000000\" (string, smallest unit). Used for: service sale prices, compensation fund balances, Treasury deposits, arbitration fees, reward amounts, stock quantities."},"token_type":{"type":"string","description":"Asset type of Coin objects. Supports CoinWrapper<...> format for order receive operations."},"received":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Received CoinWrapper object ID"},"balance":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"A coin/balance amount. Accepts three formats: (1) DISPLAY FORMAT with token symbol: \"2.5WOW\", \"10USDC\", \"0.05WOW\" — auto-converted to smallest units via the Fund Processing Layer (token precision resolved from official registry → cache → on-chain). The symbol MUST match the token's type_parameter. (2) SMALLEST UNIT (numeric string): \"10000000000\" — used as-is, no conversion. (3) SMALLEST UNIT (number): 10000000000 — used as-is only within the safe integer range (±2^53); numbers outside it are REJECTED, use a numeric string instead. PRECISION RULE: for values exceeding 2^53 (9007199254740991), ALWAYS use format (1) or (2) — JS numbers lose integer precision silently and such inputs are blocked. Raw amounts must be plain non-negative integers; a decimal value without a token symbol (e.g. \"2.5\") is rejected — append the symbol (\"2.5WOW\") so the Fund Processing Layer converts it. WARNING — BARE INTEGER MEANS SMALLEST UNIT, NOT TOKENS: formats (2)/(3) are NEVER interpreted as display tokens. For example amount=\"5\" or 5 means 5 raw units = 0.000000005 WOW (9 decimals) — NOT 5 WOW. When the user asks for a token amount, you MUST use display format (\"5WOW\", \"2USDC\"); a bare integer is only correct for unitless counts (e.g. stock quantity) or when you computed exact raw units yourself. Default token: WOW (9 decimals, 1 WOW = 10^9 MIST). For custom tokens: use display format with the token's symbol, or pass smallest units directly. MONEY CONFIRMATION: all monetary fields trigger user confirmation via the Fund Processing Layer, where the token's FULL type, decimals and raw amount are always visible. MULTIPLE ISSUERS: several on-chain tokens may legally share the same symbol (e.g. multiple \"USDT\" coins). When a bare symbol matches more than one token, the operation is BLOCKED and every candidate is listed with full details (type, name, decimals, verified tag) — present the list to the USER and let them choose (they may answer by number), then re-issue with the chosen token's FULL type string in type_parameter; never guess an issuer from the bare symbol. MISSING TOKEN INFO: when a token's precision cannot be resolved, the operation is REFUSED (raw u64 included — amount magnitude could not be verified). Recovery: provide the token's FULL type in package::module::Name form in type_parameter (a bare symbol like \"USDT\" cannot be resolved), and verify the WOW network is correct. Examples: \"2.5WOW\" (display → 2500000000), 10000000000 (number, smallest unit), \"50000000000\" (string, smallest unit). Used for: service sale prices, compensation fund balances, Treasury deposits, arbitration fees, reward amounts, stock quantities."},"payment":{"type":"string","description":"Payment object ID"},"type":{"description":"Type of the received object (or inner coin type); used for token_type detection","type":"string"},"version":{"description":"Object version, required to build a Receiving<T> argument for owner_receive","type":"string"},"digest":{"description":"Object digest, required to build a Receiving<T> argument for owner_receive","type":"string"}},"required":["id","balance","payment"],"additionalProperties":false,"description":"Received CoinWrapper object record"},"description":"Received records of Coin objects"}},"required":["balance","token_type","received"],"additionalProperties":false,"description":"Received record of Coin objects"}]},"um":{"description":"Contact object ID or name — the Service's customer-service channel. This is the object that Messenger routes encrypted messages to for pre-order negotiation, private-info delivery (see customer_required), and post-sale support. ⚠️ REQUIRED whenever customer_required is set: without um, the customer's private information has no channel to reach the merchant.","anyOf":[{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},{"type":"null"}]},"arb_statement":{"description":"Service (defendant-side) statement on an arbitration case — permission index 321. Lets the Service permission holder put a bounded text on the record for any case against an order of this service WITHOUT holding the order. Callable in ANY case status. The Arb's coin type is derived automatically from the arb object on-chain.","type":"object","properties":{"arb":{"type":"string","description":"Arb object (case) to attach the statement to."},"order":{"type":"string","description":"The order the case was opened against — must belong to this Service."},"statement":{"type":"string","maxLength":4000,"description":"Seller's text statement appended to the case record (ArbStatementEvent). Event-only: nothing on the Arb object is mutated; the record cannot be rewritten or deleted. Use to declare facts or report the customer's behavior (e.g. absence, non-cooperation). PRIMARY evidence channel is Messenger (encrypted WTS records with the customer); this is the SECONDARY on-chain declare/report channel."}},"required":["arb","order","statement"],"additionalProperties":false},"pause":{"description":"Whether to pause accepting new orders.","type":"boolean"},"publish":{"description":"Whether to publish the Service. After publishing, customers can place orders. ⚠️ PRE-PUBLISH EVALUATION (mandatory, stop-node fund-exit coverage): service.allocators MUST cover EVERY stop node of the bound Machine — every node where an order can rest (terminal nodes AND waiting states: review windows, handovers, open disputes) needs BOTH a withdrawal (release) AND a refund allocation rule, and each mapping guard must be satisfiable in BOTH directions. An uncovered stop node strands escrowed funds permanently (order_allocators is L1-immutable). Review-gated release is a TIME VARIANT inside ONE exit guard ('reviewed OR unreviewed after T'), never parallel outgoing edges (race deadlock). See pattern.fund_flow_stop_node_coverage + rules R-M5-03 / R-M5-09. VERIFIED against Move source + SDK (4-level immutability matrix):\n L1 — PERMANENTLY LOCKED after publish (assert!(!bPublished), no pause+lock exception):\n • machine (workflow template)\n • order_allocators (fund distribution rules — full replacement locked; APPEND-ONLY additions remain possible via order_allocators_append, prefix/threshold frozen)\n L2 — TIME-LOCKED after publish (unpublished-state check — requires pause + setting_lock_duration elapsed):\n • arbitrations remove/clear (dispute resolution objects)\n • rewards remove/clear (reward objects)\n • compensation_fund_withdraw (withdraw ALL funds)\n RATIONALE (deliberate design, NOT a defect): these three REVOKE buyer-facing guarantees that placed orders already rely on — the lock protects buyer expectations. Daily operations (sales add/remove, price, stock, description) are NEVER gated by this lock.\n L3 — REMAIN MUTABLE after publish (no SDK check, no Move check):\n • arbitrations add, rewards add (no assert — can add after publish)\n • buy_guard, sales, discount, description, location, pause, repositories,\n • compensation_fund_add, setting_lock_duration_add, customer_required, um (Contact)\nThese 2 L1-LOCKED fields (machine/order_allocators) MUST be set BEFORE publish=true.\narbitrations/rewards can be ADDED after publish but remove/clear requires pause+lock.\n\n⚠️ COMPENSATION_FUND + ARBITRATION LINKAGE:\n At publish time, if compensation_fund > 0, Arbitration MUST be bound:\n if (balance::value(&self.compensation_fund) > 0) {\n assert!(arbitration_count > 0, E_ARBITRATION_NOT_SET_WITH_COMPENSATION_FUND);\n }\n The MCP handler enforces this as a HARD PRE-CHECK: if publish=true AND compensation_fund_add is set in the same call AND arbitrations is empty, the call is REJECTED before submission. If compensation_fund was deposited in a prior call, a SOFT WARNING is issued.\n\nSCHEMA-03 / P0-01 fix — DEPLOYMENT WORKFLOW (two-phase, avoids circular dependency):\n Phase 1 — CREATE (no publish): object={name:'my-service', type_parameter, permission} + machine + order_allocators + arbitrations.\n NOTE: buy_guard can use a LocalMark NAME (not address) to break the Guard→Service circular dependency.\n The name is resolved to an address at transaction build time.\n Phase 2 — PUBLISH: object='my-service' (string ref) + publish=true.\n All L1-LOCKED fields must be set in Phase 1; Phase 2 only flips the publish flag.\n Post-publish updates: buy_guard, sales, description, repositories (add), rewards (add), arbitrations (add), etc.","type":"boolean"},"creation_plan":{"description":"WIZARD CONTRACT: the Plan JSON that merchant_guide delivered (its creation_plan / plan field), passed back VERBATIM on the Service publish call (data.publish=true). The publish gate replays the plan's freeze matrix (preflight) right before submission and REJECTS the publish when any gate fails (structural issues, critical audit findings, or a failed rule check) — this closes the preflight bypass where a plan that failed merchant_guide's audit could still be materialized manually. OMIT this field on every NON-publish call and on fully manual (non-wizard) builds — the manual path is unchanged and never gated by this field. Do NOT edit, trim, or 'improve' the plan in transit: a mutated plan is rejected (target cross-check) and the publish must be redone from merchant_guide."},"reentry_kind":{"description":"AP-3 loop-semantics declaration for the publish audit (ctra F-06 root cure): overrides the word-stem loop classifier when the machine graph contains a cycle. 'none' = default (word-stem classification) / 'review-loop' = same-order no-charge revisits / 'paid-cycle' = per-revisit fee, fund gate required. MCP-side audit declaration ONLY (pre_publish harness hook) — never sent on-chain; the handler strips it before the SDK call. Mirror of the template frontmatter twin (template-loader).","type":"string","enum":["none","review-loop","paid-cycle"]},"arbitration_open_vote_ack":{"description":"MCP-gate-only declaration (R-ARB-VOTE-LOCK double insurance, TRIAGE-261109 item D): true acknowledges that this Service deliberately binds an identity-less (open-vote) Arbitration voting_guard, downgrading the publish gate's finding from CRITICAL to a disclosed warning. Consumed by the pre_publish harness hook ONLY — never sent on-chain (the handler strips it before the SDK call). Omit for a roster/party voting_guard.","type":"boolean"}},"required":["object"],"additionalProperties":false,"description":"On-chain Service operations. USAGE: (1) CREATE NEW: Set 'object' field with OBJECT format {name, type_parameter, permission, ...} to create a Service. NOTE: 'name' goes INSIDE 'object', NOT at the data root level. 'permission' can be a new Permission object or reference an existing one - check 'object' field description for details. (2) OPERATE EXISTING: Set 'object' field with STRING format (object ID or name). The 'object' field is CRITICAL and REQUIRED in both cases. STRING for existing, OBJECT for new creation."},"idempotency_key":{"type":"string","minLength":8,"maxLength":128,"pattern":"^[A-Za-z0-9._:-]+$","description":"F-RQ-13A (prescription ⑨): idempotency key for this business attempt. REPLAY GUARD: if a previous call with the SAME key is still open (dispatched but outcome unresolved, or already committed), this call is HELD — you get a structured state_conflict envelope with the prior attempt's verification data instead of a second on-chain submission (the ghost-order guard: two live mainnet orders, two escrows). Lifecycle: a deterministic failure (nothing submitted / provably reverted) clears the key — fix the cause and retry with the SAME key; an unknown-outcome failure (submission may have landed) keeps the key HELD — verify on-chain state first (result.submission_verification tells you where to look), and only retry with a NEW key once the outcome is resolved. Keep one key per business attempt (e.g. 'ord-20261030-042-buy'); do not reuse across attempts."},"env":{"type":"object","properties":{"account":{"default":"","type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"permission_guard":{"description":"List of permission guard IDs. Used to extend additional operation permissions (requires verification and configuration in the Permission object).","type":"array","items":{"type":"string"}},"no_cache":{"description":"Whether to disable caching.","type":"boolean"},"network":{"description":"Omit in chat-client contexts — the runtime stamps the user's CURRENT network (the client's UI selection). Standalone MCP/CLI: omit to use the current network; set ONLY when the user explicitly names a different network (a mismatch pauses for user confirmation). Never guess or hardcode a network.","type":"string","enum":["localnet","testnet","mainnet"]},"referrer":{"description":"Referrer ID. If the user is using the network for the first time, the referrer ID will be recorded (also applied when the SDK auto-registers the sender in the global Entity table).","type":"string"},"no_auto_register":{"description":"Opt-out of SDK-level Entity auto-registration. By default, a business transaction whose sender has no entry in the global Entity table automatically appends an entity registration: the sender gets registered and receives an owned Resource object (their on-chain mark book) in the wallet. Set true ONLY when the user explicitly cancelled their entity registration or demands that the transaction not touch the Entity table.","type":"boolean"},"confirmed":{"description":"Phase 2 ConfirmGate: set to true to proceed after a 'pending_confirmation' result. The operation is NOT executed until you re-call with confirmed=true after user consent.","type":"boolean"},"user_intent_phrases":{"description":"Phase 2 ConfirmGate: explicit user intent phrases collected from conversation context (e.g. 'use default account', 'force publish'). Used to bypass confirmation rules whose bypass_on_explicit_intent matches.","type":"array","items":{"type":"string"}},"plan_approval":{"description":"K3 24 PlanApproval: id of a goal whose plan was approved via goal_operation action='approve'. When set: 1) the ConfirmGate treats fail-open rules (standard/none levels) as pre-approved for operations under this goal's plan; 2) after successful CREATION operations, the created objects are auto-registered into the goal (GoalRecord.objects + its TaskProcess manifest — ACT station 'execution registers'). Fail-closed levels (irreversible/publish/amount) still require per-operation confirmation with env.confirmed=true.","type":"string"},"client_schema_version":{"description":"Client-side schema version (semver, e.g. '1.0.0'). When provided, the server checks compatibility and attaches warnings if mismatched.","type":"string"},"schema_strict_mode":{"default":false,"description":"When true, schema incompatibility returns an error instead of a warning. Default: false (warn mode).","type":"boolean"},"dry_run":{"description":"Phase 1 dry_run: when true, SIMULATE the transaction without signing or submitting. Returns effects + events showing what WOULD happen — no on-chain state is modified, no gas is charged. Use this to verify that an operation will succeed before committing. The returned digest will be 'dry_run:<timestamp>' and objectChanges will be empty (simulation only).","type":"boolean"},"window_profile":{"description":"Time-window profile for trial runs (N8 ktt6 F-14 re-carving of the 'business windows are never test-compressed' ruling, 2026-11-04). 'production' (default): compressed time-window violations BLOCK publish exactly as before. 'test': compressed windows are ADMITTED so a disposable trial store can run its full lifecycle fast — R-TIME-PROFILE violations degrade to loud named disclosures, and the publish itself is BLOCKED on a real network (testnet/mainnet); point the trial at a local/dev chain (env.network='localnet'). Trial discipline: test-profile stores are throwaway — a production store must re-issue WITHOUT this flag (guards freeze at publish, so compressed windows are unrepairable except by rebuilding the store).","type":"string","enum":["production","test"]},"response_level":{"description":"Write-success response size. 'compact' (default) trims the structured result to key fields (digest + created object references); 'full' includes the complete raw result. Default: compact.","type":"string","enum":["compact","full"]},"confirm_mode":{"description":"Confirmation frequency for this call. 'full': confirm every matched gate rule. 'streamlined' (client default): skip fail-open 'standard' level prompts — fail-closed levels (irreversible/publish/amount) ALWAYS still confirm. 'quiet': same hard floor as streamlined, for clients that batch/suppress repeat low-risk prompts in their own UI. This field NEVER downgrades fail-closed levels.","type":"string","enum":["full","streamlined","quiet"]}},"required":["account","schema_strict_mode"],"additionalProperties":false,"description":"IMPORTANT: Execution environment includes: account for signing operations, network selection (testnet | localnet | mainnet), additional Guard permissions, and more. Used to specify context information during the call. If account is not specified, the default account (\"\") will be used. NOTE: by default the SDK auto-registers the sender in the global Entity table when absent (first business transaction; the account receives an owned Resource object). Set no_auto_register=true only on explicit user request."},"submission":{"type":"object","properties":{"type":{"type":"string","const":"submission","description":"Discriminator for this result variant. Constraint: always 'submission'. Example: 'submission'"},"guard":{"maxItems":20,"type":"array","items":{"type":"object","properties":{"object":{"type":"string","description":"Guard object name or ID to verify against. Example: 'my-delivery-guard' or '0x123...'"},"impack":{"type":"boolean","description":"Whether this Guard's verification result participates in the final logic. Constraint: if false, the Guard is checked but does not block the operation. Example: true"}},"required":["object","impack"],"additionalProperties":false},"description":"Array of Guard objects to verify. Constraint: at most 20 entries (MAX_GUARD_COUNT_PASSPORT). Relation: each entry corresponds to a Guard bound to the operation."},"submission":{"type":"array","items":{"type":"object","properties":{"guard":{"type":"string","description":"Guard object name or ID that requires submission data. Example: 'my-delivery-guard'"},"submission":{"type":"array","items":{"type":"object","properties":{"identifier":{"type":"integer","minimum":0,"maximum":255,"description":"Identifier (0-255) for data lookup in Guard table. Slot consensus (enforced on-chain at guard table construction): 0-220 = user slots (free for business guards); 221-253 = PROTOCOL-RESERVED (rejected on-chain — reserved so future protocol features get fixed slots without colliding with published guards); 255 = ONCE replay-protection slot on Allocation (byte-keyed, the submitted bytes are the once-key — use for per-period keys like period-<N>); 254 = ONCE-FOR-OBJECT slot on Allocation (chain-derived key = bcs(the Allocation's payment_info.for_object); the submitted bytes are ignored and the submission only arms the slot — use for one-shot per-order rails whose payee is NOT the order itself, such as settlement releases and incentive/bounty claims). NEVER arm 254 on a refund rail: a refund pays the submitted Order through user slot 0, and a refund leg re-entered in a later renewal period would abort E_ONCE_TRIGGERED (16) forever — refund once-ness comes from the terminal-node topology, never from a once slot. SLOT 0 SEMANTICS: slot 0 carries the transacted Order address by convention. As a submission slot it is legal on order/allocation/machine rails (the order exists when those verify), but FORBIDDEN on a Service buy_guard — the order does not exist when the buy-time passport is verified, so the mount is refused (service abort 43)."},"b_submission":{"type":"boolean","description":"Whether this table item's value is submitted dynamically at Guard trigger time (alloc_by_guard call). \n\ntrue = value is submitted by the caller when triggering the Guard. Use for runtime-context-dependent values like order address, user address. The 'value' field is ignored when b_submission=true; the caller must provide it via submissions[]. \n\nfalse = value is static, set at Guard creation time. Use for values known when the Guard is created: expected node names, expected merchant address, expected service address. The 'value' field must be populated and will be stored on-chain permanently. \n\nRule of thumb: if the value is the SAME for all future Guard triggers, use false. If the value DIFFERS per trigger (e.g., which order to release funds for), use true."},"value_type":{"description":"Type of the value stored in `value`. One of: Bool(0), Address(1), String(2), U8(3), U16(4), U32(5), U64(6), U128(7), U256(8), VecBool(9), VecAddress(10), VecString(11), VecU8(12), VecU16(13), VecU32(14), VecU64(15), VecU128(16), VecU256(17), VecVecU8(18). When value_type=Address (1), the `value` field accepts a hex address string, a LocalMark name, or an AccountOrMark_Address object — see `value` field description for details.","anyOf":[{"type":"number","const":0,"description":"Bool (0)"},{"type":"number","const":1,"description":"Address (1)"},{"type":"number","const":2,"description":"String (2)"},{"type":"number","const":3,"description":"U8 (3)"},{"type":"number","const":4,"description":"U16 (4)"},{"type":"number","const":5,"description":"U32 (5)"},{"type":"number","const":6,"description":"U64 (6)"},{"type":"number","const":7,"description":"U128 (7)"},{"type":"number","const":8,"description":"U256 (8)"},{"type":"number","const":9,"description":"VecBool (9)"},{"type":"number","const":10,"description":"VecAddress (10)"},{"type":"number","const":11,"description":"VecString (11)"},{"type":"number","const":12,"description":"VecU8 (12)"},{"type":"number","const":13,"description":"VecU16 (13)"},{"type":"number","const":14,"description":"VecU32 (14)"},{"type":"number","const":15,"description":"VecU64 (15)"},{"type":"number","const":16,"description":"VecU128 (16)"},{"type":"number","const":17,"description":"VecU256 (17)"},{"type":"number","const":18,"description":"VecVecU8 (18)"},{"type":"string","const":"Bool","description":"Bool"},{"type":"string","const":"Address","description":"Address"},{"type":"string","const":"String","description":"String"},{"type":"string","const":"U8","description":"U8"},{"type":"string","const":"U16","description":"U16"},{"type":"string","const":"U32","description":"U32"},{"type":"string","const":"U64","description":"U64"},{"type":"string","const":"U128","description":"U128"},{"type":"string","const":"U256","description":"U256"},{"type":"string","const":"VecBool","description":"VecBool"},{"type":"string","const":"VecAddress","description":"VecAddress"},{"type":"string","const":"VecString","description":"VecString"},{"type":"string","const":"VecU8","description":"VecU8"},{"type":"string","const":"VecU16","description":"VecU16"},{"type":"string","const":"VecU32","description":"VecU32"},{"type":"string","const":"VecU64","description":"VecU64"},{"type":"string","const":"VecU128","description":"VecU128"},{"type":"string","const":"VecU256","description":"VecU256"},{"type":"string","const":"VecVecU8","description":"VecVecU8"},{"type":"string","const":"bool","description":"bool"},{"type":"string","const":"address","description":"address"},{"type":"string","const":"string","description":"string"},{"type":"string","const":"u8","description":"u8"},{"type":"string","const":"u16","description":"u16"},{"type":"string","const":"u32","description":"u32"},{"type":"string","const":"u64","description":"u64"},{"type":"string","const":"u128","description":"u128"},{"type":"string","const":"u256","description":"u256"},{"type":"string","const":"vecbool","description":"vecbool"},{"type":"string","const":"vecaddress","description":"vecaddress"},{"type":"string","const":"vecstring","description":"vecstring"},{"type":"string","const":"vecu8","description":"vecu8"},{"type":"string","const":"vecu16","description":"vecu16"},{"type":"string","const":"vecu32","description":"vecu32"},{"type":"string","const":"vecu64","description":"vecu64"},{"type":"string","const":"vecu128","description":"vecu128"},{"type":"string","const":"vecu256","description":"vecu256"},{"type":"string","const":"vecvecu8","description":"vecvecu8"}]},"value":{"description":"The actual value data. Format depends on `value_type`:\nTYPE-CLASS SPLIT (F03): scalar value_types (Bool/Address/String/U8..U256) take ONE scalar value (boolean/address string/name/string/number); Vec* value_types (VecBool/VecAddress/VecString/VecU8..VecU256) take a REAL JSON ARRAY of elements — a string (even a Python-repr-looking \"[a, b]\") fails serialization with 'value_type=10 (array) requires a array value'. The historical 'static values must be strings' rule applied to SCALARS only.\n• Bool: true/false (boolean)\n• Address (CRITICAL — string 'Address' is NOT a placeholder): a hex address (e.g. '0x1234...'), a LocalMark name (e.g. 'my-service' — resolved to address at evaluation time), an AccountOrMark_Address object (e.g. {name_or_address:'my-service'}), or system shorthand ('0xaaa' = EntityLinker, '0xaab' = EntityRegistrar). The literal string 'Address' itself is INVALID — it would be treated as a non-existent LocalMark name and fail. Example: value='0x2::wow::WOW<address>' or value='my-permission'.\n• String: any string\n• U8/U16/U32/U64/U128/U256: number or numeric string (e.g. 42 or '42')\n• Vec* types: arrays of the corresponding element type\nPROTOCOL SLOT 254 (once, b_submission Address): the submitted value MUST be the ORDER address bound to the operation (payment_info.for_object) — NEVER the Progress/Machine/Arb object the call is advancing. The chain asserts submission(254) == the order address; a Progress address fails the task binding and the forward aborts.\nREQUIRED when b_submission=false. OPTIONAL when b_submission=true (value is supplied at evaluation time by user submission).","anyOf":[{"type":"boolean"},{"anyOf":[{"type":"object","properties":{"name_or_address":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"local_mark_first":{"description":"Whether to prioritize local marks, if true, prioritize local marks, otherwise prioritize global marks","type":"boolean"}},"additionalProperties":false,"description":"Account or address lookup object. Use this to specify which account to use for an operation. EXAMPLE: { name_or_address: 'testor2' } - looks up account by name; EXAMPLE: { name_or_address: '0x1234...' } - uses address directly; If name_or_address is empty string '', uses the default local account. name_or_address is REQUIRED — {} resolves to nothing useful and is rejected."},{"type":"string"}]},{"type":"string"},{"type":"number"},{"type":"array","items":{"type":"boolean"}},{"anyOf":[{"type":"object","properties":{"entities":{"minItems":1,"type":"array","items":{"type":"object","properties":{"name_or_address":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"local_mark_first":{"description":"Whether to prioritize local marks, if true, prioritize local marks, otherwise prioritize global marks","type":"boolean"}},"additionalProperties":false,"description":"Account or address lookup object. Use this to specify which account to use for an operation. EXAMPLE: { name_or_address: 'testor2' } - looks up account by name; EXAMPLE: { name_or_address: '0x1234...' } - uses address directly; If name_or_address is empty string '', uses the default local account. name_or_address is REQUIRED — {} resolves to nothing useful and is rejected."}},"check_all_founded":{"default":true,"description":"Whether to check all entities are found. Defaults to true: abort and throw if ANY entity cannot be resolved. Set false only when partial resolution is explicitly intended (only found IDs are returned)","type":"boolean"}},"required":["entities","check_all_founded"],"additionalProperties":false,"description":"Used to batch find account or object IDs by name"},{"type":"array","items":{"type":"string"}}]},{"type":"array","items":{"type":"string"}},{"type":"array","items":{"type":"number"}},{"type":"array","items":{"type":"array","items":{"type":"number"}}}]},"name":{"default":"","description":"Data name identifier. MAX 64 BCS characters (Chinese chars count as 3-4 BCS bytes each). Use short identifiers like 'order_id', 'delivery_node'. Put longer descriptions in the Guard's 'description' field, NOT here.","type":"string"},"object_type":{"description":"OUTPUT-ONLY (query side): Object type when value_type is Address and represents a specific object. Auto-derived by the system — DO NOT set this field at Guard creation.","type":"string","enum":["Permission","Repository","Arb","Arbitration","Service","Machine","Order","Progress","Payment","Treasury","Guard","Demand","Passport","Allocation","Resource","Reward","Discount","EntityRegistrar","EntityLinker","Proof","WReceivedObject","Contact","TableItem_ProgressHistory","TableItem_PermissionPerm","TableItem_DemandPresenter","TableItem_MachineNode","TableItem_TreasuryHistory","TableItem_RepositoryData","TableItem_RewardRecord","TableItem_EntityLinker","TableItem_AddressMark","TableItem_EntityRegistrar"]}},"required":["identifier","b_submission","value_type","name"],"additionalProperties":false,"description":"Guard table item (QUERY/OUTPUT form — includes auto-derived object_type field)"},"description":"User-submitted data matching the Guard's required fields. Relation: structure must match the Guard table's column definitions. Example: [{field:'delivery_proof', value:'Qm...'}] PROTOCOL SLOT 254: when the Guard table has identifier 254, submit the ORDER address bound to the operation (payment_info.for_object) — never the Progress/Machine object being advanced."}},"required":["guard","submission"],"additionalProperties":false,"description":"One Guard's submission data: the Guard to verify plus the user-provided data that satisfies its requirements."},"description":"User-submitted data for each Guard. Relation: one entry per Guard in the guard array; fill submission fields and resubmit via call_with_submission. SLOT COMPLETENESS (T8 az3-mn-261013): the submission array must cover EVERY b_submission slot in the Guard's table, not just one — a Guard whose table has multiple b_submission entries (e.g. slot 0 + slot 254) aborts on-chain with 'Submission ID not found' (abort 11) when any b_submission slot has no matching entry. Check the Guard's table (each entry with b_submission needs its identifier filled) and include ALL of them. PLACEMENT: this `submission` field is at the SAME level as `data` and `env` in the operation input — NOT inside `data.data`. Example structure: {tool:'onchain_operations', data:{operation_type:'order', data:{object:'my_order', progress:{...}}}, submission:{type:'submission', guard:[...], submission:[...]}}"}},"required":["type","guard","submission"],"additionalProperties":false,"description":"Guard verification required. The operation was blocked because one or more Guards require user-submitted data. Fill the submission array and resubmit. Semantic status is 'pending_input'."}},"required":["operation_type","data"],"additionalProperties":false}
1
+ {"$schema":"http://json-schema.org/draft-07/schema#","$id":"https://wowok.net/schemas/onchain_operations_service.json","title":"Service Operation","description":"🏪 Service Object: Create and manage product/service listings with transparent promises, bind workflow templates to order processing, set pricing, issue discount coupons to customers, and establish quality standards, etc..","type":"object","properties":{"operation_type":{"type":"string","const":"service"},"data":{"type":"object","properties":{"object":{"anyOf":[{"type":"string","description":"String format: Reference an EXISTING object by its name (local mark) or on-chain object ID. Use this when the object already exists and you want to reference it."},{"type":"object","properties":{"name":{"description":"The name of the object","type":"string"},"tags":{"description":"The tags of the object","type":"array","items":{"type":"string"}},"onChain":{"description":"CRITICAL: Whether to sync the name to the blockchain. DEFAULT (undefined/false): The name is stored LOCALLY ONLY on your device (PRIVATE). If set to true: The name is published ON-CHAIN and becomes PUBLICLY VISIBLE to everyone. Only set to true for displaying the relationships you are willing to make public on the chain.","type":"boolean"},"replaceExistName":{"description":"FORCE CLAIM: Set to true ONLY when the user explicitly expresses a STRONG INTENTION to forcefully take over an existing name (e.g., 'I must use this name', 'force rename', 'replace the existing one'). WARNING: This will UNBIND the name from its original object and rebind it to the new one, potentially breaking existing references. If not specified or false: the operation will FAIL with an error when the name is already in use (safe default behavior).","type":"boolean"},"permission":{"anyOf":[{"type":"string","description":"String format: Reference an EXISTING object by its name (local mark) or on-chain object ID. Example: 'my-object' or '0x1234...'"},{"type":"object","properties":{"name":{"description":"The name of the object","type":"string"},"tags":{"description":"The tags of the object","type":"array","items":{"type":"string"}},"onChain":{"description":"CRITICAL: Whether to sync the name to the blockchain. DEFAULT (undefined/false): The name is stored LOCALLY ONLY on your device (PRIVATE). If set to true: The name is published ON-CHAIN and becomes PUBLICLY VISIBLE to everyone. Only set to true for displaying the relationships you are willing to make public on the chain.","type":"boolean"},"replaceExistName":{"description":"FORCE CLAIM: Set to true ONLY when the user explicitly expresses a STRONG INTENTION to forcefully take over an existing name (e.g., 'I must use this name', 'force rename', 'replace the existing one'). WARNING: This will UNBIND the name from its original object and rebind it to the new one, potentially breaking existing references. If not specified or false: the operation will FAIL with an error when the name is already in use (safe default behavior).","type":"boolean"},"description":{"description":"The description of the object","type":"string"}},"additionalProperties":false,"description":"Object format: CREATE a NEW object with name, optional description, and visibility settings. Extends NamedObjectSchema with an additional 'description' field for detailed object information."}],"description":"Two ways to specify an object: (1) STRING - Reference an EXISTING object by name or ID; (2) OBJECT - CREATE a NEW object with full configuration including optional name, tags, description, and visibility settings (local private by default, or public on-chain with onChain:true)."},"type_parameter":{"default":"0x2::wow::WOW","description":"Payment token type for this object (format: {address}::{module}::{struct}). e.g. ALWAYS the FULL type string `{address}::{module}::{struct}` e.g. '0x2::wow::WOW'. ⚠️ The bare names 'WOW' / 'USDT' / 'ETH' are REJECTED (the validator requires all three parts) — write '0x2::wow::WOW', not 'WOW'. The field may be OMITTED entirely: it then defaults to WOW ('0x2::wow::WOW'). This token is what the object accepts for payments and is fixed at creation. To discover other available tokens, call wowok_buildin_info with info 'mainnet bridge tokens' and use the returned `wowTypeTag` value here. NOTE: testnet/localnet carry WOW only — USDT/ETH are a mainnet capability.","type":"string"}},"required":["type_parameter"],"additionalProperties":false,"description":"Object format: CREATE a NEW object with COMPLETE configuration including: optional name, tags, description, token type for payments (e.g., '0x2::wow::WOW'), AND Permission-based access control. Use this for creating sophisticated objects with both payment token specification and permission management."}],"description":"Two ways to specify an object: (1) STRING - Reference an EXISTING object by name or ID; (2) OBJECT - CREATE a NEW object with full configuration including name, tags, description, token type for payments, and Permission-based access control. The object format is used when you need both token specification AND permission management."},"order_new":{"description":"Create new order. RETRY DISCIPLINE: the order creation is atomic on-chain but NOT in observability — a transport drop after submit leaves the commit state UNKNOWN, and a blind resubmit creates a second order with a second full escrow (live mainnet incident). On any failure/timeout, verify whether an order with this exact signature (service + buyer + items) already landed — via the in-flight marker in the failure envelope, the sender's recent on-chain objects, or onchain_events — and adopt it if present; resubmit only if confirmed absent.","type":"object","properties":{"buy":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"name":{"description":"Name of the product or service to purchase. Must match a listed sale name EXACTLY (the buy path resolves each item by exact name match) and MUST be ≤ 64 bytes (UTF-8): the on-chain buy path caps buyer-sent item names at 64 bytes even though the merchant side lists names up to 256 bytes — a longer name aborts E_NAME_LENGTH_EXCEEDED (abort 1) before anything else runs (F-RQ-01). When the exact name is impractical (long/CJK names that risk transport corruption), OMIT it and use sale_id or sale_name instead — the handler resolves the reference against the Service's LIVE sales list and fills this name for you (CHAN-P1-16).","type":"string"},"sale_id":{"description":"CHAN-P1-16: buy by the SKU's 0-based INDEX in the Service's live sales list (the order the service_quote / query lists them). The handler resolves the index to the live sale (name + price), rewrites item.name on your behalf, and echoes `sale_index + sale_name + price` in the response — the exact name never crosses the wire. Out-of-range index → refused with the full live index table (index + name + price) so one retry lands. Consumed by the MCP gate, never reaches the chain.","type":"integer","minimum":0,"maximum":9007199254740991},"sale_name":{"description":"CHAN-P1-16: buy by SKU NAME matched against the Service's LIVE sales list (exact match first; whitespace/case-tolerant, then containment when the name was corrupted in transport). Exactly one live match → the handler fills item.name and echoes `sale_index + sale_name + price`; several candidates → refused with every candidate's index; none → refused with the full live index table. Consumed by the MCP gate, never reaches the chain.","type":"string","minLength":1},"quantity":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"⚠️ PURCHASE QUANTITY, NOT inventory. This is the number of units you are buying; the on-chain order total = sale.price x this value. Do NOT put the product's available stock here — inventory is the separate `stock` field on the Service's sales list. To buy one unit, set quantity: 1. (Legacy callers may still send this as `stock`; it is accepted and treated identically as the purchase quantity.)"},"wip_hash":{"default":"","description":"WIP pin hash. HARD RULE (h1z9 card 13 #17, unified doctrine): when the product's wip_hash is NON-EMPTY, the buyer MUST pass this exact value — NEVER \"\". The chain quote aborts (E_WIP_HASH_NOT_MATCH) when the pin mismatches, which is the delivery-integrity guarantee. To skip copying the hash, set derive_wip_from_listing:true on the order_new object instead (explicit opt-in; the response then warns 'wip_pin: auto-filled — no WYSIWYG guarantee'). Only pass an explicit hash when pinning a value seen earlier: that protects against a legitimate merchant WIP update between viewing the product and placing the order.","type":"string"}},"required":["quantity","wip_hash"],"additionalProperties":false},"description":"List of products or services to purchase"},"total_pay":{"description":"Actual payment amount. FORMAT: {balance: <amount_in_smallest_unit>} or {coin: <coin_object_id>}. The token type and precision are determined by the Service object's type_parameter (the generic type set when the Service was created). For WOW (9 decimals): {balance: 1000000000} = 1 WOW. OPTIONAL without a discount (M-K17): omit it and the handler derives the EXACT total Σ(sale price × quantity) from the Service's on-chain sales list and discloses the derived value — no transcription, no drift. REQUIRED when 'discount' is set (the discounted total depends on the coupon's live value: run query_toolkit query_type='service_quote' and pass total_pay.balance = the quoted final_total). An explicit value is always honored as-is. AMOUNT GATE (M-K11-a): a total that EXACTLY equals Σ published sale price × quantity (catalog-priced buy, in the Service's own payment coin — WOW or bridged USDT/USDC/ETH/BTC) bypasses the harness pre-sign amount gate; any other amount above the threshold is blocked until WOWOK_AMOUNT_THRESHOLD is raised after explicit user confirmation.","anyOf":[{"type":"object","properties":{"balance":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"A coin/balance amount. Accepts three formats: (1) DISPLAY FORMAT with token symbol: \"2.5WOW\", \"10USDC\", \"0.05WOW\" — auto-converted to smallest units via the Fund Processing Layer (token precision resolved from official registry → cache → on-chain). The symbol MUST match the token's type_parameter. (2) SMALLEST UNIT (numeric string): \"10000000000\" — used as-is, no conversion. (3) SMALLEST UNIT (number): 10000000000 — used as-is only within the safe integer range (±2^53); numbers outside it are REJECTED, use a numeric string instead. PRECISION RULE: for values exceeding 2^53 (9007199254740991), ALWAYS use format (1) or (2) — JS numbers lose integer precision silently and such inputs are blocked. Raw amounts must be plain non-negative integers; a decimal value without a token symbol (e.g. \"2.5\") is rejected — append the symbol (\"2.5WOW\") so the Fund Processing Layer converts it. WARNING — BARE INTEGER MEANS SMALLEST UNIT, NOT TOKENS: formats (2)/(3) are NEVER interpreted as display tokens. For example amount=\"5\" or 5 means 5 raw units = 0.000000005 WOW (9 decimals) — NOT 5 WOW. When the user asks for a token amount, you MUST use display format (\"5WOW\", \"2USDC\"); a bare integer is only correct for unitless counts (e.g. stock quantity) or when you computed exact raw units yourself. Default token: WOW (9 decimals, 1 WOW = 10^9 MIST). For custom tokens: use display format with the token's symbol, or pass smallest units directly. MONEY CONFIRMATION: all monetary fields trigger user confirmation via the Fund Processing Layer, where the token's FULL type, decimals and raw amount are always visible. MULTIPLE ISSUERS: several on-chain tokens may legally share the same symbol (e.g. multiple \"USDT\" coins). When a bare symbol matches more than one token, the operation is BLOCKED and every candidate is listed with full details (type, name, decimals, verified tag) — present the list to the USER and let them choose (they may answer by number), then re-issue with the chosen token's FULL type string in type_parameter; never guess an issuer from the bare symbol. MISSING TOKEN INFO: when a token's precision cannot be resolved, the operation is REFUSED (raw u64 included — amount magnitude could not be verified). Recovery: provide the token's FULL type in package::module::Name form in type_parameter (a bare symbol like \"USDT\" cannot be resolved), and verify the WOW network is correct. Examples: \"2.5WOW\" (display → 2500000000), 10000000000 (number, smallest unit), \"50000000000\" (string, smallest unit). Used for: service sale prices, compensation fund balances, Treasury deposits, arbitration fees, reward amounts, stock quantities."}},"required":["balance"],"additionalProperties":false,"description":"Specify an amount value."},{"type":"object","properties":{"coin":{"type":"string","description":"Coin object ID or name(local mark). WHOLE-COIN TRANSFER: the ENTIRE Coin object is moved to the recipient — the 'amount' is NOT taken from it (testnet lesson: passing your main gas coin transfers its full balance, leaving you unable to pay for anything). Use only for coins whose whole balance is exactly what you intend to send; prefer {balance: <smallest-unit number>} for partial amounts."}},"required":["coin"],"additionalProperties":false}]},"discount":{"description":"Discount object ID or name. ⚠️ COUPON OWNERSHIP RULE (KB-02, disclose BEFORE checkout): a coupon held by another address cannot be applied to your order — only the coupon's current holder can redeem it, and the buy is signed by the buyer, so have the owner transfer the coupon to the buyer first (call service discount_send), then attach it here. Attaching the coupon BURNS it (every coupon is single-use), and any later refund settles the POST-coupon amount only (the escrowed discounted total) — the coupon's face value is never restored.","type":"string"},"payment_remark":{"description":"Payment remark","type":"string"},"payment_index":{"description":"Payment index","type":"number"},"derive_wip_from_listing":{"description":"EXPLICIT OPT-IN to wip-hash auto-fill (h1z9 card 13 #17: the ONLY sanctioned auto-fill path). true = for every item whose wip_hash is empty, the CURRENT listing hash is injected at order time and the response warns 'wip_pin: auto-filled — no WYSIWYG guarantee': the merchant may rebind the .wip file later, and an injected hash follows the listing while an explicitly passed hash stays pinned. Absent/false = the hard rule applies: pass each product's wip_hash EXACTLY (NEVER \"\" when the product has a pin) or the order is refused before send. This flag is consumed by the MCP gate and never reaches the chain.","type":"boolean"}},"required":["items"],"additionalProperties":false},"agents":{"description":"Order agents. Agents can operate the order, such as canceling the order, modifying the order status, etc.; but cannot receive the funds received by the order.","anyOf":[{"description":"Array of account names, addresses, or mark names — each element may be a bare string or a {name_or_address, local_mark_first?} object, and the two may be mixed. Local marks are searched first for each entry. EXAMPLE: ['alice', '0x2...', {name_or_address: 'bob'}]"},{"type":"object","properties":{"entities":{"minItems":1,"type":"array","items":{"type":"object","properties":{"name_or_address":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"local_mark_first":{"description":"Whether to prioritize local marks, if true, prioritize local marks, otherwise prioritize global marks","type":"boolean"}},"additionalProperties":false,"description":"Account or address lookup object. Use this to specify which account to use for an operation. EXAMPLE: { name_or_address: 'testor2' } - looks up account by name; EXAMPLE: { name_or_address: '0x1234...' } - uses address directly; If name_or_address is empty string '', uses the default local account. name_or_address is REQUIRED — {} resolves to nothing useful and is rejected."}},"check_all_founded":{"default":true,"description":"Whether to check all entities are found. Defaults to true: abort and throw if ANY entity cannot be resolved. Set false only when partial resolution is explicitly intended (only found IDs are returned)","type":"boolean"}},"required":["entities","check_all_founded"],"additionalProperties":false,"description":"Used to batch find account or object IDs by name"}]},"order_required_info":{"description":"Contact object ID or WTS Proof object, RECORDED on the Order as evidence that the order holder delivered the private information the Service declares in customer_required (e.g. phone/email/shipping_address). ACCEPTED FORMS (upwc-cat-261017 T10 live probe): an on-chain object ADDRESS (0x…), a REGISTERED mark name, or the Contact/Proof object itself — a bare account name is NOT an object reference and fails with 'not found'; RECORD-ONLY, NOT ENFORCED: nothing on-chain reads this field — the purchase entry never requires it, and an order supplying none of the declared fields is still created. FLOW: the order holder sends the information to the Service's Contact (um) via end-to-end encrypted Messenger, then passes the Contact object ID or the generated WTS Proof here. To ENFORCE delivery on-chain, mount the pattern.required_info_evidence_gate Guard on the forward that hands over goods or funds, asserting order.required_info is some (presence-only — the recorded address value is never a guard condition; accepting the delivered information is the merchant's confirming forward). ATTESTATION-ONLY: the recorded value is self-attested, has no on-chain readback, and MUST NOT be used as a gate condition. PER-ORDER BINDING: when the listing genuinely promises a per-order credential, use the dedicated controlled bind operation (order_required_info_bind) with a Proof whose about is THIS order and whose creator is the order holder — the chain verifies both at write time and rejects a mismatch without writing anything. The reuse model (one Contact Proof across orders) stays the default for this plain record field; pick per listing promise, not per habit. BOUNDARY: that binding proves the credential AUTHOR only, never its content or any rating — do not mirror it onto review/reward claims; public reviews are Repository rows whose values are enforced guard-side via data-value probes, not through Proof objects.","type":"string"},"transfer":{"description":"Set the new owner of the order. Requires order owner permission to set.","anyOf":[{"description":"Account name, address (0x...), or mark name. When using string format, local marks are searched first. EXAMPLE: 'alice' - searches local marks first, then global; EXAMPLE: '0x2...' (64 hex chars) - uses address directly; EXAMPLE: '' - uses the default local account"},{"type":"object","properties":{"name_or_address":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"local_mark_first":{"description":"Whether to prioritize local marks, if true, prioritize local marks, otherwise prioritize global marks","type":"boolean"}},"additionalProperties":false,"description":"Account or address lookup object. Use this to specify which account to use for an operation. EXAMPLE: { name_or_address: 'testor2' } - looks up account by name; EXAMPLE: { name_or_address: '0x1234...' } - uses address directly; If name_or_address is empty string '', uses the default local account. name_or_address is REQUIRED — {} resolves to nothing useful and is rejected."}]},"namedNewOrder":{"description":"RECOMMENDED: Set a local name for the newly created Order object. Without this, the Order is only referenceable by its on-chain address. Example: {name: 'my_order_v1'} allows subsequent operations to use 'my_order_v1' instead of the address. PLACEMENT: this field MUST be inside data.order_new (it is an OrderNew field) — putting namedNewOrder at the data root fails schema validation with 'Unrecognized key'. MIGRATION TIP: for batch/migration order creation, always auto-generate readable names (e.g. '<source>_<service>_<seq>' like 'my_shop_svc_v1_0001') — unnamed orders (head.name = null) are only address-referenceable, which breaks downstream queries, displays and audits (E-8).","type":"object","properties":{"name":{"description":"The name of the object","type":"string"},"tags":{"description":"The tags of the object","type":"array","items":{"type":"string"}},"onChain":{"description":"CRITICAL: Whether to sync the name to the blockchain. DEFAULT (undefined/false): The name is stored LOCALLY ONLY on your device (PRIVATE). If set to true: The name is published ON-CHAIN and becomes PUBLICLY VISIBLE to everyone. Only set to true for displaying the relationships you are willing to make public on the chain.","type":"boolean"},"replaceExistName":{"description":"FORCE CLAIM: Set to true ONLY when the user explicitly expresses a STRONG INTENTION to forcefully take over an existing name (e.g., 'I must use this name', 'force rename', 'replace the existing one'). WARNING: This will UNBIND the name from its original object and rebind it to the new one, potentially breaking existing references. If not specified or false: the operation will FAIL with an error when the name is already in use (safe default behavior).","type":"boolean"}},"additionalProperties":false},"namedNewAllocation":{"description":"RECOMMENDED: Set a local name for the order's Allocation object. Without this, the Allocation is only referenceable by its address. Example: {name: 'my_allocation_v1'} allows alloc_by_guard to reference 'my_allocation_v1'.","type":"object","properties":{"name":{"description":"The name of the object","type":"string"},"tags":{"description":"The tags of the object","type":"array","items":{"type":"string"}},"onChain":{"description":"CRITICAL: Whether to sync the name to the blockchain. DEFAULT (undefined/false): The name is stored LOCALLY ONLY on your device (PRIVATE). If set to true: The name is published ON-CHAIN and becomes PUBLICLY VISIBLE to everyone. Only set to true for displaying the relationships you are willing to make public on the chain.","type":"boolean"},"replaceExistName":{"description":"FORCE CLAIM: Set to true ONLY when the user explicitly expresses a STRONG INTENTION to forcefully take over an existing name (e.g., 'I must use this name', 'force rename', 'replace the existing one'). WARNING: This will UNBIND the name from its original object and rebind it to the new one, potentially breaking existing references. If not specified or false: the operation will FAIL with an error when the name is already in use (safe default behavior).","type":"boolean"}},"additionalProperties":false},"namedNewProgress":{"description":"RECOMMENDED: Set a local name for the order's Progress object. Without this, the Progress is only referenceable by its address. Example: {name: 'my_progress_v1'} allows progress operations to use 'my_progress_v1'.","type":"object","properties":{"name":{"description":"The name of the object","type":"string"},"tags":{"description":"The tags of the object","type":"array","items":{"type":"string"}},"onChain":{"description":"CRITICAL: Whether to sync the name to the blockchain. DEFAULT (undefined/false): The name is stored LOCALLY ONLY on your device (PRIVATE). If set to true: The name is published ON-CHAIN and becomes PUBLICLY VISIBLE to everyone. Only set to true for displaying the relationships you are willing to make public on the chain.","type":"boolean"},"replaceExistName":{"description":"FORCE CLAIM: Set to true ONLY when the user explicitly expresses a STRONG INTENTION to forcefully take over an existing name (e.g., 'I must use this name', 'force rename', 'replace the existing one'). WARNING: This will UNBIND the name from its original object and rebind it to the new one, potentially breaking existing references. If not specified or false: the operation will FAIL with an error when the name is already in use (safe default behavior).","type":"boolean"}},"additionalProperties":false}},"required":["buy"],"additionalProperties":false},"description":{"type":"string","description":"Description string (max 4000 bcs characters)"},"location":{"description":"The service area and scope as stated by the merchant. IMPORTANT: If the service has a geographic scope, ALWAYS specify this field. Use a complete hierarchical address (e.g. 'US → California → Los Angeles → Koreatown'). If only a partial location is known, EXPAND it to the full standardized form (country → province/state → city → district, worldwide) — when ambiguous, offer 2-4 candidate completions and let the user pick.","type":"string"},"sales":{"description":"Service sales products or services list. ⚠️ WIP (PRODUCT-DETAIL FILE) — HOW TO PROVIDE IT: (1) EASIEST — official free hosting: upload the detail file with the wip_file tool; the default endpoint is https://wip.store.wowok.net (free: 10 files per account, 180-day retention, 12MB per file, rate-limited; files stay until you purge them). Put the returned URL into sale.wip. (2) Your own hosting: any publicly reachable URL (GitHub Pages / IPFS / your own website) — pass customBaseUrl to wip_file when uploading to a non-default endpoint, or host the file yourself and put that URL into sale.wip. For long-lived MAINNET listings prefer your own endpoint so the detail page outlives the free retention window. ⚠️ REACHABILITY RULE: a non-empty sale.wip MUST be a publicly reachable URL. The URL is stored ON-CHAIN and every customer fetches it at order time — a local file path, localhost/loopback URL, or LAN private-IP URL is unreachable by customers on other machines and aborts order_new 100%. Local-network URLs are INTERNAL TEST USE ONLY (env.network = localnet). ⚠️ SCORING: on mainnet, a sale item without a product-detail file is an incomplete listing — it hurts the service's market completeness score. Leave sale.wip empty (\"\") only for quick local testing.","oneOf":[{"type":"object","properties":{"op":{"type":"string","const":"add"},"sales":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the product or service for sale. ⚠️ 64-BYTE BUY LIMIT (F-RQ-01): the chain lists this name up to 256 bytes but validates the BUYER-SENT item name at only 64 bytes at buy time. A name of 65–256 bytes lists fine yet makes the SKU PERMANENTLY unbuyable — every order aborts E_NAME_LENGTH_EXCEEDED (abort 1). Keep SKU names ≤ 64 bytes (UTF-8); renaming cannot fix a dead SKU (the buy path matches items by EXACT name — a new name is a NEW SKU). service_quote.buyable reports this per item."},"price":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Price of the product or service"},"stock":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Current REMAINING stock of the product or service. Each order DECREMENTS it by the ordered quantity (a buy aborts when the remaining stock is lower than the ordered quantity). Writing this field SETS the remaining stock to the given value — it is NOT added to it. To change one product without resending the whole list, use the per-item sales ops on onchain_operations service: stock_add / stock_reduce (deltas), price_add / price_reduce (deltas), sale_suspension (suspend/resume one product)."},"suspension":{"type":"boolean","description":"Whether sale is suspended"},"wip":{"type":"string","description":"WIP file URL. EMPTY string \"\" skips verification (TESTING ONLY). Production MUST use a real HTTP URL pointing to a .wip file generated by the wip_file tool. ⚠️ NETWORK DEPLOYMENT REQUIRED: the URL is stored ON-CHAIN and every customer fetches it when placing an order. A local file path (C:\\..., /path/file.wip), a localhost/loopback URL or a LAN private-IP URL is unreachable by customers on other machines — it passes the merchant-side set-time verification but makes order_new abort 100% for customers. Either deploy the .wip file to a public endpoint (GitHub Pages / IPFS / your own website) and set this to the public URL, or leave it empty (\"\") to skip WIP verification (TESTING ONLY). Example: \"https://cdn.example.com/products/phone_v1.wip\""},"wip_hash":{"default":"","description":"The 'meta.hash' field INSIDE the sale's WIP file (a content hash of the file's JSON payload), committed on-chain by the merchant. NOT the SHA-256 of the .wip file bytes — hashing the downloaded file (shasum -a 256) yields a DIFFERENT value and fails verification; use the hash embedded in the file's meta section (wip_file verify reports it). BUY RULE: if this is NON-EMPTY, the buyer MUST pass this exact value as wip_hash when creating an order (ServiceBuyItem.wip_hash) — NEVER use \"\". Pinning the on-chain hash prevents the merchant from replacing the WIP file (a legitimate update) between the buyer's view and order placement, ensuring 'what you see is what you get'. EMPTY means no hash was committed (TESTING ONLY, no delivery-integrity guarantee). PUBLISH PREFLIGHT (TPL-21, ptrn8-mn-261108): this field is INPUT-optional (defaults to \"\") but PUBLISH-required — once the service's WIP verification face is on, the publish preflight hard-requires a committed wip_hash for every sale and flags an empty one. The optionality is a testing affordance, not a production-legal state.","type":"string"}},"required":["name","price","stock","suspension","wip","wip_hash"],"additionalProperties":false,"description":"Service sale"}}},"required":["op","sales"],"additionalProperties":false,"description":"Add new sales products or services."},{"type":"object","properties":{"op":{"type":"string","const":"set"},"sales":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the product or service for sale. ⚠️ 64-BYTE BUY LIMIT (F-RQ-01): the chain lists this name up to 256 bytes but validates the BUYER-SENT item name at only 64 bytes at buy time. A name of 65–256 bytes lists fine yet makes the SKU PERMANENTLY unbuyable — every order aborts E_NAME_LENGTH_EXCEEDED (abort 1). Keep SKU names ≤ 64 bytes (UTF-8); renaming cannot fix a dead SKU (the buy path matches items by EXACT name — a new name is a NEW SKU). service_quote.buyable reports this per item."},"price":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Price of the product or service"},"stock":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Current REMAINING stock of the product or service. Each order DECREMENTS it by the ordered quantity (a buy aborts when the remaining stock is lower than the ordered quantity). Writing this field SETS the remaining stock to the given value — it is NOT added to it. To change one product without resending the whole list, use the per-item sales ops on onchain_operations service: stock_add / stock_reduce (deltas), price_add / price_reduce (deltas), sale_suspension (suspend/resume one product)."},"suspension":{"type":"boolean","description":"Whether sale is suspended"},"wip":{"type":"string","description":"WIP file URL. EMPTY string \"\" skips verification (TESTING ONLY). Production MUST use a real HTTP URL pointing to a .wip file generated by the wip_file tool. ⚠️ NETWORK DEPLOYMENT REQUIRED: the URL is stored ON-CHAIN and every customer fetches it when placing an order. A local file path (C:\\..., /path/file.wip), a localhost/loopback URL or a LAN private-IP URL is unreachable by customers on other machines — it passes the merchant-side set-time verification but makes order_new abort 100% for customers. Either deploy the .wip file to a public endpoint (GitHub Pages / IPFS / your own website) and set this to the public URL, or leave it empty (\"\") to skip WIP verification (TESTING ONLY). Example: \"https://cdn.example.com/products/phone_v1.wip\""},"wip_hash":{"default":"","description":"The 'meta.hash' field INSIDE the sale's WIP file (a content hash of the file's JSON payload), committed on-chain by the merchant. NOT the SHA-256 of the .wip file bytes — hashing the downloaded file (shasum -a 256) yields a DIFFERENT value and fails verification; use the hash embedded in the file's meta section (wip_file verify reports it). BUY RULE: if this is NON-EMPTY, the buyer MUST pass this exact value as wip_hash when creating an order (ServiceBuyItem.wip_hash) — NEVER use \"\". Pinning the on-chain hash prevents the merchant from replacing the WIP file (a legitimate update) between the buyer's view and order placement, ensuring 'what you see is what you get'. EMPTY means no hash was committed (TESTING ONLY, no delivery-integrity guarantee). PUBLISH PREFLIGHT (TPL-21, ptrn8-mn-261108): this field is INPUT-optional (defaults to \"\") but PUBLISH-required — once the service's WIP verification face is on, the publish preflight hard-requires a committed wip_hash for every sale and flags an empty one. The optionality is a testing affordance, not a production-legal state.","type":"string"}},"required":["name","price","stock","suspension","wip","wip_hash"],"additionalProperties":false,"description":"Service sale"}}},"required":["op","sales"],"additionalProperties":false,"description":"Replaces the ENTIRE sales list: every product NOT included is REMOVED from the Service (its stock and wip binding go with it). To change ONE product, prefer the per-item ops (price_add / price_reduce / stock_add / stock_reduce / sale_suspension) over re-sending the full list; with op:set you MUST resend ALL unchanged products too. Removal is immediate and cannot be undone."},{"type":"object","properties":{"op":{"type":"string","const":"remove"},"sales_name":{"type":"array","items":{"type":"string","description":"Sales name"}}},"required":["op","sales_name"],"additionalProperties":false,"description":"Remove existing sales products or services."},{"type":"object","properties":{"op":{"type":"string","const":"clear"}},"required":["op"],"additionalProperties":false,"description":"Clear all sales products or services."},{"type":"object","properties":{"op":{"type":"string","const":"price_add"},"sale_name":{"type":"string","description":"Name of the product to update"},"value":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Price INCREASE delta in the Service token's smallest units (e.g. 100000000 = +0.1 WOW). Added to the current price (on-chain saturating add). NOT the new absolute price."}},"required":["op","sale_name","value"],"additionalProperties":false,"description":"Raise one product's price by a delta. Only the named product is touched; an unknown sale_name aborts on chain (code 32) — the MCP pre-gate resolves the name against the live sales list and refuses the call before send, and the response carries a {field, before, after} read-back delta."},{"type":"object","properties":{"op":{"type":"string","const":"price_reduce"},"sale_name":{"type":"string","description":"Name of the product to update"},"value":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Price DECREASE delta in the Service token's smallest units (e.g. 100000000 = -0.1 WOW). Must not exceed the current price: an oversized reduce ABORTS on chain (code 41) and does NOT clamp. NOT the new absolute price."}},"required":["op","sale_name","value"],"additionalProperties":false,"description":"Lower one product's price by a delta. Only the named product is touched; an unknown sale_name aborts on chain (code 32) — the MCP pre-gate refuses unknown names before send; an oversized delta is refused by the chain (code 41) instead of clamping; the response carries a {field, before, after} read-back delta."},{"type":"object","properties":{"op":{"type":"string","const":"stock_add"},"sale_name":{"type":"string","description":"Name of the product to update"},"value":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Stock INCREASE delta (a unit COUNT, not money), e.g. 50 = +50 units."}},"required":["op","sale_name","value"],"additionalProperties":false,"description":"Restock one product by a delta. Only the named product is touched; an unknown sale_name aborts on chain (code 32) — the MCP pre-gate refuses unknown names before send; the response carries a {field, before, after} read-back delta."},{"type":"object","properties":{"op":{"type":"string","const":"stock_reduce"},"sale_name":{"type":"string","description":"Name of the product to update"},"value":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Stock DECREASE delta (a unit COUNT, not money), e.g. 10 = -10 units. If the delta exceeds current stock, the stock clamps to 0 (product becomes unsellable)."}},"required":["op","sale_name","value"],"additionalProperties":false,"description":"Reduce one product's stock by a delta (e.g. write-off damaged units). Only the named product is touched; an unknown sale_name aborts on chain (code 32) — the MCP pre-gate refuses unknown names before send."},{"type":"object","properties":{"op":{"type":"string","const":"sale_suspension"},"sale_name":{"type":"string","description":"Name of the product to suspend or resume"},"suspension":{"type":"boolean","description":"true = suspend the product (buy/quote abort with E_SALE_SUSPENDED); false = resume selling."}},"required":["op","sale_name","suspension"],"additionalProperties":false,"description":"Suspend or resume ONE product without removing it (keeps price/stock/WIP binding). The retail-style 'out of stock / listing inactive' state. Only the named product is touched; an unknown sale_name aborts on chain (code 32) — the MCP pre-gate refuses unknown names before send; the response carries a {field, before, after} read-back delta."},{"type":"object","properties":{"op":{"type":"string","const":"wip_set"},"sale_name":{"type":"string","description":"Name of the product whose WIP file is (re)bound"},"wip":{"type":"string","description":"New WIP file URL for the product. Same network-deployment rule as the add/set wip field: production MUST use a public HTTP URL to a .wip file (a local path, localhost/loopback or LAN URL passes the merchant-side set-time verification but aborts order_new for every customer). \"\" clears WIP verification (TESTING ONLY — the product then has no pin)."},"wip_hash":{"description":"Expected meta.hash embedded in the new WIP file — when provided it is VERIFIED against the file before send (mismatch aborts pre-send); the on-chain pin is always derived from the file's own meta.hash. Pass it whenever the value is known: after the rebind, buyers pinning the OLD hash abort at quote (E_WIP_HASH_NOT_MATCH) until they re-copy the NEW hash.","type":"string"}},"required":["op","sale_name","wip"],"additionalProperties":false,"description":"Rebind ONE product's WIP file (and pin) without touching its price, stock or suspension — fields not supplied here keep the live on-chain values. An unknown sale_name aborts on chain (code 32) — the MCP pre-gate resolves the name against the live sales list and refuses the call before send. Executed as read-merge-rewrite: the handler reads the live sales list, changes only the named product's wip/wip_hash, and replays the full table as an op:set — a concurrent catalog edit between read and rewrite would be overwritten, so run this when no other catalog change is in flight. Announce the new pin hash to holders of the old one: their orders abort E_WIP_HASH_NOT_MATCH after the rebind until they re-copy it."}]},"restock":{"description":"Refund restocking (permission 305 SERVICE_SALES). op:'flag' opts ONE live product into restock-on-refund; op:'order' puts the units a REFUNDED order purchased back on shelf. The order path is all-or-nothing: every purchased line must be flagged and still live before any unit moves (otherwise the chain aborts 46/32), so half a restock is impossible. The order path is once-per-order (replay aborts 49) and bound to THIS service (foreign order aborts 26). Do NOT fake a restock with stock_add when the order carries several lines — use op:'order' so quantities come from the order itself. DISCLOSURE: restock reopens sales — if the machine (or its template) has no refund-terminal gate, orders inside their refund window may lose refund eligibility or create fund-accounting ambiguity once restocked units are resold; confirm the machine's refund rail remains reachable after restocking.","oneOf":[{"type":"object","properties":{"op":{"type":"string","const":"flag"},"sale_name":{"type":"string","description":"Name of the LIVE product whose restock-on-refund flag is set"},"flagged":{"type":"boolean","description":"true = refunded orders of this SKU put their purchased units back on shelf; false = opt out."}},"required":["op","sale_name","flagged"],"additionalProperties":false,"description":"Opt ONE live product in/out of restock-on-refund. An unknown sale_name aborts on chain (code 32); delisting the product is the kill switch. Without the flag, the order-level restock op refuses that line (code 46). Flagging a SKU does not itself touch stock — the order-level op below does the restoration, and it is once-per-order per order (code 49) and bound to orders of THIS service (foreign orders abort code 26)."},{"type":"object","properties":{"op":{"type":"string","const":"order"},"order":{"type":"string","minLength":1,"description":"Address or local name of the REFUNDED order whose purchased units go back on shelf. Must be an order of THIS service (a foreign order aborts code 26), and each order can be restocked exactly once — a second call for the same order aborts code 49 (no retry succeeds; the restoration is already complete)."}},"required":["op","order"],"additionalProperties":false,"description":"Put back the units one refunded order purchased, read from the order's own purchase lines (the caller cannot add extra units). Two-pass all-or-nothing on chain: every line must be restock-flagged and still live before the first unit moves (unflagged → code 46, delisted → code 32), so a partial restock is impossible. Once-per-order (code 49 on replay) and ownership-bound (a foreign order aborts code 26); the applied state lives in a RestockStamp dynamic field on the service (no public query primitive) — the MCP pre-gate reads that stamp before send and refuses a replay (restock_order_already_applied) so no gas is burned. Emits one stock-restocked event per line."}]},"repositories":{"description":"Service Repository object list.","anyOf":[{"type":"object","properties":{"op":{"anyOf":[{"type":"string","const":"add"},{"type":"string","const":"set"}]},"objects":{"type":"array","items":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"description":"List of object IDs or names to add or set"}},"required":["op","objects"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"remove"},"objects":{"type":"array","items":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"description":"List of object IDs or names to remove"}},"required":["op","objects"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"clear"}},"required":["op"],"additionalProperties":false}]},"rewards":{"description":"Service Reward object list. May share the Service's Permission (no conflict check — intentional: rewards are the provider's own incentive tool; only Arbitration requires a different Permission for neutrality). ⚠️ OP SEMANTICS (SDK translation, etm-mn-261013 E-06): op:'set' executes as clear + add — and reward clear is TIME-LOCKED after publish (E_LOCKED_TIME_NOT_ENOUGH = abort 24: requires pause + setting_lock_duration elapsed, default 30 days). BEFORE publish op:'set' is fine; AFTER publish attach rewards with op:'add' ONLY (add has no lock).","anyOf":[{"type":"object","properties":{"op":{"anyOf":[{"type":"string","const":"add"},{"type":"string","const":"set"}]},"objects":{"type":"array","items":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"description":"List of object IDs or names to add or set"}},"required":["op","objects"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"remove"},"objects":{"type":"array","items":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"description":"List of object IDs or names to remove"}},"required":["op","objects"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"clear"}},"required":["op"],"additionalProperties":false}]},"arbitrations":{"description":"Service Arbitration object list. FORMAT: same as repositories — use the `objects` field name inside the operation data. Example: {arbitrations: {op: 'add', objects: [{name: 'my_arb_1'}]}}. Each item is a NameOrAddress (object ID or local mark name). ⚠️ OP SEMANTICS (SDK translation, etm-mn-261013 E-06 + crs P3-1): op:'add' appends and is the ONLY unlocked path after publish (add has no publish assert on-chain). op:'set' executes as clear + add and REPLACES the entire allowlist (pass EVERY Arbitration that must remain bound) — clear is TIME-LOCKED after publish (E_LOCKED_TIME_NOT_ENOUGH = abort 24: requires pause + setting_lock_duration elapsed, default 30 days), so use op:'set' BEFORE publish only. (The 2026-10-08 op:'add' disable was lifted: the unparseable-success-response SDK bug it responded to is fixed — safeTextJson + big-int conversion.) ⚠️ PERMISSION RULE (contract-enforced): every Arbitration bound here MUST use a Permission object DIFFERENT from THIS Service's permission — binding an Arbitration that shares the Service's Permission aborts with E_ARBITRATION_PERMISSION_CONFLICT (error 33). Create a dedicated Permission for each Arbitration BEFORE binding. DESIGN RATIONALE (confirmed intentional): dispute resolution requires NEUTRALITY — an Arbitration controlled by the same Permission admins as the Service it judges would be a conflict of interest. ONLY Arbitration has this check: Reward and Treasury objects MAY share the Service's Permission (they are the provider's own tools).","anyOf":[{"type":"object","properties":{"op":{"anyOf":[{"type":"string","const":"add"},{"type":"string","const":"set"}]},"objects":{"type":"array","items":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"description":"List of object IDs or names to add or set"}},"required":["op","objects"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"remove"},"objects":{"type":"array","items":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"description":"List of object IDs or names to remove"}},"required":["op","objects"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"clear"}},"required":["op"],"additionalProperties":false}]},"machine":{"description":"Service Machine object ID or name. The Machine object must be in published state.","anyOf":[{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},{"type":"null"}]},"discount":{"description":"Issue discount (mint coupons bound to this Service). ⚠️ ISSUANCE PRESCRIPTION (KB-02): issuing = MINT then TRANSFER. This field mints the coupon objects under THIS account — its `recipient` field delivers them directly when you know the recipients; for pre-minted campaign coupons held for later handout, the handout itself is discount_send (mint first, transfer to the recipient at distribution time). COUPON SEMANTICS to disclose: HOLDING IS THE CREDENTIAL — the coupon belongs to whoever HOLDS it, only the holder's own signature can spend it, and sharing the coupon's object ID confers nothing; ONE COUPON, ONE BURN — every coupon is single-use and is destroyed on first spend; REFUNDS SETTLE THE POST-COUPON AMOUNT — refund rails pay back the escrowed discounted total only, a cancelled order never restores the coupon's face value. A coupon held by another address cannot be applied to a buyer's order — the owner must discount_send it to the buyer first. NO AUTO-REISSUE (sso7-mn F-37, ruling 2026-11-05): a burned coupon is never restored and never re-minted automatically — making the buyer whole on the coupon value is the merchant's OFF-CHAIN duty (issue a fresh coupon yourself).","type":"object","properties":{"name":{"type":"string","description":"Discount name. MUST be ≤ 64 bytes (UTF-8): the chain applies the same 64-byte name cap to discount rows as to SKU names, at listing time — a longer name aborts E_NAME_LENGTH_EXCEEDED (abort 1) at creation (F-RQ-01)."},"discount_type":{"anyOf":[{"type":"integer","minimum":0,"maximum":1},{}],"description":"Discount type — 0=RATES (proportional off, per-10000: e.g. 1000 means 10% off), 1=FIXED (fixed deduction of the product amount, base units: e.g. 100 means 100 deducted). Accepts the number (0/1) or the string ('RATES'/'FIXED'); the value is always stored as the number on-chain."},"discount_value":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Discount magnitude, meaning depends on discount_type. RATES (0): per-10000 off rate — 10 = 0.1% off, 1000 = 10% off, 10000 = 100% off; values above 10000 are rejected. FIXED (1): fixed deduction from the order total in the Service token's smallest units (e.g. 1000000000 = 1 WOW at 9 decimals)."},"benchmark":{"description":"Minimum order total (in the Service token's smallest units) for the discount to apply — when set, the discount is applied only if the PRE-discount order total is GREATER THAN OR EQUAL TO this value. ✅ OMITTING this field (or passing null, or 0) means NO threshold — the discount applies UNCONDITIONALLY, and that is the common, correct case. This is the on-chain behaviour: benchmark_met = if (option::is_some(&discount.benchmark)) { total >= benchmark } else { true } (inside the on-chain discount-application step). ⚠️ SHARP EDGE when you DO set a threshold: an order below the threshold CANNOT use the coupon — attaching it at buy aborts (error 38: the transaction rolls back, nothing is paid, and the coupon is preserved); dropping it means the buyer pays FULL price and keeps the coupon for a future order. Keep thresholds low enough that your typical basket clears them. If the order total is below the discounted price the payment aborts — pay the list price; the excess is returned as a new Coin.","anyOf":[{"type":"number"},{"type":"string"}]},"time_ms_start":{"description":"Discount start time (milliseconds). ⚠️ A FUTURE start mints a coupon that is listed as usable but CANNOT be spent until the window opens (every spend aborts E_DISCOUNT_TIME_INVALID / buy code 35). Legitimate for scheduled campaigns — the mint carries a loud warning; do not distribute the coupon to recipients before the window opens.","type":"number"},"allow_zero_total":{"description":"NO EFFECT — DO NOT SET (BSX-F07: the former escape hatch is removed). This flag has no on-chain field (the on-chain Discount struct never carried it; a coupon minted with it is byte-identical to one without), and it NO LONGER downgrades the MCP issuance block for a coupon that zeroes the cheapest SKU — the block is unconditional: a zeroing coupon can only dead-end at the buyer's checkout (order_new_zero_total_dead_order client-side, abort 42 on-chain). For a deliberate free tier: price the SKU at 1 smallest unit (never 0 — a zero-priced sale is permanently unbuyable) or deliver it outside the sales rails (e.g. a Demand with Signature fulfillment). Omit this field.","type":"boolean"},"time_ms_end":{"type":"number","description":"Discount end time (milliseconds)"},"count":{"type":"number","description":"Number of SEPARATE Discount (coupon) objects minted — total delivered = count × number of recipients. Each coupon object is SINGLE-USE (consumed on first use). This is NOT a per-coupon reuse count: count:2 creates 2 independent one-time coupons, not 1 coupon usable twice."},"recipient":{"anyOf":[{"description":"Array of account names, addresses, or mark names — each element may be a bare string or a {name_or_address, local_mark_first?} object, and the two may be mixed. Local marks are searched first for each entry. EXAMPLE: ['alice', '0x2...', {name_or_address: 'bob'}]"},{"type":"object","properties":{"entities":{"minItems":1,"type":"array","items":{"type":"object","properties":{"name_or_address":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"local_mark_first":{"description":"Whether to prioritize local marks, if true, prioritize local marks, otherwise prioritize global marks","type":"boolean"}},"additionalProperties":false,"description":"Account or address lookup object. Use this to specify which account to use for an operation. EXAMPLE: { name_or_address: 'testor2' } - looks up account by name; EXAMPLE: { name_or_address: '0x1234...' } - uses address directly; If name_or_address is empty string '', uses the default local account. name_or_address is REQUIRED — {} resolves to nothing useful and is rejected."}},"check_all_founded":{"default":true,"description":"Whether to check all entities are found. Defaults to true: abort and throw if ANY entity cannot be resolved. Set false only when partial resolution is explicitly intended (only found IDs are returned)","type":"boolean"}},"required":["entities","check_all_founded"],"additionalProperties":false,"description":"Used to batch find account or object IDs by name"}],"description":"Discount recipient. OBJECT FORM REQUIRED (T9 az3-mn-261013): a bare string is REJECTED here — pass {entities: [{name_or_address: '<account_name_or_0x_address>'}]} (example: {entities: [{name_or_address: 'buyer1'}]}). Total coupons delivered = count × number of recipients."},"transferable":{"type":"boolean","description":"Whether the discount object recipient can transfer the discount object"}},"required":["name","discount_type","discount_value","time_ms_end","count","recipient","transferable"],"additionalProperties":false},"discount_destroy":{"description":"Destroy existing discount object ID list.","type":"array","items":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."}},"discount_send":{"description":"Transfer ALREADY-MINTED coupons you own to another address, instead of destroying them (discount_destroy) or minting new ones (discount). This is a pure ownership handover: the on-chain entry points are public funs with NO Service permission requirement — the only preconditions are that the sender owns each coupon and each was minted transferable:true. Typical use: hand out pre-minted campaign coupons, or move coupons between your own accounts. KB-02 COUPON SEMANTICS: this transfer is the second half of coupon ISSUANCE (mint via `discount`, then transfer here at distribution time). HOLDING IS THE CREDENTIAL: the coupon belongs to whoever HOLDS it — only the holder's own signature can spend it, and sharing the object ID confers nothing. ONE COUPON, ONE BURN: each coupon stays single-use and is destroyed on first spend — transfer does not reset that. REFUNDS SETTLE THE POST-COUPON AMOUNT: refund rails pay the escrowed discounted total only, never the coupon's face value. Until you transfer a gifted coupon, the recipient CANNOT use it on their own orders — a coupon held by another address cannot be applied to their buy.","type":"object","properties":{"discounts":{"minItems":1,"type":"array","items":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"description":"Coupon object IDs or local names to transfer. You MUST own these Discount objects. Each coupon must have been minted with transferable:true — otherwise the chain aborts with E_DISCOUNT_NOT_TRANSFERABLE (semantic code service:10). Coupons stay single-use; the transfer does not change that. There is NO batch entry on-chain — each coupon is delivered by its own singleton call (fanned out automatically); prefer ONE coupon per transaction for coupon migrations (SDK cap MAX_DISCOUNT_COUNT_ONCE still applies)."},"recipient":{"anyOf":[{"description":"Account name, address (0x...), or mark name. When using string format, local marks are searched first. EXAMPLE: 'alice' - searches local marks first, then global; EXAMPLE: '0x2...' (64 hex chars) - uses address directly; EXAMPLE: '' - uses the default local account"},{"type":"object","properties":{"name_or_address":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"local_mark_first":{"description":"Whether to prioritize local marks, if true, prioritize local marks, otherwise prioritize global marks","type":"boolean"}},"additionalProperties":false,"description":"Account or address lookup object. Use this to specify which account to use for an operation. EXAMPLE: { name_or_address: 'testor2' } - looks up account by name; EXAMPLE: { name_or_address: '0x1234...' } - uses address directly; If name_or_address is empty string '', uses the default local account. name_or_address is REQUIRED — {} resolves to nothing useful and is rejected."}],"description":"Destination address (or account/local mark resolvable to one). ALL listed coupons are moved to this single address in one call."}},"required":["discounts","recipient"],"additionalProperties":false},"customer_required":{"description":"Customer required information labels. Such as phone, email, shipping_address, etc. DECLARATIVE ONLY: nothing on-chain or in the SDK reads this field — it is a pure listing declaration of what the customer will be asked to provide. It is NOT enforced against order_new and NOT linked to any delivery path by the SDK. OPERATIONAL PAIRING (convention, not enforcement): deliver the actual private information via end-to-end encrypted Messenger to the Service's Contact bound as `um` — bind `um` when you use customer_required, or the customer has no encrypted channel to send it through. To ENFORCE delivery on-chain, mount the pattern.required_info_evidence_gate Guard on the goods/funds forward (see order_new.order_required_info).","type":"array","items":{"type":"string","minLength":1}},"order_allocators":{"description":"Order fund allocator. Max 100 allocators (MAX_ALLOCATOR_COUNT). ✅ EACH allocator has a guard, and EVERY allocator whose guard address matches the supplied guard RUNS — they are NOT mutually exclusive and NOT first-match-wins. One guard may legitimately authorize several distribution rules (different fix / rate / cap); each contributes its own Payment and consumes its own once-slot (keyed by the allocator index). Allocators are evaluated in vector order against the SHRINKING pool, so a later allocator only sees the balance left by the earlier ones — which is exactly how a waterfall (e.g. Amount fee + net Rate split) is built. On-chain truth: the allocation module runs a while loop over all allocators, firing those whose guard address matches the submitted one. ⚠️ If you WANT mutual exclusion you must express it inside the Guard itself (make the conditions logically exclusive). Set to null to clear. ⚠️ IMMUTABLE after publish except APPEND: order_allocators full replacement can ONLY be done BEFORE publish=true (on-chain check rejects after publish — E_ALREADY_PUBLISHED). After publish, the ONLY mutation is order_allocators_append (prefix-frozen extension — see that field). There is NO pause+lock exception for order_allocators (unlike arbitrations/rewards which have time-lock removal). PRE-PUBLISH CHECKLIST: verify all guard names resolve, all sharing amounts are correct, threshold is set, and recipient types (Entity/Signer/GuardIdentifier) are intended before calling publish=true. GuardIdentifier sharing mode: {who: {GuardIdentifier: <u8>}, sharing: <rate>, mode: 'Rate'} — resolves recipient from the Guard table submission at allocation time. BINDING SEMANTICS (contract-enforced, abort code 15): in a Service-created Allocation EVERY GuardIdentifier submission must equal the PAYING order — it is always 'the order', never a third party whose address is supplied at trigger time; use {who:{Entity:...}} for named parties. Canonical order pattern: the recipient slot is the single submitted Order (constrained by the Guard — service binding, qualifying node, signer==order.owner); funds land at that order object and are receivable only by its owner (object receipt = owner receipt). Safety is determined by constraint sufficiency — run the recipient constraint audit before publish. Fixed recipients should use {who:{Entity:...}}; unbound Signer recipients are a CRITICAL theft risk. MULTI-CALL ALLOCATION: an allocation can be executed MULTIPLE times (no consumed flag in contract). Use Amount mode (not Surplus) for recurring allocations — an uncapped Surplus sweeps the entire remaining balance on first run. For monthly payment scenarios, create multiple Allocators with time-based Guards + Amount mode sharing items.","anyOf":[{"type":"object","properties":{"description":{"type":"string","description":"Description of fund allocator list"},"threshold":{"default":0,"description":"Minimum balance required for allocation to fire. When the Allocation object's balance < threshold, allocation aborts with EINSUFFICIENT_BALANCE=7. Also: when an Allocator has only Amount items (no Rate, no Surplus), the sum of Amount items must be >= threshold (EAMOUNT_BELOW_THRESHOLD=12). Set to 0 (default) to allow any balance.","anyOf":[{"type":"number"},{"type":"string"}]},"allocators":{"type":"array","items":{"type":"object","properties":{"guard":{"type":"string","description":"Guard object ID or name. A distribution call submits ONE guard; EVERY Allocator bound to that guard fires — in vector order, each against the balance left by the previous (the distribution loop matches the submitted guard address, it does NOT evaluate guards competitively). NOT first-match-wins: Allocators with different guards are alternative distribution paths selected by the caller's choice of guard (e.g., a refund guard vs a damage guard), and mutual exclusion must be expressed inside the Guard conditions themselves, never assumed from ordering."},"sharing":{"type":"array","items":{"type":"object","properties":{"who":{"anyOf":[{"type":"object","properties":{"GuardIdentifier":{"type":"integer","minimum":0,"maximum":255,"description":"Identifier (0-255) for data lookup in Guard table. Slot consensus (enforced on-chain at guard table construction): 0-220 = user slots (free for business guards); 221-253 = PROTOCOL-RESERVED (rejected on-chain — reserved so future protocol features get fixed slots without colliding with published guards); 255 = ONCE replay-protection slot on Allocation (byte-keyed, the submitted bytes are the once-key — use for per-period keys like period-<N>); 254 = ONCE-FOR-OBJECT slot on Allocation (chain-derived key = bcs(the Allocation's payment_info.for_object); the submitted bytes are ignored and the submission only arms the slot — use for one-shot per-order rails whose payee is NOT the order itself, such as settlement releases and incentive/bounty claims). NEVER arm 254 on a refund rail: a refund pays the submitted Order through user slot 0, and a refund leg re-entered in a later renewal period would abort E_ONCE_TRIGGERED (16) forever — refund once-ness comes from the terminal-node topology, never from a once slot. SLOT 0 SEMANTICS: slot 0 carries the transacted Order address by convention. As a submission slot it is legal on order/allocation/machine rails (the order exists when those verify), but FORBIDDEN on a Service buy_guard — the order does not exist when the buy-time passport is verified, so the mount is refused (service abort 43)."}},"required":["GuardIdentifier"],"additionalProperties":false,"description":"Guard verified recipient ID. Get recipient ID from specified data index in Guard table. The ID must be of address type. ALLOCATION rails only — the REWARD claim rail requires recipient == the transaction sender (abort 14), so a GuardIdentifier recipient on reward.guard_add resolves to the submitted Order and is structurally unpayable; the tool gate rejects it (crs-mn-261015 F-12)."},{"type":"object","properties":{"Entity":{"anyOf":[{"description":"Account name, address (0x...), or mark name. When using string format, local marks are searched first. EXAMPLE: 'alice' - searches local marks first, then global; EXAMPLE: '0x2...' (64 hex chars) - uses address directly; EXAMPLE: '' - uses the default local account"},{"type":"object","properties":{"name_or_address":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"local_mark_first":{"description":"Whether to prioritize local marks, if true, prioritize local marks, otherwise prioritize global marks","type":"boolean"}},"additionalProperties":false,"description":"Account or address lookup object. Use this to specify which account to use for an operation. EXAMPLE: { name_or_address: 'testor2' } - looks up account by name; EXAMPLE: { name_or_address: '0x1234...' } - uses address directly; If name_or_address is empty string '', uses the default local account. name_or_address is REQUIRED — {} resolves to nothing useful and is rejected."}],"description":"Account or address lookup. Can be a simple string (recommended for AI) or full object with explicit local_mark_first control. String form auto-converts to { name_or_address: <string>, local_mark_first: true }."}},"required":["Entity"],"additionalProperties":false,"description":"Static address resolved via LocalMark. Format: {Entity: 'mark_name'} (string shorthand) or {Entity: {name_or_address: 'mark_name'}} (full object).F-RQ-11 (rq2 promotion): string shorthand accepted — the FIX-005 transform resolves local marks first."},{"type":"object","properties":{"Signer":{"type":"string","const":"signer"}},"required":["Signer"],"additionalProperties":false,"description":"Current transaction signer (tx_context::sender) at the time of the alloc() call. On refund rails the recipient resolution does NOT check who fires the transaction: with {Signer} the FUNDS GO TO whoever sends the tx (klk3-mn D1: a non-owner successfully fired a refund alloc_by_guard on mainnet). So for a buyer self-refund the BUYER must be the sender — an operator firing it would pay itself. With an order-anchored recipient (GuardIdentifier/Entity) anyone may fire alloc_by_guard; the refund CoinWrapper is owned by the ORDER object and the ORDER OWNER unwraps it via order receive. On the REWARD claim rail this is the CANONICAL recipient (the claim entry REQUIRES recipient == the tx sender — abort 14 otherwise)."}],"description":"Recipient of this allocation. Three forms — each resolves the address at a DIFFERENT time:\n• { GuardIdentifier: u8 } — DYNAMIC address resolved from Passport at alloc() time (from the passport's submission record). Use 0 for Order owner in Service-integrated mode (Customer who created the Order). The identifier must match a Guard table entry with b_submission=true. If Passport has no matching submission, contract aborts with E_VERIFY_FAILED. Use when the recipient address is not known at config time and must be supplied via Guard submission data.\n• { Entity: { name_or_address: '...' } } — FIXED address resolved via LocalMark at SDK build time (passed to contract as a literal address). Use for known recipients (e.g., 'turo_host', or a Treasury object address). Use when the recipient is a stable, known address (e.g., operator receives rent, platform fee to treasury).\n• 'Signer' — the transaction sender at the time of the alloc() call (tx_context::sender). RESOLVED AT EXECUTION TIME, not at config time. CORRECTION (klk3-mn D1, mainnet-verified): on REFUND rails the contract does NOT enforce that the sender be the Order owner — whoever fires alloc_by_guard with a {Signer} recipient BECOMES the recipient. For a customer self-refund the CUSTOMER must therefore be the tx sender (an operator/keeper firing it pays itself). With an order-anchored recipient the CoinWrapper is owned by the ORDER and the order owner unwraps via order receive regardless of who fired the alloc. The recipient == sender HARD constraint exists only on the REWARD claim rail (abort 14). Use when the recipient is whoever submits the allocation transaction (e.g., customer receives refund)."},"sharing":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Allocation value. SEMANTICS DEPEND ON `mode`:\n• mode='Amount': absolute amount in smallest unit (e.g., '750000000' for 0.75 WOW, '250000000' for 0.25 WOW). Allocated first; sum of Amount items cached as `fix`.\n• mode='Rate' (NET): basis-points rate off the post-fix base (balance - fix, or max - fix), 10000 = 100% (e.g., '7500' for 75%, '2500' for 25%). When no Surplus in same Allocator, sum MUST == 10000; when Surplus present, sum MUST <= 10000.\n• mode='RateGross': basis-points rate off the FULL pool (balance) or the `max` cap — the fixed Amount total is NOT subtracted, 10000 = 100%. sum MUST <= 10000 (and, with `max` set, fix×10000 + sum×max <= max×10000). Cannot be mixed with mode='Rate' in the same Allocator while a fixed Amount total is present.\n• mode='Surplus': IGNORED (contract forces to 0). Set to '0' for clarity. Receives remaining balance after Amount + Rate/RateGross allocations.\n• mode='Formula': basis-points COEFFICIENT (MUST be <= 10000) of a RUNTIME repository scalar — payout = clamp(coefficient × scalar / 10000, 0, headroom). Does NOT join any rate sum (its base is the queried scalar, not the pool) and skips the Amount>=threshold declaration check. Bind the slot's data source via allocation formula_spec_set, else the scalar reads 0.\n⚠️ T1 LOSSY POINT (B-2): Amount/Rate/RateGross/Surplus values are PRE-CONFIGURED and STATIC — a free-form continuous amount still cannot be expressed with them. Formula mode covers the bounded case: a coefficient (<= 10000 bps) of an attested repository aggregate (record count / value sum) — use it for runtime-proportional payouts; for anything richer, model (a) a fixed-tier Allocator list guarded by distinct Guards, or (b) an Amount with a `max` cap — both are finite configurations."},"mode":{"anyOf":[{"type":"string","enum":["Amount","Rate","Surplus","RateGross","Formula"]},{}],"description":"Allocation mode — determines how the `sharing` field is interpreted. Modes can be used individually OR combined within a single Allocator; when combined, allocation order is strictly: Amount first, then Rate/RateGross, then Formula scalar legs, then Surplus. Understanding these modes allows modeling almost any fund distribution pattern.\n• Amount (0): `sharing` is a FIXED amount in smallest unit (e.g., '750000000' = 0.75 WOW). Allocated FIRST; sum of all Amount items is cached as `fix` by the contract. Validation: when no Rate and no Surplus items exist, sum of Amount items must be >= allocators.threshold (EAMOUNT_BELOW_THRESHOLD=12); when `max` is set, sum of Amount items must be <= max (EAMOUNT_EXCEEDS_MAX=13).\n• Rate (1): `sharing` is a NET basis-points rate (10000 = 100%). Allocated AFTER Amount; formula: allocated = (sharing × total_rates) / 10000, where total_rates = balance - fix (or max - fix if `max` is set) — the cached fixed Amount total IS subtracted. Validation: when no Surplus items exist, sum of all Rate items must be EXACTLY 10000 (ERATE_NOT_10000=4); when Surplus items exist, sum of all Rate items must be <= 10000 (ERATE_EXCEEDS_10000=6).\n• RateGross (3): `sharing` is a GROSS basis-points rate (10000 = 100%). Allocated AFTER Amount; formula: allocated = (sharing × total_rates) / 10000, where total_rates = balance (the full pool) or the `max` cap when set — the fixed Amount total is NOT subtracted, so fixed Amount entries and percentage-of-total rates coexist exactly. Validation: sum of all RateGross items must be <= 10000 (ERATE_EXCEEDS_10000=6); when `max` is set, fix×10000 + sum(rate)×max <= max×10000 must hold (6); with no `max` and a fixed total > 0, sum of RateGross items must be < 10000 (6). RateGross cannot be mixed with NET Rate entries in the same Allocator while a fixed Amount total is present (EMIXED_RATE_BASES=17).\n• Surplus (2): `sharing` is IGNORED (contract forces it to 0). Allocated LAST; receives the remaining balance after Amount + Rate allocations. Validation: MAX ONE Surplus item per Allocator (EMULTIPLE_SURPLUS=5). When Surplus exists, Rate sum constraint relaxes from == 10000 to <= 10000.\n• Formula (4): `sharing` is a basis-points COEFFICIENT (<= 10000, ERATE_EXCEEDS_10000=6) applied to a RUNTIME scalar queried from a Repository at alloc() time — amount = clamp(coefficient × scalar / 10000, 0, headroom). The scalar comes from the slot's bound FormulaSpec (record-count or value-sum over a repository policy key, predicate wire identical to the 1173/1174 count/sum-where guard queries; explicit candidate ids, max 100, empty list = zero hits = scalar 0). A Formula leg does NOT join total_rate (its base is the queried scalar, not the pool) and its presence SKIPS the Amount-sum >= threshold declaration check (payout is runtime-defined). Requires a spec bound via allocation formula_spec_set — an unbound Formula slot prices its scalar as 0. binding a malformed spec aborts (EFORMULA_SPEC_INVALID=24).\nALLOCATION ORDER (strict): Amount items (fixed, cached as fix) → Rate/RateGross items → Formula scalar legs → Surplus item (remaining).\nRECOMMENDATION: Use Amount mode for known fixed amounts (clearer, no sum constraint). Use Rate mode for proportional splits off the post-fix remainder (requires sum == 10000 unless Surplus present). Use RateGross mode for a percentage of the FULL pool/`max` that must coexist with fixed Amount entries. Use Surplus to capture remainder (e.g., platform fee + host gets rest). Use Formula for payouts proportional to an attested on-chain aggregate (e.g. N records served, total value logged in a Repository) that cannot be known at configuration time. Accepts string ('Amount'/'Rate'/'Surplus'/'RateGross'/'Formula', recommended) or number (0/1/2/3/4)."}},"required":["who","sharing","mode"],"additionalProperties":false,"description":"Fund allocation item — one recipient's share of the Allocation balance. The `sharing` value's meaning depends on `mode` (see AllocationModeSchema). Multiple items in the same Allocator are evaluated together: Amount items first, Rate/RateGross items second, Surplus last."},"description":"Fund allocation item list. Each item specifies a recipient (who), a value (sharing), and a mode. Items can mix modes (Amount + Rate/RateGross + Formula + Surplus) within the same Allocator. RECIPIENT SEMANTICS: the Guard constrains what each submission slot may be; a recipient's safety follows from the sufficiency of those constraints (run the recipient constraint audit). Canonical order pattern: recipient = the single submitted Order — funds land at that object and are receivable only by its owner. ALLOCATION ORDER: Amount items first (cached as fix) → Rate items (proportional to balance - fix; RateGross proportional to the full pool) → Formula legs (coefficient of the runtime repository scalar) → Surplus item (remaining). CONSTRAINTS: max ONE Surplus item per Allocator; NET Rate sum must == 10000 (no Surplus) or <= 10000 (with Surplus); RateGross sum must <= 10000 (never mixed with NET Rate while a fixed total is present); each Formula leg's coefficient must <= 10000 but does NOT count into any rate sum; Amount sum must >= threshold (no Rate, no RateGross and no Formula present — a Formula leg skips this floor since its payout is runtime-defined) and <= max (if max set)."},"fix":{"description":"OUTPUT-ONLY (query result). Cached sum of all Amount-mode `sharing` values in this Allocator. Computed by the contract when the allocator is added — DO NOT set this field at creation. Used internally to compute `total_rates = balance - fix` for NET Rate allocation (RateGross ignores fix and uses the full pool/`max`).","anyOf":[{"type":"number"},{"type":"string"}]},"max":{"description":"Maximum allocation cap (OPTIONAL — omit the field or set to null to disable the cap; do NOT set to 0 as that means a cap of zero). Passed through to the contract as Option<u64> when the allocator is added: when null/omitted the contract treats it as `none` (no cap); when set, the contract enforces it. Has THREE effects when set:\n1. Construction: sum of Amount items must be <= max (EAMOUNT_EXCEEDS_MAX=13)\n2. Rate execution: NET Rate total_rates = max - fix; RateGross total_rates = max (fix NOT subtracted)\n3. Surplus execution: surplus_amount = max - alloced_amount (instead of balance - alloced_amount)\nUse when you want to cap total allocation regardless of Order balance (e.g., cap payout to declared amount). SDK pre-validates Amount sum <= max at build time to give actionable error messages before on-chain abort.","anyOf":[{"anyOf":[{"type":"number"},{"type":"string"}],"description":"A coin/balance amount. Accepts three formats: (1) DISPLAY FORMAT with token symbol: \"2.5WOW\", \"10USDC\", \"0.05WOW\" — auto-converted to smallest units via the Fund Processing Layer (token precision resolved from official registry → cache → on-chain). The symbol MUST match the token's type_parameter. (2) SMALLEST UNIT (numeric string): \"10000000000\" — used as-is, no conversion. (3) SMALLEST UNIT (number): 10000000000 — used as-is only within the safe integer range (±2^53); numbers outside it are REJECTED, use a numeric string instead. PRECISION RULE: for values exceeding 2^53 (9007199254740991), ALWAYS use format (1) or (2) — JS numbers lose integer precision silently and such inputs are blocked. Raw amounts must be plain non-negative integers; a decimal value without a token symbol (e.g. \"2.5\") is rejected — append the symbol (\"2.5WOW\") so the Fund Processing Layer converts it. WARNING — BARE INTEGER MEANS SMALLEST UNIT, NOT TOKENS: formats (2)/(3) are NEVER interpreted as display tokens. For example amount=\"5\" or 5 means 5 raw units = 0.000000005 WOW (9 decimals) — NOT 5 WOW. When the user asks for a token amount, you MUST use display format (\"5WOW\", \"2USDC\"); a bare integer is only correct for unitless counts (e.g. stock quantity) or when you computed exact raw units yourself. Default token: WOW (9 decimals, 1 WOW = 10^9 MIST). For custom tokens: use display format with the token's symbol, or pass smallest units directly. MONEY CONFIRMATION: all monetary fields trigger user confirmation via the Fund Processing Layer, where the token's FULL type, decimals and raw amount are always visible. MULTIPLE ISSUERS: several on-chain tokens may legally share the same symbol (e.g. multiple \"USDT\" coins). When a bare symbol matches more than one token, the operation is BLOCKED and every candidate is listed with full details (type, name, decimals, verified tag) — present the list to the USER and let them choose (they may answer by number), then re-issue with the chosen token's FULL type string in type_parameter; never guess an issuer from the bare symbol. MISSING TOKEN INFO: when a token's precision cannot be resolved, the operation is REFUSED (raw u64 included — amount magnitude could not be verified). Recovery: provide the token's FULL type in package::module::Name form in type_parameter (a bare symbol like \"USDT\" cannot be resolved), and verify the WOW network is correct. Examples: \"2.5WOW\" (display → 2500000000), 10000000000 (number, smallest unit), \"50000000000\" (string, smallest unit). Used for: service sale prices, compensation fund balances, Treasury deposits, arbitration fees, reward amounts, stock quantities."},{"type":"null"}]}},"required":["guard","sharing"],"additionalProperties":false,"description":"Fund allocator — a complete allocation strategy triggered by a Guard. Contains a sharing[] array where items can mix Amount/Rate/RateGross/Surplus modes. When the Guard passes, the contract allocates funds in strict order: Amount → Rate/RateGross → Surplus."},"description":"Fund allocator list. NOT first-match-wins: a distribution call submits ONE guard and EVERY allocator bound to that guard fires, in vector order, each against the shrinking pool left by the previous (this is how a waterfall like Amount fee + net Rate split is built). Alternative paths (e.g., refund / damage-deduct / arbitrate) are expressed as allocators bound to DIFFERENT guards; the caller's submitted guard selects the path."}},"required":["description","threshold","allocators"],"additionalProperties":false,"description":"Fund allocator list — the top-level allocation configuration attached to an Order. Contains a threshold and a list of Allocators. A distribution call submits ONE guard; every Allocator bound to that guard executes its sharing[] in strict order (Amount → Rate/RateGross → Surplus) against the shrinking pool. MULTI-TIER ALLOCATION (DOC-04): Each Order binds ONE Allocators template (set on Service.order_allocators before publish). For multi-tier distribution (e.g., customer→agency→suppliers), use a two-phase approach: (1) Tier-1 Allocators on the customer's Order (allocates to agency + refund fund); (2) Tier-2 Allocators on a NEW Order created by the agency (allocates agency's received funds to suppliers). Each tier's NET Rate-mode sharing[] must independently sum to 10000 (or <= 10000 with Surplus); RateGross-mode sharing[] must sum to <= 10000."},{"type":"null"}]},"order_allocators_append":{"description":"Append-only correction window for order_allocators — the ONLY allocator mutation allowed AFTER publish (J1). REQUIREMENTS (chain-enforced, allocation abort code 20 EALLOCATORS_NOT_EXTENSION): the supplied Allocators must be a pure EXTENSION of the current on-chain plan — every existing allocator appears VERBATIM as a prefix (same guard, same sharing, same fix/max), threshold must be UNCHANGED; only description may change freely. New allocators are appended after the prefix. WHY: rewriting an existing allocator or changing the threshold would retroactively alter payout rules for orders already escrowed against the old plan. Clearing the plan (null) is NOT possible here — that would strand in-flight orders. Permission: same index 313 as order_allocators. USE CASE: you forgot one allocator guard (e.g. the refund exit for a review node) and the Service is already published — instead of abandoning the Service, append the missing allocator. ⚠️ SCOPE — NEW ORDERS ONLY: each order instantiates its own Allocation from this plan AT BUY TIME, so appending changes the template for FUTURE orders only. Orders already escrowed under the previous plan do NOT gain the appended allocator — their Allocation (and its fund exits) is frozen as originally instantiated; if in-flight orders are already stranded, this append does NOT rescue them. ⚠️ Appended allocators are evaluated AFTER the existing ones against the shrinking pool (vector order), so they see the balance left by earlier allocators — design appended waterfall tails accordingly. ⚠️ Once appended, an allocator can NEVER be edited or removed — same permanence as the original plan.","type":"object","properties":{"description":{"type":"string","description":"Description of fund allocator list"},"threshold":{"default":0,"description":"Minimum balance required for allocation to fire. When the Allocation object's balance < threshold, allocation aborts with EINSUFFICIENT_BALANCE=7. Also: when an Allocator has only Amount items (no Rate, no Surplus), the sum of Amount items must be >= threshold (EAMOUNT_BELOW_THRESHOLD=12). Set to 0 (default) to allow any balance.","anyOf":[{"type":"number"},{"type":"string"}]},"allocators":{"type":"array","items":{"type":"object","properties":{"guard":{"type":"string","description":"Guard object ID or name. A distribution call submits ONE guard; EVERY Allocator bound to that guard fires — in vector order, each against the balance left by the previous (the distribution loop matches the submitted guard address, it does NOT evaluate guards competitively). NOT first-match-wins: Allocators with different guards are alternative distribution paths selected by the caller's choice of guard (e.g., a refund guard vs a damage guard), and mutual exclusion must be expressed inside the Guard conditions themselves, never assumed from ordering."},"sharing":{"type":"array","items":{"type":"object","properties":{"who":{"anyOf":[{"type":"object","properties":{"GuardIdentifier":{"type":"integer","minimum":0,"maximum":255,"description":"Identifier (0-255) for data lookup in Guard table. Slot consensus (enforced on-chain at guard table construction): 0-220 = user slots (free for business guards); 221-253 = PROTOCOL-RESERVED (rejected on-chain — reserved so future protocol features get fixed slots without colliding with published guards); 255 = ONCE replay-protection slot on Allocation (byte-keyed, the submitted bytes are the once-key — use for per-period keys like period-<N>); 254 = ONCE-FOR-OBJECT slot on Allocation (chain-derived key = bcs(the Allocation's payment_info.for_object); the submitted bytes are ignored and the submission only arms the slot — use for one-shot per-order rails whose payee is NOT the order itself, such as settlement releases and incentive/bounty claims). NEVER arm 254 on a refund rail: a refund pays the submitted Order through user slot 0, and a refund leg re-entered in a later renewal period would abort E_ONCE_TRIGGERED (16) forever — refund once-ness comes from the terminal-node topology, never from a once slot. SLOT 0 SEMANTICS: slot 0 carries the transacted Order address by convention. As a submission slot it is legal on order/allocation/machine rails (the order exists when those verify), but FORBIDDEN on a Service buy_guard — the order does not exist when the buy-time passport is verified, so the mount is refused (service abort 43)."}},"required":["GuardIdentifier"],"additionalProperties":false,"description":"Guard verified recipient ID. Get recipient ID from specified data index in Guard table. The ID must be of address type. ALLOCATION rails only — the REWARD claim rail requires recipient == the transaction sender (abort 14), so a GuardIdentifier recipient on reward.guard_add resolves to the submitted Order and is structurally unpayable; the tool gate rejects it (crs-mn-261015 F-12)."},{"type":"object","properties":{"Entity":{"anyOf":[{"description":"Account name, address (0x...), or mark name. When using string format, local marks are searched first. EXAMPLE: 'alice' - searches local marks first, then global; EXAMPLE: '0x2...' (64 hex chars) - uses address directly; EXAMPLE: '' - uses the default local account"},{"type":"object","properties":{"name_or_address":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"local_mark_first":{"description":"Whether to prioritize local marks, if true, prioritize local marks, otherwise prioritize global marks","type":"boolean"}},"additionalProperties":false,"description":"Account or address lookup object. Use this to specify which account to use for an operation. EXAMPLE: { name_or_address: 'testor2' } - looks up account by name; EXAMPLE: { name_or_address: '0x1234...' } - uses address directly; If name_or_address is empty string '', uses the default local account. name_or_address is REQUIRED — {} resolves to nothing useful and is rejected."}],"description":"Account or address lookup. Can be a simple string (recommended for AI) or full object with explicit local_mark_first control. String form auto-converts to { name_or_address: <string>, local_mark_first: true }."}},"required":["Entity"],"additionalProperties":false,"description":"Static address resolved via LocalMark. Format: {Entity: 'mark_name'} (string shorthand) or {Entity: {name_or_address: 'mark_name'}} (full object).F-RQ-11 (rq2 promotion): string shorthand accepted — the FIX-005 transform resolves local marks first."},{"type":"object","properties":{"Signer":{"type":"string","const":"signer"}},"required":["Signer"],"additionalProperties":false,"description":"Current transaction signer (tx_context::sender) at the time of the alloc() call. On refund rails the recipient resolution does NOT check who fires the transaction: with {Signer} the FUNDS GO TO whoever sends the tx (klk3-mn D1: a non-owner successfully fired a refund alloc_by_guard on mainnet). So for a buyer self-refund the BUYER must be the sender — an operator firing it would pay itself. With an order-anchored recipient (GuardIdentifier/Entity) anyone may fire alloc_by_guard; the refund CoinWrapper is owned by the ORDER object and the ORDER OWNER unwraps it via order receive. On the REWARD claim rail this is the CANONICAL recipient (the claim entry REQUIRES recipient == the tx sender — abort 14 otherwise)."}],"description":"Recipient of this allocation. Three forms — each resolves the address at a DIFFERENT time:\n• { GuardIdentifier: u8 } — DYNAMIC address resolved from Passport at alloc() time (from the passport's submission record). Use 0 for Order owner in Service-integrated mode (Customer who created the Order). The identifier must match a Guard table entry with b_submission=true. If Passport has no matching submission, contract aborts with E_VERIFY_FAILED. Use when the recipient address is not known at config time and must be supplied via Guard submission data.\n• { Entity: { name_or_address: '...' } } — FIXED address resolved via LocalMark at SDK build time (passed to contract as a literal address). Use for known recipients (e.g., 'turo_host', or a Treasury object address). Use when the recipient is a stable, known address (e.g., operator receives rent, platform fee to treasury).\n• 'Signer' — the transaction sender at the time of the alloc() call (tx_context::sender). RESOLVED AT EXECUTION TIME, not at config time. CORRECTION (klk3-mn D1, mainnet-verified): on REFUND rails the contract does NOT enforce that the sender be the Order owner — whoever fires alloc_by_guard with a {Signer} recipient BECOMES the recipient. For a customer self-refund the CUSTOMER must therefore be the tx sender (an operator/keeper firing it pays itself). With an order-anchored recipient the CoinWrapper is owned by the ORDER and the order owner unwraps via order receive regardless of who fired the alloc. The recipient == sender HARD constraint exists only on the REWARD claim rail (abort 14). Use when the recipient is whoever submits the allocation transaction (e.g., customer receives refund)."},"sharing":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Allocation value. SEMANTICS DEPEND ON `mode`:\n• mode='Amount': absolute amount in smallest unit (e.g., '750000000' for 0.75 WOW, '250000000' for 0.25 WOW). Allocated first; sum of Amount items cached as `fix`.\n• mode='Rate' (NET): basis-points rate off the post-fix base (balance - fix, or max - fix), 10000 = 100% (e.g., '7500' for 75%, '2500' for 25%). When no Surplus in same Allocator, sum MUST == 10000; when Surplus present, sum MUST <= 10000.\n• mode='RateGross': basis-points rate off the FULL pool (balance) or the `max` cap — the fixed Amount total is NOT subtracted, 10000 = 100%. sum MUST <= 10000 (and, with `max` set, fix×10000 + sum×max <= max×10000). Cannot be mixed with mode='Rate' in the same Allocator while a fixed Amount total is present.\n• mode='Surplus': IGNORED (contract forces to 0). Set to '0' for clarity. Receives remaining balance after Amount + Rate/RateGross allocations.\n• mode='Formula': basis-points COEFFICIENT (MUST be <= 10000) of a RUNTIME repository scalar — payout = clamp(coefficient × scalar / 10000, 0, headroom). Does NOT join any rate sum (its base is the queried scalar, not the pool) and skips the Amount>=threshold declaration check. Bind the slot's data source via allocation formula_spec_set, else the scalar reads 0.\n⚠️ T1 LOSSY POINT (B-2): Amount/Rate/RateGross/Surplus values are PRE-CONFIGURED and STATIC — a free-form continuous amount still cannot be expressed with them. Formula mode covers the bounded case: a coefficient (<= 10000 bps) of an attested repository aggregate (record count / value sum) — use it for runtime-proportional payouts; for anything richer, model (a) a fixed-tier Allocator list guarded by distinct Guards, or (b) an Amount with a `max` cap — both are finite configurations."},"mode":{"anyOf":[{"type":"string","enum":["Amount","Rate","Surplus","RateGross","Formula"]},{}],"description":"Allocation mode — determines how the `sharing` field is interpreted. Modes can be used individually OR combined within a single Allocator; when combined, allocation order is strictly: Amount first, then Rate/RateGross, then Formula scalar legs, then Surplus. Understanding these modes allows modeling almost any fund distribution pattern.\n• Amount (0): `sharing` is a FIXED amount in smallest unit (e.g., '750000000' = 0.75 WOW). Allocated FIRST; sum of all Amount items is cached as `fix` by the contract. Validation: when no Rate and no Surplus items exist, sum of Amount items must be >= allocators.threshold (EAMOUNT_BELOW_THRESHOLD=12); when `max` is set, sum of Amount items must be <= max (EAMOUNT_EXCEEDS_MAX=13).\n• Rate (1): `sharing` is a NET basis-points rate (10000 = 100%). Allocated AFTER Amount; formula: allocated = (sharing × total_rates) / 10000, where total_rates = balance - fix (or max - fix if `max` is set) — the cached fixed Amount total IS subtracted. Validation: when no Surplus items exist, sum of all Rate items must be EXACTLY 10000 (ERATE_NOT_10000=4); when Surplus items exist, sum of all Rate items must be <= 10000 (ERATE_EXCEEDS_10000=6).\n• RateGross (3): `sharing` is a GROSS basis-points rate (10000 = 100%). Allocated AFTER Amount; formula: allocated = (sharing × total_rates) / 10000, where total_rates = balance (the full pool) or the `max` cap when set — the fixed Amount total is NOT subtracted, so fixed Amount entries and percentage-of-total rates coexist exactly. Validation: sum of all RateGross items must be <= 10000 (ERATE_EXCEEDS_10000=6); when `max` is set, fix×10000 + sum(rate)×max <= max×10000 must hold (6); with no `max` and a fixed total > 0, sum of RateGross items must be < 10000 (6). RateGross cannot be mixed with NET Rate entries in the same Allocator while a fixed Amount total is present (EMIXED_RATE_BASES=17).\n• Surplus (2): `sharing` is IGNORED (contract forces it to 0). Allocated LAST; receives the remaining balance after Amount + Rate allocations. Validation: MAX ONE Surplus item per Allocator (EMULTIPLE_SURPLUS=5). When Surplus exists, Rate sum constraint relaxes from == 10000 to <= 10000.\n• Formula (4): `sharing` is a basis-points COEFFICIENT (<= 10000, ERATE_EXCEEDS_10000=6) applied to a RUNTIME scalar queried from a Repository at alloc() time — amount = clamp(coefficient × scalar / 10000, 0, headroom). The scalar comes from the slot's bound FormulaSpec (record-count or value-sum over a repository policy key, predicate wire identical to the 1173/1174 count/sum-where guard queries; explicit candidate ids, max 100, empty list = zero hits = scalar 0). A Formula leg does NOT join total_rate (its base is the queried scalar, not the pool) and its presence SKIPS the Amount-sum >= threshold declaration check (payout is runtime-defined). Requires a spec bound via allocation formula_spec_set — an unbound Formula slot prices its scalar as 0. binding a malformed spec aborts (EFORMULA_SPEC_INVALID=24).\nALLOCATION ORDER (strict): Amount items (fixed, cached as fix) → Rate/RateGross items → Formula scalar legs → Surplus item (remaining).\nRECOMMENDATION: Use Amount mode for known fixed amounts (clearer, no sum constraint). Use Rate mode for proportional splits off the post-fix remainder (requires sum == 10000 unless Surplus present). Use RateGross mode for a percentage of the FULL pool/`max` that must coexist with fixed Amount entries. Use Surplus to capture remainder (e.g., platform fee + host gets rest). Use Formula for payouts proportional to an attested on-chain aggregate (e.g. N records served, total value logged in a Repository) that cannot be known at configuration time. Accepts string ('Amount'/'Rate'/'Surplus'/'RateGross'/'Formula', recommended) or number (0/1/2/3/4)."}},"required":["who","sharing","mode"],"additionalProperties":false,"description":"Fund allocation item — one recipient's share of the Allocation balance. The `sharing` value's meaning depends on `mode` (see AllocationModeSchema). Multiple items in the same Allocator are evaluated together: Amount items first, Rate/RateGross items second, Surplus last."},"description":"Fund allocation item list. Each item specifies a recipient (who), a value (sharing), and a mode. Items can mix modes (Amount + Rate/RateGross + Formula + Surplus) within the same Allocator. RECIPIENT SEMANTICS: the Guard constrains what each submission slot may be; a recipient's safety follows from the sufficiency of those constraints (run the recipient constraint audit). Canonical order pattern: recipient = the single submitted Order — funds land at that object and are receivable only by its owner. ALLOCATION ORDER: Amount items first (cached as fix) → Rate items (proportional to balance - fix; RateGross proportional to the full pool) → Formula legs (coefficient of the runtime repository scalar) → Surplus item (remaining). CONSTRAINTS: max ONE Surplus item per Allocator; NET Rate sum must == 10000 (no Surplus) or <= 10000 (with Surplus); RateGross sum must <= 10000 (never mixed with NET Rate while a fixed total is present); each Formula leg's coefficient must <= 10000 but does NOT count into any rate sum; Amount sum must >= threshold (no Rate, no RateGross and no Formula present — a Formula leg skips this floor since its payout is runtime-defined) and <= max (if max set)."},"fix":{"description":"OUTPUT-ONLY (query result). Cached sum of all Amount-mode `sharing` values in this Allocator. Computed by the contract when the allocator is added — DO NOT set this field at creation. Used internally to compute `total_rates = balance - fix` for NET Rate allocation (RateGross ignores fix and uses the full pool/`max`).","anyOf":[{"type":"number"},{"type":"string"}]},"max":{"description":"Maximum allocation cap (OPTIONAL — omit the field or set to null to disable the cap; do NOT set to 0 as that means a cap of zero). Passed through to the contract as Option<u64> when the allocator is added: when null/omitted the contract treats it as `none` (no cap); when set, the contract enforces it. Has THREE effects when set:\n1. Construction: sum of Amount items must be <= max (EAMOUNT_EXCEEDS_MAX=13)\n2. Rate execution: NET Rate total_rates = max - fix; RateGross total_rates = max (fix NOT subtracted)\n3. Surplus execution: surplus_amount = max - alloced_amount (instead of balance - alloced_amount)\nUse when you want to cap total allocation regardless of Order balance (e.g., cap payout to declared amount). SDK pre-validates Amount sum <= max at build time to give actionable error messages before on-chain abort.","anyOf":[{"anyOf":[{"type":"number"},{"type":"string"}],"description":"A coin/balance amount. Accepts three formats: (1) DISPLAY FORMAT with token symbol: \"2.5WOW\", \"10USDC\", \"0.05WOW\" — auto-converted to smallest units via the Fund Processing Layer (token precision resolved from official registry → cache → on-chain). The symbol MUST match the token's type_parameter. (2) SMALLEST UNIT (numeric string): \"10000000000\" — used as-is, no conversion. (3) SMALLEST UNIT (number): 10000000000 — used as-is only within the safe integer range (±2^53); numbers outside it are REJECTED, use a numeric string instead. PRECISION RULE: for values exceeding 2^53 (9007199254740991), ALWAYS use format (1) or (2) — JS numbers lose integer precision silently and such inputs are blocked. Raw amounts must be plain non-negative integers; a decimal value without a token symbol (e.g. \"2.5\") is rejected — append the symbol (\"2.5WOW\") so the Fund Processing Layer converts it. WARNING — BARE INTEGER MEANS SMALLEST UNIT, NOT TOKENS: formats (2)/(3) are NEVER interpreted as display tokens. For example amount=\"5\" or 5 means 5 raw units = 0.000000005 WOW (9 decimals) — NOT 5 WOW. When the user asks for a token amount, you MUST use display format (\"5WOW\", \"2USDC\"); a bare integer is only correct for unitless counts (e.g. stock quantity) or when you computed exact raw units yourself. Default token: WOW (9 decimals, 1 WOW = 10^9 MIST). For custom tokens: use display format with the token's symbol, or pass smallest units directly. MONEY CONFIRMATION: all monetary fields trigger user confirmation via the Fund Processing Layer, where the token's FULL type, decimals and raw amount are always visible. MULTIPLE ISSUERS: several on-chain tokens may legally share the same symbol (e.g. multiple \"USDT\" coins). When a bare symbol matches more than one token, the operation is BLOCKED and every candidate is listed with full details (type, name, decimals, verified tag) — present the list to the USER and let them choose (they may answer by number), then re-issue with the chosen token's FULL type string in type_parameter; never guess an issuer from the bare symbol. MISSING TOKEN INFO: when a token's precision cannot be resolved, the operation is REFUSED (raw u64 included — amount magnitude could not be verified). Recovery: provide the token's FULL type in package::module::Name form in type_parameter (a bare symbol like \"USDT\" cannot be resolved), and verify the WOW network is correct. Examples: \"2.5WOW\" (display → 2500000000), 10000000000 (number, smallest unit), \"50000000000\" (string, smallest unit). Used for: service sale prices, compensation fund balances, Treasury deposits, arbitration fees, reward amounts, stock quantities."},{"type":"null"}]}},"required":["guard","sharing"],"additionalProperties":false,"description":"Fund allocator — a complete allocation strategy triggered by a Guard. Contains a sharing[] array where items can mix Amount/Rate/RateGross/Surplus modes. When the Guard passes, the contract allocates funds in strict order: Amount → Rate/RateGross → Surplus."},"description":"Fund allocator list. NOT first-match-wins: a distribution call submits ONE guard and EVERY allocator bound to that guard fires, in vector order, each against the shrinking pool left by the previous (this is how a waterfall like Amount fee + net Rate split is built). Alternative paths (e.g., refund / damage-deduct / arbitrate) are expressed as allocators bound to DIFFERENT guards; the caller's submitted guard selects the path."}},"required":["description","threshold","allocators"],"additionalProperties":false},"buy_guard":{"description":"Buy guard object ID or name (null CLEARS the mount). RUNTIME SWITCH (permission 307 SERVICE_BUY_GUARD — the guard OBJECT is immutable but its MOUNT on the Service is mutable at any time). ROUND-ROTATION DUTY (拍板② dm-mtw-261027): for daily/group rounds whose cutoff is an absolute timestamp, the precise batch boundary is THIS mount, not the time guard — at the cutoff instant the keeper cron SETS the buy_guard (new entrants refused at BUY time) and CLEARs/re-arms it when the next round opens; the on-chain Clock >= cutoff comparison stays the settlement/advance authority. Disclose the publisher's time source the cron fires on. Full Machine reuse across rounds (advance gate re-reading a repository cutoff row) is filed for a protocol window.","anyOf":[{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},{"type":"null"}]},"compensation_fund_add":{"description":"Deposit funds into the Service compensation_fund. Used to pay indemnity when arbitration resolves in customer's favor. FORMAT: {balance: <amount_in_smallest_unit>} — the field name is 'balance' (NOT 'amount'). The token type and precision are determined by the Service object's type_parameter (the generic type set when the Service was created). For WOW (9 decimals): {balance: 1000000000} = 1 WOW. For tokens with different decimals, adjust accordingly (e.g. USDC has 6 decimals, so {balance: 1000000} = 1 USDC). REQUIRES: Permission index 315 (SERVICE_COMPENSATION_FUND_DEPOSIT) for NON-ADMIN callers. The Permission owner and admin short-circuit every builtin index check (no grant needed); only non-admin callers must be granted 315 first. COMMON MISTAKE: using {amount: ...} or {amount: ..., type: 'WOW'} — these will fail. The correct field is 'balance'.","anyOf":[{"type":"object","properties":{"balance":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"A coin/balance amount. Accepts three formats: (1) DISPLAY FORMAT with token symbol: \"2.5WOW\", \"10USDC\", \"0.05WOW\" — auto-converted to smallest units via the Fund Processing Layer (token precision resolved from official registry → cache → on-chain). The symbol MUST match the token's type_parameter. (2) SMALLEST UNIT (numeric string): \"10000000000\" — used as-is, no conversion. (3) SMALLEST UNIT (number): 10000000000 — used as-is only within the safe integer range (±2^53); numbers outside it are REJECTED, use a numeric string instead. PRECISION RULE: for values exceeding 2^53 (9007199254740991), ALWAYS use format (1) or (2) — JS numbers lose integer precision silently and such inputs are blocked. Raw amounts must be plain non-negative integers; a decimal value without a token symbol (e.g. \"2.5\") is rejected — append the symbol (\"2.5WOW\") so the Fund Processing Layer converts it. WARNING — BARE INTEGER MEANS SMALLEST UNIT, NOT TOKENS: formats (2)/(3) are NEVER interpreted as display tokens. For example amount=\"5\" or 5 means 5 raw units = 0.000000005 WOW (9 decimals) — NOT 5 WOW. When the user asks for a token amount, you MUST use display format (\"5WOW\", \"2USDC\"); a bare integer is only correct for unitless counts (e.g. stock quantity) or when you computed exact raw units yourself. Default token: WOW (9 decimals, 1 WOW = 10^9 MIST). For custom tokens: use display format with the token's symbol, or pass smallest units directly. MONEY CONFIRMATION: all monetary fields trigger user confirmation via the Fund Processing Layer, where the token's FULL type, decimals and raw amount are always visible. MULTIPLE ISSUERS: several on-chain tokens may legally share the same symbol (e.g. multiple \"USDT\" coins). When a bare symbol matches more than one token, the operation is BLOCKED and every candidate is listed with full details (type, name, decimals, verified tag) — present the list to the USER and let them choose (they may answer by number), then re-issue with the chosen token's FULL type string in type_parameter; never guess an issuer from the bare symbol. MISSING TOKEN INFO: when a token's precision cannot be resolved, the operation is REFUSED (raw u64 included — amount magnitude could not be verified). Recovery: provide the token's FULL type in package::module::Name form in type_parameter (a bare symbol like \"USDT\" cannot be resolved), and verify the WOW network is correct. Examples: \"2.5WOW\" (display → 2500000000), 10000000000 (number, smallest unit), \"50000000000\" (string, smallest unit). Used for: service sale prices, compensation fund balances, Treasury deposits, arbitration fees, reward amounts, stock quantities."}},"required":["balance"],"additionalProperties":false,"description":"Specify an amount value."},{"type":"object","properties":{"coin":{"type":"string","description":"Coin object ID or name(local mark). WHOLE-COIN TRANSFER: the ENTIRE Coin object is moved to the recipient — the 'amount' is NOT taken from it (testnet lesson: passing your main gas coin transfers its full balance, leaving you unable to pay for anything). Use only for coins whose whole balance is exactly what you intend to send; prefer {balance: <smallest-unit number>} for partial amounts."}},"required":["coin"],"additionalProperties":false}]},"compensation_fund_withdraw":{"description":"Withdraw ALL funds from the compensation_fund to a new Payment object owned by `receipt`. REQUIRES: Service must be paused AND setting_lock_duration must have elapsed since pause (the unpublished-state check). Withdraws the ENTIRE compensation_fund balance via balance::withdraw_all. DIFFERENT from the order-side compensation claim (for arbitration-winning users, no pause+lock required).","type":"object","properties":{"receipt":{"anyOf":[{"description":"Account name, address (0x...), or mark name. When using string format, local marks are searched first. EXAMPLE: 'alice' - searches local marks first, then global; EXAMPLE: '0x2...' (64 hex chars) - uses address directly; EXAMPLE: '' - uses the default local account"},{"type":"object","properties":{"name_or_address":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"local_mark_first":{"description":"Whether to prioritize local marks, if true, prioritize local marks, otherwise prioritize global marks","type":"boolean"}},"additionalProperties":false,"description":"Account or address lookup object. Use this to specify which account to use for an operation. EXAMPLE: { name_or_address: 'testor2' } - looks up account by name; EXAMPLE: { name_or_address: '0x1234...' } - uses address directly; If name_or_address is empty string '', uses the default local account. name_or_address is REQUIRED — {} resolves to nothing useful and is rejected."}],"description":"Receipt address that will receive the withdrawn funds (as a new Payment object)"},"payment_info":{"type":"object","properties":{"for_object":{"description":"Binding anchor for this distribution. On an Allocation a SET for_object is ENFORCED at alloc(): every GuardIdentifier recipient submission must equal this address or the whole tx aborts (ERECIPIENT_NOT_FOR_OBJECT, code 15) — verify the anchor matches the intended recipient flow BEFORE create; payment_info is immutable afterwards. NULL/omitted = no anchor: nothing is enforced on-chain, recipient routing is entirely the creator's design. Also recorded at creation for auditors to query the distribution's business context.","anyOf":[{"type":"string"},{"type":"null"}]},"for_guard":{"description":"Payment to satisfy verification of a Guard object","anyOf":[{"type":"string"},{"type":"null"}]},"remark":{"type":"string","description":"Payment record remark"},"index":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Payment record index (non-negative integer)"}},"required":["remark","index"],"additionalProperties":false,"description":"Payment info for the new Payment object created to hold the withdrawn funds"}},"required":["receipt","payment_info"],"additionalProperties":false},"setting_lock_duration_add":{"description":"Additional lock duration to ADD to 'setting_lock_duration' (Move field name). UNIT: milliseconds (ms). Example: 2592000000 = 30 days, 7776000000 = 90 days, 86400000 = 1 day. DEFAULT: 2592000000 (30 days, DEFAULT_LOCK_DURATION). This is the initial value when a Service is created. Behavior: additive (safe_add) — only increases, never decreases. Can be called BEFORE or AFTER publish (no publish check). Affects the waiting time required by: compensation_fund_withdraw, arbitrations remove/clear, rewards remove/clear (all require pause + setting_lock_duration elapsed since pause).","type":"number"},"compensation_fund_receive":{"description":"Receive order compensation funds from this Service object.\n\nACCEPTED FORMATS (F-06 unified receive operation block):\n• 'recently' (string literal) — auto-query and receive ALL recently received balance.\n Use this for the common case: \"deposit all recently received coins into pending balance.\"\n Example: receive: 'recently'\n REWARD-OBJECT TRAP (F55 gf32-mn-261103): on a REWARD object, 'recently' resolves through\n the Payment-derived ReceivedBalance primitive — a Reward that holds plain CoinWrapper\n sweeps (query_received answers ReceivedNormal[]) aborts with 'received is ReceivedNormal[]\n (expected ReceivedBalance)'. For a plain coin sweep on a Reward use owner_receive:'recently'\n (same call — it unwraps received objects to the Permission owner) instead of receive.\n• ReceivedBalance ({token_type, balance, received: [{id, balance, payment}]}) —\n receive a specific balance record from a Payment/payer.\n Use this when targeting a specific received balance (advanced).\n Example: receive: {token_type: '0x2::wow::WOW', balance: 1000000, received: [{id: '0xrec1', balance: 1000000, payment: '0xpay1'}]}\nANTI-PATTERN: do NOT wrap in {result: ...} — pass the value directly.","anyOf":[{"type":"object","properties":{"balance":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"A coin/balance amount. Accepts three formats: (1) DISPLAY FORMAT with token symbol: \"2.5WOW\", \"10USDC\", \"0.05WOW\" — auto-converted to smallest units via the Fund Processing Layer (token precision resolved from official registry → cache → on-chain). The symbol MUST match the token's type_parameter. (2) SMALLEST UNIT (numeric string): \"10000000000\" — used as-is, no conversion. (3) SMALLEST UNIT (number): 10000000000 — used as-is only within the safe integer range (±2^53); numbers outside it are REJECTED, use a numeric string instead. PRECISION RULE: for values exceeding 2^53 (9007199254740991), ALWAYS use format (1) or (2) — JS numbers lose integer precision silently and such inputs are blocked. Raw amounts must be plain non-negative integers; a decimal value without a token symbol (e.g. \"2.5\") is rejected — append the symbol (\"2.5WOW\") so the Fund Processing Layer converts it. WARNING — BARE INTEGER MEANS SMALLEST UNIT, NOT TOKENS: formats (2)/(3) are NEVER interpreted as display tokens. For example amount=\"5\" or 5 means 5 raw units = 0.000000005 WOW (9 decimals) — NOT 5 WOW. When the user asks for a token amount, you MUST use display format (\"5WOW\", \"2USDC\"); a bare integer is only correct for unitless counts (e.g. stock quantity) or when you computed exact raw units yourself. Default token: WOW (9 decimals, 1 WOW = 10^9 MIST). For custom tokens: use display format with the token's symbol, or pass smallest units directly. MONEY CONFIRMATION: all monetary fields trigger user confirmation via the Fund Processing Layer, where the token's FULL type, decimals and raw amount are always visible. MULTIPLE ISSUERS: several on-chain tokens may legally share the same symbol (e.g. multiple \"USDT\" coins). When a bare symbol matches more than one token, the operation is BLOCKED and every candidate is listed with full details (type, name, decimals, verified tag) — present the list to the USER and let them choose (they may answer by number), then re-issue with the chosen token's FULL type string in type_parameter; never guess an issuer from the bare symbol. MISSING TOKEN INFO: when a token's precision cannot be resolved, the operation is REFUSED (raw u64 included — amount magnitude could not be verified). Recovery: provide the token's FULL type in package::module::Name form in type_parameter (a bare symbol like \"USDT\" cannot be resolved), and verify the WOW network is correct. Examples: \"2.5WOW\" (display → 2500000000), 10000000000 (number, smallest unit), \"50000000000\" (string, smallest unit). Used for: service sale prices, compensation fund balances, Treasury deposits, arbitration fees, reward amounts, stock quantities."},"token_type":{"type":"string","description":"Asset type of Coin objects. Supports CoinWrapper<...> format for order receive operations."},"received":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Received CoinWrapper object ID"},"balance":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"A coin/balance amount. Accepts three formats: (1) DISPLAY FORMAT with token symbol: \"2.5WOW\", \"10USDC\", \"0.05WOW\" — auto-converted to smallest units via the Fund Processing Layer (token precision resolved from official registry → cache → on-chain). The symbol MUST match the token's type_parameter. (2) SMALLEST UNIT (numeric string): \"10000000000\" — used as-is, no conversion. (3) SMALLEST UNIT (number): 10000000000 — used as-is only within the safe integer range (±2^53); numbers outside it are REJECTED, use a numeric string instead. PRECISION RULE: for values exceeding 2^53 (9007199254740991), ALWAYS use format (1) or (2) — JS numbers lose integer precision silently and such inputs are blocked. Raw amounts must be plain non-negative integers; a decimal value without a token symbol (e.g. \"2.5\") is rejected — append the symbol (\"2.5WOW\") so the Fund Processing Layer converts it. WARNING — BARE INTEGER MEANS SMALLEST UNIT, NOT TOKENS: formats (2)/(3) are NEVER interpreted as display tokens. For example amount=\"5\" or 5 means 5 raw units = 0.000000005 WOW (9 decimals) — NOT 5 WOW. When the user asks for a token amount, you MUST use display format (\"5WOW\", \"2USDC\"); a bare integer is only correct for unitless counts (e.g. stock quantity) or when you computed exact raw units yourself. Default token: WOW (9 decimals, 1 WOW = 10^9 MIST). For custom tokens: use display format with the token's symbol, or pass smallest units directly. MONEY CONFIRMATION: all monetary fields trigger user confirmation via the Fund Processing Layer, where the token's FULL type, decimals and raw amount are always visible. MULTIPLE ISSUERS: several on-chain tokens may legally share the same symbol (e.g. multiple \"USDT\" coins). When a bare symbol matches more than one token, the operation is BLOCKED and every candidate is listed with full details (type, name, decimals, verified tag) — present the list to the USER and let them choose (they may answer by number), then re-issue with the chosen token's FULL type string in type_parameter; never guess an issuer from the bare symbol. MISSING TOKEN INFO: when a token's precision cannot be resolved, the operation is REFUSED (raw u64 included — amount magnitude could not be verified). Recovery: provide the token's FULL type in package::module::Name form in type_parameter (a bare symbol like \"USDT\" cannot be resolved), and verify the WOW network is correct. Examples: \"2.5WOW\" (display → 2500000000), 10000000000 (number, smallest unit), \"50000000000\" (string, smallest unit). Used for: service sale prices, compensation fund balances, Treasury deposits, arbitration fees, reward amounts, stock quantities."},"payment":{"type":"string","description":"Payment object ID"},"type":{"description":"Type of the received object (or inner coin type); used for token_type detection","type":"string"},"version":{"description":"Object version, required to build a Receiving<T> argument for owner_receive","type":"string"},"digest":{"description":"Object digest, required to build a Receiving<T> argument for owner_receive","type":"string"}},"required":["id","balance","payment"],"additionalProperties":false,"description":"Received CoinWrapper object record"},"description":"Received records of Coin objects"}},"required":["balance","token_type","received"],"additionalProperties":false,"description":"Received record of Coin objects"},{"type":"string","const":"recently"}]},"owner_receive":{"description":"Unwrap CoinWrapper objects and other objects received by this Service object and send them to the owner of its Permission object.\n\nACCEPTED FORMATS (F-06 unified receive operation block):\n• 'recently' (string literal) — auto-query and receive ALL recently received objects.\n Use this for the common case: \"withdraw everything the object has received\" — for\n order.receive this is the correct default for \"the buyer got their refund\".\n Example: receive: 'recently'\n• bare object id (string, 0x-prefixed) — one-object form, auto-expanded (F-15):\n pass the id of the single received object you want to unwrap (e.g. a CoinWrapper id).\n Example: receive: '0xabc...'\n• ReceivedNormal[] (array) — explicit list of received objects to unwrap.\n Use this when you want to receive specific objects only (not all).\n Example: receive: [{id: '0xobj1', type: '0x2::coin::Coin<0x2::wow::WOW>'}]\n• ReceivedBalance ({token_type, balance, received: [{id, balance, payment}]}) —\n receive a balance record from a specific Payment/payer.\n Use this for precise balance targeting (advanced — usually after querying\n the object's received history via query_received).\n Example: receive: {token_type: '0x2::wow::WOW', balance: 1000000, received: [{id: '0xrec1', balance: 1000000, payment: '0xpay1'}]}\nANTI-PATTERN: do NOT wrap in {result: ...} — pass the value directly.","anyOf":[{"type":"string","const":"recently"},{"type":"string","pattern":"^0x[0-9a-fA-F]{8,}$"},{"minItems":1,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1,"description":"Received object ID"},"type":{"type":"string","minLength":1,"description":"Object type"},"content_raw":{"description":"Raw content data"},"version":{"description":"Object version, required to build a Receiving<T> argument for owner_receive","type":"string"},"digest":{"description":"Object digest, required to build a Receiving<T> argument for owner_receive","type":"string"}},"required":["id","type"],"additionalProperties":false,"description":"Received normal object record"}},{"type":"object","properties":{"balance":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"A coin/balance amount. Accepts three formats: (1) DISPLAY FORMAT with token symbol: \"2.5WOW\", \"10USDC\", \"0.05WOW\" — auto-converted to smallest units via the Fund Processing Layer (token precision resolved from official registry → cache → on-chain). The symbol MUST match the token's type_parameter. (2) SMALLEST UNIT (numeric string): \"10000000000\" — used as-is, no conversion. (3) SMALLEST UNIT (number): 10000000000 — used as-is only within the safe integer range (±2^53); numbers outside it are REJECTED, use a numeric string instead. PRECISION RULE: for values exceeding 2^53 (9007199254740991), ALWAYS use format (1) or (2) — JS numbers lose integer precision silently and such inputs are blocked. Raw amounts must be plain non-negative integers; a decimal value without a token symbol (e.g. \"2.5\") is rejected — append the symbol (\"2.5WOW\") so the Fund Processing Layer converts it. WARNING — BARE INTEGER MEANS SMALLEST UNIT, NOT TOKENS: formats (2)/(3) are NEVER interpreted as display tokens. For example amount=\"5\" or 5 means 5 raw units = 0.000000005 WOW (9 decimals) — NOT 5 WOW. When the user asks for a token amount, you MUST use display format (\"5WOW\", \"2USDC\"); a bare integer is only correct for unitless counts (e.g. stock quantity) or when you computed exact raw units yourself. Default token: WOW (9 decimals, 1 WOW = 10^9 MIST). For custom tokens: use display format with the token's symbol, or pass smallest units directly. MONEY CONFIRMATION: all monetary fields trigger user confirmation via the Fund Processing Layer, where the token's FULL type, decimals and raw amount are always visible. MULTIPLE ISSUERS: several on-chain tokens may legally share the same symbol (e.g. multiple \"USDT\" coins). When a bare symbol matches more than one token, the operation is BLOCKED and every candidate is listed with full details (type, name, decimals, verified tag) — present the list to the USER and let them choose (they may answer by number), then re-issue with the chosen token's FULL type string in type_parameter; never guess an issuer from the bare symbol. MISSING TOKEN INFO: when a token's precision cannot be resolved, the operation is REFUSED (raw u64 included — amount magnitude could not be verified). Recovery: provide the token's FULL type in package::module::Name form in type_parameter (a bare symbol like \"USDT\" cannot be resolved), and verify the WOW network is correct. Examples: \"2.5WOW\" (display → 2500000000), 10000000000 (number, smallest unit), \"50000000000\" (string, smallest unit). Used for: service sale prices, compensation fund balances, Treasury deposits, arbitration fees, reward amounts, stock quantities."},"token_type":{"type":"string","description":"Asset type of Coin objects. Supports CoinWrapper<...> format for order receive operations."},"received":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Received CoinWrapper object ID"},"balance":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"A coin/balance amount. Accepts three formats: (1) DISPLAY FORMAT with token symbol: \"2.5WOW\", \"10USDC\", \"0.05WOW\" — auto-converted to smallest units via the Fund Processing Layer (token precision resolved from official registry → cache → on-chain). The symbol MUST match the token's type_parameter. (2) SMALLEST UNIT (numeric string): \"10000000000\" — used as-is, no conversion. (3) SMALLEST UNIT (number): 10000000000 — used as-is only within the safe integer range (±2^53); numbers outside it are REJECTED, use a numeric string instead. PRECISION RULE: for values exceeding 2^53 (9007199254740991), ALWAYS use format (1) or (2) — JS numbers lose integer precision silently and such inputs are blocked. Raw amounts must be plain non-negative integers; a decimal value without a token symbol (e.g. \"2.5\") is rejected — append the symbol (\"2.5WOW\") so the Fund Processing Layer converts it. WARNING — BARE INTEGER MEANS SMALLEST UNIT, NOT TOKENS: formats (2)/(3) are NEVER interpreted as display tokens. For example amount=\"5\" or 5 means 5 raw units = 0.000000005 WOW (9 decimals) — NOT 5 WOW. When the user asks for a token amount, you MUST use display format (\"5WOW\", \"2USDC\"); a bare integer is only correct for unitless counts (e.g. stock quantity) or when you computed exact raw units yourself. Default token: WOW (9 decimals, 1 WOW = 10^9 MIST). For custom tokens: use display format with the token's symbol, or pass smallest units directly. MONEY CONFIRMATION: all monetary fields trigger user confirmation via the Fund Processing Layer, where the token's FULL type, decimals and raw amount are always visible. MULTIPLE ISSUERS: several on-chain tokens may legally share the same symbol (e.g. multiple \"USDT\" coins). When a bare symbol matches more than one token, the operation is BLOCKED and every candidate is listed with full details (type, name, decimals, verified tag) — present the list to the USER and let them choose (they may answer by number), then re-issue with the chosen token's FULL type string in type_parameter; never guess an issuer from the bare symbol. MISSING TOKEN INFO: when a token's precision cannot be resolved, the operation is REFUSED (raw u64 included — amount magnitude could not be verified). Recovery: provide the token's FULL type in package::module::Name form in type_parameter (a bare symbol like \"USDT\" cannot be resolved), and verify the WOW network is correct. Examples: \"2.5WOW\" (display → 2500000000), 10000000000 (number, smallest unit), \"50000000000\" (string, smallest unit). Used for: service sale prices, compensation fund balances, Treasury deposits, arbitration fees, reward amounts, stock quantities."},"payment":{"type":"string","description":"Payment object ID"},"type":{"description":"Type of the received object (or inner coin type); used for token_type detection","type":"string"},"version":{"description":"Object version, required to build a Receiving<T> argument for owner_receive","type":"string"},"digest":{"description":"Object digest, required to build a Receiving<T> argument for owner_receive","type":"string"}},"required":["id","balance","payment"],"additionalProperties":false,"description":"Received CoinWrapper object record"},"description":"Received records of Coin objects"}},"required":["balance","token_type","received"],"additionalProperties":false,"description":"Received record of Coin objects"}]},"um":{"description":"Contact object ID or name — the Service's customer-service channel. This is the object that Messenger routes encrypted messages to for pre-order negotiation, private-info delivery (see customer_required), and post-sale support. ⚠️ REQUIRED whenever customer_required is set: without um, the customer's private information has no channel to reach the merchant.","anyOf":[{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},{"type":"null"}]},"arb_statement":{"description":"Service (defendant-side) statement on an arbitration case — permission index 321. Lets the Service permission holder put a bounded text on the record for any case against an order of this service WITHOUT holding the order. Callable in ANY case status. The Arb's coin type is derived automatically from the arb object on-chain.","type":"object","properties":{"arb":{"type":"string","description":"Arb object (case) to attach the statement to."},"order":{"type":"string","description":"The order the case was opened against — must belong to this Service."},"statement":{"type":"string","maxLength":4000,"description":"Seller's text statement appended to the case record (ArbStatementEvent). Event-only: nothing on the Arb object is mutated; the record cannot be rewritten or deleted. Use to declare facts or report the customer's behavior (e.g. absence, non-cooperation). PRIMARY evidence channel is Messenger (encrypted WTS records with the customer); this is the SECONDARY on-chain declare/report channel."}},"required":["arb","order","statement"],"additionalProperties":false},"pause":{"description":"Whether to pause accepting new orders.","type":"boolean"},"publish":{"description":"Whether to publish the Service. After publishing, customers can place orders. ⚠️ PRE-PUBLISH EVALUATION (mandatory, stop-node fund-exit coverage): service.allocators MUST cover EVERY stop node of the bound Machine — every node where an order can rest (terminal nodes AND waiting states: review windows, handovers, open disputes) needs BOTH a withdrawal (release) AND a refund allocation rule, and each mapping guard must be satisfiable in BOTH directions. An uncovered stop node strands escrowed funds permanently (order_allocators is L1-immutable). Review-gated release is a TIME VARIANT inside ONE exit guard ('reviewed OR unreviewed after T'), never parallel outgoing edges (race deadlock). See pattern.fund_flow_stop_node_coverage + rules R-M5-03 / R-M5-09. VERIFIED against Move source + SDK (4-level immutability matrix):\n L1 — PERMANENTLY LOCKED after publish (assert!(!bPublished), no pause+lock exception):\n • machine (workflow template)\n • order_allocators (fund distribution rules — full replacement locked; APPEND-ONLY additions remain possible via order_allocators_append, prefix/threshold frozen)\n L2 — TIME-LOCKED after publish (unpublished-state check — requires pause + setting_lock_duration elapsed):\n • arbitrations remove/clear (dispute resolution objects)\n • rewards remove/clear (reward objects)\n • compensation_fund_withdraw (withdraw ALL funds)\n RATIONALE (deliberate design, NOT a defect): these three REVOKE buyer-facing guarantees that placed orders already rely on — the lock protects buyer expectations. Daily operations (sales add/remove, price, stock, description) are NEVER gated by this lock.\n L3 — REMAIN MUTABLE after publish (no SDK check, no Move check):\n • arbitrations add, rewards add (no assert — can add after publish)\n • buy_guard, sales, discount, description, location, pause, repositories,\n • compensation_fund_add, setting_lock_duration_add, customer_required, um (Contact)\nThese 2 L1-LOCKED fields (machine/order_allocators) MUST be set BEFORE publish=true.\narbitrations/rewards can be ADDED after publish but remove/clear requires pause+lock.\n\n⚠️ COMPENSATION_FUND + ARBITRATION LINKAGE:\n At publish time, if compensation_fund > 0, Arbitration MUST be bound:\n if (balance::value(&self.compensation_fund) > 0) {\n assert!(arbitration_count > 0, E_ARBITRATION_NOT_SET_WITH_COMPENSATION_FUND);\n }\n The MCP handler enforces this as a HARD PRE-CHECK: if publish=true AND compensation_fund_add is set in the same call AND arbitrations is empty, the call is REJECTED before submission. If compensation_fund was deposited in a prior call, a SOFT WARNING is issued.\n\nSCHEMA-03 / P0-01 fix — DEPLOYMENT WORKFLOW (two-phase, avoids circular dependency):\n Phase 1 — CREATE (no publish): object={name:'my-service', type_parameter, permission} + machine + order_allocators + arbitrations.\n NOTE: buy_guard can use a LocalMark NAME (not address) to break the Guard→Service circular dependency.\n The name is resolved to an address at transaction build time.\n Phase 2 — PUBLISH: object='my-service' (string ref) + publish=true.\n All L1-LOCKED fields must be set in Phase 1; Phase 2 only flips the publish flag.\n Post-publish updates: buy_guard, sales, description, repositories (add), rewards (add), arbitrations (add), etc.","type":"boolean"},"creation_plan":{"description":"WIZARD CONTRACT: the Plan JSON that merchant_guide delivered (its creation_plan / plan field), passed back VERBATIM on the Service publish call (data.publish=true). The publish gate replays the plan's freeze matrix (preflight) right before submission and REJECTS the publish when any gate fails (structural issues, critical audit findings, or a failed rule check) — this closes the preflight bypass where a plan that failed merchant_guide's audit could still be materialized manually. OMIT this field on every NON-publish call and on fully manual (non-wizard) builds — the manual path is unchanged and never gated by this field. Do NOT edit, trim, or 'improve' the plan in transit: a mutated plan is rejected (target cross-check) and the publish must be redone from merchant_guide."},"reentry_kind":{"description":"AP-3 loop-semantics declaration for the publish audit (ctra F-06 root cure): overrides the word-stem loop classifier when the machine graph contains a cycle. 'none' = default (word-stem classification) / 'review-loop' = same-order no-charge revisits / 'paid-cycle' = per-revisit fee, fund gate required. MCP-side audit declaration ONLY (pre_publish harness hook) — never sent on-chain; the handler strips it before the SDK call. Mirror of the template frontmatter twin (template-loader).","type":"string","enum":["none","review-loop","paid-cycle"]},"arbitration_open_vote_ack":{"description":"MCP-gate-only declaration (R-ARB-VOTE-LOCK double insurance, TRIAGE-261109 item D): true acknowledges that this Service deliberately binds an identity-less (open-vote) Arbitration voting_guard, downgrading the publish gate's finding from CRITICAL to a disclosed warning. Consumed by the pre_publish harness hook ONLY — never sent on-chain (the handler strips it before the SDK call). Omit for a roster/party voting_guard.","type":"boolean"}},"required":["object"],"additionalProperties":false,"description":"On-chain Service operations. USAGE: (1) CREATE NEW: Set 'object' field with OBJECT format {name, type_parameter, permission, ...} to create a Service. NOTE: 'name' goes INSIDE 'object', NOT at the data root level. 'permission' can be a new Permission object or reference an existing one - check 'object' field description for details. (2) OPERATE EXISTING: Set 'object' field with STRING format (object ID or name). The 'object' field is CRITICAL and REQUIRED in both cases. STRING for existing, OBJECT for new creation."},"idempotency_key":{"type":"string","minLength":8,"maxLength":128,"pattern":"^[A-Za-z0-9._:-]+$","description":"F-RQ-13A (prescription ⑨): idempotency key for this business attempt. REPLAY GUARD: if a previous call with the SAME key is still open (dispatched but outcome unresolved, or already committed), this call is HELD — you get a structured state_conflict envelope with the prior attempt's verification data instead of a second on-chain submission (the ghost-order guard: two live mainnet orders, two escrows). Lifecycle: a deterministic failure (nothing submitted / provably reverted) clears the key — fix the cause and retry with the SAME key; an unknown-outcome failure (submission may have landed) keeps the key HELD — verify on-chain state first (result.submission_verification tells you where to look), and only retry with a NEW key once the outcome is resolved. Keep one key per business attempt (e.g. 'ord-20261030-042-buy'); do not reuse across attempts."},"env":{"type":"object","properties":{"account":{"default":"","type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"permission_guard":{"description":"List of permission guard IDs. Used to extend additional operation permissions (requires verification and configuration in the Permission object).","type":"array","items":{"type":"string"}},"no_cache":{"description":"Whether to disable caching.","type":"boolean"},"network":{"description":"Omit in chat-client contexts — the runtime stamps the user's CURRENT network (the client's UI selection). Standalone MCP/CLI: omit to use the current network; set ONLY when the user explicitly names a different network (a mismatch pauses for user confirmation). Never guess or hardcode a network.","type":"string","enum":["localnet","testnet","mainnet"]},"referrer":{"description":"Referrer ID. If the user is using the network for the first time, the referrer ID will be recorded (also applied when the SDK auto-registers the sender in the global Entity table).","type":"string"},"no_auto_register":{"description":"Opt-out of SDK-level Entity auto-registration. By default, a business transaction whose sender has no entry in the global Entity table automatically appends an entity registration: the sender gets registered and receives an owned Resource object (their on-chain mark book) in the wallet. Set true ONLY when the user explicitly cancelled their entity registration or demands that the transaction not touch the Entity table.","type":"boolean"},"confirmed":{"description":"Phase 2 ConfirmGate: set to true to proceed after a 'pending_confirmation' result. The operation is NOT executed until you re-call with confirmed=true after user consent.","type":"boolean"},"user_intent_phrases":{"description":"Phase 2 ConfirmGate: explicit user intent phrases collected from conversation context (e.g. 'use default account', 'force publish'). Used to bypass confirmation rules whose bypass_on_explicit_intent matches.","type":"array","items":{"type":"string"}},"plan_approval":{"description":"K3 24 PlanApproval: id of a goal whose plan was approved via goal_operation action='approve'. When set: 1) the ConfirmGate treats fail-open rules (standard/none levels) as pre-approved for operations under this goal's plan; 2) after successful CREATION operations, the created objects are auto-registered into the goal (GoalRecord.objects + its TaskProcess manifest — ACT station 'execution registers'). Fail-closed levels (irreversible/publish/amount) still require per-operation confirmation with env.confirmed=true.","type":"string"},"client_schema_version":{"description":"Client-side schema version (semver, e.g. '1.0.0'). When provided, the server checks compatibility and attaches warnings if mismatched.","type":"string"},"schema_strict_mode":{"default":false,"description":"When true, schema incompatibility returns an error instead of a warning. Default: false (warn mode).","type":"boolean"},"dry_run":{"description":"Phase 1 dry_run: when true, SIMULATE the transaction without signing or submitting. Returns effects + events showing what WOULD happen — no on-chain state is modified, no gas is charged. Use this to verify that an operation will succeed before committing. The returned digest will be 'dry_run:<timestamp>' and objectChanges will be empty (simulation only).","type":"boolean"},"window_profile":{"description":"Time-window profile for trial runs (N8 ktt6 F-14 re-carving of the 'business windows are never test-compressed' ruling, 2026-11-04). 'production' (default): compressed time-window violations BLOCK publish exactly as before. 'test': compressed windows are ADMITTED so a disposable trial store can run its full lifecycle fast — R-TIME-PROFILE violations degrade to loud named disclosures, and the publish itself is BLOCKED on a real network (testnet/mainnet); point the trial at a local/dev chain (env.network='localnet'). Trial discipline: test-profile stores are throwaway — a production store must re-issue WITHOUT this flag (guards freeze at publish, so compressed windows are unrepairable except by rebuilding the store).","type":"string","enum":["production","test"]},"response_level":{"description":"Write-success response size. 'compact' (default) trims the structured result to key fields (digest + created object references); 'full' includes the complete raw result. Default: compact.","type":"string","enum":["compact","full"]},"confirm_mode":{"description":"Confirmation frequency for this call. 'full': confirm every matched gate rule. 'streamlined' (client default): skip fail-open 'standard' level prompts — fail-closed levels (irreversible/publish/amount) ALWAYS still confirm. 'quiet': same hard floor as streamlined, for clients that batch/suppress repeat low-risk prompts in their own UI. This field NEVER downgrades fail-closed levels.","type":"string","enum":["full","streamlined","quiet"]}},"required":["account","schema_strict_mode"],"additionalProperties":false,"description":"IMPORTANT: Execution environment includes: account for signing operations, network selection (testnet | localnet | mainnet), additional Guard permissions, and more. Used to specify context information during the call. If account is not specified, the default account (\"\") will be used. NOTE: by default the SDK auto-registers the sender in the global Entity table when absent (first business transaction; the account receives an owned Resource object). Set no_auto_register=true only on explicit user request."},"submission":{"type":"object","properties":{"type":{"type":"string","const":"submission","description":"Discriminator for this result variant. Constraint: always 'submission'. Example: 'submission'"},"guard":{"maxItems":20,"type":"array","items":{"type":"object","properties":{"object":{"type":"string","description":"Guard object name or ID to verify against. Example: 'my-delivery-guard' or '0x123...'"},"impack":{"type":"boolean","description":"Whether this Guard's verification result participates in the final logic. Constraint: if false, the Guard is checked but does not block the operation. Example: true"}},"required":["object","impack"],"additionalProperties":false},"description":"Array of Guard objects to verify. Constraint: at most 20 entries (MAX_GUARD_COUNT_PASSPORT); each entry is an OBJECT {object, impack} — NOT a bare address string. An EMPTY array is rejected at dispatch unless the forward genuinely carries no guards — prefer omitting submission entirely for guard-less edges (kq4x-mn MCP-1: an empty guard list produced no transaction and burned 6 retries on a misleading 'no result'). Relation: each entry corresponds to a Guard bound to the operation."},"submission":{"type":"array","items":{"type":"object","properties":{"guard":{"type":"string","description":"Guard object name or ID that requires submission data. Example: 'my-delivery-guard'"},"submission":{"type":"array","items":{"type":"object","properties":{"identifier":{"type":"integer","minimum":0,"maximum":255,"description":"Identifier (0-255) for data lookup in Guard table. Slot consensus (enforced on-chain at guard table construction): 0-220 = user slots (free for business guards); 221-253 = PROTOCOL-RESERVED (rejected on-chain — reserved so future protocol features get fixed slots without colliding with published guards); 255 = ONCE replay-protection slot on Allocation (byte-keyed, the submitted bytes are the once-key — use for per-period keys like period-<N>); 254 = ONCE-FOR-OBJECT slot on Allocation (chain-derived key = bcs(the Allocation's payment_info.for_object); the submitted bytes are ignored and the submission only arms the slot — use for one-shot per-order rails whose payee is NOT the order itself, such as settlement releases and incentive/bounty claims). NEVER arm 254 on a refund rail: a refund pays the submitted Order through user slot 0, and a refund leg re-entered in a later renewal period would abort E_ONCE_TRIGGERED (16) forever — refund once-ness comes from the terminal-node topology, never from a once slot. SLOT 0 SEMANTICS: slot 0 carries the transacted Order address by convention. As a submission slot it is legal on order/allocation/machine rails (the order exists when those verify), but FORBIDDEN on a Service buy_guard — the order does not exist when the buy-time passport is verified, so the mount is refused (service abort 43)."},"b_submission":{"type":"boolean","description":"Whether this table item's value is submitted dynamically at Guard trigger time (alloc_by_guard call). \n\ntrue = value is submitted by the caller when triggering the Guard. Use for runtime-context-dependent values like order address, user address. The 'value' field is ignored when b_submission=true; the caller must provide it via submissions[]. \n\nfalse = value is static, set at Guard creation time. Use for values known when the Guard is created: expected node names, expected merchant address, expected service address. The 'value' field must be populated and will be stored on-chain permanently. \n\nRule of thumb: if the value is the SAME for all future Guard triggers, use false. If the value DIFFERS per trigger (e.g., which order to release funds for), use true."},"value_type":{"description":"Type of the value stored in `value`. One of: Bool(0), Address(1), String(2), U8(3), U16(4), U32(5), U64(6), U128(7), U256(8), VecBool(9), VecAddress(10), VecString(11), VecU8(12), VecU16(13), VecU32(14), VecU64(15), VecU128(16), VecU256(17), VecVecU8(18). When value_type=Address (1), the `value` field accepts a hex address string, a LocalMark name, or an AccountOrMark_Address object — see `value` field description for details.","anyOf":[{"type":"number","const":0,"description":"Bool (0)"},{"type":"number","const":1,"description":"Address (1)"},{"type":"number","const":2,"description":"String (2)"},{"type":"number","const":3,"description":"U8 (3)"},{"type":"number","const":4,"description":"U16 (4)"},{"type":"number","const":5,"description":"U32 (5)"},{"type":"number","const":6,"description":"U64 (6)"},{"type":"number","const":7,"description":"U128 (7)"},{"type":"number","const":8,"description":"U256 (8)"},{"type":"number","const":9,"description":"VecBool (9)"},{"type":"number","const":10,"description":"VecAddress (10)"},{"type":"number","const":11,"description":"VecString (11)"},{"type":"number","const":12,"description":"VecU8 (12)"},{"type":"number","const":13,"description":"VecU16 (13)"},{"type":"number","const":14,"description":"VecU32 (14)"},{"type":"number","const":15,"description":"VecU64 (15)"},{"type":"number","const":16,"description":"VecU128 (16)"},{"type":"number","const":17,"description":"VecU256 (17)"},{"type":"number","const":18,"description":"VecVecU8 (18)"},{"type":"string","const":"Bool","description":"Bool"},{"type":"string","const":"Address","description":"Address"},{"type":"string","const":"String","description":"String"},{"type":"string","const":"U8","description":"U8"},{"type":"string","const":"U16","description":"U16"},{"type":"string","const":"U32","description":"U32"},{"type":"string","const":"U64","description":"U64"},{"type":"string","const":"U128","description":"U128"},{"type":"string","const":"U256","description":"U256"},{"type":"string","const":"VecBool","description":"VecBool"},{"type":"string","const":"VecAddress","description":"VecAddress"},{"type":"string","const":"VecString","description":"VecString"},{"type":"string","const":"VecU8","description":"VecU8"},{"type":"string","const":"VecU16","description":"VecU16"},{"type":"string","const":"VecU32","description":"VecU32"},{"type":"string","const":"VecU64","description":"VecU64"},{"type":"string","const":"VecU128","description":"VecU128"},{"type":"string","const":"VecU256","description":"VecU256"},{"type":"string","const":"VecVecU8","description":"VecVecU8"},{"type":"string","const":"bool","description":"bool"},{"type":"string","const":"address","description":"address"},{"type":"string","const":"string","description":"string"},{"type":"string","const":"u8","description":"u8"},{"type":"string","const":"u16","description":"u16"},{"type":"string","const":"u32","description":"u32"},{"type":"string","const":"u64","description":"u64"},{"type":"string","const":"u128","description":"u128"},{"type":"string","const":"u256","description":"u256"},{"type":"string","const":"vecbool","description":"vecbool"},{"type":"string","const":"vecaddress","description":"vecaddress"},{"type":"string","const":"vecstring","description":"vecstring"},{"type":"string","const":"vecu8","description":"vecu8"},{"type":"string","const":"vecu16","description":"vecu16"},{"type":"string","const":"vecu32","description":"vecu32"},{"type":"string","const":"vecu64","description":"vecu64"},{"type":"string","const":"vecu128","description":"vecu128"},{"type":"string","const":"vecu256","description":"vecu256"},{"type":"string","const":"vecvecu8","description":"vecvecu8"}]},"value":{"description":"The actual value data. Format depends on `value_type`:\nTYPE-CLASS SPLIT (F03): scalar value_types (Bool/Address/String/U8..U256) take ONE scalar value (boolean/address string/name/string/number); Vec* value_types (VecBool/VecAddress/VecString/VecU8..VecU256) take a REAL JSON ARRAY of elements — a string (even a Python-repr-looking \"[a, b]\") fails serialization with 'value_type=10 (array) requires a array value'. The historical 'static values must be strings' rule applied to SCALARS only.\n• Bool: true/false (boolean)\n• Address (CRITICAL — string 'Address' is NOT a placeholder): a hex address (e.g. '0x1234...'), a LocalMark name (e.g. 'my-service' — resolved to address at evaluation time), an AccountOrMark_Address object (e.g. {name_or_address:'my-service'}), or system shorthand ('0xaaa' = EntityLinker, '0xaab' = EntityRegistrar). The literal string 'Address' itself is INVALID — it would be treated as a non-existent LocalMark name and fail. Example: value='0x2::wow::WOW<address>' or value='my-permission'.\n• String: any string\n• U8/U16/U32/U64/U128/U256: number or numeric string (e.g. 42 or '42')\n• Vec* types: arrays of the corresponding element type\nPROTOCOL SLOT 254 (once, b_submission Address): the submitted value MUST be the ORDER address bound to the operation (payment_info.for_object) — NEVER the Progress/Machine/Arb object the call is advancing. The chain asserts submission(254) == the order address; a Progress address fails the task binding and the forward aborts.\nREQUIRED when b_submission=false. OPTIONAL when b_submission=true (value is supplied at evaluation time by user submission).","anyOf":[{"type":"boolean"},{"anyOf":[{"type":"object","properties":{"name_or_address":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"local_mark_first":{"description":"Whether to prioritize local marks, if true, prioritize local marks, otherwise prioritize global marks","type":"boolean"}},"additionalProperties":false,"description":"Account or address lookup object. Use this to specify which account to use for an operation. EXAMPLE: { name_or_address: 'testor2' } - looks up account by name; EXAMPLE: { name_or_address: '0x1234...' } - uses address directly; If name_or_address is empty string '', uses the default local account. name_or_address is REQUIRED — {} resolves to nothing useful and is rejected."},{"type":"string"}]},{"type":"string"},{"type":"number"},{"type":"array","items":{"type":"boolean"}},{"anyOf":[{"type":"object","properties":{"entities":{"minItems":1,"type":"array","items":{"type":"object","properties":{"name_or_address":{"type":"string","description":"Account/Object name or ID. If specifying an account, use empty string '' for the default account. If it starts with '0x', it will be treated as an ID. Otherwise, it will be treated as a name (max 64 bcs characters)."},"local_mark_first":{"description":"Whether to prioritize local marks, if true, prioritize local marks, otherwise prioritize global marks","type":"boolean"}},"additionalProperties":false,"description":"Account or address lookup object. Use this to specify which account to use for an operation. EXAMPLE: { name_or_address: 'testor2' } - looks up account by name; EXAMPLE: { name_or_address: '0x1234...' } - uses address directly; If name_or_address is empty string '', uses the default local account. name_or_address is REQUIRED — {} resolves to nothing useful and is rejected."}},"check_all_founded":{"default":true,"description":"Whether to check all entities are found. Defaults to true: abort and throw if ANY entity cannot be resolved. Set false only when partial resolution is explicitly intended (only found IDs are returned)","type":"boolean"}},"required":["entities","check_all_founded"],"additionalProperties":false,"description":"Used to batch find account or object IDs by name"},{"type":"array","items":{"type":"string"}}]},{"type":"array","items":{"type":"string"}},{"type":"array","items":{"type":"number"}},{"type":"array","items":{"type":"array","items":{"type":"number"}}}]},"name":{"default":"","description":"Data name identifier. MAX 64 BCS characters (Chinese chars count as 3-4 BCS bytes each). Use short identifiers like 'order_id', 'delivery_node'. Put longer descriptions in the Guard's 'description' field, NOT here.","type":"string"},"object_type":{"description":"OUTPUT-ONLY (query side): Object type when value_type is Address and represents a specific object. Auto-derived by the system — DO NOT set this field at Guard creation.","type":"string","enum":["Permission","Repository","Arb","Arbitration","Service","Machine","Order","Progress","Payment","Treasury","Guard","Demand","Passport","Allocation","Resource","Reward","Discount","EntityRegistrar","EntityLinker","Proof","WReceivedObject","Contact","TableItem_ProgressHistory","TableItem_PermissionPerm","TableItem_DemandPresenter","TableItem_MachineNode","TableItem_TreasuryHistory","TableItem_RepositoryData","TableItem_RewardRecord","TableItem_EntityLinker","TableItem_AddressMark","TableItem_EntityRegistrar"]}},"required":["identifier","b_submission","value_type","name"],"additionalProperties":false,"description":"Guard table item (QUERY/OUTPUT form — includes auto-derived object_type field)"},"description":"User-submitted data matching the Guard's required fields. Relation: structure must match the Guard table's column definitions. Example: [{field:'delivery_proof', value:'Qm...'}] PROTOCOL SLOT 254: when the Guard table has identifier 254, submit the ORDER address bound to the operation (payment_info.for_object) — never the Progress/Machine object being advanced."}},"required":["guard","submission"],"additionalProperties":false,"description":"One Guard's submission data: the Guard to verify plus the user-provided data that satisfies its requirements."},"description":"User-submitted data for each Guard. Relation: one entry per Guard in the guard array; fill submission fields and resubmit via call_with_submission. SLOT COMPLETENESS (T8 az3-mn-261013): the submission array must cover EVERY b_submission slot in the Guard's table, not just one — a Guard whose table has multiple b_submission entries (e.g. slot 0 + slot 254) aborts on-chain with 'Submission ID not found' (abort 11) when any b_submission slot has no matching entry. Check the Guard's table (each entry with b_submission needs its identifier filled) and include ALL of them. PLACEMENT: this `submission` field is at the SAME level as `data` and `env` in the operation input — NOT inside `data.data`. Example structure: {tool:'onchain_operations', data:{operation_type:'order', data:{object:'my_order', progress:{...}}}, submission:{type:'submission', guard:[...], submission:[...]}}"}},"required":["type","guard","submission"],"additionalProperties":false,"description":"Guard verification required. The operation was blocked because one or more Guards require user-submitted data. Fill the submission array and resubmit. Semantic status is 'pending_input'."}},"required":["operation_type","data"],"additionalProperties":false}