metered-protocol 1.0.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 (206) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +103 -0
  3. package/contracts/metered.ag +135 -0
  4. package/contracts/metered_ag.tests.json +1226 -0
  5. package/contracts/metered_session.sil +237 -0
  6. package/contracts/metered_session.tests.json +1113 -0
  7. package/dist/contracts/metered.ag +135 -0
  8. package/dist/contracts/metered_ag.tests.json +1226 -0
  9. package/dist/contracts/metered_session.sil +237 -0
  10. package/dist/contracts/metered_session.tests.json +1113 -0
  11. package/dist/src/bias.d.ts +48 -0
  12. package/dist/src/bias.d.ts.map +1 -0
  13. package/dist/src/bias.js +43 -0
  14. package/dist/src/bias.js.map +1 -0
  15. package/dist/src/checkpoint.d.ts +57 -0
  16. package/dist/src/checkpoint.d.ts.map +1 -0
  17. package/dist/src/checkpoint.js +84 -0
  18. package/dist/src/checkpoint.js.map +1 -0
  19. package/dist/src/deadline.d.ts +71 -0
  20. package/dist/src/deadline.d.ts.map +1 -0
  21. package/dist/src/deadline.js +77 -0
  22. package/dist/src/deadline.js.map +1 -0
  23. package/dist/src/encoding.d.ts +72 -0
  24. package/dist/src/encoding.d.ts.map +1 -0
  25. package/dist/src/encoding.js +187 -0
  26. package/dist/src/encoding.js.map +1 -0
  27. package/dist/src/history.d.ts +33 -0
  28. package/dist/src/history.d.ts.map +1 -0
  29. package/dist/src/history.js +38 -0
  30. package/dist/src/history.js.map +1 -0
  31. package/dist/src/http/buyer.d.ts +57 -0
  32. package/dist/src/http/buyer.d.ts.map +1 -0
  33. package/dist/src/http/buyer.js +151 -0
  34. package/dist/src/http/buyer.js.map +1 -0
  35. package/dist/src/http/client.d.ts +55 -0
  36. package/dist/src/http/client.d.ts.map +1 -0
  37. package/dist/src/http/client.js +83 -0
  38. package/dist/src/http/client.js.map +1 -0
  39. package/dist/src/http/harness.d.ts +18 -0
  40. package/dist/src/http/harness.d.ts.map +1 -0
  41. package/dist/src/http/harness.js +16 -0
  42. package/dist/src/http/harness.js.map +1 -0
  43. package/dist/src/http/protocol.d.ts +84 -0
  44. package/dist/src/http/protocol.d.ts.map +1 -0
  45. package/dist/src/http/protocol.js +22 -0
  46. package/dist/src/http/protocol.js.map +1 -0
  47. package/dist/src/http/provider.d.ts +123 -0
  48. package/dist/src/http/provider.d.ts.map +1 -0
  49. package/dist/src/http/provider.js +197 -0
  50. package/dist/src/http/provider.js.map +1 -0
  51. package/dist/src/http/serve.d.ts +34 -0
  52. package/dist/src/http/serve.d.ts.map +1 -0
  53. package/dist/src/http/serve.js +171 -0
  54. package/dist/src/http/serve.js.map +1 -0
  55. package/dist/src/http/service.d.ts +86 -0
  56. package/dist/src/http/service.d.ts.map +1 -0
  57. package/dist/src/http/service.js +161 -0
  58. package/dist/src/http/service.js.map +1 -0
  59. package/dist/src/index.d.ts +68 -0
  60. package/dist/src/index.d.ts.map +1 -0
  61. package/dist/src/index.js +62 -0
  62. package/dist/src/index.js.map +1 -0
  63. package/dist/src/meter.d.ts +39 -0
  64. package/dist/src/meter.d.ts.map +1 -0
  65. package/dist/src/meter.js +100 -0
  66. package/dist/src/meter.js.map +1 -0
  67. package/dist/src/offer.d.ts +6 -0
  68. package/dist/src/offer.d.ts.map +1 -0
  69. package/dist/src/offer.js +92 -0
  70. package/dist/src/offer.js.map +1 -0
  71. package/dist/src/reconcile.d.ts +18 -0
  72. package/dist/src/reconcile.d.ts.map +1 -0
  73. package/dist/src/reconcile.js +101 -0
  74. package/dist/src/reconcile.js.map +1 -0
  75. package/dist/src/reservation.d.ts +51 -0
  76. package/dist/src/reservation.d.ts.map +1 -0
  77. package/dist/src/reservation.js +124 -0
  78. package/dist/src/reservation.js.map +1 -0
  79. package/dist/src/session.d.ts +40 -0
  80. package/dist/src/session.d.ts.map +1 -0
  81. package/dist/src/session.js +92 -0
  82. package/dist/src/session.js.map +1 -0
  83. package/dist/src/signer.d.ts +31 -0
  84. package/dist/src/signer.d.ts.map +1 -0
  85. package/dist/src/signer.js +57 -0
  86. package/dist/src/signer.js.map +1 -0
  87. package/dist/src/store.d.ts +30 -0
  88. package/dist/src/store.d.ts.map +1 -0
  89. package/dist/src/store.js +120 -0
  90. package/dist/src/store.js.map +1 -0
  91. package/dist/src/types.d.ts +80 -0
  92. package/dist/src/types.d.ts.map +1 -0
  93. package/dist/src/types.js +9 -0
  94. package/dist/src/types.js.map +1 -0
  95. package/dist/tools/anchor-cli.d.ts +2 -0
  96. package/dist/tools/anchor-cli.d.ts.map +1 -0
  97. package/dist/tools/anchor-cli.js +101 -0
  98. package/dist/tools/anchor-cli.js.map +1 -0
  99. package/dist/tools/anchor.d.ts +68 -0
  100. package/dist/tools/anchor.d.ts.map +1 -0
  101. package/dist/tools/anchor.js +136 -0
  102. package/dist/tools/anchor.js.map +1 -0
  103. package/dist/tools/chain.d.ts +18 -0
  104. package/dist/tools/chain.d.ts.map +1 -0
  105. package/dist/tools/chain.js +18 -0
  106. package/dist/tools/chain.js.map +1 -0
  107. package/dist/tools/conformance.d.ts +2 -0
  108. package/dist/tools/conformance.d.ts.map +1 -0
  109. package/dist/tools/conformance.js +220 -0
  110. package/dist/tools/conformance.js.map +1 -0
  111. package/dist/tools/contracts.d.ts +2 -0
  112. package/dist/tools/contracts.d.ts.map +1 -0
  113. package/dist/tools/contracts.js +68 -0
  114. package/dist/tools/contracts.js.map +1 -0
  115. package/dist/tools/covenant-binding.d.ts +40 -0
  116. package/dist/tools/covenant-binding.d.ts.map +1 -0
  117. package/dist/tools/covenant-binding.js +60 -0
  118. package/dist/tools/covenant-binding.js.map +1 -0
  119. package/dist/tools/covenant-profile.d.ts +41 -0
  120. package/dist/tools/covenant-profile.d.ts.map +1 -0
  121. package/dist/tools/covenant-profile.js +74 -0
  122. package/dist/tools/covenant-profile.js.map +1 -0
  123. package/dist/tools/covenant.d.ts +30 -0
  124. package/dist/tools/covenant.d.ts.map +1 -0
  125. package/dist/tools/covenant.js +54 -0
  126. package/dist/tools/covenant.js.map +1 -0
  127. package/dist/tools/demo-report.d.ts +24 -0
  128. package/dist/tools/demo-report.d.ts.map +1 -0
  129. package/dist/tools/demo-report.js +40 -0
  130. package/dist/tools/demo-report.js.map +1 -0
  131. package/dist/tools/demo.d.ts +2 -0
  132. package/dist/tools/demo.d.ts.map +1 -0
  133. package/dist/tools/demo.js +204 -0
  134. package/dist/tools/demo.js.map +1 -0
  135. package/dist/tools/dust-map.d.ts +2 -0
  136. package/dist/tools/dust-map.d.ts.map +1 -0
  137. package/dist/tools/dust-map.js +63 -0
  138. package/dist/tools/dust-map.js.map +1 -0
  139. package/dist/tools/expire-cases.d.ts +4 -0
  140. package/dist/tools/expire-cases.d.ts.map +1 -0
  141. package/dist/tools/expire-cases.js +211 -0
  142. package/dist/tools/expire-cases.js.map +1 -0
  143. package/dist/tools/fee-check.d.ts +2 -0
  144. package/dist/tools/fee-check.d.ts.map +1 -0
  145. package/dist/tools/fee-check.js +127 -0
  146. package/dist/tools/fee-check.js.map +1 -0
  147. package/dist/tools/fixtures.d.ts +39 -0
  148. package/dist/tools/fixtures.d.ts.map +1 -0
  149. package/dist/tools/fixtures.js +31 -0
  150. package/dist/tools/fixtures.js.map +1 -0
  151. package/dist/tools/gen-contract-tests.d.ts +2 -0
  152. package/dist/tools/gen-contract-tests.d.ts.map +1 -0
  153. package/dist/tools/gen-contract-tests.js +170 -0
  154. package/dist/tools/gen-contract-tests.js.map +1 -0
  155. package/dist/tools/kaspa.d.ts +13 -0
  156. package/dist/tools/kaspa.d.ts.map +1 -0
  157. package/dist/tools/kaspa.js +76 -0
  158. package/dist/tools/kaspa.js.map +1 -0
  159. package/dist/tools/live-deadline.d.ts +2 -0
  160. package/dist/tools/live-deadline.d.ts.map +1 -0
  161. package/dist/tools/live-deadline.js +122 -0
  162. package/dist/tools/live-deadline.js.map +1 -0
  163. package/dist/tools/live-expire.d.ts +2 -0
  164. package/dist/tools/live-expire.d.ts.map +1 -0
  165. package/dist/tools/live-expire.js +127 -0
  166. package/dist/tools/live-expire.js.map +1 -0
  167. package/dist/tools/live-settle.d.ts +2 -0
  168. package/dist/tools/live-settle.d.ts.map +1 -0
  169. package/dist/tools/live-settle.js +226 -0
  170. package/dist/tools/live-settle.js.map +1 -0
  171. package/dist/tools/live-steps.d.ts +63 -0
  172. package/dist/tools/live-steps.d.ts.map +1 -0
  173. package/dist/tools/live-steps.js +155 -0
  174. package/dist/tools/live-steps.js.map +1 -0
  175. package/dist/tools/model.d.ts +32 -0
  176. package/dist/tools/model.d.ts.map +1 -0
  177. package/dist/tools/model.js +99 -0
  178. package/dist/tools/model.js.map +1 -0
  179. package/dist/tools/send.d.ts +2 -0
  180. package/dist/tools/send.d.ts.map +1 -0
  181. package/dist/tools/send.js +41 -0
  182. package/dist/tools/send.js.map +1 -0
  183. package/dist/tools/session-chain.d.ts +69 -0
  184. package/dist/tools/session-chain.d.ts.map +1 -0
  185. package/dist/tools/session-chain.js +113 -0
  186. package/dist/tools/session-chain.js.map +1 -0
  187. package/dist/tools/sighash.d.ts +9 -0
  188. package/dist/tools/sighash.d.ts.map +1 -0
  189. package/dist/tools/sighash.js +68 -0
  190. package/dist/tools/sighash.js.map +1 -0
  191. package/dist/tools/sigscript-check.d.ts +2 -0
  192. package/dist/tools/sigscript-check.d.ts.map +1 -0
  193. package/dist/tools/sigscript-check.js +113 -0
  194. package/dist/tools/sigscript-check.js.map +1 -0
  195. package/dist/tools/sigscript.d.ts +61 -0
  196. package/dist/tools/sigscript.d.ts.map +1 -0
  197. package/dist/tools/sigscript.js +70 -0
  198. package/dist/tools/sigscript.js.map +1 -0
  199. package/dist/tools/state-layout.d.ts +2 -0
  200. package/dist/tools/state-layout.d.ts.map +1 -0
  201. package/dist/tools/state-layout.js +57 -0
  202. package/dist/tools/state-layout.js.map +1 -0
  203. package/package.json +59 -0
  204. package/spec/CONFORMANCE.md +80 -0
  205. package/spec/SPEC.md +821 -0
  206. package/spec/conformance-vectors.json +677 -0
