@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,502 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Address,
|
|
3
|
+
checksumAddress,
|
|
4
|
+
type Hex,
|
|
5
|
+
isAddress,
|
|
6
|
+
isHex,
|
|
7
|
+
stringToBytes,
|
|
8
|
+
toHex,
|
|
9
|
+
} from "viem"
|
|
10
|
+
import { DECIMAL_UNIT, decimalToUnits, unitsToDecimal } from "./decimal"
|
|
11
|
+
import { InvalidValueError, MissingValueError, UntypedValueError } from "./errors"
|
|
12
|
+
import {
|
|
13
|
+
type AddrValue,
|
|
14
|
+
type AnyArkivValue,
|
|
15
|
+
type ArkivValue,
|
|
16
|
+
type BoolValue,
|
|
17
|
+
type Bytes32Value,
|
|
18
|
+
type BytesValue,
|
|
19
|
+
type DecValue,
|
|
20
|
+
type I32Value,
|
|
21
|
+
isArkivValue,
|
|
22
|
+
type KeyValue,
|
|
23
|
+
makeValue,
|
|
24
|
+
type StrValue,
|
|
25
|
+
type U64Value,
|
|
26
|
+
type U256Value,
|
|
27
|
+
} from "./types"
|
|
28
|
+
|
|
29
|
+
/** The widest `i32`. */
|
|
30
|
+
export const I32_MAX = 2147483647
|
|
31
|
+
/** The narrowest `i32`. */
|
|
32
|
+
export const I32_MIN = -2147483648
|
|
33
|
+
/** The widest `u64`. */
|
|
34
|
+
export const U64_MAX = 2n ** 64n - 1n
|
|
35
|
+
/** The widest `u256`. */
|
|
36
|
+
export const U256_MAX = 2n ** 256n - 1n
|
|
37
|
+
/**
|
|
38
|
+
* The longest `str`, in UTF-8 bytes
|
|
39
|
+
*/
|
|
40
|
+
export const MAX_STRING_BYTES = 128
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Finds the first C0 control or DEL — the characters a `str` may not contain.
|
|
44
|
+
*/
|
|
45
|
+
function findControlChar(value: string): { index: number; code: number } | undefined {
|
|
46
|
+
for (let index = 0; index < value.length; index++) {
|
|
47
|
+
const code = value.charCodeAt(index)
|
|
48
|
+
if (code <= 0x1f || code === 0x7f) return { index, code }
|
|
49
|
+
}
|
|
50
|
+
return undefined
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* A boolean.
|
|
55
|
+
*
|
|
56
|
+
* `bool` is the one type that may also be written bare — `{ flagged: true }` and
|
|
57
|
+
* `{ flagged: bool(true) }` are the same attribute.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* bool(true) // { type: "bool", value: true }
|
|
61
|
+
*/
|
|
62
|
+
export function bool(value: boolean): BoolValue {
|
|
63
|
+
if (typeof value !== "boolean") {
|
|
64
|
+
throw new InvalidValueError("bool", value, "not a boolean")
|
|
65
|
+
}
|
|
66
|
+
return makeValue("bool", value)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* A 32-bit signed integer, indexed for equality and range queries. This is the default type for a
|
|
71
|
+
* bare number, so `{ level: 10 }` and `{ level: i32(10) }` are the same attribute.
|
|
72
|
+
*
|
|
73
|
+
* @param value - An integer in [-2147483648, 2147483647].
|
|
74
|
+
* @throws {InvalidValueError} If the value is not an integer, or does not fit an `i32`.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* i32(10) // { type: "i32", value: 10 }
|
|
78
|
+
* i32(-42) // negative values are fine — i32 is the signed integer
|
|
79
|
+
*/
|
|
80
|
+
export function i32(value: number | bigint): I32Value {
|
|
81
|
+
if (typeof value === "bigint") {
|
|
82
|
+
if (value > BigInt(I32_MAX) || value < BigInt(I32_MIN)) {
|
|
83
|
+
throw new InvalidValueError("i32", value, outOfI32Range(value >= 0n))
|
|
84
|
+
}
|
|
85
|
+
return makeValue("i32", Number(value))
|
|
86
|
+
}
|
|
87
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
88
|
+
throw new InvalidValueError("i32", value, "not a number")
|
|
89
|
+
}
|
|
90
|
+
if (!Number.isInteger(value)) {
|
|
91
|
+
throw new InvalidValueError(
|
|
92
|
+
"i32",
|
|
93
|
+
value,
|
|
94
|
+
"not an integer",
|
|
95
|
+
`Use dec(${JSON.stringify(String(value))}) for a fixed-point decimal.`,
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
if (value > I32_MAX || value < I32_MIN) {
|
|
99
|
+
throw new InvalidValueError("i32", value, outOfI32Range(value >= 0))
|
|
100
|
+
}
|
|
101
|
+
return makeValue("i32", value)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function outOfI32Range(nonNegative: boolean): string {
|
|
105
|
+
const range = `outside the i32 range [${I32_MIN}, ${I32_MAX}]`
|
|
106
|
+
return nonNegative
|
|
107
|
+
? `${range} — use u64(...) for large counters, timestamps and block heights (Date.now() does ` +
|
|
108
|
+
`not fit an i32), or u256(...) beyond 2**64 - 1`
|
|
109
|
+
: `${range} — use dec(...) for values that need more range than an i32`
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* A 256-bit unsigned integer, indexed for equality and range queries. The type for token amounts
|
|
114
|
+
* and anything else that can outgrow 2⁶⁴ — reach for {@link u64} first for counters, timestamps
|
|
115
|
+
* and block heights.
|
|
116
|
+
*
|
|
117
|
+
* @param value - A non-negative integer, as a `bigint`, a safe `number`, or a decimal or `0x` hex
|
|
118
|
+
* string.
|
|
119
|
+
* @throws {InvalidValueError} If the value is negative, non-integral, or wider than 256 bits.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* u256(1_000_000n)
|
|
123
|
+
* u256(Date.now()) // safe integers are accepted
|
|
124
|
+
* u256("0xf4240") // hex, as it comes back over JSON-RPC
|
|
125
|
+
*/
|
|
126
|
+
export function u256(value: bigint | number | string): U256Value {
|
|
127
|
+
return makeValue("u256", toUnsigned("u256", value, U256_MAX))
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* A 64-bit unsigned integer, indexed for equality and range queries.
|
|
132
|
+
*
|
|
133
|
+
* This is the width the protocol counts in: block heights, `$expiresAt` and the entity-nonce are
|
|
134
|
+
* all `u64`, so it is the type to reach for when a value has to line up with one of them. Use
|
|
135
|
+
* {@link u256} for token amounts and anything else that can exceed 2⁶⁴.
|
|
136
|
+
*
|
|
137
|
+
* @param value - A non-negative integer, as a `bigint`, a safe `number`, or a decimal or `0x` hex
|
|
138
|
+
* string.
|
|
139
|
+
* @throws {InvalidValueError} If the value is negative, non-integral, or wider than 64 bits.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* u64(1_200_000n) // a block height
|
|
143
|
+
* u64(Date.now()) // safe integers are accepted
|
|
144
|
+
* u64("0x124f80") // hex, as it comes back over JSON-RPC
|
|
145
|
+
*/
|
|
146
|
+
export function u64(value: bigint | number | string): U64Value {
|
|
147
|
+
return makeValue("u64", toUnsigned("u64", value, U64_MAX))
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Parses and range-checks an unsigned integer for `tag`, whose widest value is `max`.
|
|
152
|
+
*
|
|
153
|
+
* Shared by {@link u64} and {@link u256} so the two differ in exactly one thing — their width —
|
|
154
|
+
* rather than in how they read a string or how they explain a failure.
|
|
155
|
+
*/
|
|
156
|
+
function toUnsigned(tag: "u64" | "u256", value: bigint | number | string, max: bigint): bigint {
|
|
157
|
+
const parsed = toUnsignedBigint(tag, value)
|
|
158
|
+
if (parsed < 0n) {
|
|
159
|
+
throw new InvalidValueError(
|
|
160
|
+
tag,
|
|
161
|
+
value,
|
|
162
|
+
`negative — ${tag} is unsigned`,
|
|
163
|
+
"Use i32(...) for small signed integers, or dec(...) for a signed fixed-point value.",
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
if (parsed > max) {
|
|
167
|
+
const bits = tag === "u64" ? 64 : 256
|
|
168
|
+
throw new InvalidValueError(
|
|
169
|
+
tag,
|
|
170
|
+
value,
|
|
171
|
+
`wider than ${bits} bits`,
|
|
172
|
+
tag === "u64" ? "Use u256(...) for values beyond 2**64 - 1." : undefined,
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
return parsed
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function toUnsignedBigint(tag: "u64" | "u256", value: bigint | number | string): bigint {
|
|
179
|
+
if (typeof value === "bigint") return value
|
|
180
|
+
if (typeof value === "number") {
|
|
181
|
+
if (!Number.isInteger(value)) {
|
|
182
|
+
throw new InvalidValueError(
|
|
183
|
+
tag,
|
|
184
|
+
value,
|
|
185
|
+
"not an integer",
|
|
186
|
+
`Use dec(${JSON.stringify(String(value))}) for a fixed-point decimal.`,
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
if (!Number.isSafeInteger(value)) {
|
|
190
|
+
throw new InvalidValueError(
|
|
191
|
+
tag,
|
|
192
|
+
value,
|
|
193
|
+
"beyond the safe integer range, so it may already have lost precision",
|
|
194
|
+
"Pass it as a bigint literal (e.g. 12345678901234567890n) or a string instead.",
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
return BigInt(value)
|
|
198
|
+
}
|
|
199
|
+
if (typeof value === "string") {
|
|
200
|
+
if (!/^(0x[0-9a-fA-F]+|\d+)$/.test(value)) {
|
|
201
|
+
throw new InvalidValueError(tag, value, "not a decimal or 0x-hex integer")
|
|
202
|
+
}
|
|
203
|
+
return BigInt(value)
|
|
204
|
+
}
|
|
205
|
+
throw new InvalidValueError(tag, value, "not a bigint, number or string")
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* A signed fixed-point decimal with exactly 18 decimal places, indexed for equality and range
|
|
210
|
+
* queries.
|
|
211
|
+
*
|
|
212
|
+
* Pass fractional values as **strings**. A JavaScript number cannot represent most decimals
|
|
213
|
+
* exactly, so accepting `dec(0.1 + 0.2)` would quietly store `0.30000000000000004`; requiring the
|
|
214
|
+
* string keeps what you write and what is stored the same thing. Excess precision is likewise an
|
|
215
|
+
* error rather than a rounding.
|
|
216
|
+
*
|
|
217
|
+
* @param value - A decimal string, or an integral `number` / `bigint`.
|
|
218
|
+
* @throws {InvalidValueError} If the value is malformed, has more than 18 fractional digits, or
|
|
219
|
+
* falls outside the `int256` range.
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* dec("3.5")
|
|
223
|
+
* dec("-0.000000000000000001") // the smallest step
|
|
224
|
+
* dec(5) // integers may be passed bare
|
|
225
|
+
*/
|
|
226
|
+
export function dec(value: string | number | bigint): DecValue {
|
|
227
|
+
if (typeof value === "string") {
|
|
228
|
+
return makeValue("dec", unitsToDecimal(decimalToUnits(value)))
|
|
229
|
+
}
|
|
230
|
+
if (typeof value === "bigint") {
|
|
231
|
+
return decFromUnits(value * DECIMAL_UNIT)
|
|
232
|
+
}
|
|
233
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
234
|
+
throw new InvalidValueError("dec", value, "not a number")
|
|
235
|
+
}
|
|
236
|
+
if (!Number.isInteger(value)) {
|
|
237
|
+
throw new InvalidValueError(
|
|
238
|
+
"dec",
|
|
239
|
+
value,
|
|
240
|
+
"a fractional number cannot be represented exactly in binary floating point",
|
|
241
|
+
`Pass it as a string instead: dec(${JSON.stringify(String(value))}).`,
|
|
242
|
+
)
|
|
243
|
+
}
|
|
244
|
+
return decFromUnits(BigInt(value) * DECIMAL_UNIT)
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* The exact scaled integer behind a `dec` — the value multiplied by 10 ** 18, which is what the
|
|
249
|
+
* protocol stores and compares. Use it when you need exact arithmetic; JavaScript has no native
|
|
250
|
+
* decimal type, so the SDK carries the canonical string and leaves the maths to you.
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* decUnits(dec("3.5")) // 3500000000000000000n
|
|
254
|
+
*/
|
|
255
|
+
export function decUnits(value: DecValue): bigint {
|
|
256
|
+
return decimalToUnits(value.value)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* A `dec` built from its scaled integer units — the inverse of {@link decUnits}.
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* decFromUnits(3_500_000_000_000_000_000n) // dec("3.5")
|
|
264
|
+
*/
|
|
265
|
+
export function decFromUnits(units: bigint): DecValue {
|
|
266
|
+
return makeValue("dec", unitsToDecimal(units))
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* A UTF-8 string of at most 128 bytes, indexed for equality and prefix (`STARTSWITH`) matching.
|
|
271
|
+
*
|
|
272
|
+
* The limit is on **bytes**, not characters: a string of 128 emoji does not fit.
|
|
273
|
+
*
|
|
274
|
+
* @throws {InvalidValueError} If the string exceeds 128 UTF-8 bytes.
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* str("Bob")
|
|
278
|
+
*/
|
|
279
|
+
export function str(value: string): StrValue {
|
|
280
|
+
if (typeof value !== "string") {
|
|
281
|
+
throw new InvalidValueError("str", value, "not a string")
|
|
282
|
+
}
|
|
283
|
+
const control = findControlChar(value)
|
|
284
|
+
if (control !== undefined) {
|
|
285
|
+
const code = control.code.toString(16).padStart(4, "0").toUpperCase()
|
|
286
|
+
throw new InvalidValueError(
|
|
287
|
+
"str",
|
|
288
|
+
value,
|
|
289
|
+
`contains the control character U+${code} at index ${control.index}`,
|
|
290
|
+
"A str is written into a query as str('...'), whose only escape is a doubled quote — there " +
|
|
291
|
+
"is no spelling for a control character, so this value could be stored but never queried. " +
|
|
292
|
+
"Free-form text belongs in the entity payload; keep a short, printable key here.",
|
|
293
|
+
)
|
|
294
|
+
}
|
|
295
|
+
const bytes = stringToBytes(value).length
|
|
296
|
+
if (bytes > MAX_STRING_BYTES) {
|
|
297
|
+
throw new InvalidValueError(
|
|
298
|
+
"str",
|
|
299
|
+
value,
|
|
300
|
+
`${bytes} UTF-8 bytes exceeds the ${MAX_STRING_BYTES}-byte limit on a str`,
|
|
301
|
+
"Store the long form in the entity payload and keep a short, queryable key here.",
|
|
302
|
+
)
|
|
303
|
+
}
|
|
304
|
+
return makeValue("str", value)
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* A 20-byte Ethereum address, indexed for equality.
|
|
309
|
+
*
|
|
310
|
+
* All-lowercase and all-uppercase input carries no checksum and is accepted as-is; mixed-case
|
|
311
|
+
* input is checked against its EIP-55 checksum, so a mistyped address is caught here rather than
|
|
312
|
+
* being written to a wrong account. The stored value is always EIP-55 checksummed.
|
|
313
|
+
*
|
|
314
|
+
* @throws {InvalidValueError} If the value is not 20 hex bytes, or fails its EIP-55 checksum.
|
|
315
|
+
*
|
|
316
|
+
* @example
|
|
317
|
+
* addr("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
|
|
318
|
+
*/
|
|
319
|
+
export function addr(value: string): AddrValue {
|
|
320
|
+
if (typeof value !== "string" || !/^0x[0-9a-fA-F]{40}$/.test(value)) {
|
|
321
|
+
throw new InvalidValueError("addr", value, "not a 20-byte 0x-prefixed hex address")
|
|
322
|
+
}
|
|
323
|
+
const body = value.slice(2)
|
|
324
|
+
const cased = body !== body.toLowerCase() && body !== body.toUpperCase()
|
|
325
|
+
if (cased && !isAddress(value, { strict: true })) {
|
|
326
|
+
throw new InvalidValueError(
|
|
327
|
+
"addr",
|
|
328
|
+
value,
|
|
329
|
+
"fails its EIP-55 checksum, so a digit is probably mistyped",
|
|
330
|
+
`If those hex digits are right, the correctly checksummed form is ` +
|
|
331
|
+
`${checksumAddress(value as Address)}.`,
|
|
332
|
+
)
|
|
333
|
+
}
|
|
334
|
+
return makeValue("addr", checksumAddress(value as Address))
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* A reference to another entity, indexed for equality.
|
|
339
|
+
*
|
|
340
|
+
* References are **weak**: nothing checks that the target exists when you write it, and a
|
|
341
|
+
* reference to a deleted or expired entity is allowed to dangle.
|
|
342
|
+
*
|
|
343
|
+
* @param value - A 32-byte entity key, as `0x` hex or raw bytes.
|
|
344
|
+
* @throws {InvalidValueError} If the value is not exactly 32 bytes.
|
|
345
|
+
*
|
|
346
|
+
* @example
|
|
347
|
+
* key(parentEntityKey)
|
|
348
|
+
*/
|
|
349
|
+
export function key(value: Hex | Uint8Array): KeyValue {
|
|
350
|
+
return makeValue("key", asFixedHex("key", value, 32))
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* 32 opaque bytes — a hash, a digest, an identifier from another system — indexed for equality.
|
|
355
|
+
*
|
|
356
|
+
* Use {@link key} instead when the bytes are an Arkiv entity key: same wire width, but the
|
|
357
|
+
* distinct type makes the reference visible to readers and to the query language.
|
|
358
|
+
*
|
|
359
|
+
* @param value - 32 bytes, as `0x` hex or raw bytes.
|
|
360
|
+
* @throws {InvalidValueError} If the value is not exactly 32 bytes.
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* bytes32(keccak256(toBytes("hello")))
|
|
364
|
+
*/
|
|
365
|
+
export function bytes32(value: Hex | Uint8Array): Bytes32Value {
|
|
366
|
+
return makeValue("bytes32", asFixedHex("bytes32", value, 32))
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/** Normalizes hex-or-bytes input of a known width into lowercase `0x` hex. */
|
|
370
|
+
function asFixedHex(tag: "key" | "bytes32", value: Hex | Uint8Array, size: number): Hex {
|
|
371
|
+
if (value instanceof Uint8Array) {
|
|
372
|
+
if (value.length !== size) {
|
|
373
|
+
throw new InvalidValueError(tag, `<${value.length} bytes>`, `not exactly ${size} bytes`)
|
|
374
|
+
}
|
|
375
|
+
return toHex(value)
|
|
376
|
+
}
|
|
377
|
+
if (typeof value !== "string" || !isHex(value, { strict: true })) {
|
|
378
|
+
throw new InvalidValueError(tag, value, "not 0x-prefixed hex")
|
|
379
|
+
}
|
|
380
|
+
if (value.length !== 2 + size * 2) {
|
|
381
|
+
throw new InvalidValueError(
|
|
382
|
+
tag,
|
|
383
|
+
value,
|
|
384
|
+
`${(value.length - 2) / 2} bytes, not exactly ${size} bytes`,
|
|
385
|
+
)
|
|
386
|
+
}
|
|
387
|
+
return value.toLowerCase() as Hex
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* A JavaScript value accepted wherever a typed value is expected: either a tagged value, or one of
|
|
392
|
+
* the four bare forms that map unambiguously onto a single type.
|
|
393
|
+
*
|
|
394
|
+
* | bare form | type |
|
|
395
|
+
* | --------- | ------- |
|
|
396
|
+
* | `boolean` | `bool` |
|
|
397
|
+
* | `number` | `i32` |
|
|
398
|
+
* | `bigint` | `u256` |
|
|
399
|
+
* | `string` | `str` |
|
|
400
|
+
*
|
|
401
|
+
* Anything else — a large number, a decimal, an address, an entity key — must name its type, which
|
|
402
|
+
* is what keeps `"0x1234..."` a string rather than silently becoming a key.
|
|
403
|
+
*
|
|
404
|
+
* These defaults apply identically when writing and when querying, so a value written bare and
|
|
405
|
+
* queried bare always agrees with itself. The mismatch to watch for is mixing the two: an attribute
|
|
406
|
+
* written as {@link u64} does not match a bare `bigint` predicate, because that predicate asserts
|
|
407
|
+
* `u256`. A type mismatch is not an error to the engine — it simply matches nothing.
|
|
408
|
+
*/
|
|
409
|
+
export type ValueInput = ArkivValue | boolean | number | bigint | string
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Resolves a {@link ValueInput} to a typed value, applying the bare-form defaults above. Tagged
|
|
413
|
+
* values pass through untouched.
|
|
414
|
+
*
|
|
415
|
+
* @param input - The value to resolve.
|
|
416
|
+
* @param attributeName - The attribute this value belongs to, used to make errors name it.
|
|
417
|
+
*
|
|
418
|
+
* @throws {MissingValueError} If the input is `undefined` or `null` — an attribute is either set
|
|
419
|
+
* with a value and a type, or not set at all.
|
|
420
|
+
* @throws {UntypedValueError} If the input is not a tagged value or a bare boolean, number, bigint
|
|
421
|
+
* or string.
|
|
422
|
+
* @throws {InvalidValueError} If a bare value does not fit the type it defaults to.
|
|
423
|
+
*
|
|
424
|
+
* @example
|
|
425
|
+
* toValue(10) // i32(10)
|
|
426
|
+
* toValue(10n) // u256(10n)
|
|
427
|
+
* toValue("hello") // str("hello")
|
|
428
|
+
* toValue(dec("3.5")) // unchanged
|
|
429
|
+
*/
|
|
430
|
+
export function toValue(input: ValueInput, attributeName?: string): ArkivValue {
|
|
431
|
+
// `undefined` and `null` are rejected before the type switch. They are not assignable to
|
|
432
|
+
// ValueInput, but they still arrive at runtime — from a spread of an optional-shaped object, or
|
|
433
|
+
// from data that never went through the type system — and "cannot infer a type for undefined"
|
|
434
|
+
// does not tell you the fix, which is always to leave the attribute out.
|
|
435
|
+
if (input === undefined || input === null) {
|
|
436
|
+
throw new MissingValueError(input, attributeName)
|
|
437
|
+
}
|
|
438
|
+
switch (typeof input) {
|
|
439
|
+
case "boolean":
|
|
440
|
+
return bool(input)
|
|
441
|
+
case "number":
|
|
442
|
+
return i32(input)
|
|
443
|
+
case "bigint":
|
|
444
|
+
return u256(input)
|
|
445
|
+
case "string":
|
|
446
|
+
return str(input)
|
|
447
|
+
default: {
|
|
448
|
+
// Widened to AnyArkivValue: `bytes` is not a member of ValueInput, but it is what a decoded
|
|
449
|
+
// `$payload` carries, so a round-trip through a decoded entity must be rejected by name
|
|
450
|
+
// rather than fall through to "cannot infer a type".
|
|
451
|
+
const candidate = input as AnyArkivValue
|
|
452
|
+
if (isArkivValue(candidate)) {
|
|
453
|
+
if (candidate.type === "bytes") {
|
|
454
|
+
throw new InvalidValueError(
|
|
455
|
+
"bytes",
|
|
456
|
+
candidate.value,
|
|
457
|
+
"system-only — bytes backs the entity payload and cannot be set as an attribute",
|
|
458
|
+
"Pass the bytes as the entity payload instead.",
|
|
459
|
+
)
|
|
460
|
+
}
|
|
461
|
+
return revalidate(candidate)
|
|
462
|
+
}
|
|
463
|
+
throw new UntypedValueError(input)
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Re-runs a tagged value through its own constructor.
|
|
470
|
+
*
|
|
471
|
+
* {@link isArkivValue} can only check shape — the `validated` brand is a type-level construct with
|
|
472
|
+
* no runtime existence, so a hand-written `{ type: "u256", value: "1000" }` (from `JSON.parse`, a
|
|
473
|
+
* config file, an `as any` boundary) is indistinguishable from a real `u256(1000n)`. Passing it
|
|
474
|
+
* through unchecked was silent corruption rather than an error: the ABI encoder would take the
|
|
475
|
+
* *string* "1000" and write its UTF-8 bytes into the word, storing 2.27e76 on chain.
|
|
476
|
+
*
|
|
477
|
+
* Running the constructor again is what makes the brand's promise — "every value crossing the wire
|
|
478
|
+
* has been range-, length- and format-checked" — true at runtime. For a value that really did come
|
|
479
|
+
* from a constructor it is a no-op that returns an equal value.
|
|
480
|
+
*/
|
|
481
|
+
function revalidate(value: Exclude<AnyArkivValue, BytesValue>): ArkivValue {
|
|
482
|
+
switch (value.type) {
|
|
483
|
+
case "bool":
|
|
484
|
+
return bool(value.value)
|
|
485
|
+
case "i32":
|
|
486
|
+
return i32(value.value)
|
|
487
|
+
case "u64":
|
|
488
|
+
return u64(value.value)
|
|
489
|
+
case "u256":
|
|
490
|
+
return u256(value.value)
|
|
491
|
+
case "dec":
|
|
492
|
+
return dec(value.value)
|
|
493
|
+
case "bytes32":
|
|
494
|
+
return bytes32(value.value)
|
|
495
|
+
case "str":
|
|
496
|
+
return str(value.value)
|
|
497
|
+
case "addr":
|
|
498
|
+
return addr(value.value)
|
|
499
|
+
case "key":
|
|
500
|
+
return key(value.value)
|
|
501
|
+
}
|
|
502
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { defineChain } from "viem"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Cheesecake is Arkiv's testnet.
|
|
5
|
+
*/
|
|
6
|
+
export const cheesecake = defineChain({
|
|
7
|
+
id: 7733102,
|
|
8
|
+
name: "Cheesecake",
|
|
9
|
+
network: "cheesecake",
|
|
10
|
+
nativeCurrency: {
|
|
11
|
+
name: "Golem",
|
|
12
|
+
symbol: "GLM",
|
|
13
|
+
decimals: 18,
|
|
14
|
+
},
|
|
15
|
+
rpcUrls: {
|
|
16
|
+
default: {
|
|
17
|
+
http: ["https://rpc.cheesecake.db-chain.devnet.gobas.me"],
|
|
18
|
+
webSocket: ["wss://rpc.cheesecake.db-chain.devnet.gobas.me"],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
testnet: true,
|
|
22
|
+
})
|
package/src/chains/index.ts
CHANGED
|
@@ -18,8 +18,6 @@ test("creates", () => {
|
|
|
18
18
|
expect(uid).toBeDefined()
|
|
19
19
|
expect(client.getEntity).toBeDefined()
|
|
20
20
|
expect(typeof client.getEntity).toBe("function")
|
|
21
|
-
expect(client.buildQuery).toBeDefined()
|
|
22
|
-
expect(typeof client.buildQuery).toBe("function")
|
|
23
21
|
expect(client.select).toBeDefined()
|
|
24
22
|
expect(typeof client.select).toBe("function")
|
|
25
23
|
expect(client.query).toBeDefined()
|
|
@@ -28,12 +26,12 @@ test("creates", () => {
|
|
|
28
26
|
expect(typeof client.getEntityCount).toBe("function")
|
|
29
27
|
expect(client.getBlockTiming).toBeDefined()
|
|
30
28
|
expect(typeof client.getBlockTiming).toBe("function")
|
|
31
|
-
expect(client.
|
|
32
|
-
expect(typeof client.
|
|
29
|
+
expect(client.watchEntityEvents).toBeDefined()
|
|
30
|
+
expect(typeof client.watchEntityEvents).toBe("function")
|
|
33
31
|
expect(client.watchEvent).toBeDefined()
|
|
34
32
|
expect(typeof client.watchEvent).toBe("function")
|
|
35
33
|
expect(client.createEntity).not.toBeDefined()
|
|
36
|
-
expect(client.
|
|
34
|
+
expect(client.patchEntity).not.toBeDefined()
|
|
37
35
|
expect(client.deleteEntity).not.toBeDefined()
|
|
38
36
|
expect(client.extendEntity).not.toBeDefined()
|
|
39
37
|
expect(client.changeOwnership).not.toBeDefined()
|
|
@@ -27,17 +27,18 @@ export type PublicArkivClient<
|
|
|
27
27
|
*
|
|
28
28
|
* - Docs: https://docs.arkiv.network/ts-sdk/clients/public
|
|
29
29
|
*
|
|
30
|
-
* A Public Client is an interface to "public" [Ethereum JSON-RPC API](https://ethereum.org/en/developers/docs/apis/json-rpc/), [Arkiv JSON-RPC API](https://docs.arkiv.network/json-rpc/), and [
|
|
30
|
+
* A Public Client is an interface to "public" [Ethereum JSON-RPC API](https://ethereum.org/en/developers/docs/apis/json-rpc/), [Arkiv JSON-RPC API](https://docs.arkiv.network/json-rpc/), and [Cheesecake JSON-RPC API](https://rpc.cheesecake.db-chain.devnet.gobas.me) methods such as retrieving block numbers, transactions, reading from smart contracts, etc through [Public Actions](/docs/actions/public/introduction).
|
|
31
31
|
*
|
|
32
32
|
* @param parameters - Configuration object for the public client (chain, transport, etc.)
|
|
33
33
|
* @returns A Arkiv Public Client. {@link PublicArkivClient}
|
|
34
34
|
*
|
|
35
35
|
* @example
|
|
36
|
-
* import { createPublicClient
|
|
37
|
-
* import {
|
|
36
|
+
* import { createPublicClient } from "@arkiv-network/sdk"
|
|
37
|
+
* import { cheesecake } from "@arkiv-network/sdk/chains"
|
|
38
|
+
* import { http } from "viem"
|
|
38
39
|
*
|
|
39
40
|
* const client = createPublicClient({
|
|
40
|
-
* chain:
|
|
41
|
+
* chain: cheesecake,
|
|
41
42
|
* transport: http(),
|
|
42
43
|
* })
|
|
43
44
|
*/
|
|
@@ -21,8 +21,8 @@ test("creates", () => {
|
|
|
21
21
|
expect(typeof client.waitForTransactionReceipt).toBe("function")
|
|
22
22
|
expect(client.createEntity).toBeDefined()
|
|
23
23
|
expect(typeof client.createEntity).toBe("function")
|
|
24
|
-
expect(client.
|
|
25
|
-
expect(typeof client.
|
|
24
|
+
expect(client.patchEntity).toBeDefined()
|
|
25
|
+
expect(typeof client.patchEntity).toBe("function")
|
|
26
26
|
expect(client.deleteEntity).toBeDefined()
|
|
27
27
|
expect(typeof client.deleteEntity).toBe("function")
|
|
28
28
|
expect(client.extendEntity).toBeDefined()
|
|
@@ -23,22 +23,28 @@ export type WalletArkivClient<
|
|
|
23
23
|
>
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* Creates a
|
|
26
|
+
* Creates a Wallet Client with a given [Transport](https://viem.sh/docs/clients/intro) configured
|
|
27
|
+
* for a [Chain](https://viem.sh/docs/clients/chains) and an account.
|
|
27
28
|
*
|
|
28
|
-
* - Docs: https://docs.arkiv.network/ts-sdk/clients/
|
|
29
|
+
* - Docs: https://docs.arkiv.network/ts-sdk/clients/wallet
|
|
29
30
|
*
|
|
30
|
-
* A
|
|
31
|
+
* A Wallet Client signs and sends transactions, so it carries an `account` and exposes everything
|
|
32
|
+
* that mutates state — `createEntity`, `patchEntity`, `deleteEntity`, `extendEntity`,
|
|
33
|
+
* `changeOwnership` and `mutateEntities` — on top of the read actions a Public Client has.
|
|
31
34
|
*
|
|
32
35
|
* @param parameters - Configuration object for the wallet client (chain, transport, account, etc.)
|
|
33
36
|
* @returns A Arkiv Wallet Client. {@link WalletArkivClient}
|
|
34
37
|
*
|
|
35
38
|
* @example
|
|
36
|
-
* import {
|
|
37
|
-
* import {
|
|
39
|
+
* import { createWalletClient } from "@arkiv-network/sdk"
|
|
40
|
+
* import { cheesecake } from "@arkiv-network/sdk/chains"
|
|
41
|
+
* import { http } from "viem"
|
|
42
|
+
* import { privateKeyToAccount } from "viem/accounts"
|
|
38
43
|
*
|
|
39
|
-
* const client =
|
|
40
|
-
* chain:
|
|
44
|
+
* const client = createWalletClient({
|
|
45
|
+
* chain: cheesecake,
|
|
41
46
|
* transport: http(),
|
|
47
|
+
* account: privateKeyToAccount("0x..."),
|
|
42
48
|
* })
|
|
43
49
|
*/
|
|
44
50
|
export function createWalletClient<
|