@arkiv-network/sdk 0.7.0-dev.1 → 0.8.0-advanced.2

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 (237) hide show
  1. package/README.md +71 -16
  2. package/dist/actions/advanced/index.cjs +13 -0
  3. package/dist/actions/advanced/index.d.cts +8 -0
  4. package/dist/actions/advanced/index.d.ts +9 -0
  5. package/dist/actions/advanced/index.js +9 -0
  6. package/dist/advanced-8ZPTmmaN.js +598 -0
  7. package/dist/advanced-8ZPTmmaN.js.map +1 -0
  8. package/dist/advanced-fPImL6lW.cjs +656 -0
  9. package/dist/arkivTransactions-D74gERHG.d.cts +571 -0
  10. package/dist/arkivTransactions-D74gERHG.d.cts.map +1 -0
  11. package/dist/arkivTransactions-NtGD6uk5.d.ts +571 -0
  12. package/dist/arkivTransactions-NtGD6uk5.d.ts.map +1 -0
  13. package/dist/attr/index.cjs +35 -0
  14. package/dist/attr/index.d.cts +2 -0
  15. package/dist/attr/index.d.ts +3 -0
  16. package/dist/attr/index.js +4 -0
  17. package/dist/attributes-BhY5DwJp.js +809 -0
  18. package/dist/attributes-BhY5DwJp.js.map +1 -0
  19. package/dist/attributes-Df9IsCVs.cjs +1029 -0
  20. package/dist/chains/index.cjs +2 -3
  21. package/dist/chains/index.d.cts +22 -60
  22. package/dist/chains/index.d.cts.map +1 -1
  23. package/dist/chains/index.d.ts +22 -60
  24. package/dist/chains/index.d.ts.map +1 -1
  25. package/dist/chains/index.js +2 -2
  26. package/dist/chains-BJrZs6sG.js +57 -0
  27. package/dist/chains-BJrZs6sG.js.map +1 -0
  28. package/dist/chains-BYRTTipa.cjs +73 -0
  29. package/dist/codec-Car3KkFF.d.ts +102 -0
  30. package/dist/codec-Car3KkFF.d.ts.map +1 -0
  31. package/dist/entity/index.cjs +20 -0
  32. package/dist/entity/index.d.cts +4 -0
  33. package/dist/entity/index.d.ts +5 -0
  34. package/dist/entity/index.js +7 -0
  35. package/dist/entity-B00Li04j.cjs +71 -0
  36. package/dist/entity-B7G8q_Eo.cjs +0 -0
  37. package/dist/entity-BYQR1uoe.js +67 -0
  38. package/dist/entity-BYQR1uoe.js.map +1 -0
  39. package/dist/entity-CD_qFF2M.js +0 -0
  40. package/dist/errors-BVbjKVMN.cjs +56 -0
  41. package/dist/errors-LTe7bOYS.js +33 -0
  42. package/dist/errors-LTe7bOYS.js.map +1 -0
  43. package/dist/expiry-BELY2Kpw.cjs +135 -0
  44. package/dist/expiry-BjpxZZQU.js +95 -0
  45. package/dist/expiry-BjpxZZQU.js.map +1 -0
  46. package/dist/expiry-DRV29F1r.d.cts +79 -0
  47. package/dist/expiry-DRV29F1r.d.cts.map +1 -0
  48. package/dist/expiry-nDbCgZX4.d.ts +79 -0
  49. package/dist/expiry-nDbCgZX4.d.ts.map +1 -0
  50. package/dist/flags-5dTNRnow.d.ts +41 -0
  51. package/dist/flags-5dTNRnow.d.ts.map +1 -0
  52. package/dist/flags-CRjPpoh3.d.cts +41 -0
  53. package/dist/flags-CRjPpoh3.d.cts.map +1 -0
  54. package/dist/flags-DFBs2J94.js +33 -0
  55. package/dist/flags-DFBs2J94.js.map +1 -0
  56. package/dist/flags-kr276q6i.cjs +43 -0
  57. package/dist/index-B5j76711.d.ts +184 -0
  58. package/dist/index-B5j76711.d.ts.map +1 -0
  59. package/dist/index-BF7Mq9Is.d.cts +280 -0
  60. package/dist/index-BF7Mq9Is.d.cts.map +1 -0
  61. package/dist/index-CA4V7Pdh.d.cts +167 -0
  62. package/dist/index-CA4V7Pdh.d.cts.map +1 -0
  63. package/dist/index-CV5zCdpa.d.cts +417 -0
  64. package/dist/index-CV5zCdpa.d.cts.map +1 -0
  65. package/dist/index-DHDud2hC.d.ts +280 -0
  66. package/dist/index-DHDud2hC.d.ts.map +1 -0
  67. package/dist/index-DvYvrkdk.d.ts +320 -0
  68. package/dist/index-DvYvrkdk.d.ts.map +1 -0
  69. package/dist/index-EeUO0nnJ.d.cts +184 -0
  70. package/dist/index-EeUO0nnJ.d.cts.map +1 -0
  71. package/dist/index-fX_XyqLp.d.ts +167 -0
  72. package/dist/index-fX_XyqLp.d.ts.map +1 -0
  73. package/dist/index.cjs +411 -405
  74. package/dist/index.d.cts +360 -209
  75. package/dist/index.d.cts.map +1 -1
  76. package/dist/index.d.ts +361 -209
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +342 -387
  79. package/dist/index.js.map +1 -1
  80. package/dist/key-D1Bh7MF0.js +70 -0
  81. package/dist/key-D1Bh7MF0.js.map +1 -0
  82. package/dist/key-WKhXnXuU.cjs +98 -0
  83. package/dist/logger-CVpvU8ik.js +153 -0
  84. package/dist/logger-CVpvU8ik.js.map +1 -0
  85. package/dist/logger-Cr15lPAQ.cjs +188 -0
  86. package/dist/payload-BNoud2KZ.d.cts +94 -0
  87. package/dist/payload-BNoud2KZ.d.cts.map +1 -0
  88. package/dist/payload-Bz6651ax.js +67 -0
  89. package/dist/payload-Bz6651ax.js.map +1 -0
  90. package/dist/payload-CcUj85ys.d.ts +94 -0
  91. package/dist/payload-CcUj85ys.d.ts.map +1 -0
  92. package/dist/payload-KC14SDlN.cjs +83 -0
  93. package/dist/query/index.cjs +26 -150
  94. package/dist/query/index.d.cts +5 -3
  95. package/dist/query/index.d.ts +6 -3
  96. package/dist/query/index.js +8 -138
  97. package/dist/queryBuilder-DM6AWCBa.js +820 -0
  98. package/dist/queryBuilder-DM6AWCBa.js.map +1 -0
  99. package/dist/queryBuilder-DbUMEZln.cjs +944 -0
  100. package/dist/selection-C4UhsMOO.d.ts +434 -0
  101. package/dist/selection-C4UhsMOO.d.ts.map +1 -0
  102. package/dist/selection-DPg0uyJf.d.cts +433 -0
  103. package/dist/selection-DPg0uyJf.d.cts.map +1 -0
  104. package/dist/types/index.cjs +3 -3
  105. package/dist/types/index.d.cts +7 -2
  106. package/dist/types/index.d.ts +8 -2
  107. package/dist/types/index.js +3 -3
  108. package/dist/types-Bu_ZwMbZ.js +0 -0
  109. package/dist/types-NRqymi6S.cjs +0 -0
  110. package/dist/utils/index.cjs +4 -17
  111. package/dist/utils/index.d.cts +3 -17
  112. package/dist/utils/index.d.ts +3 -17
  113. package/dist/utils/index.js +4 -18
  114. package/package.json +26 -5
  115. package/src/actions/advanced/advanced.test.ts +258 -0
  116. package/src/actions/advanced/buildMutation.ts +104 -0
  117. package/src/actions/advanced/getMutationResult.ts +112 -0
  118. package/src/actions/advanced/index.ts +21 -0
  119. package/src/actions/advanced/pingTransaction.ts +43 -0
  120. package/src/actions/advanced/sendMutation.ts +59 -0
  121. package/src/actions/public/getEntity.ts +27 -43
  122. package/src/actions/public/getEntityNonce.ts +30 -0
  123. package/src/actions/public/predictEntityKeys.test.ts +143 -0
  124. package/src/actions/public/predictEntityKeys.ts +138 -0
  125. package/src/actions/public/query.ts +35 -67
  126. package/src/actions/public/watchEntityEvents.test.ts +414 -0
  127. package/src/actions/public/watchEntityEvents.ts +225 -0
  128. package/src/actions/wallet/changeOwnership.ts +2 -2
  129. package/src/actions/wallet/createEntity.ts +99 -24
  130. package/src/actions/wallet/extendEntity.ts +37 -13
  131. package/src/actions/wallet/mutateEntities.test.ts +76 -0
  132. package/src/actions/wallet/mutateEntities.ts +16 -33
  133. package/src/actions/wallet/patchEntity.ts +90 -0
  134. package/src/attr/attributes.test.ts +120 -0
  135. package/src/attr/attributes.ts +190 -0
  136. package/src/attr/codec.test.ts +162 -0
  137. package/src/attr/codec.ts +220 -0
  138. package/src/attr/decimal.ts +86 -0
  139. package/src/attr/errors.ts +145 -0
  140. package/src/attr/index.ts +50 -0
  141. package/src/attr/names.ts +106 -0
  142. package/src/attr/types.ts +150 -0
  143. package/src/attr/values.test.ts +271 -0
  144. package/src/attr/values.ts +502 -0
  145. package/src/chains/cheesecake.ts +22 -0
  146. package/src/chains/index.ts +1 -2
  147. package/src/clients/createPublicClient.test.ts +3 -5
  148. package/src/clients/createPublicClient.ts +5 -4
  149. package/src/clients/createWalletClient.test.ts +2 -2
  150. package/src/clients/createWalletClient.ts +13 -7
  151. package/src/clients/decorators/arkivAdvanced.ts +144 -0
  152. package/src/clients/decorators/arkivPublic.ts +172 -139
  153. package/src/clients/decorators/arkivWallet.ts +101 -94
  154. package/src/entity/create.test.ts +184 -0
  155. package/src/entity/errors.ts +38 -0
  156. package/src/entity/events.ts +16 -0
  157. package/src/entity/expiry.test.ts +195 -0
  158. package/src/entity/expiry.ts +181 -0
  159. package/src/entity/flags.ts +65 -0
  160. package/src/entity/index.ts +15 -0
  161. package/src/entity/key.ts +68 -0
  162. package/src/entity/operations.ts +134 -0
  163. package/src/entity/params.ts +15 -0
  164. package/src/errors.ts +26 -49
  165. package/src/index.ts +19 -0
  166. package/src/query/engine.ts +68 -137
  167. package/src/query/errors.ts +151 -0
  168. package/src/query/expression.test.ts +286 -0
  169. package/src/query/expression.ts +493 -0
  170. package/src/query/index.ts +40 -4
  171. package/src/query/injection.test.ts +151 -0
  172. package/src/query/queryBuilder.test.ts +342 -637
  173. package/src/query/queryBuilder.ts +133 -359
  174. package/src/query/queryResult.ts +54 -51
  175. package/src/query/selection.test.ts +48 -98
  176. package/src/query/selection.ts +77 -65
  177. package/src/types/entity.test.ts +44 -155
  178. package/src/types/entity.ts +60 -52
  179. package/src/types/events.ts +59 -16
  180. package/src/types/index.ts +20 -17
  181. package/src/types/rpcSchema.ts +69 -37
  182. package/src/utils/arkivTransactions.test.ts +600 -155
  183. package/src/utils/arkivTransactions.ts +350 -219
  184. package/src/utils/chains.test.ts +21 -24
  185. package/src/utils/compression.ts +1 -1
  186. package/src/utils/entities.test.ts +62 -0
  187. package/src/utils/entities.ts +109 -37
  188. package/src/utils/expirationTime.ts +114 -10
  189. package/src/utils/logger.ts +2 -2
  190. package/src/utils/revert.test.ts +99 -0
  191. package/src/utils/revert.ts +145 -0
  192. package/dist/chains-BifaY04V.cjs +0 -108
  193. package/dist/chains-CrtkVbBh.js +0 -86
  194. package/dist/chains-CrtkVbBh.js.map +0 -1
  195. package/dist/consts-Bz0LZQZY.js +0 -7
  196. package/dist/consts-Bz0LZQZY.js.map +0 -1
  197. package/dist/consts-CxT1-RXU.cjs +0 -18
  198. package/dist/entity-BhSXaB23.cjs +0 -81
  199. package/dist/entity-CN41IOrq.d.cts +0 -401
  200. package/dist/entity-CN41IOrq.d.cts.map +0 -1
  201. package/dist/entity-DGfVyB-a.js +0 -71
  202. package/dist/entity-DGfVyB-a.js.map +0 -1
  203. package/dist/entity-NnEVlePN.d.ts +0 -401
  204. package/dist/entity-NnEVlePN.d.ts.map +0 -1
  205. package/dist/index-ClkpS6s_.d.ts +0 -481
  206. package/dist/index-ClkpS6s_.d.ts.map +0 -1
  207. package/dist/index-w4qop0Pe.d.cts +0 -481
  208. package/dist/index-w4qop0Pe.d.cts.map +0 -1
  209. package/dist/payload-BpNUPOnY.js +0 -13
  210. package/dist/payload-BpNUPOnY.js.map +0 -1
  211. package/dist/payload-C2KHOUoj.d.ts +0 -6
  212. package/dist/payload-C2KHOUoj.d.ts.map +0 -1
  213. package/dist/payload-CJN8fTvX.d.cts +0 -6
  214. package/dist/payload-CJN8fTvX.d.cts.map +0 -1
  215. package/dist/payload-D8YLKcJj.cjs +0 -23
  216. package/dist/query/index.js.map +0 -1
  217. package/dist/queryBuilder-BE_XhLLa.js +0 -735
  218. package/dist/queryBuilder-BE_XhLLa.js.map +0 -1
  219. package/dist/queryBuilder-J37buGCi.cjs +0 -865
  220. package/dist/utils/index.d.cts.map +0 -1
  221. package/dist/utils/index.d.ts.map +0 -1
  222. package/dist/utils/index.js.map +0 -1
  223. package/src/actions/public/buildQuery.ts +0 -10
  224. package/src/actions/public/subscribeEntityEvents.ts +0 -93
  225. package/src/actions/wallet/updateEntity.ts +0 -59
  226. package/src/chains/braga.ts +0 -26
  227. package/src/chains/kaolin.ts +0 -29
  228. package/src/query/engine.test.ts +0 -571
  229. package/src/query/predicate.test.ts +0 -461
  230. package/src/query/predicate.ts +0 -144
  231. package/src/query/queryResult.test.ts +0 -270
  232. package/src/query/selectQueryBuilder.test.ts +0 -213
  233. package/src/types/attributes.ts +0 -28
  234. package/src/utils/validation.test.ts +0 -106
  235. package/src/utils/validation.ts +0 -80
  236. /package/dist/{types-Ci4BRClw.js → attr-DlmErkvR.cjs} +0 -0
  237. /package/dist/{types-a8gm_IaQ.cjs → attr-GcQKatub.js} +0 -0
