@ottochain/sdk 2.4.0 → 2.6.0

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 (227) hide show
  1. package/dist/cjs/apps/compute/index.js +33 -0
  2. package/dist/cjs/apps/compute/state-machines/compute-rule110.js +164 -0
  3. package/dist/cjs/apps/compute/state-machines/index.js +9 -0
  4. package/dist/cjs/apps/contracts/index.js +1 -1
  5. package/dist/cjs/apps/contracts/state-machines/contract-agreement.js +126 -148
  6. package/dist/cjs/apps/contracts/state-machines/contract-escrow.js +153 -174
  7. package/dist/cjs/apps/contracts/state-machines/contract-universal.js +46 -58
  8. package/dist/cjs/apps/corporate/state-machines/corp-board.js +415 -481
  9. package/dist/cjs/apps/corporate/state-machines/corp-entity.js +368 -440
  10. package/dist/cjs/apps/corporate/state-machines/corp-securities.js +532 -647
  11. package/dist/cjs/apps/corporate/state-machines/corp-shareholders.js +499 -603
  12. package/dist/cjs/apps/governance/index.js +7 -7
  13. package/dist/cjs/apps/governance/state-machines/dao-multisig.js +170 -209
  14. package/dist/cjs/apps/governance/state-machines/dao-reputation.js +161 -214
  15. package/dist/cjs/apps/governance/state-machines/dao-single.js +92 -92
  16. package/dist/cjs/apps/governance/state-machines/dao-token.js +169 -223
  17. package/dist/cjs/apps/governance/state-machines/governance-simple.js +185 -217
  18. package/dist/cjs/apps/governance/state-machines/governance-universal.js +64 -64
  19. package/dist/cjs/apps/identity/constants.js +16 -24
  20. package/dist/cjs/apps/identity/index.js +1 -1
  21. package/dist/cjs/apps/identity/state-machines/identity-agent.js +124 -158
  22. package/dist/cjs/apps/identity/state-machines/identity-oracle.js +151 -169
  23. package/dist/cjs/apps/identity/state-machines/identity-registry.js +89 -115
  24. package/dist/cjs/apps/identity/state-machines/identity-universal.js +51 -57
  25. package/dist/cjs/apps/index.js +4 -1
  26. package/dist/cjs/apps/lending/assets.js +41 -17
  27. package/dist/cjs/apps/lending/credit-scoring.js +4 -4
  28. package/dist/cjs/apps/lending/eligibility.js +9 -25
  29. package/dist/cjs/apps/lending/index.js +1 -1
  30. package/dist/cjs/apps/lending/state-machines/lending-zk-loan.js +177 -156
  31. package/dist/cjs/apps/markets/index.js +1 -1
  32. package/dist/cjs/apps/markets/state-machines/market-auction.js +115 -134
  33. package/dist/cjs/apps/markets/state-machines/market-crowdfund.js +122 -137
  34. package/dist/cjs/apps/markets/state-machines/market-group-buy.js +158 -177
  35. package/dist/cjs/apps/markets/state-machines/market-prediction.js +193 -227
  36. package/dist/cjs/apps/markets/state-machines/market-universal.js +65 -80
  37. package/dist/cjs/apps/oracles/index.js +1 -1
  38. package/dist/cjs/apps/privacy/index.js +67 -0
  39. package/dist/cjs/apps/privacy/state-machines/index.js +17 -0
  40. package/dist/cjs/apps/privacy/state-machines/mixer-ddhRing.js +286 -0
  41. package/dist/cjs/apps/privacy/state-machines/note-pool.js +476 -0
  42. package/dist/cjs/apps/staked-pool/assets.js +103 -0
  43. package/dist/cjs/apps/staked-pool/base.js +498 -0
  44. package/dist/cjs/apps/staked-pool/consumer.js +55 -0
  45. package/dist/cjs/apps/staked-pool/index.js +83 -0
  46. package/dist/cjs/apps/staked-pool/state-machines/index.js +12 -0
  47. package/dist/cjs/apps/staked-pool/state-machines/staked-pool-base.js +49 -0
  48. package/dist/cjs/apps/staked-pool/state-machines/staked-pool-oracle.js +131 -0
  49. package/dist/cjs/generated/google/protobuf/struct.js +1 -1
  50. package/dist/cjs/generated/google/protobuf/timestamp.js +1 -1
  51. package/dist/cjs/generated/ottochain/apps/contracts/v1/contract.js +1 -1
  52. package/dist/cjs/generated/ottochain/apps/corporate/v1/corporate.js +1 -1
  53. package/dist/cjs/generated/ottochain/apps/governance/v1/governance.js +1 -1
  54. package/dist/cjs/generated/ottochain/apps/identity/v1/attestation.js +1 -1
  55. package/dist/cjs/generated/ottochain/apps/identity/v1/identity.js +1 -1
  56. package/dist/cjs/generated/ottochain/apps/markets/v1/market.js +1 -1
  57. package/dist/cjs/generated/ottochain/v1/common.js +1 -1
  58. package/dist/cjs/generated/ottochain/v1/fiber.js +40 -2
  59. package/dist/cjs/generated/ottochain/v1/messages.js +1 -1
  60. package/dist/cjs/generated/ottochain/v1/records.js +1 -1
  61. package/dist/cjs/index.js +21 -3
  62. package/dist/cjs/ottochain/genesis-manifest.js +6 -0
  63. package/dist/cjs/ottochain/metagraph-client.js +63 -11
  64. package/dist/cjs/ottochain/snapshot.js +2 -4
  65. package/dist/cjs/ottochain/transaction.js +10 -0
  66. package/dist/cjs/privacy/sealed-bid.js +85 -82
  67. package/dist/cjs/privacy/shield-app.js +32 -32
  68. package/dist/cjs/schema/effects.js +145 -1
  69. package/dist/cjs/schema/fiber-app.js +139 -5
  70. package/dist/cjs/schema/guard-lint.js +3 -12
  71. package/dist/cjs/schema/guards.js +38 -38
  72. package/dist/cjs/templates/asset-policy.js +190 -0
  73. package/dist/cjs/templates/index.js +86 -0
  74. package/dist/cjs/templates/machine.js +130 -0
  75. package/dist/cjs/templates/migration.js +39 -0
  76. package/dist/cjs/templates/state-shape.js +38 -0
  77. package/dist/cjs/validation.js +1 -3
  78. package/dist/esm/apps/compute/index.js +29 -0
  79. package/dist/esm/apps/compute/state-machines/compute-rule110.js +161 -0
  80. package/dist/esm/apps/compute/state-machines/index.js +5 -0
  81. package/dist/esm/apps/contracts/index.js +4 -4
  82. package/dist/esm/apps/contracts/state-machines/contract-agreement.js +128 -150
  83. package/dist/esm/apps/contracts/state-machines/contract-escrow.js +155 -176
  84. package/dist/esm/apps/contracts/state-machines/contract-universal.js +47 -59
  85. package/dist/esm/apps/corporate/index.js +2 -2
  86. package/dist/esm/apps/corporate/state-machines/corp-board.js +418 -484
  87. package/dist/esm/apps/corporate/state-machines/corp-entity.js +371 -443
  88. package/dist/esm/apps/corporate/state-machines/corp-securities.js +535 -650
  89. package/dist/esm/apps/corporate/state-machines/corp-shareholders.js +502 -606
  90. package/dist/esm/apps/governance/index.js +10 -10
  91. package/dist/esm/apps/governance/state-machines/dao-multisig.js +172 -211
  92. package/dist/esm/apps/governance/state-machines/dao-reputation.js +163 -216
  93. package/dist/esm/apps/governance/state-machines/dao-single.js +94 -94
  94. package/dist/esm/apps/governance/state-machines/dao-token.js +171 -225
  95. package/dist/esm/apps/governance/state-machines/governance-simple.js +187 -219
  96. package/dist/esm/apps/governance/state-machines/governance-universal.js +65 -65
  97. package/dist/esm/apps/identity/constants.js +18 -26
  98. package/dist/esm/apps/identity/index.js +8 -8
  99. package/dist/esm/apps/identity/state-machines/identity-agent.js +125 -159
  100. package/dist/esm/apps/identity/state-machines/identity-oracle.js +153 -171
  101. package/dist/esm/apps/identity/state-machines/identity-registry.js +91 -117
  102. package/dist/esm/apps/identity/state-machines/identity-universal.js +52 -58
  103. package/dist/esm/apps/index.js +9 -6
  104. package/dist/esm/apps/lending/assets.js +41 -17
  105. package/dist/esm/apps/lending/credit-scoring.js +6 -6
  106. package/dist/esm/apps/lending/eligibility.js +10 -26
  107. package/dist/esm/apps/lending/index.js +5 -5
  108. package/dist/esm/apps/lending/state-machines/lending-zk-loan.js +178 -157
  109. package/dist/esm/apps/markets/index.js +5 -5
  110. package/dist/esm/apps/markets/state-machines/market-auction.js +117 -136
  111. package/dist/esm/apps/markets/state-machines/market-crowdfund.js +124 -139
  112. package/dist/esm/apps/markets/state-machines/market-group-buy.js +160 -179
  113. package/dist/esm/apps/markets/state-machines/market-prediction.js +195 -229
  114. package/dist/esm/apps/markets/state-machines/market-universal.js +66 -81
  115. package/dist/esm/apps/oracles/index.js +3 -3
  116. package/dist/esm/apps/privacy/index.js +56 -0
  117. package/dist/esm/apps/privacy/state-machines/index.js +6 -0
  118. package/dist/esm/apps/privacy/state-machines/mixer-ddhRing.js +282 -0
  119. package/dist/esm/apps/privacy/state-machines/note-pool.js +470 -0
  120. package/dist/esm/apps/staked-pool/assets.js +91 -0
  121. package/dist/esm/apps/staked-pool/base.js +493 -0
  122. package/dist/esm/apps/staked-pool/consumer.js +49 -0
  123. package/dist/esm/apps/staked-pool/index.js +60 -0
  124. package/dist/esm/apps/staked-pool/state-machines/index.js +6 -0
  125. package/dist/esm/apps/staked-pool/state-machines/staked-pool-base.js +46 -0
  126. package/dist/esm/apps/staked-pool/state-machines/staked-pool-oracle.js +127 -0
  127. package/dist/esm/generated/google/protobuf/struct.js +1 -1
  128. package/dist/esm/generated/google/protobuf/timestamp.js +1 -1
  129. package/dist/esm/generated/ottochain/apps/contracts/v1/contract.js +1 -1
  130. package/dist/esm/generated/ottochain/apps/corporate/v1/corporate.js +1 -1
  131. package/dist/esm/generated/ottochain/apps/governance/v1/governance.js +1 -1
  132. package/dist/esm/generated/ottochain/apps/identity/v1/attestation.js +1 -1
  133. package/dist/esm/generated/ottochain/apps/identity/v1/identity.js +1 -1
  134. package/dist/esm/generated/ottochain/apps/markets/v1/market.js +1 -1
  135. package/dist/esm/generated/ottochain/v1/common.js +1 -1
  136. package/dist/esm/generated/ottochain/v1/fiber.js +40 -2
  137. package/dist/esm/generated/ottochain/v1/messages.js +1 -1
  138. package/dist/esm/generated/ottochain/v1/records.js +1 -1
  139. package/dist/esm/index.js +10 -4
  140. package/dist/esm/ottochain/genesis-manifest.js +6 -0
  141. package/dist/esm/ottochain/metagraph-client.js +63 -11
  142. package/dist/esm/ottochain/snapshot.js +2 -4
  143. package/dist/esm/ottochain/transaction.js +8 -0
  144. package/dist/esm/privacy/index.js +2 -2
  145. package/dist/esm/privacy/sealed-bid.js +87 -84
  146. package/dist/esm/privacy/shield-app.js +33 -33
  147. package/dist/esm/schema/effects.js +137 -0
  148. package/dist/esm/schema/fiber-app.js +134 -5
  149. package/dist/esm/schema/guard-lint.js +3 -12
  150. package/dist/esm/schema/guards.js +36 -37
  151. package/dist/esm/templates/asset-policy.js +182 -0
  152. package/dist/esm/templates/index.js +41 -0
  153. package/dist/esm/templates/machine.js +125 -0
  154. package/dist/esm/templates/migration.js +34 -0
  155. package/dist/esm/templates/state-shape.js +34 -0
  156. package/dist/esm/validation.js +1 -3
  157. package/dist/esm/zk/index.js +4 -4
  158. package/dist/types/apps/compute/index.d.ts +176 -0
  159. package/dist/types/apps/compute/state-machines/compute-rule110.d.ts +157 -0
  160. package/dist/types/apps/compute/state-machines/index.d.ts +5 -0
  161. package/dist/types/apps/contracts/index.d.ts +14 -14
  162. package/dist/types/apps/contracts/state-machines/contract-agreement.d.ts +3 -3
  163. package/dist/types/apps/contracts/state-machines/contract-escrow.d.ts +3 -3
  164. package/dist/types/apps/contracts/state-machines/contract-universal.d.ts +4 -4
  165. package/dist/types/apps/corporate/index.d.ts +162 -162
  166. package/dist/types/apps/corporate/state-machines/corp-board.d.ts +88 -88
  167. package/dist/types/apps/corporate/state-machines/corp-entity.d.ts +14 -14
  168. package/dist/types/apps/corporate/state-machines/corp-securities.d.ts +18 -18
  169. package/dist/types/apps/corporate/state-machines/corp-shareholders.d.ts +43 -43
  170. package/dist/types/apps/governance/index.d.ts +81 -81
  171. package/dist/types/apps/governance/state-machines/dao-multisig.d.ts +16 -16
  172. package/dist/types/apps/governance/state-machines/dao-reputation.d.ts +22 -22
  173. package/dist/types/apps/governance/state-machines/dao-token.d.ts +21 -21
  174. package/dist/types/apps/governance/state-machines/governance-simple.d.ts +11 -11
  175. package/dist/types/apps/governance/state-machines/governance-universal.d.ts +4 -4
  176. package/dist/types/apps/identity/constants.d.ts +2 -2
  177. package/dist/types/apps/identity/index.d.ts +70 -70
  178. package/dist/types/apps/identity/state-machines/identity-agent.d.ts +23 -23
  179. package/dist/types/apps/identity/state-machines/identity-oracle.d.ts +11 -11
  180. package/dist/types/apps/identity/state-machines/identity-registry.d.ts +27 -27
  181. package/dist/types/apps/identity/state-machines/identity-universal.d.ts +4 -4
  182. package/dist/types/apps/index.d.ts +9 -6
  183. package/dist/types/apps/lending/assets.d.ts +2 -2
  184. package/dist/types/apps/lending/credit-scoring.d.ts +5 -5
  185. package/dist/types/apps/lending/eligibility.d.ts +2 -2
  186. package/dist/types/apps/lending/index.d.ts +20 -12
  187. package/dist/types/apps/lending/state-machines/lending-zk-loan.d.ts +15 -7
  188. package/dist/types/apps/markets/index.d.ts +76 -76
  189. package/dist/types/apps/markets/state-machines/market-auction.d.ts +12 -12
  190. package/dist/types/apps/markets/state-machines/market-crowdfund.d.ts +19 -19
  191. package/dist/types/apps/markets/state-machines/market-group-buy.d.ts +18 -18
  192. package/dist/types/apps/markets/state-machines/market-prediction.d.ts +15 -15
  193. package/dist/types/apps/markets/state-machines/market-universal.d.ts +7 -7
  194. package/dist/types/apps/oracles/index.d.ts +1 -1
  195. package/dist/types/apps/privacy/index.d.ts +328 -0
  196. package/dist/types/apps/privacy/state-machines/index.d.ts +6 -0
  197. package/dist/types/apps/privacy/state-machines/mixer-ddhRing.d.ts +337 -0
  198. package/dist/types/apps/privacy/state-machines/note-pool.d.ts +196 -0
  199. package/dist/types/apps/staked-pool/assets.d.ts +53 -0
  200. package/dist/types/apps/staked-pool/base.d.ts +80 -0
  201. package/dist/types/apps/staked-pool/consumer.d.ts +29 -0
  202. package/dist/types/apps/staked-pool/index.d.ts +51 -0
  203. package/dist/types/apps/staked-pool/state-machines/index.d.ts +6 -0
  204. package/dist/types/apps/staked-pool/state-machines/staked-pool-base.d.ts +8 -0
  205. package/dist/types/apps/staked-pool/state-machines/staked-pool-oracle.d.ts +34 -0
  206. package/dist/types/generated/openapi.d.ts +13 -0
  207. package/dist/types/generated/ottochain/v1/fiber.d.ts +7 -0
  208. package/dist/types/index.d.ts +3 -3
  209. package/dist/types/openapi.d.ts +4 -2
  210. package/dist/types/ottochain/genesis-manifest.d.ts +6 -0
  211. package/dist/types/ottochain/index.d.ts +1 -1
  212. package/dist/types/ottochain/metagraph-client.d.ts +69 -15
  213. package/dist/types/ottochain/transaction.d.ts +9 -1
  214. package/dist/types/ottochain/types.d.ts +1 -1
  215. package/dist/types/privacy/index.d.ts +2 -2
  216. package/dist/types/privacy/sealed-bid.d.ts +9 -9
  217. package/dist/types/privacy/shield-app.d.ts +1 -1
  218. package/dist/types/schema/effects.d.ts +132 -0
  219. package/dist/types/schema/fiber-app.d.ts +281 -0
  220. package/dist/types/schema/guards.d.ts +12 -0
  221. package/dist/types/templates/asset-policy.d.ts +119 -0
  222. package/dist/types/templates/index.d.ts +26 -0
  223. package/dist/types/templates/machine.d.ts +139 -0
  224. package/dist/types/templates/migration.d.ts +34 -0
  225. package/dist/types/templates/state-shape.d.ts +30 -0
  226. package/dist/types/zk/index.d.ts +4 -4
  227. package/package.json +31 -13
