@arkiv-network/sdk 0.7.0 → 0.8.0-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -16
- package/dist/attr/index.cjs +34 -0
- package/dist/attr/index.d.cts +2 -0
- package/dist/attr/index.d.ts +2 -0
- package/dist/attr/index.js +3 -0
- package/dist/attr-BDZ-APg5.js +809 -0
- package/dist/attr-BDZ-APg5.js.map +1 -0
- package/dist/attr-BvxHN99W.cjs +1029 -0
- package/dist/chains/index.cjs +2 -3
- package/dist/chains/index.d.cts +39 -77
- package/dist/chains/index.d.cts.map +1 -1
- package/dist/chains/index.d.ts +22 -60
- package/dist/chains/index.d.ts.map +1 -1
- package/dist/chains/index.js +2 -2
- package/dist/chains-BJrZs6sG.js +57 -0
- package/dist/chains-BJrZs6sG.js.map +1 -0
- package/dist/chains-BYRTTipa.cjs +73 -0
- package/dist/changeOwnership-B7bEgla4.d.cts +509 -0
- package/dist/changeOwnership-B7bEgla4.d.cts.map +1 -0
- package/dist/changeOwnership-DwgtdSFc.d.ts +509 -0
- package/dist/changeOwnership-DwgtdSFc.d.ts.map +1 -0
- package/dist/entity/index.cjs +19 -0
- package/dist/entity/index.d.cts +4 -0
- package/dist/entity/index.d.ts +4 -0
- package/dist/entity/index.js +6 -0
- package/dist/entity-B0t6sN7F.cjs +71 -0
- package/dist/entity-BIp_df9u.js +67 -0
- package/dist/entity-BIp_df9u.js.map +1 -0
- package/dist/entity-CFhbAv0R.js +70 -0
- package/dist/entity-CFhbAv0R.js.map +1 -0
- package/dist/entity-wfBnZd91.cjs +98 -0
- package/dist/errors-D-eJkGVc.cjs +56 -0
- package/dist/errors-DGB8AgT2.js +33 -0
- package/dist/errors-DGB8AgT2.js.map +1 -0
- package/dist/expiry-BUYIXTGb.cjs +135 -0
- package/dist/expiry-BxOlvVWC.d.ts +79 -0
- package/dist/expiry-BxOlvVWC.d.ts.map +1 -0
- package/dist/expiry-DGRzrSan.js +95 -0
- package/dist/expiry-DGRzrSan.js.map +1 -0
- package/dist/expiry-DRV29F1r.d.cts +79 -0
- package/dist/expiry-DRV29F1r.d.cts.map +1 -0
- package/dist/flags-0Vl5rrHq.d.cts +41 -0
- package/dist/flags-0Vl5rrHq.d.cts.map +1 -0
- package/dist/flags-Ct8k0gpB.cjs +43 -0
- package/dist/flags-ZtlvOIIk.js +33 -0
- package/dist/flags-ZtlvOIIk.js.map +1 -0
- package/dist/flags-wmcMoAnN.d.ts +41 -0
- package/dist/flags-wmcMoAnN.d.ts.map +1 -0
- package/dist/index-Cgw1u5aY.d.cts +278 -0
- package/dist/index-Cgw1u5aY.d.cts.map +1 -0
- package/dist/index-ClgIuxJ8.d.ts +159 -0
- package/dist/index-ClgIuxJ8.d.ts.map +1 -0
- package/dist/index-D0CmtiWT.d.cts +159 -0
- package/dist/index-D0CmtiWT.d.cts.map +1 -0
- package/dist/index-D8LZt-3J.d.cts +417 -0
- package/dist/index-D8LZt-3J.d.cts.map +1 -0
- package/dist/index-DVYFaXNV.d.ts +417 -0
- package/dist/index-DVYFaXNV.d.ts.map +1 -0
- package/dist/index-VCqgn29D.d.ts +278 -0
- package/dist/index-VCqgn29D.d.ts.map +1 -0
- package/dist/index.cjs +675 -357
- package/dist/index.d.cts +251 -203
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +251 -203
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +626 -355
- package/dist/index.js.map +1 -1
- package/dist/payload-Bnw1hrvb.cjs +83 -0
- package/dist/payload-CIxSn_DW.js +67 -0
- package/dist/payload-CIxSn_DW.js.map +1 -0
- package/dist/payload-Dgx3PQeK.d.ts +94 -0
- package/dist/payload-Dgx3PQeK.d.ts.map +1 -0
- package/dist/payload-P0nWyjLg.d.cts +94 -0
- package/dist/payload-P0nWyjLg.d.cts.map +1 -0
- package/dist/query/index.cjs +24 -149
- package/dist/query/index.d.cts +5 -3
- package/dist/query/index.d.ts +5 -3
- package/dist/query/index.js +6 -137
- package/dist/queryBuilder-BXDvX1K_.cjs +1123 -0
- package/dist/queryBuilder-CbLL4pG5.js +963 -0
- package/dist/queryBuilder-CbLL4pG5.js.map +1 -0
- package/dist/selection-BvK6yX0g.d.cts +433 -0
- package/dist/selection-BvK6yX0g.d.cts.map +1 -0
- package/dist/selection-fpmI3ADQ.d.ts +433 -0
- package/dist/selection-fpmI3ADQ.d.ts.map +1 -0
- package/dist/types/index.cjs +4 -1
- package/dist/types/index.d.cts +7 -2
- package/dist/types/index.d.ts +7 -2
- package/dist/types/index.js +4 -1
- package/dist/utils/index.cjs +4 -17
- package/dist/utils/index.d.cts +3 -17
- package/dist/utils/index.d.ts +3 -17
- package/dist/utils/index.js +4 -18
- package/package.json +26 -5
- package/src/actions/public/getEntity.ts +27 -43
- package/src/actions/public/getEntityNonce.ts +30 -0
- package/src/actions/public/predictEntityKeys.test.ts +143 -0
- package/src/actions/public/predictEntityKeys.ts +138 -0
- package/src/actions/public/query.ts +33 -69
- package/src/actions/public/watchEntityEvents.test.ts +414 -0
- package/src/actions/public/watchEntityEvents.ts +225 -0
- package/src/actions/wallet/changeOwnership.ts +8 -8
- package/src/actions/wallet/createEntity.ts +104 -26
- package/src/actions/wallet/deleteEntity.ts +2 -3
- package/src/actions/wallet/extendEntity.ts +39 -16
- package/src/actions/wallet/mutateEntities.test.ts +76 -0
- package/src/actions/wallet/mutateEntities.ts +29 -74
- package/src/actions/wallet/patchEntity.ts +90 -0
- package/src/attr/attributes.test.ts +120 -0
- package/src/attr/attributes.ts +190 -0
- package/src/attr/codec.test.ts +162 -0
- package/src/attr/codec.ts +220 -0
- package/src/attr/decimal.ts +86 -0
- package/src/attr/errors.ts +145 -0
- package/src/attr/index.ts +50 -0
- package/src/attr/names.ts +106 -0
- package/src/attr/types.ts +150 -0
- package/src/attr/values.test.ts +271 -0
- package/src/attr/values.ts +502 -0
- package/src/chains/cheesecake.ts +22 -0
- package/src/chains/index.ts +1 -2
- package/src/clients/createPublicClient.test.ts +3 -5
- package/src/clients/createPublicClient.ts +5 -4
- package/src/clients/createWalletClient.test.ts +2 -2
- package/src/clients/createWalletClient.ts +13 -7
- package/src/clients/decorators/arkivPublic.ts +160 -139
- package/src/clients/decorators/arkivWallet.ts +91 -95
- package/src/consts.ts +2 -1
- package/src/entity/create.test.ts +184 -0
- package/src/entity/errors.ts +38 -0
- package/src/entity/events.ts +16 -0
- package/src/entity/expiry.test.ts +195 -0
- package/src/entity/expiry.ts +181 -0
- package/src/entity/flags.ts +65 -0
- package/src/entity/index.ts +14 -0
- package/src/entity/key.ts +68 -0
- package/src/entity/operations.ts +134 -0
- package/src/entity/params.ts +15 -0
- package/src/errors.ts +33 -28
- package/src/index.ts +6 -0
- package/src/query/engine.ts +59 -134
- package/src/query/errors.ts +151 -0
- package/src/query/expression.test.ts +286 -0
- package/src/query/expression.ts +493 -0
- package/src/query/index.ts +40 -4
- package/src/query/injection.test.ts +151 -0
- package/src/query/queryBuilder.test.ts +322 -637
- package/src/query/queryBuilder.ts +126 -359
- package/src/query/queryResult.ts +54 -51
- package/src/query/selection.test.ts +48 -98
- package/src/query/selection.ts +77 -65
- package/src/types/entity.test.ts +44 -155
- package/src/types/entity.ts +62 -44
- package/src/types/events.ts +64 -23
- package/src/types/index.ts +20 -16
- package/src/types/rpcSchema.ts +70 -33
- package/src/utils/arkivTransactions.test.ts +681 -38
- package/src/utils/arkivTransactions.ts +249 -104
- package/src/utils/chains.test.ts +21 -24
- package/src/utils/compression.ts +1 -1
- package/src/utils/entities.test.ts +62 -0
- package/src/utils/entities.ts +111 -29
- package/src/utils/expirationTime.ts +114 -10
- package/src/utils/logger.ts +2 -2
- package/src/utils/payload.ts +4 -2
- package/src/utils/revert.test.ts +99 -0
- package/src/utils/revert.ts +145 -0
- package/dist/chains-BifaY04V.cjs +0 -108
- package/dist/chains-CrtkVbBh.js +0 -86
- package/dist/chains-CrtkVbBh.js.map +0 -1
- package/dist/consts-AUoL-v42.cjs +0 -18
- package/dist/consts-BV4PR-de.js +0 -7
- package/dist/consts-BV4PR-de.js.map +0 -1
- package/dist/entity-B6g_EPm1.d.cts +0 -382
- package/dist/entity-B6g_EPm1.d.cts.map +0 -1
- package/dist/entity-qoLMAuuk.d.ts +0 -382
- package/dist/entity-qoLMAuuk.d.ts.map +0 -1
- package/dist/index-DdspxNAA.d.ts +0 -481
- package/dist/index-DdspxNAA.d.ts.map +0 -1
- package/dist/index-Ds9dwqb5.d.cts +0 -481
- package/dist/index-Ds9dwqb5.d.cts.map +0 -1
- package/dist/payload-B2kFJyah.d.ts +0 -6
- package/dist/payload-B2kFJyah.d.ts.map +0 -1
- package/dist/payload-CJN8fTvX.d.cts +0 -6
- package/dist/payload-CJN8fTvX.d.cts.map +0 -1
- package/dist/payload-Claf2jUO.js +0 -13
- package/dist/payload-Claf2jUO.js.map +0 -1
- package/dist/payload-DpA5PA-w.cjs +0 -23
- package/dist/query/index.js.map +0 -1
- package/dist/queryBuilder-D2uwP9jI.js +0 -704
- package/dist/queryBuilder-D2uwP9jI.js.map +0 -1
- package/dist/queryBuilder-UW2MCaX4.cjs +0 -792
- package/dist/utils/index.d.cts.map +0 -1
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js.map +0 -1
- package/src/actions/public/buildQuery.ts +0 -10
- package/src/actions/public/subscribeEntityEvents.ts +0 -119
- package/src/actions/wallet/updateEntity.ts +0 -60
- package/src/chains/braga.ts +0 -26
- package/src/chains/kaolin.ts +0 -29
- package/src/query/engine.test.ts +0 -526
- package/src/query/predicate.test.ts +0 -461
- package/src/query/predicate.ts +0 -144
- package/src/query/queryResult.test.ts +0 -270
- package/src/query/selectQueryBuilder.test.ts +0 -210
- package/src/types/attributes.ts +0 -16
- package/src/utils/validation.test.ts +0 -60
- package/src/utils/validation.ts +0 -32
- /package/dist/{types-H-TSmRpm.js → types-Bx1EKe0v.js} +0 -0
- /package/dist/{types-o3zWarRp.cjs → types-CKPddlfS.cjs} +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
|
+
})
|