@@ -0,0 +1,677 @@
1
+ {
2
+ "version": 1,
3
+ "about": "Conformance vectors for the metered protocol. See spec/CONFORMANCE.md.",
4
+ "offer": {
5
+ "v": 1,
6
+ "scheme": "metered",
7
+ "network": "kaspa:testnet-10",
8
+ "asset": "KAS",
9
+ "sessionId": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
10
+ "unit": "llm.output_tokens.v1",
11
+ "meter": "o200k_base",
12
+ "unitPriceSompi": 3630,
13
+ "babelUnits": 550,
14
+ "maxBabels": 64,
15
+ "toleranceAbs": 1,
16
+ "checkpointEvery": 2,
17
+ "responseWindowDaa": 600,
18
+ "buyerPubkey": "4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa",
19
+ "providerPubkey": "466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27",
20
+ "partiesCommitment": "62e84a374e44f83866d72147508efd746dad5e0d599269e79392741fa8781ab0",
21
+ "sig": "ba46fea71a8d6303272980526caa33027db52d20e8e81d7446c9ec5facc48d1b06569755ad61bf5d055eecc2b942000383fd85ef14a0a6f1b37612646a3a7765"
22
+ },
23
+ "groups": [
24
+ {
25
+ "section": "2",
26
+ "about": "Canonical JSON, and the digest taken over it. Sorted keys, no insignificant whitespace.",
27
+ "cases": [
28
+ {
29
+ "name": "nested objects sort by key at every level",
30
+ "given": {
31
+ "b": 1,
32
+ "a": {
33
+ "d": 4,
34
+ "c": 3
35
+ }
36
+ },
37
+ "expect": {
38
+ "canonical": "{\"a\":{\"c\":3,\"d\":4},\"b\":1}",
39
+ "digest": "01e1eca594767ceefeb7f27b5099fac5c1f8bfd666c7d140e04d538e6e56c69d"
40
+ }
41
+ },
42
+ {
43
+ "name": "arrays keep their order, unlike objects",
44
+ "given": {
45
+ "a": [
46
+ 3,
47
+ 1,
48
+ 2
49
+ ]
50
+ },
51
+ "expect": {
52
+ "canonical": "{\"a\":[3,1,2]}",
53
+ "digest": "c79a0df4f21717febed9c43fab7a37594b9c157a01ba185c7938660fbdcde3fb"
54
+ }
55
+ },
56
+ {
57
+ "name": "non-ASCII is NOT escaped",
58
+ "given": {
59
+ "s": "Cafe 🔒 計量"
60
+ },
61
+ "expect": {
62
+ "canonical": "{\"s\":\"Cafe 🔒 計量\"}",
63
+ "digest": "4709ddb8b4ba13e1a329025cb63e74442f948a0a8f9a1bcbeb44d6ae53235ed2"
64
+ }
65
+ },
66
+ {
67
+ "name": "a null is preserved where the spec names one",
68
+ "given": {
69
+ "prevState": null,
70
+ "seq": 0
71
+ },
72
+ "expect": {
73
+ "canonical": "{\"prevState\":null,\"seq\":0}",
74
+ "digest": "cfeb1de1bcd161fa9b6ce19cbbf7ae952e2a5c4e7bab8ee6a57bbf921e0a16df"
75
+ }
76
+ },
77
+ {
78
+ "name": "negative and zero integers",
79
+ "given": {
80
+ "a": -1,
81
+ "b": 0,
82
+ "c": -9007199254740991
83
+ },
84
+ "expect": {
85
+ "canonical": "{\"a\":-1,\"b\":0,\"c\":-9007199254740991}",
86
+ "digest": "c5319a83b84661ae89c8e78128970093732220d1230c47a431aa7432f9119e26"
87
+ }
88
+ },
89
+ {
90
+ "name": "UTF-16 code-unit order, where it DIFFERS from code-point order",
91
+ "given": {
92
+ "�": 1,
93
+ "𐀀": 2
94
+ },
95
+ "expect": {
96
+ "canonical": "{\"𐀀\":2,\"�\":1}",
97
+ "digest": "2c6f001457cf78eb1e71a5110211a79a3f8cdfaeef3231c5e135e5d0410cc117"
98
+ }
99
+ },
100
+ {
101
+ "name": "BMP keys, where the two orders agree",
102
+ "given": {
103
+ "aZ": 1,
104
+ "aa": 2,
105
+ "az": 3
106
+ },
107
+ "expect": {
108
+ "canonical": "{\"az\":3,\"aZ\":1,\"aa\":2}",
109
+ "digest": "eb9dd5a425de835f202c28fb2bea23c62a0c470f598566524216e7a1021aa2d6"
110
+ }
111
+ }
112
+ ]
113
+ },
114
+ {
115
+ "section": "3.4.1",
116
+ "about": "The 72-byte settlement preimage: sessionId(16) seq(8) units(8) sompi(8) prevState(32).",
117
+ "cases": [
118
+ {
119
+ "name": "a mid-session State",
120
+ "given": {
121
+ "v": 1,
122
+ "sessionId": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
123
+ "seq": 3,
124
+ "cumulativeUnits": 2199,
125
+ "cumulativeSompi": 7982370,
126
+ "prevState": "b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2"
127
+ },
128
+ "expect": {
129
+ "lengthBytes": 72,
130
+ "preimageHex": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a10300000000000000970800000000000022cd790000000000b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2",
131
+ "digestHex": "1f7be2293ccad7405c071238329da1ddaf216888cc48dc2b147154a566f01646"
132
+ }
133
+ },
134
+ {
135
+ "name": "seq 0, where prevState is null and becomes 32 ZERO bytes",
136
+ "given": {
137
+ "v": 1,
138
+ "sessionId": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
139
+ "seq": 0,
140
+ "cumulativeUnits": 550,
141
+ "cumulativeSompi": 1996500,
142
+ "prevState": null
143
+ },
144
+ "expect": {
145
+ "lengthBytes": 72,
146
+ "preimageHex": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a100000000000000002602000000000000d4761e00000000000000000000000000000000000000000000000000000000000000000000000000",
147
+ "digestHex": "3fa460ab20b80da89cc033137226ea4ce8ac9ebd445b0cdff7d321adf6990769"
148
+ }
149
+ },
150
+ {
151
+ "name": "a NEGATIVE integer is signed-magnitude, not two-complement",
152
+ "given": {
153
+ "v": 1,
154
+ "sessionId": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
155
+ "seq": -1,
156
+ "cumulativeUnits": 0,
157
+ "cumulativeSompi": 0,
158
+ "prevState": null
159
+ },
160
+ "expect": {
161
+ "lengthBytes": 72,
162
+ "preimageHex": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a10100000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
163
+ "digestHex": "cb1aa89c1a3a99b41a855a160650df54c943f872abccf6a5e5264773748d926e"
164
+ }
165
+ },
166
+ {
167
+ "name": "the largest integer the protocol admits",
168
+ "given": {
169
+ "v": 1,
170
+ "sessionId": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
171
+ "seq": 1,
172
+ "cumulativeUnits": 9007199254740991,
173
+ "cumulativeSompi": 9007199254740991,
174
+ "prevState": "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
175
+ },
176
+ "expect": {
177
+ "lengthBytes": 72,
178
+ "preimageHex": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a10100000000000000ffffffffffff1f00ffffffffffff1f00cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
179
+ "digestHex": "47ed6bfde19f92dfa5070e0cf86625992318d99ba5c12cbbad772e26fbdedacc"
180
+ }
181
+ }
182
+ ]
183
+ },
184
+ {
185
+ "section": "2.6 / 3.4",
186
+ "about": "Verification vectors. A correct implementation MUST agree on true and on false alike.",
187
+ "cases": [
188
+ {
189
+ "name": "the Offer verifies against the provider key that signed it",
190
+ "given": {
191
+ "message": {
192
+ "v": 1,
193
+ "scheme": "metered",
194
+ "network": "kaspa:testnet-10",
195
+ "asset": "KAS",
196
+ "sessionId": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
197
+ "unit": "llm.output_tokens.v1",
198
+ "meter": "o200k_base",
199
+ "unitPriceSompi": 3630,
200
+ "babelUnits": 550,
201
+ "maxBabels": 64,
202
+ "toleranceAbs": 1,
203
+ "checkpointEvery": 2,
204
+ "responseWindowDaa": 600,
205
+ "buyerPubkey": "4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa",
206
+ "providerPubkey": "466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27",
207
+ "partiesCommitment": "62e84a374e44f83866d72147508efd746dad5e0d599269e79392741fa8781ab0",
208
+ "sig": "ba46fea71a8d6303272980526caa33027db52d20e8e81d7446c9ec5facc48d1b06569755ad61bf5d055eecc2b942000383fd85ef14a0a6f1b37612646a3a7765"
209
+ },
210
+ "publicKey": "466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27",
211
+ "field": "sig"
212
+ },
213
+ "expect": {
214
+ "verifies": true
215
+ }
216
+ },
217
+ {
218
+ "name": "the Offer does NOT verify against the buyer key",
219
+ "given": {
220
+ "message": {
221
+ "v": 1,
222
+ "scheme": "metered",
223
+ "network": "kaspa:testnet-10",
224
+ "asset": "KAS",
225
+ "sessionId": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
226
+ "unit": "llm.output_tokens.v1",
227
+ "meter": "o200k_base",
228
+ "unitPriceSompi": 3630,
229
+ "babelUnits": 550,
230
+ "maxBabels": 64,
231
+ "toleranceAbs": 1,
232
+ "checkpointEvery": 2,
233
+ "responseWindowDaa": 600,
234
+ "buyerPubkey": "4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa",
235
+ "providerPubkey": "466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27",
236
+ "partiesCommitment": "62e84a374e44f83866d72147508efd746dad5e0d599269e79392741fa8781ab0",
237
+ "sig": "ba46fea71a8d6303272980526caa33027db52d20e8e81d7446c9ec5facc48d1b06569755ad61bf5d055eecc2b942000383fd85ef14a0a6f1b37612646a3a7765"
238
+ },
239
+ "publicKey": "4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa",
240
+ "field": "sig"
241
+ },
242
+ "expect": {
243
+ "verifies": false
244
+ }
245
+ },
246
+ {
247
+ "name": "a State signature verifies over the 72-byte preimage, not over JSON",
248
+ "given": {
249
+ "state": {
250
+ "v": 1,
251
+ "sessionId": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
252
+ "seq": 0,
253
+ "cumulativeUnits": 550,
254
+ "cumulativeSompi": 1996500,
255
+ "prevState": null
256
+ },
257
+ "signature": "522747eb597897a1b78c2d43807518ffc32880e437ed00e50894400741fb6bf1ebf8473182bb386392842ef9525f6b24b72a68d24b25b40d9b460f666fdab063",
258
+ "publicKey": "4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa"
259
+ },
260
+ "expect": {
261
+ "verifies": true
262
+ }
263
+ },
264
+ {
265
+ "name": "the same signature fails once an amount changes",
266
+ "given": {
267
+ "state": {
268
+ "v": 1,
269
+ "sessionId": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
270
+ "seq": 0,
271
+ "cumulativeUnits": 550,
272
+ "cumulativeSompi": 1996501,
273
+ "prevState": null
274
+ },
275
+ "signature": "522747eb597897a1b78c2d43807518ffc32880e437ed00e50894400741fb6bf1ebf8473182bb386392842ef9525f6b24b72a68d24b25b40d9b460f666fdab063",
276
+ "publicKey": "4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa"
277
+ },
278
+ "expect": {
279
+ "verifies": false
280
+ }
281
+ }
282
+ ]
283
+ },
284
+ {
285
+ "section": "5",
286
+ "about": "Reconciliation. Rule 6 bills the lower count; a digest mismatch is unresolvable.",
287
+ "cases": [
288
+ {
289
+ "name": "identical counts bill that count",
290
+ "given": {
291
+ "buyer": {
292
+ "v": 1,
293
+ "sessionId": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
294
+ "seq": 0,
295
+ "by": "buyer",
296
+ "units": 550,
297
+ "cumulativeUnits": 550,
298
+ "contentDigest": "063eca1a984bed0d83f038c2c63877d2d2fedb4613fc12bf45fa2c45bad2d1cc",
299
+ "measurementId": "55af581dd51e7375c29f247b70eea67d",
300
+ "sig": "bfba1bf89d5495f3a4ef1c98d6c2c740e27c112bb40562cae825aa03315bc7ceb01ae436398bfb361a78f777b3ff075ac80901bd1979e80a26f9e36ae7a92729"
301
+ },
302
+ "provider": {
303
+ "v": 1,
304
+ "sessionId": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
305
+ "seq": 0,
306
+ "by": "provider",
307
+ "units": 550,
308
+ "cumulativeUnits": 550,
309
+ "contentDigest": "063eca1a984bed0d83f038c2c63877d2d2fedb4613fc12bf45fa2c45bad2d1cc",
310
+ "measurementId": "c29347185f14bda8c1012d9e143c6c2b",
311
+ "sig": "be8e48643bf54f897c23fd9dfca257912354c8857b8ff7869ac1a4b10688dcedf7fe1059f3292ca3b743364d7a002e222132f6e938769dbec0d71121dd4251a2"
312
+ },
313
+ "seq": 0,
314
+ "toleranceAbs": 1
315
+ },
316
+ "expect": {
317
+ "ok": true,
318
+ "billedUnits": 550,
319
+ "billedCumulativeUnits": 550,
320
+ "residual": 0
321
+ }
322
+ },
323
+ {
324
+ "name": "a one-token disagreement inside tolerance bills the LOWER",
325
+ "given": {
326
+ "buyer": {
327
+ "v": 1,
328
+ "sessionId": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
329
+ "seq": 0,
330
+ "by": "buyer",
331
+ "units": 549,
332
+ "cumulativeUnits": 549,
333
+ "contentDigest": "063eca1a984bed0d83f038c2c63877d2d2fedb4613fc12bf45fa2c45bad2d1cc",
334
+ "measurementId": "55af581dd51e7375c29f247b70eea67d",
335
+ "sig": "622917b7d2e55f23936928bb1a4c53063c628ea1ef1fcdfa8f7ff0ca65b125f9d2c181bffcd2cf67681680dbb200fbfc2219decc04e6ad3b2e1b7381160a8660"
336
+ },
337
+ "provider": {
338
+ "v": 1,
339
+ "sessionId": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
340
+ "seq": 0,
341
+ "by": "provider",
342
+ "units": 550,
343
+ "cumulativeUnits": 550,
344
+ "contentDigest": "063eca1a984bed0d83f038c2c63877d2d2fedb4613fc12bf45fa2c45bad2d1cc",
345
+ "measurementId": "c29347185f14bda8c1012d9e143c6c2b",
346
+ "sig": "88b8785074cf7885460ae2e57d8b45e296229c83f21195735055ba5e50f192b90513a2d1ab6c036fe50c7f72f084c2862fd8aa04a742f1466e2115993f37d185"
347
+ },
348
+ "seq": 0,
349
+ "toleranceAbs": 1
350
+ },
351
+ "expect": {
352
+ "ok": true,
353
+ "billedUnits": 549,
354
+ "billedCumulativeUnits": 549,
355
+ "residual": 1
356
+ }
357
+ },
358
+ {
359
+ "name": "beyond tolerance the session halts",
360
+ "given": {
361
+ "buyer": {
362
+ "v": 1,
363
+ "sessionId": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
364
+ "seq": 0,
365
+ "by": "buyer",
366
+ "units": 500,
367
+ "cumulativeUnits": 500,
368
+ "contentDigest": "063eca1a984bed0d83f038c2c63877d2d2fedb4613fc12bf45fa2c45bad2d1cc",
369
+ "measurementId": "55af581dd51e7375c29f247b70eea67d",
370
+ "sig": "d7a597be05491180f0360b3ce54ec0bfcf9e41ef7ebd01cc4f1e84d8389015ba45e47f0d1490ad2dbadd09ce55afd5df3597c616d6111807ffeaccb25572058d"
371
+ },
372
+ "provider": {
373
+ "v": 1,
374
+ "sessionId": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
375
+ "seq": 0,
376
+ "by": "provider",
377
+ "units": 550,
378
+ "cumulativeUnits": 550,
379
+ "contentDigest": "063eca1a984bed0d83f038c2c63877d2d2fedb4613fc12bf45fa2c45bad2d1cc",
380
+ "measurementId": "c29347185f14bda8c1012d9e143c6c2b",
381
+ "sig": "9e4ba24dc981afd6db4b92c9f94accdb251051958d91ceecedbe5016d7cc1cacec20265996cc100efea1900b252a8f1ee7ad69c0e8e3fb8ae1e9e86b9a0b835a"
382
+ },
383
+ "seq": 0,
384
+ "toleranceAbs": 1
385
+ },
386
+ "expect": {
387
+ "ok": false,
388
+ "reason": "tolerance-babel",
389
+ "detail": "|500 − 550| exceeds 1"
390
+ }
391
+ },
392
+ {
393
+ "name": "a different contentDigest halts, whatever the counts",
394
+ "given": {
395
+ "buyer": {
396
+ "v": 1,
397
+ "sessionId": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
398
+ "seq": 0,
399
+ "by": "buyer",
400
+ "units": 550,
401
+ "cumulativeUnits": 550,
402
+ "contentDigest": "a7875304962469af06a8e9efcb3cf30f65312f5258879d66b2349826bb91a0af",
403
+ "measurementId": "55af581dd51e7375c29f247b70eea67d",
404
+ "sig": "aeac9b75fa95d35b5e75a1c151b8058bc1f252d20eb35cac28ff6aa1b794dff9432a482b7dc3fbe9bbdfbcc44ce85fdb5222f87890e70c5fb22c3f28119d1cfc"
405
+ },
406
+ "provider": {
407
+ "v": 1,
408
+ "sessionId": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
409
+ "seq": 0,
410
+ "by": "provider",
411
+ "units": 550,
412
+ "cumulativeUnits": 550,
413
+ "contentDigest": "063eca1a984bed0d83f038c2c63877d2d2fedb4613fc12bf45fa2c45bad2d1cc",
414
+ "measurementId": "c29347185f14bda8c1012d9e143c6c2b",
415
+ "sig": "e02ac7b24dd7c82bbc699163d95850d0e59d805966084cc91812d760c4e1d9786a5d53af2b2f19d10548ab120cc8cbd2ecd0cea5dea54cc11ef73adb72c4a5e3"
416
+ },
417
+ "seq": 0,
418
+ "toleranceAbs": 1
419
+ },
420
+ "expect": {
421
+ "ok": false,
422
+ "reason": "content-digest",
423
+ "detail": "the parties are describing different bytes"
424
+ }
425
+ }
426
+ ]
427
+ },
428
+ {
429
+ "section": "7.4a / 7.4b",
430
+ "about": "Close shape by claim, the funding floor, and a tolerance that does not scale.",
431
+ "cases": [
432
+ {
433
+ "name": "claim 0 of 50000000",
434
+ "given": {
435
+ "pendingSompi": 0,
436
+ "covenantSompi": 50000000
437
+ },
438
+ "expect": {
439
+ "shape": {
440
+ "outputs": 1,
441
+ "to": [
442
+ "buyer"
443
+ ]
444
+ }
445
+ }
446
+ },
447
+ {
448
+ "name": "claim 100000 of 50000000",
449
+ "given": {
450
+ "pendingSompi": 100000,
451
+ "covenantSompi": 50000000
452
+ },
453
+ "expect": {
454
+ "shape": {
455
+ "outputs": 1,
456
+ "to": [
457
+ "buyer"
458
+ ]
459
+ }
460
+ }
461
+ },
462
+ {
463
+ "name": "claim 2599999 of 50000000",
464
+ "given": {
465
+ "pendingSompi": 2599999,
466
+ "covenantSompi": 50000000
467
+ },
468
+ "expect": {
469
+ "shape": {
470
+ "outputs": 1,
471
+ "to": [
472
+ "buyer"
473
+ ]
474
+ }
475
+ }
476
+ },
477
+ {
478
+ "name": "claim 2600000 of 50000000",
479
+ "given": {
480
+ "pendingSompi": 2600000,
481
+ "covenantSompi": 50000000
482
+ },
483
+ "expect": {
484
+ "shape": {
485
+ "outputs": 2,
486
+ "to": [
487
+ "provider",
488
+ "buyer"
489
+ ]
490
+ }
491
+ }
492
+ },
493
+ {
494
+ "name": "claim 4000000 of 50000000",
495
+ "given": {
496
+ "pendingSompi": 4000000,
497
+ "covenantSompi": 50000000
498
+ },
499
+ "expect": {
500
+ "shape": {
501
+ "outputs": 2,
502
+ "to": [
503
+ "provider",
504
+ "buyer"
505
+ ]
506
+ }
507
+ }
508
+ },
509
+ {
510
+ "name": "claim 47600000 of 50000000",
511
+ "given": {
512
+ "pendingSompi": 47600000,
513
+ "covenantSompi": 50000000
514
+ },
515
+ "expect": {
516
+ "shape": {
517
+ "outputs": 1,
518
+ "to": [
519
+ "provider"
520
+ ]
521
+ }
522
+ }
523
+ },
524
+ {
525
+ "name": "the funding floor for this Offer",
526
+ "given": {
527
+ "babelUnits": 550,
528
+ "maxBabels": 64,
529
+ "unitPriceSompi": 3630
530
+ },
531
+ "expect": {
532
+ "requiredFunding": 128176000,
533
+ "closeFee": 400000,
534
+ "minCovenant": 10000000
535
+ }
536
+ },
537
+ {
538
+ "name": "the tolerance bound does not grow with the babel",
539
+ "given": {
540
+ "toleranceAbs": 1,
541
+ "providerUnits": [
542
+ 10,
543
+ 550,
544
+ 5000,
545
+ 1000000
546
+ ]
547
+ },
548
+ "expect": {
549
+ "bounds": [
550
+ 1,
551
+ 1,
552
+ 1,
553
+ 1
554
+ ]
555
+ }
556
+ }
557
+ ]
558
+ },
559
+ {
560
+ "section": "6",
561
+ "about": "Units and meters. An exact meter permits a tolerance of 0; a lossy one requires 1.",
562
+ "cases": [
563
+ {
564
+ "name": "octets of \"\"",
565
+ "given": {
566
+ "meter": "octets",
567
+ "content": ""
568
+ },
569
+ "expect": {
570
+ "units": 0,
571
+ "contentDigest": "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262"
572
+ }
573
+ },
574
+ {
575
+ "name": "octets of \"hello\"",
576
+ "given": {
577
+ "meter": "octets",
578
+ "content": "hello"
579
+ },
580
+ "expect": {
581
+ "units": 5,
582
+ "contentDigest": "ea8f163db38682925e4491c5e58d4bb3506ef8c14eb78a86e908c5624a67200f"
583
+ }
584
+ },
585
+ {
586
+ "name": "octets of \"café\"",
587
+ "given": {
588
+ "meter": "octets",
589
+ "content": "café"
590
+ },
591
+ "expect": {
592
+ "units": 5,
593
+ "contentDigest": "e4e52b2a0ab9d8584bf4b913af316d96865f92f305b17a0d50b6677bd9ec71c0"
594
+ }
595
+ },
596
+ {
597
+ "name": "octets of \"計量\"",
598
+ "given": {
599
+ "meter": "octets",
600
+ "content": "計量"
601
+ },
602
+ "expect": {
603
+ "units": 6,
604
+ "contentDigest": "6d43d03d507ab958e776186a509420151fdc522d5a2f9496bee3fb3ffb4fab5b"
605
+ }
606
+ },
607
+ {
608
+ "name": "octets of \"🔒\"",
609
+ "given": {
610
+ "meter": "octets",
611
+ "content": "🔒"
612
+ },
613
+ "expect": {
614
+ "units": 4,
615
+ "contentDigest": "0ab675acfca644fe08e976223ed7788f5b827dc7f75e1a3d85fd84c4e1a94dbe"
616
+ }
617
+ },
618
+ {
619
+ "name": "octets of \"a\\nb\\tc d\"",
620
+ "given": {
621
+ "meter": "octets",
622
+ "content": "a\nb\tc d"
623
+ },
624
+ "expect": {
625
+ "units": 8,
626
+ "contentDigest": "52a61701c211c186592c79081a889b571ffadb782263c134b0d9edebfcf349a6"
627
+ }
628
+ },
629
+ {
630
+ "name": "octets of \"xxxxxxxxxxxxxxxxxxxxxxxxxxx",
631
+ "given": {
632
+ "meter": "octets",
633
+ "content": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
634
+ },
635
+ "expect": {
636
+ "units": 1000,
637
+ "contentDigest": "ff6f2cf7750b0d32858b758ef1cd7971064f53e81ec62ff560a953792599ca69"
638
+ }
639
+ },
640
+ {
641
+ "name": "the tolerance floor belongs to the meter, not the protocol",
642
+ "given": {
643
+ "meters": [
644
+ "octets",
645
+ "o200k_base"
646
+ ]
647
+ },
648
+ "expect": {
649
+ "floors": [
650
+ 0,
651
+ 1
652
+ ],
653
+ "exact": [
654
+ true,
655
+ false
656
+ ]
657
+ }
658
+ },
659
+ {
660
+ "name": "each meter measures exactly one unit",
661
+ "given": {
662
+ "meters": [
663
+ "octets",
664
+ "o200k_base"
665
+ ]
666
+ },
667
+ "expect": {
668
+ "units": [
669
+ "net.bytes_delivered.v1",
670
+ "llm.output_tokens.v1"
671
+ ]
672
+ }
673
+ }
674
+ ]
675
+ }
676
+ ]
677
+ }