@@ -6,12 +6,132 @@
6
6
  * no JSON, no code generation. Import types directly.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.IMMUTABLE_POLICY = void 0;
10
+ exports.unconstrained = unconstrained;
11
+ exports.immutable = immutable;
12
+ exports.constrained = constrained;
13
+ exports.projectFiberPolicy = projectFiberPolicy;
9
14
  exports.defineFiberApp = defineFiberApp;
10
15
  exports.getTransitionsFrom = getTransitionsFrom;
11
16
  exports.getEventsFrom = getEventsFrom;
12
17
  exports.isFinalState = isFinalState;
13
18
  exports.toJSON = toJSON;
14
19
  exports.toProtoDefinition = toProtoDefinition;
20
+ /**
21
+ * The wire (and authoring) tag for the `Immutable` policy VARIANT: the bare JSON string
22
+ * `"Immutable"`. EXACT casing, capital-I — this is the POLICY-LEVEL variant name and is
23
+ * DISTINCT from the `upgradePolicy` dial VALUE `"immutable"` (lowercase). The chain emits
24
+ * exactly this capital-I string for `Immutable`, so the SDK must too, byte-for-byte.
25
+ */
26
+ exports.IMMUTABLE_POLICY = 'Immutable';
27
+ /** The names of the 15 policy dials, in declaration order. Used by the projector. */
28
+ const FIBER_POLICY_DIALS = [
29
+ 'selfReproducing',
30
+ 'allowedEffects',
31
+ 'spawnOwnerPolicy',
32
+ 'maxGenerations',
33
+ 'maxSpawnFanout',
34
+ 'acceptedCallers',
35
+ 'sealedStates',
36
+ 'transitionPolicy',
37
+ 'transferPolicy',
38
+ 'dependencyPolicy',
39
+ 'upgradePolicy',
40
+ 'version',
41
+ 'compatibleWith',
42
+ 'interfaces',
43
+ 'migrationAuthority',
44
+ ];
45
+ /**
46
+ * The canonical UNCONSTRAINED policy: omission. Provided as a named export for
47
+ * readability at call sites — `policy: unconstrained()` documents intent, and projects
48
+ * to NO `policy` key (identical to leaving `policy` off entirely).
49
+ */
50
+ function unconstrained() {
51
+ return undefined;
52
+ }
53
+ /**
54
+ * The canonical IMMUTABLE policy: the definition is permanently locked. Projects to the
55
+ * bare JSON string `"Immutable"` ({@link IMMUTABLE_POLICY}), the chain's `Immutable`
56
+ * variant tag. Semantically equivalent to `constrained({ upgradePolicy: 'immutable' })`
57
+ * with no other dial set — which `constrained()`/`projectFiberPolicy()` collapse to the
58
+ * same string for wire parity (see {@link constrained}).
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * const def = defineFiberApp({ ...spec, policy: immutable() });
63
+ * ```
64
+ */
65
+ function immutable() {
66
+ return exports.IMMUTABLE_POLICY;
67
+ }
68
+ /**
69
+ * Build a CONSTRAINED `FiberPolicy` from any subset of the 15 dials.
70
+ *
71
+ * Pass only the dials you want to set. Dials left `undefined`/`null` are dropped so the
72
+ * result is a clean, minimal object that serializes identically to the chain's
73
+ * `dropNulls`-stripped `Constrained`. If NO dial is effectively set, this returns
74
+ * `undefined` (an empty constraint == `Unconstrained`), which projects to no `policy`
75
+ * key — preserving wire parity.
76
+ *
77
+ * CANONICAL COLLAPSE: `constrained({ upgradePolicy: 'immutable' })` with NO other dial set
78
+ * collapses to the bare string `"Immutable"` ({@link IMMUTABLE_POLICY}), because the chain
79
+ * collapses that exact `Constrained` into the `Immutable` variant. NOTE the casing: the
80
+ * collapse triggers on the chain's LOWERCASE upgradePolicy dial value `"immutable"`, and
81
+ * the result is the capital-I policy-variant tag `"Immutable"`. Signing the dials object
82
+ * `{ "upgradePolicy": "immutable" }` instead would diverge the canonical (the chain
83
+ * re-encodes it as `"Immutable"`) and break the create signature. Adding ANY other dial
84
+ * keeps it a dials object.
85
+ *
86
+ * @example
87
+ * ```ts
88
+ * const policy = constrained({
89
+ * selfReproducing: false,
90
+ * maxGenerations: 3,
91
+ * allowedEffects: ['EMIT', 'TRANSFER'],
92
+ * sealedStates: ['ARCHIVED'],
93
+ * });
94
+ * ```
95
+ */
96
+ function constrained(dials) {
97
+ const out = {};
98
+ for (const k of FIBER_POLICY_DIALS) {
99
+ const v = dials[k];
100
+ if (v === undefined || v === null)
101
+ continue;
102
+ out[k] = v;
103
+ }
104
+ const keys = Object.keys(out);
105
+ if (keys.length === 0)
106
+ return undefined;
107
+ // Canonical collapse: a lone LOWERCASE `upgradePolicy: 'immutable'` (the chain's dial
108
+ // value) IS the `Immutable` variant — emit the capital-I `"Immutable"` tag, not the dials.
109
+ if (keys.length === 1 && out.upgradePolicy === 'immutable')
110
+ return exports.IMMUTABLE_POLICY;
111
+ return out;
112
+ }
113
+ /**
114
+ * Project an authoring `policy` value onto the wire form. Returns one of:
115
+ * - `undefined` when the policy is (effectively) `Unconstrained` — i.e. omit the `policy`
116
+ * key entirely;
117
+ * - the bare string `"Immutable"` ({@link IMMUTABLE_POLICY}) for the `Immutable` variant
118
+ * (also the collapse of a lone LOWERCASE `upgradePolicy: 'immutable'`); or
119
+ * - the minimal `Constrained` dials object otherwise.
120
+ *
121
+ * Centralizes the omit-on-unconstrained AND the Immutable-collapse parity rules so every
122
+ * projection path (`toProtoDefinition`, the genesis manifest) stays consistent.
123
+ */
124
+ function projectFiberPolicy(policy) {
125
+ if (policy === undefined || policy === null)
126
+ return undefined;
127
+ // The Immutable variant is already its canonical bare-string wire form.
128
+ if (policy === exports.IMMUTABLE_POLICY)
129
+ return exports.IMMUTABLE_POLICY;
130
+ // Re-run the dial filter so a hand-built object with explicit-undefined/empty dials
131
+ // collapses to Unconstrained, and a lone `upgradePolicy: 'immutable'` collapses to
132
+ // `"Immutable"`, exactly like `constrained()` does.
133
+ return constrained(policy);
134
+ }
15
135
  // =============================================================================