@@ -0,0 +1,271 @@
1
+ import { describe, expect, it } from "bun:test"
2
+ import { InvalidValueError, MissingValueError, UntypedValueError } from "./errors"
3
+ import { TYPE_IDS } from "./types"
4
+ import {
5
+ addr,
6
+ bool,
7
+ bytes32,
8
+ dec,
9
+ decFromUnits,
10
+ decUnits,
11
+ I32_MAX,
12
+ I32_MIN,
13
+ i32,
14
+ key,
15
+ str,
16
+ toValue,
17
+ U64_MAX,
18
+ U256_MAX,
19
+ u64,
20
+ u256,
21
+ } from "./values"
22
+
23
+ const KEY = `0x${"ab".repeat(32)}` as const
24
+ const VITALIK = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
25
+
26
+ describe("tagged constructors", () => {
27
+ it("tag each value with the type it was built as", () => {
28
+ const built = [
29
+ [bool(true), "bool", true],
30
+ [i32(10), "i32", 10],
31
+ [u256(10n), "u256", 10n],
32
+ [dec("3.5"), "dec", "3.5"],
33
+ [str("Bob"), "str", "Bob"],
34
+ [key(KEY), "key", KEY],
35
+ [bytes32(KEY), "bytes32", KEY],
36
+ [addr(VITALIK), "addr", VITALIK],
37
+ ] as const
38
+ for (const [value, tag, decoded] of built) {
39
+ expect(value.type).toBe(tag)
40
+ expect(value.value).toBe(decoded)
41
+ }
42
+ })
43
+
44
+ it("keep the tag distinct from the wire typeId", () => {
45
+ // The tag is what a client says; the typeId is what the wire carries.
46
+ expect(TYPE_IDS[i32(1).type]).toBe(2)
47
+ expect(TYPE_IDS[key(KEY).type]).toBe(10)
48
+ expect(TYPE_IDS[bytes32(KEY).type]).toBe(6)
49
+ })
50
+ })
51
+
52
+ describe("i32", () => {
53
+ it("accepts the full signed 32-bit range", () => {
54
+ expect(i32(I32_MIN).value).toBe(I32_MIN)
55
+ expect(i32(I32_MAX).value).toBe(I32_MAX)
56
+ expect(i32(-42).value).toBe(-42)
57
+ expect(i32(0n).value).toBe(0)
58
+ })
59
+
60
+ it("rejects values outside the range, naming the type that fits", () => {
61
+ expect(() => i32(I32_MAX + 1)).toThrow(InvalidValueError)
62
+ expect(() => i32(Date.now())).toThrow(/use u64/)
63
+ expect(() => i32(I32_MIN - 1)).toThrow(/use dec/)
64
+ expect(() => i32(2n ** 40n)).toThrow(InvalidValueError)
65
+ })
66
+
67
+ it("rejects non-integers, quoting the dec call that would work", () => {
68
+ expect(() => i32(3.5)).toThrow(/dec\("3\.5"\)/)
69
+ expect(() => i32(Number.NaN)).toThrow(InvalidValueError)
70
+ expect(() => i32(Number.POSITIVE_INFINITY)).toThrow(InvalidValueError)
71
+ })
72
+ })
73
+
74
+ describe("u64", () => {
75
+ it("accepts bigints, safe numbers, and decimal or hex strings", () => {
76
+ expect(u64(0n).value).toBe(0n)
77
+ expect(u64(U64_MAX).value).toBe(U64_MAX)
78
+ expect(u64(1_200_000).value).toBe(1_200_000n)
79
+ expect(u64("1200000").value).toBe(1_200_000n)
80
+ expect(u64("0x124f80").value).toBe(1_200_000n)
81
+ })
82
+
83
+ it("rejects negatives, overflow, and lossy numbers", () => {
84
+ expect(() => u64(-1n)).toThrow(/unsigned/)
85
+ expect(() => u64(U64_MAX + 1n)).toThrow(/wider than 64 bits/)
86
+ expect(() => u64(2 ** 53)).toThrow(/safe integer/)
87
+ expect(() => u64(1.5)).toThrow(/dec\("1\.5"\)/)
88
+ expect(() => u64("12abc")).toThrow(InvalidValueError)
89
+ })
90
+
91
+ it("points at u256 when the value is simply too wide", () => {
92
+ expect(() => u64(U64_MAX + 1n)).toThrow(/Use u256/)
93
+ })
94
+
95
+ it("is a distinct type from u256, not an alias for a small one", () => {
96
+ expect(TYPE_IDS[u64(1n).type]).toBe(3)
97
+ expect(TYPE_IDS[u256(1n).type]).toBe(4)
98
+ })
99
+ })
100
+
101
+ describe("u256", () => {
102
+ it("accepts bigints, safe numbers, and decimal or hex strings", () => {
103
+ expect(u256(0n).value).toBe(0n)
104
+ expect(u256(U256_MAX).value).toBe(U256_MAX)
105
+ expect(u256(1_000_000).value).toBe(1_000_000n)
106
+ expect(u256("1000000").value).toBe(1_000_000n)
107
+ expect(u256("0xf4240").value).toBe(1_000_000n)
108
+ })
109
+
110
+ it("rejects negatives, overflow, and lossy numbers", () => {
111
+ expect(() => u256(-1n)).toThrow(/unsigned/)
112
+ expect(() => u256(U256_MAX + 1n)).toThrow(/wider than 256 bits/)
113
+ expect(() => u256(2 ** 53)).toThrow(/safe integer/)
114
+ expect(() => u256(1.5)).toThrow(/dec\("1\.5"\)/)
115
+ expect(() => u256("12abc")).toThrow(InvalidValueError)
116
+ })
117
+ })
118
+
119
+ describe("dec", () => {
120
+ it("canonicalises the decimal it was given", () => {
121
+ expect(dec("3.5").value).toBe("3.5")
122
+ expect(dec("3.50").value).toBe("3.5")
123
+ expect(dec("003.5").value).toBe("3.5")
124
+ expect(dec("+3.5").value).toBe("3.5")
125
+ expect(dec("-0.0").value).toBe("0")
126
+ expect(dec("5").value).toBe("5")
127
+ expect(dec(5).value).toBe("5")
128
+ expect(dec(-5n).value).toBe("-5")
129
+ })
130
+
131
+ it("holds exactly 18 decimal places", () => {
132
+ expect(dec("0.000000000000000001").value).toBe("0.000000000000000001")
133
+ expect(decUnits(dec("0.000000000000000001"))).toBe(1n)
134
+ expect(decUnits(dec("3.5"))).toBe(3_500_000_000_000_000_000n)
135
+ expect(decUnits(dec("-3.5"))).toBe(-3_500_000_000_000_000_000n)
136
+ })
137
+
138
+ it("errors rather than rounding away excess precision", () => {
139
+ expect(() => dec("0.0000000000000000001")).toThrow(/19 fractional digits/)
140
+ expect(() => dec("1e18")).toThrow(/not a decimal literal/)
141
+ expect(() => dec("3.")).toThrow(/not a decimal literal/)
142
+ expect(() => dec(".5")).toThrow(/not a decimal literal/)
143
+ })
144
+
145
+ it("refuses fractional numbers, since binary floats cannot hold them", () => {
146
+ expect(() => dec(3.5)).toThrow(/dec\("3\.5"\)/)
147
+ expect(() => dec(0.1 + 0.2)).toThrow(/dec\("0\.30000000000000004"\)/)
148
+ })
149
+
150
+ it("round-trips through its scaled units", () => {
151
+ for (const literal of ["0", "1", "-1", "3.5", "-0.25", "123456789.000000000000000001"]) {
152
+ expect(decFromUnits(decUnits(dec(literal))).value).toBe(dec(literal).value)
153
+ }
154
+ })
155
+ })
156
+
157
+ describe("str", () => {
158
+ it("measures its 128-byte limit in bytes, not characters", () => {
159
+ expect(str("a".repeat(128)).value).toHaveLength(128)
160
+ expect(() => str("a".repeat(129))).toThrow(/129 UTF-8 bytes/)
161
+ // "é" is two UTF-8 bytes, so 64 of them exactly fill the limit.
162
+ expect(str("é".repeat(64)).value).toHaveLength(64)
163
+ expect(() => str("é".repeat(65))).toThrow(/130 UTF-8 bytes/)
164
+ })
165
+ })
166
+
167
+ describe("addr", () => {
168
+ it("normalises to EIP-55 regardless of the case it was given", () => {
169
+ expect(addr(VITALIK).value).toBe(VITALIK)
170
+ expect(addr(VITALIK.toLowerCase()).value).toBe(VITALIK)
171
+ expect(addr(`0x${VITALIK.slice(2).toUpperCase()}`).value).toBe(VITALIK)
172
+ })
173
+
174
+ it("catches a mistyped mixed-case address via its checksum", () => {
175
+ const mistyped = `0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96046`
176
+ expect(() => addr(mistyped)).toThrow(/EIP-55 checksum/)
177
+ expect(() => addr(mistyped)).toThrow(/correctly checksummed form is 0x/)
178
+ })
179
+
180
+ it("rejects anything that is not 20 hex bytes", () => {
181
+ expect(() => addr("0x1234")).toThrow(InvalidValueError)
182
+ expect(() => addr(KEY)).toThrow(InvalidValueError)
183
+ })
184
+ })
185
+
186
+ describe("key and bytes32", () => {
187
+ it("accept hex or raw bytes and normalise to lowercase hex", () => {
188
+ expect(key(`0x${"AB".repeat(32)}`).value).toBe(KEY)
189
+ expect(bytes32(new Uint8Array(32).fill(0xab)).value).toBe(KEY)
190
+ })
191
+
192
+ it("reject anything that is not exactly 32 bytes", () => {
193
+ expect(() => key(`0x${"ab".repeat(31)}`)).toThrow(/31 bytes/)
194
+ expect(() => bytes32(new Uint8Array(31))).toThrow(/not exactly 32 bytes/)
195
+ expect(() => key("not hex" as `0x${string}`)).toThrow(/not 0x-prefixed hex/)
196
+ })
197
+ })
198
+
199
+ describe("toValue", () => {
200
+ it("gives each bare form its unambiguous default type", () => {
201
+ expect(toValue(true)).toEqual(bool(true))
202
+ expect(toValue(10)).toEqual(i32(10))
203
+ expect(toValue(10n)).toEqual(u256(10n))
204
+ expect(toValue("hello")).toEqual(str("hello"))
205
+ })
206
+
207
+ it("leaves a hex-looking string a string, rather than guessing at a key", () => {
208
+ expect(toValue(KEY)).toEqual(str(KEY))
209
+ })
210
+
211
+ it("leaves a tagged value's type and value alone", () => {
212
+ for (const tagged of [dec("3.5"), i32(-42), u256(10n), str("hi"), bool(true), key(KEY)]) {
213
+ expect(toValue(tagged)).toEqual(tagged)
214
+ }
215
+ })
216
+
217
+ it("re-validates a tagged value rather than trusting its shape", () => {
218
+ // The `validated` brand is type-level only, so nothing at runtime distinguishes a real u256
219
+ // from an object that looks like one — out of JSON.parse, a config file, or an `as any`. Left
220
+ // unchecked this was silent corruption, not an error: the ABI encoder would take the *string*
221
+ // "1000" and write its UTF-8 bytes into the word, storing 2.27e76 on chain.
222
+ const lookAlike = { type: "u256", value: "1000" } as unknown as string
223
+ expect(toValue(lookAlike)).toEqual(u256(1000n))
224
+ expect(toValue(lookAlike).value).toBe(1000n)
225
+
226
+ // And a look-alike carrying something its type cannot hold is now rejected outright.
227
+ expect(() => toValue({ type: "i32", value: 2 ** 40 } as unknown as string)).toThrow(
228
+ InvalidValueError,
229
+ )
230
+ expect(() => toValue({ type: "addr", value: "0x1234" } as unknown as string)).toThrow(
231
+ InvalidValueError,
232
+ )
233
+ expect(() => toValue({ type: "str", value: 42 } as unknown as string)).toThrow(
234
+ InvalidValueError,
235
+ )
236
+ })
237
+
238
+ it("rejects values it cannot type", () => {
239
+ expect(() => toValue({ type: "nope", value: 1 } as unknown as string)).toThrow(
240
+ UntypedValueError,
241
+ )
242
+ expect(() => toValue(new Uint8Array(32) as unknown as string)).toThrow(UntypedValueError)
243
+ // `in` would have walked the prototype chain and accepted these as type tags.
244
+ for (const inherited of ["constructor", "toString", "valueOf", "hasOwnProperty"]) {
245
+ expect(() => toValue({ type: inherited, value: 1 } as unknown as string)).toThrow(
246
+ UntypedValueError,
247
+ )
248
+ }
249
+ })
250
+
251
+ it("rejects an absent value by telling you to omit the attribute, not to infer a type", () => {
252
+ // `undefined` and `null` are not assignable to ValueInput, but they still reach here at
253
+ // runtime — from a spread of an optional-shaped object, or from data that never saw a type.
254
+ for (const absent of [undefined, null]) {
255
+ expect(() => toValue(absent as unknown as string)).toThrow(MissingValueError)
256
+ expect(() => toValue(absent as unknown as string, "score")).toThrow(/Omit "score"/)
257
+ }
258
+ expect(() => toValue(undefined as unknown as string, "score")).toThrow(
259
+ /attribute "score" is undefined/,
260
+ )
261
+ })
262
+ })
263
+
264
+ describe("the validated brand", () => {
265
+ it("makes a hand-written value object a compile error", () => {
266
+ // @ts-expect-error — only the tagged constructors produce a validated value, which is what
267
+ // guarantees every value on the wire has been range- and format-checked.
268
+ const forged: ReturnType<typeof i32> = { type: "i32", value: 3.5 }
269
+ expect(forged.value).toBe(3.5)
270
+ })
271
+ })