16
136
  // Helper: defineFiberApp
17
137
  // =============================================================================
@@ -39,11 +159,11 @@ function defineFiberApp(definition) {
39
159
  }
40
160
  /** Get valid transitions from a given state */
41
161
  function getTransitionsFrom(def, state) {
42
- return def.transitions.filter(t => t.from === state);
162
+ return def.transitions.filter((t) => t.from === state);
43
163
  }
44
164
  /** Get valid event names from a given state */
45
165
  function getEventsFrom(def, state) {
46
- return getTransitionsFrom(def, state).map(t => t.eventName);
166
+ return getTransitionsFrom(def, state).map((t) => t.eventName);
47
167
  }
48
168
  /** Check if a state is final */
49
169
  function isFinalState(def, state) {
@@ -70,12 +190,17 @@ function toProtoDefinition(def) {
70
190
  const protoDef = {
71
191
  states: {},
72
192
  initialState: def.initialState,
73
- transitions: def.transitions.map(t => ({
193
+ transitions: def.transitions.map((t) => ({
74
194
  from: t.from,
75
195
  to: t.to,
76
196
  eventName: t.eventName,
77
- guard: t.guard, // Required - Scala has no default
78
- effect: t.effect, // Required - Scala has no default
197
+ // guard/effect are REQUIRED by the Scala `Transition` case class (no defaults). The authoring
198
+ // `Transition` types them OPTIONAL for ergonomics, so ALWAYS project a concrete value here — an
199
+ // omitted key would serialize to `undefined`, get dropped, and fail the chain's decode (HTTP 400).
200
+ // The defaults are the exact shapes the chain's `PublishVersionSigningCanonicalSuite` accepts:
201
+ // an always-true guard `{"==":[1,1]}` and an empty (no-op) effect `{}`.
202
+ guard: t.guard ?? { '==': [1, 1] },
203
+ effect: t.effect ?? {},
79
204
  // Chain `Transition.dependencies: Set[UUID]` is REQUIRED (no Scala default), and each
80
205
  // element must be a fiber UUID string. A `DependencySpec` object is a build-time-only
81
206
  // authoring affordance with no wire representation (concrete dependency UUIDs are per
@@ -98,5 +223,14 @@ function toProtoDefinition(def) {
98
223
  // change the signed digest of an otherwise-identical machine), so it is deliberately NOT emitted
99
224
  // (the chain's `StateMachineDefinition.metadata` stays absent → `None`). A caller that genuinely
100
225
  // needs on-chain metadata sets `ProtoStateMachineDefinition.metadata` explicitly after conversion.
226
+ // Fiber constitution. OMIT the `policy` key entirely for `Unconstrained` (the chain
227
+ // emits nothing for it); emit the bare string `"Immutable"` for `Immutable`; emit a bare
228
+ // object of only the SET dials for `Constrained`. `projectFiberPolicy` returns `undefined`
229
+ // for an (effectively) unconstrained policy, so we assign only when it is a real policy —
230
+ // keeping the wire byte-for-byte identical to the chain's encoding.
231
+ const policy = projectFiberPolicy(def.policy);
232
+ if (policy !== undefined) {
233
+ protoDef.policy = policy;
234
+ }
101
235
  return protoDef;
102
236
  }
@@ -64,11 +64,7 @@ exports.LINT_CODES = {
64
64
  * The ONLY `$`-prefixed keys the engine injects (`ReservedKeys`). Anything else
65
65
  * (`$timestamp`, `$now`, ...) resolves to null on chain.
66
66
  */
67
- exports.INJECTED_RESERVED_VARS = new Set([
68
- '$ordinal',
69
- '$lastSnapshotHash',
70
- '$epochProgress',
71
- ]);
67
+ exports.INJECTED_RESERVED_VARS = new Set(['$ordinal', '$lastSnapshotHash', '$epochProgress']);
72
68
  /**
73
69
  * Tags that LOOK like opcodes and appear in real definitions but are NOT valid
74
70
  * JLVM operators — metakit mis-decodes each as a literal Map. These are always
@@ -123,11 +119,7 @@ function lintGuardExpression(node, ctx, path, inDataLiteral = false) {
123
119
  const ref = obj.var;
124
120
  // The reference may be a string, or `[path, default]`, or (rarely) a
125
121
  // nested expression; only string refs carry the patterns we check.
126
- const refStr = typeof ref === 'string'
127
- ? ref
128
- : Array.isArray(ref) && typeof ref[0] === 'string'
129
- ? ref[0]
130
- : undefined;
122
+ const refStr = typeof ref === 'string' ? ref : Array.isArray(ref) && typeof ref[0] === 'string' ? ref[0] : undefined;
131
123
  if (refStr !== undefined) {
132
124
  // rule 1 — unknown reserved `$`-key
133
125
  if (refStr.startsWith('$') && !exports.INJECTED_RESERVED_VARS.has(refStr)) {
@@ -156,8 +148,7 @@ function lintGuardExpression(node, ctx, path, inDataLiteral = false) {
156
148
  });
157
149
  }
158
150
  // rule 3 — `witness.*` read inside a fiber transition
159
- if (ctx.flagWitness &&
160
- (refStr === 'witness' || refStr.startsWith('witness.'))) {
151
+ if (ctx.flagWitness && (refStr === 'witness' || refStr.startsWith('witness.'))) {
161
152
  out.push({
162
153
  app: ctx.app,
163
154
  transition: ctx.transition,
@@ -13,14 +13,14 @@
13
13
  * Use these so the safe pattern is consistent, greppable, and impossible to get subtly wrong.
14
14
  */
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.depInState = exports.signerHasRoleVia = exports.signerHasReputationVia = exports.signerHasRole = exports.signerHasReputation = exports.actorHasEntry = exports.actorInSet = exports.actorIsSigner = exports.assetSignerIs = exports.signerHasEntry = exports.signerIsNotParty = exports.signerInSet = exports.signerIsAnyParty = exports.signerIsParty = void 0;
16
+ exports.depInState = exports.actorNotInArray = exports.signerHasRoleVia = exports.signerHasReputationVia = exports.signerHasRole = exports.signerHasReputation = exports.actorHasEntry = exports.actorInSet = exports.actorIsSigner = exports.assetSignerIs = exports.signerHasEntry = exports.signerIsNotParty = exports.signerInSet = exports.signerIsAnyParty = exports.signerIsParty = void 0;
17
17
  /**
18
18
  * FIBER-transition authorization: the pinned `partyVar` (a `state` path holding an address, e.g.
19
19
  * `"state.borrower"`) MUST be among the op's verified signers (`proofs[].address`). The replay-safe
20
20
  * replacement for `{"===":[{"var":"event.agent"}, {"var":partyVar}]}`.
21
21
  */
22
22
  const signerIsParty = (partyVar) => ({
23
- in: [{ var: partyVar }, { map: [{ var: "proofs" }, { var: "address" }] }],
23
+ in: [{ var: partyVar }, { map: [{ var: 'proofs' }, { var: 'address' }] }],
24
24
  });
25
25
  exports.signerIsParty = signerIsParty;
26
26
  /** FIBER-transition authorization where ANY of the pinned parties signed (e.g. borrower OR lender). */
@@ -34,10 +34,7 @@ exports.signerIsAnyParty = signerIsAnyParty;
34
34
  * The replay-safe replacement for `{"in":[{"var":"event.agent"}, {"var":setVar}]}`.
35
35
  */
36
36
  const signerInSet = (setVar) => ({
37
- some: [
38
- { map: [{ var: "proofs" }, { var: "address" }] },
39
- { in: [{ var: "" }, { var: setVar }] },
40
- ],
37
+ some: [{ map: [{ var: 'proofs' }, { var: 'address' }] }, { in: [{ var: '' }, { var: setVar }] }],
41
38
  });
42
39
  exports.signerInSet = signerInSet;
43
40
  /**
@@ -45,7 +42,7 @@ exports.signerInSet = signerInSet;
45
42
  * not vote on their own proposal). The replay-safe replacement for `{"!==":[{"var":"event.agent"}, {"var":partyVar}]}`.
46
43
  */
47
44
  const signerIsNotParty = (partyVar) => ({
48
- "!": [(0, exports.signerIsParty)(partyVar)],
45
+ '!': [(0, exports.signerIsParty)(partyVar)],
49
46
  });
50
47
  exports.signerIsNotParty = signerIsNotParty;
51
48
  /**
@@ -57,10 +54,7 @@ exports.signerIsNotParty = signerIsNotParty;
57
54
  * `{"some":[{"map":[proofs,address]},{">=":[{"get":[mapVar,{"var":""}]}, N]}]}`.
58
55
  */
59
56
  const signerHasEntry = (mapVar) => ({
60
- some: [
61
- { map: [{ var: "proofs" }, { var: "address" }] },
62
- { has: [{ var: mapVar }, { var: "" }] },
63
- ],
57
+ some: [{ map: [{ var: 'proofs' }, { var: 'address' }] }, { has: [{ var: mapVar }, { var: '' }] }],
64
58
  });
65
59
  exports.signerHasEntry = signerHasEntry;
66
60
  /**
@@ -69,7 +63,7 @@ exports.signerHasEntry = signerHasEntry;
69
63
  * `event` or `proofs` — it injects `signers` directly.
70
64
  */
71
65
  const assetSignerIs = (addressVar) => ({
72
- in: [{ var: addressVar }, { var: "signers" }],
66
+ in: [{ var: addressVar }, { var: 'signers' }],
73
67
  });
74
68
  exports.assetSignerIs = assetSignerIs;
75
69
  /**
@@ -84,7 +78,7 @@ exports.assetSignerIs = assetSignerIs;
84
78
  * both signed and is authorized, and the effect can only write under that one verified key.
85
79
  * Structurally identical to {@link signerIsParty}; named for intent + greppability at write sites.
86
80
  */
87
- const actorIsSigner = (actorVar = "event.agent") => (0, exports.signerIsParty)(actorVar);
81
+ const actorIsSigner = (actorVar = 'event.agent') => (0, exports.signerIsParty)(actorVar);
88
82
  exports.actorIsSigner = actorIsSigner;
89
83
  /**
90
84
  * EFFECT-KEY-BINDING membership: the event's claimed actor (`actorVar`, default `event.agent`) is BOTH
@@ -96,7 +90,7 @@ exports.actorIsSigner = actorIsSigner;
96
90
  * verified-but-unauthorized address as the key (padding a signature/vote tally). `actorInSet` pins both
97
91
  * to the same `actorVar`.
98
92
  */
99
- const actorInSet = (setVar, actorVar = "event.agent") => ({
93
+ const actorInSet = (setVar, actorVar = 'event.agent') => ({
100
94
  and: [(0, exports.actorIsSigner)(actorVar), { in: [{ var: actorVar }, { var: setVar }] }],
101
95
  });
102
96
  exports.actorInSet = actorInSet;
@@ -109,7 +103,7 @@ exports.actorInSet = actorInSet;
109
103
  * is an authorized member, closing the vote/signature-stuffing gap that bare {@link signerHasEntry}
110
104
  * leaves open (which only proves SOME verified signer is a key, not that the written key is).
111
105
  */
112
- const actorHasEntry = (mapVar, actorVar = "event.agent") => ({
106
+ const actorHasEntry = (mapVar, actorVar = 'event.agent') => ({
113
107
  and: [(0, exports.actorIsSigner)(actorVar), { has: [{ var: mapVar }, { var: actorVar }] }],
114
108
  });
115
109
  exports.actorHasEntry = actorHasEntry;
@@ -124,9 +118,9 @@ exports.actorHasEntry = actorHasEntry;
124
118
  */
125
119
  const signerHasReputation = (repMapVar, thresholdVar) => ({
126
120
  some: [
127
- { map: [{ var: "proofs" }, { var: "address" }] },
121
+ { map: [{ var: 'proofs' }, { var: 'address' }] },
128
122
  {
129
- ">=": [{ get: [{ var: repMapVar }, { var: "" }] }, { var: thresholdVar }],
123
+ '>=': [{ get: [{ var: repMapVar }, { var: '' }] }, { var: thresholdVar }],
130
124
  },
131
125
  ],
132
126
  });
@@ -153,26 +147,23 @@ exports.signerHasRole = signerHasRole;
153
147
  */
154
148
  const signerHasReputationVia = (registryIdVar, thresholdVar) => ({
155
149
  if: [
156
- { has: [{ var: "machines" }, { var: registryIdVar }] },
150
+ { has: [{ var: 'machines' }, { var: registryIdVar }] },
157
151
  {
158
152
  some: [
159
- { map: [{ var: "proofs" }, { var: "address" }] },
153
+ { map: [{ var: 'proofs' }, { var: 'address' }] },
160
154
  {
161
- ">=": [
155
+ '>=': [
162
156
  {
163
157
  get: [
164
158
  {
165
159
  get: [
166
160
  {
167
- get: [
168
- { get: [{ var: "machines" }, { var: registryIdVar }] },
169
- "state",
170
- ],
161
+ get: [{ get: [{ var: 'machines' }, { var: registryIdVar }] }, 'state'],
171
162
  },
172
- "reputations",
163
+ 'reputations',
173
164
  ],
174
165
  },
175
- { var: "" },
166
+ { var: '' },
176
167
  ],
177
168
  },
178
169
  { var: thresholdVar },
@@ -194,24 +185,21 @@ exports.signerHasReputationVia = signerHasReputationVia;
194
185
  */
195
186
  const signerHasRoleVia = (registryIdVar, roleField) => ({
196
187
  if: [
197
- { has: [{ var: "machines" }, { var: registryIdVar }] },
188
+ { has: [{ var: 'machines' }, { var: registryIdVar }] },
198
189
  {
199
190
  some: [
200
- { map: [{ var: "proofs" }, { var: "address" }] },
191
+ { map: [{ var: 'proofs' }, { var: 'address' }] },
201
192
  {
202
193
  has: [
203
194
  {
204
195
  get: [
205
196
  {
206
- get: [
207
- { get: [{ var: "machines" }, { var: registryIdVar }] },
208
- "state",
209
- ],
197
+ get: [{ get: [{ var: 'machines' }, { var: registryIdVar }] }, 'state'],
210
198
  },
211
199
  roleField,
212
200
  ],
213
201
  },
214
- { var: "" },
202
+ { var: '' },
215
203
  ],
216
204
  },
217
205
  ],
@@ -231,14 +219,26 @@ exports.signerHasRoleVia = signerHasRoleVia;
231
219
  * so a single gated transition is split into a bind step then this assert step. See
232
220
  * docs/design/app-hardening-identity-integration.md §5–§6.
233
221
  */
222
+ /**
223
+ * EFFECT-KEY-BINDING dedup over an ARRAY of records: no existing element of the array at `arrayVar`
224
+ * (e.g. `"state.submissions"`, shaped `[ { addr, value }, … ]`) has its `field` (default `"addr"`)
225
+ * equal to the actor at `actorVar` (default `"event.agent"`). The array analog of the map-keyed
226
+ * `{"!":[has(...)]}` dedup — used where the collection is an append-only array of `{addr,…}` records
227
+ * (there is no `(array,string)` key check, but `none` over the array with a per-element `===` is total).
228
+ *
229
+ * The bare-element callback context inside `none` sees each record map directly, so `{get:[{var:""},field]}`
230
+ * is a valid `(map,string)` read. Pair with an `actorIsSigner`/`actorHasEntry` clause on the same
231
+ * `actorVar` (the dedup proves "not yet present", not "is the verified signer").
232
+ */
233
+ const actorNotInArray = (arrayVar, field = 'addr', actorVar = 'event.agent') => ({
234
+ none: [{ var: arrayVar }, { '===': [{ get: [{ var: '' }, field] }, { var: actorVar }] }],
235
+ });
236
+ exports.actorNotInArray = actorNotInArray;
234
237
  const depInState = (refVar, requiredState) => ({
235
238
  if: [
236
- { has: [{ var: "machines" }, { var: refVar }] },
239
+ { has: [{ var: 'machines' }, { var: refVar }] },
237
240
  {
238
- "==": [
239
- { get: [{ get: [{ var: "machines" }, { var: refVar }] }, "currentStateId"] },
240
- requiredState,
241
- ],
241
+ '==': [{ get: [{ get: [{ var: 'machines' }, { var: refVar }] }, 'currentStateId'] }, requiredState],
242
242
  },
243
243
  false,
244
244
  ],
@@ -0,0 +1,190 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sumBehavior = sumBehavior;
4
+ exports.defaultStateTypeName = defaultStateTypeName;
5
+ exports.fungiblePolicy = fungiblePolicy;
6
+ exports.nftPolicy = nftPolicy;
7
+ exports.soulboundPolicy = soulboundPolicy;
8
+ exports.customPolicy = customPolicy;
9
+ /**
10
+ * Asset-policy preset builders (§1.1 of the SDK std-lib/templates handoff).
11
+ *
12
+ * Each builder is a PURE function that emits the exact {@link CreateAssetPolicy} wire body the chain
13
+ * re-derives — no `Date.now()`/`Math.random()`/`crypto.randomUUID()`; fixed inputs → fixed output. The
14
+ * on-chain policy `schemaHash` and `logicHash` are both `RegistryShape.AssetPolicy.computeDigest` over
15
+ * `behavior`/`supply`/`morphisms`/`stateShape` (no JSON-Logic body), so these presets are pure data.
16
+ *
17
+ * Hard invariants (CLAUDE.md rule #1 — the signed canonical is frozen):
18
+ * - `behavior` is ALWAYS summed from {@link TOKEN_BEHAVIOR_BITS} (T=16, S=8, C=4, E=2, G=1), never a
19
+ * magic literal int.
20
+ * - `morphisms` is REQUIRED on the wire (presence required, emptiness meaningful) — emit `{}` when empty,
21
+ * NEVER omit it.
22
+ * - `supply` is REQUIRED — emit `{}` when there is no supply authority, never omit it.
23
+ * - Absent optionals are OMITTED, never emitted as `null`/`undefined` (the chain signs over
24
+ * `JCS(dropNulls(payload))`).
25
+ *
26
+ * @see src/ottochain/types.ts — CreateAssetPolicy, SupplyPolicy, MorphismSpec, MorphismKind, TOKEN_BEHAVIOR_BITS
27
+ */
28
+ const types_js_1 = require("../ottochain/types.js");
29
+ /** The default mint/burn guard the riverdale presets use: an always-true predicate `{"==":[1,1]}`. */
30
+ const alwaysTrue = () => ({ '==': [1, 1] });
31
+ /** A `PUBLIC`-visibility morphism spec (the riverdale preset visibility). Fresh object per call. */
32
+ const publicMorphism = () => ({ visibility: 'PUBLIC' });
33
+ /** Sum behavior bits from their NAMES — never a magic literal int (CLAUDE.md #1). */
34
+ function sumBehavior(bits) {
35
+ return bits.reduce((acc, name) => acc + types_js_1.TOKEN_BEHAVIOR_BITS[name], 0);
36
+ }
37
+ /**
38
+ * Derive the default `stateShape.typeName`: strip a trailing `.asset` label, PascalCase the remainder
39
+ * (splitting on `.`/`-`/`_`/space), then append `State`.
40
+ * `rvd.asset` → `RvdState`, `goods.asset` → `GoodsState`, `capped.asset` → `CappedState`.
41
+ */
42
+ function defaultStateTypeName(name) {
43
+ const ASSET_SUFFIX = '.asset';
44
+ const base = name.endsWith(ASSET_SUFFIX) ? name.slice(0, -ASSET_SUFFIX.length) : name;
45
+ const pascal = base
46
+ .split(/[.\-_\s]+/)
47
+ .filter(Boolean)
48
+ .map((seg) => seg.charAt(0).toUpperCase() + seg.slice(1))
49
+ .join('');
50
+ return `${pascal}State`;
51
+ }
52
+ /** Build a {@link SupplyPolicy}, OMITTING every absent field (no `undefined`/`null` keys). */
53
+ function buildSupply(opts) {
54
+ const supply = {};
55
+ if (opts.maxSupply !== undefined)
56
+ supply.maxSupply = opts.maxSupply;
57
+ if (opts.mintPolicy !== undefined)
58
+ supply.mintPolicy = opts.mintPolicy;
59
+ if (opts.burnPolicy !== undefined)
60
+ supply.burnPolicy = opts.burnPolicy;
61
+ if (opts.decimals !== undefined)
62
+ supply.decimals = opts.decimals;
63
+ return supply;
64
+ }
65
+ /** Assemble the final {@link CreateAssetPolicy}, attaching `metadata` only when present. */
66
+ function assemble(args) {
67
+ const stateShape = {
68
+ typeName: args.stateTypeName ?? defaultStateTypeName(args.name),
69
+ fields: [],
70
+ };
71
+ const policy = {
72
+ name: args.name,
73
+ version: args.version,
74
+ behavior: args.behavior,
75
+ supply: args.supply,
76
+ morphisms: args.morphisms,
77
+ stateShape,
78
+ };
79
+ if (args.metadata !== undefined)
80
+ policy.metadata = args.metadata;
81
+ return policy;
82
+ }
83
+ /**
84
+ * Fungible currency. Behavior `T|S|C = 28` (transferable + splittable + combinable). Standard morphism
85
+ * set TRANSFER + FRACTIONALIZE + STAKE (`stakeable`, default true) + BURN (when `burnable`), all PUBLIC.
86
+ *
87
+ * Reproduces `riverdale-economy/rvd-policy.json` exactly via
88
+ * `fungiblePolicy({ name: 'rvd.asset', version: '1.0.0', mintable: true, burnable: true })`.
89
+ */
90
+ function fungiblePolicy(p) {
91
+ const behavior = sumBehavior(['transferable', 'splittable', 'combinable']); // 28
92
+ const morphisms = {
93
+ TRANSFER: publicMorphism(),
94
+ FRACTIONALIZE: publicMorphism(),
95
+ };
96
+ if (p.stakeable !== false)
97
+ morphisms.STAKE = publicMorphism();
98
+ if (p.burnable)
99
+ morphisms.BURN = publicMorphism();
100
+ let mintPolicy;
101
+ if (p.mintGuard !== undefined)
102
+ mintPolicy = p.mintGuard;
103
+ else if (p.mintable)
104
+ mintPolicy = alwaysTrue();
105
+ const supply = buildSupply({
106
+ maxSupply: p.maxSupply,
107
+ mintPolicy,
108
+ burnPolicy: p.burnable ? alwaysTrue() : undefined,
109
+ decimals: p.decimals,
110
+ });
111
+ return assemble({
112
+ name: p.name,
113
+ version: p.version,
114
+ behavior,
115
+ supply,
116
+ morphisms,
117
+ stateTypeName: p.stateTypeName,
118
+ metadata: p.metadata,
119
+ });
120
+ }
121
+ /**
122
+ * Non-fungible token. Behavior `T = 16`, or `T|C = 20` with `combinable: true` (the riverdale
123
+ * `goods.asset`); `transferable: false` drops the T bit (a bound collectible). `morphisms` is `{}` by
124
+ * default (emitted explicitly, never omitted). Mintable by default ⇒ `supply.mintPolicy = {"==":[1,1]}`.
125
+ *
126
+ * Reproduces `riverdale-economy/goods-policy.json` exactly via
127
+ * `nftPolicy({ name: 'goods.asset', version: '1.0.0', combinable: true })`.
128
+ */
129
+ function nftPolicy(p) {
130
+ const bits = [];
131
+ if (p.transferable !== false)
132
+ bits.push('transferable');
133
+ if (p.combinable)
134
+ bits.push('combinable');
135
+ const behavior = sumBehavior(bits);
136
+ let mintPolicy;
137
+ if (p.mintGuard !== undefined)
138
+ mintPolicy = p.mintGuard;
139
+ else if (p.mintable !== false)
140
+ mintPolicy = alwaysTrue();
141
+ const supply = buildSupply({ maxSupply: p.maxSupply, mintPolicy });
142
+ return assemble({
143
+ name: p.name,
144
+ version: p.version,
145
+ behavior,
146
+ supply,
147
+ morphisms: {},
148
+ stateTypeName: p.stateTypeName,
149
+ metadata: p.metadata,
150
+ });
151
+ }
152
+ /**
153
+ * Soulbound token: non-transferable, governable only (`G = 1`; `+E = 3` when `expirable`). No TRANSFER
154
+ * morphism (`morphisms: {}`); minting is closed after issue (empty `supply`).
155
+ */
156
+ function soulboundPolicy(p) {
157
+ const bits = ['governable'];
158
+ if (p.expirable)
159
+ bits.push('expirable');
160
+ const behavior = sumBehavior(bits);
161
+ return assemble({
162
+ name: p.name,
163
+ version: p.version,
164
+ behavior,
165
+ supply: buildSupply({}), // mint closed after issue
166
+ morphisms: {}, // non-transferable: no TRANSFER morphism
167
+ stateTypeName: p.stateTypeName,
168
+ metadata: p.metadata,
169
+ });
170
+ }
171
+ /**
172
+ * Escape hatch: declare `behavior` by NAME (summed from {@link TOKEN_BEHAVIOR_BITS}, never a magic int)
173
+ * and pass `supply` + `morphisms` through raw. Use when no preset fits.
174
+ *
175
+ * Reproduces `riverdale-economy/capped-policy.json` exactly via
176
+ * `customPolicy({ name: 'capped.asset', version: '1.0.0',
177
+ * behavior: ['transferable', 'splittable', 'combinable'],
178
+ * supply: { maxSupply: 100, mintPolicy: { '==': [1, 1] } }, morphisms: {} })`.
179
+ */
180
+ function customPolicy(p) {
181
+ return assemble({
182
+ name: p.name,
183
+ version: p.version,
184
+ behavior: sumBehavior(p.behavior),
185
+ supply: p.supply,
186
+ morphisms: p.morphisms,
187
+ stateTypeName: p.stateTypeName,
188
+ metadata: p.metadata,
189
+ });
190
+ }