@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.
- package/README.md +71 -16
- package/dist/actions/advanced/index.cjs +13 -0
- package/dist/actions/advanced/index.d.cts +8 -0
- package/dist/actions/advanced/index.d.ts +9 -0
- package/dist/actions/advanced/index.js +9 -0
- package/dist/advanced-8ZPTmmaN.js +598 -0
- package/dist/advanced-8ZPTmmaN.js.map +1 -0
- package/dist/advanced-fPImL6lW.cjs +656 -0
- package/dist/arkivTransactions-D74gERHG.d.cts +571 -0
- package/dist/arkivTransactions-D74gERHG.d.cts.map +1 -0
- package/dist/arkivTransactions-NtGD6uk5.d.ts +571 -0
- package/dist/arkivTransactions-NtGD6uk5.d.ts.map +1 -0
- package/dist/attr/index.cjs +35 -0
- package/dist/attr/index.d.cts +2 -0
- package/dist/attr/index.d.ts +3 -0
- package/dist/attr/index.js +4 -0
- package/dist/attributes-BhY5DwJp.js +809 -0
- package/dist/attributes-BhY5DwJp.js.map +1 -0
- package/dist/attributes-Df9IsCVs.cjs +1029 -0
- package/dist/chains/index.cjs +2 -3
- package/dist/chains/index.d.cts +22 -60
- 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/codec-Car3KkFF.d.ts +102 -0
- package/dist/codec-Car3KkFF.d.ts.map +1 -0
- package/dist/entity/index.cjs +20 -0
- package/dist/entity/index.d.cts +4 -0
- package/dist/entity/index.d.ts +5 -0
- package/dist/entity/index.js +7 -0
- package/dist/entity-B00Li04j.cjs +71 -0
- package/dist/entity-B7G8q_Eo.cjs +0 -0
- package/dist/entity-BYQR1uoe.js +67 -0
- package/dist/entity-BYQR1uoe.js.map +1 -0
- package/dist/entity-CD_qFF2M.js +0 -0
- package/dist/errors-BVbjKVMN.cjs +56 -0
- package/dist/errors-LTe7bOYS.js +33 -0
- package/dist/errors-LTe7bOYS.js.map +1 -0
- package/dist/expiry-BELY2Kpw.cjs +135 -0
- package/dist/expiry-BjpxZZQU.js +95 -0
- package/dist/expiry-BjpxZZQU.js.map +1 -0
- package/dist/expiry-DRV29F1r.d.cts +79 -0
- package/dist/expiry-DRV29F1r.d.cts.map +1 -0
- package/dist/expiry-nDbCgZX4.d.ts +79 -0
- package/dist/expiry-nDbCgZX4.d.ts.map +1 -0
- package/dist/flags-5dTNRnow.d.ts +41 -0
- package/dist/flags-5dTNRnow.d.ts.map +1 -0
- package/dist/flags-CRjPpoh3.d.cts +41 -0
- package/dist/flags-CRjPpoh3.d.cts.map +1 -0
- package/dist/flags-DFBs2J94.js +33 -0
- package/dist/flags-DFBs2J94.js.map +1 -0
- package/dist/flags-kr276q6i.cjs +43 -0
- package/dist/index-B5j76711.d.ts +184 -0
- package/dist/index-B5j76711.d.ts.map +1 -0
- package/dist/index-BF7Mq9Is.d.cts +280 -0
- package/dist/index-BF7Mq9Is.d.cts.map +1 -0
- package/dist/index-CA4V7Pdh.d.cts +167 -0
- package/dist/index-CA4V7Pdh.d.cts.map +1 -0
- package/dist/index-CV5zCdpa.d.cts +417 -0
- package/dist/index-CV5zCdpa.d.cts.map +1 -0
- package/dist/index-DHDud2hC.d.ts +280 -0
- package/dist/index-DHDud2hC.d.ts.map +1 -0
- package/dist/index-DvYvrkdk.d.ts +320 -0
- package/dist/index-DvYvrkdk.d.ts.map +1 -0
- package/dist/index-EeUO0nnJ.d.cts +184 -0
- package/dist/index-EeUO0nnJ.d.cts.map +1 -0
- package/dist/index-fX_XyqLp.d.ts +167 -0
- package/dist/index-fX_XyqLp.d.ts.map +1 -0
- package/dist/index.cjs +411 -405
- package/dist/index.d.cts +360 -209
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +361 -209
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +342 -387
- package/dist/index.js.map +1 -1
- package/dist/key-D1Bh7MF0.js +70 -0
- package/dist/key-D1Bh7MF0.js.map +1 -0
- package/dist/key-WKhXnXuU.cjs +98 -0
- package/dist/logger-CVpvU8ik.js +153 -0
- package/dist/logger-CVpvU8ik.js.map +1 -0
- package/dist/logger-Cr15lPAQ.cjs +188 -0
- package/dist/payload-BNoud2KZ.d.cts +94 -0
- package/dist/payload-BNoud2KZ.d.cts.map +1 -0
- package/dist/payload-Bz6651ax.js +67 -0
- package/dist/payload-Bz6651ax.js.map +1 -0
- package/dist/payload-CcUj85ys.d.ts +94 -0
- package/dist/payload-CcUj85ys.d.ts.map +1 -0
- package/dist/payload-KC14SDlN.cjs +83 -0
- package/dist/query/index.cjs +26 -150
- package/dist/query/index.d.cts +5 -3
- package/dist/query/index.d.ts +6 -3
- package/dist/query/index.js +8 -138
- package/dist/queryBuilder-DM6AWCBa.js +820 -0
- package/dist/queryBuilder-DM6AWCBa.js.map +1 -0
- package/dist/queryBuilder-DbUMEZln.cjs +944 -0
- package/dist/selection-C4UhsMOO.d.ts +434 -0
- package/dist/selection-C4UhsMOO.d.ts.map +1 -0
- package/dist/selection-DPg0uyJf.d.cts +433 -0
- package/dist/selection-DPg0uyJf.d.cts.map +1 -0
- package/dist/types/index.cjs +3 -3
- package/dist/types/index.d.cts +7 -2
- package/dist/types/index.d.ts +8 -2
- package/dist/types/index.js +3 -3
- package/dist/types-Bu_ZwMbZ.js +0 -0
- package/dist/types-NRqymi6S.cjs +0 -0
- 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/advanced/advanced.test.ts +258 -0
- package/src/actions/advanced/buildMutation.ts +104 -0
- package/src/actions/advanced/getMutationResult.ts +112 -0
- package/src/actions/advanced/index.ts +21 -0
- package/src/actions/advanced/pingTransaction.ts +43 -0
- package/src/actions/advanced/sendMutation.ts +59 -0
- 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 +35 -67
- package/src/actions/public/watchEntityEvents.test.ts +414 -0
- package/src/actions/public/watchEntityEvents.ts +225 -0
- package/src/actions/wallet/changeOwnership.ts +2 -2
- package/src/actions/wallet/createEntity.ts +99 -24
- package/src/actions/wallet/extendEntity.ts +37 -13
- package/src/actions/wallet/mutateEntities.test.ts +76 -0
- package/src/actions/wallet/mutateEntities.ts +16 -33
- 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/arkivAdvanced.ts +144 -0
- package/src/clients/decorators/arkivPublic.ts +172 -139
- package/src/clients/decorators/arkivWallet.ts +101 -94
- 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 +15 -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 +26 -49
- package/src/index.ts +19 -0
- package/src/query/engine.ts +68 -137
- 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 +342 -637
- package/src/query/queryBuilder.ts +133 -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 +60 -52
- package/src/types/events.ts +59 -16
- package/src/types/index.ts +20 -17
- package/src/types/rpcSchema.ts +69 -37
- package/src/utils/arkivTransactions.test.ts +600 -155
- package/src/utils/arkivTransactions.ts +350 -219
- 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 +109 -37
- package/src/utils/expirationTime.ts +114 -10
- package/src/utils/logger.ts +2 -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-Bz0LZQZY.js +0 -7
- package/dist/consts-Bz0LZQZY.js.map +0 -1
- package/dist/consts-CxT1-RXU.cjs +0 -18
- package/dist/entity-BhSXaB23.cjs +0 -81
- package/dist/entity-CN41IOrq.d.cts +0 -401
- package/dist/entity-CN41IOrq.d.cts.map +0 -1
- package/dist/entity-DGfVyB-a.js +0 -71
- package/dist/entity-DGfVyB-a.js.map +0 -1
- package/dist/entity-NnEVlePN.d.ts +0 -401
- package/dist/entity-NnEVlePN.d.ts.map +0 -1
- package/dist/index-ClkpS6s_.d.ts +0 -481
- package/dist/index-ClkpS6s_.d.ts.map +0 -1
- package/dist/index-w4qop0Pe.d.cts +0 -481
- package/dist/index-w4qop0Pe.d.cts.map +0 -1
- package/dist/payload-BpNUPOnY.js +0 -13
- package/dist/payload-BpNUPOnY.js.map +0 -1
- package/dist/payload-C2KHOUoj.d.ts +0 -6
- package/dist/payload-C2KHOUoj.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-D8YLKcJj.cjs +0 -23
- package/dist/query/index.js.map +0 -1
- package/dist/queryBuilder-BE_XhLLa.js +0 -735
- package/dist/queryBuilder-BE_XhLLa.js.map +0 -1
- package/dist/queryBuilder-J37buGCi.cjs +0 -865
- 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 -93
- package/src/actions/wallet/updateEntity.ts +0 -59
- package/src/chains/braga.ts +0 -26
- package/src/chains/kaolin.ts +0 -29
- package/src/query/engine.test.ts +0 -571
- 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 -213
- package/src/types/attributes.ts +0 -28
- package/src/utils/validation.test.ts +0 -106
- package/src/utils/validation.ts +0 -80
- /package/dist/{types-Ci4BRClw.js → attr-DlmErkvR.cjs} +0 -0
- /package/dist/{types-a8gm_IaQ.cjs → attr-GcQKatub.js} +0 -0
|
@@ -24,12 +24,10 @@ import type {
|
|
|
24
24
|
MutateEntitiesReturnType,
|
|
25
25
|
} from "../../actions/wallet/mutateEntities"
|
|
26
26
|
import { mutateEntities } from "../../actions/wallet/mutateEntities"
|
|
27
|
-
import type {
|
|
28
|
-
|
|
29
|
-
UpdateEntityReturnType,
|
|
30
|
-
} from "../../actions/wallet/updateEntity"
|
|
31
|
-
import { updateEntity } from "../../actions/wallet/updateEntity"
|
|
27
|
+
import type { PatchEntityParameters, PatchEntityReturnType } from "../../actions/wallet/patchEntity"
|
|
28
|
+
import { patchEntity } from "../../actions/wallet/patchEntity"
|
|
32
29
|
import type { TxParams } from "../../types"
|
|
30
|
+
import { type WalletAdvancedActions, walletAdvancedActions } from "./arkivAdvanced"
|
|
33
31
|
|
|
34
32
|
export type WalletArkivActions<
|
|
35
33
|
transport extends Transport = Transport,
|
|
@@ -60,30 +58,27 @@ export type WalletArkivActions<
|
|
|
60
58
|
* @param txParams - Optional transaction parameters
|
|
61
59
|
* @returns The created entity with transaction hash
|
|
62
60
|
*
|
|
63
|
-
* @throws {
|
|
64
|
-
*
|
|
65
|
-
* @throws {
|
|
66
|
-
*
|
|
61
|
+
* @throws {InvalidExpiryError} If the expiry exceeds a protocol bound or would leave the
|
|
62
|
+
* entity dead on arrival.
|
|
63
|
+
* @throws {InvalidValueError} If an attribute value does not fit the type it names.
|
|
64
|
+
* @throws {InvalidAttributeNameError} If a name violates the attribute-name grammar.
|
|
67
65
|
*
|
|
68
66
|
* @example
|
|
69
|
-
* import {
|
|
70
|
-
* import {
|
|
67
|
+
* import { createWalletClient, ExpirationTime, jsonToPayload } from "@arkiv-network/sdk"
|
|
68
|
+
* import { i32 } from "@arkiv-network/sdk/attr"
|
|
69
|
+
* import { cheesecake } from "@arkiv-network/sdk/chains"
|
|
70
|
+
* import { http } from "viem"
|
|
71
71
|
*
|
|
72
|
-
* const client =
|
|
73
|
-
* chain:
|
|
72
|
+
* const client = createWalletClient({
|
|
73
|
+
* chain: cheesecake,
|
|
74
74
|
* transport: http(),
|
|
75
75
|
* })
|
|
76
|
-
* const { entityKey, txHash } = await client.createEntity({
|
|
77
|
-
* payload:
|
|
78
|
-
*
|
|
79
|
-
*
|
|
76
|
+
* const { entityKey, txHash, expiresAt } = await client.createEntity({
|
|
77
|
+
* payload: jsonToPayload({ entityType: "testType", entityId: "testId" }),
|
|
78
|
+
* contentType: "application/json",
|
|
79
|
+
* attributes: { testKey: "testValue", level: i32(3) },
|
|
80
|
+
* expires: ExpirationTime.fromDays(30),
|
|
80
81
|
* })
|
|
81
|
-
* console.log("entityKey", entityKey)
|
|
82
|
-
* console.log("txHash", txHash)
|
|
83
|
-
* // {
|
|
84
|
-
* // entityKey: "0x123",
|
|
85
|
-
* // txHash: "0x123",
|
|
86
|
-
* // }
|
|
87
82
|
*/
|
|
88
83
|
createEntity: (
|
|
89
84
|
data: CreateEntityParameters,
|
|
@@ -91,33 +86,43 @@ export type WalletArkivActions<
|
|
|
91
86
|
) => Promise<CreateEntityReturnType>
|
|
92
87
|
|
|
93
88
|
/**
|
|
94
|
-
*
|
|
89
|
+
* Applies a patch to the entity with the given key: sets some fields, unsets others, and leaves
|
|
90
|
+
* everything it does not name alone.
|
|
95
91
|
*
|
|
96
|
-
* - Docs: https://docs.arkiv.network/ts-sdk/actions/wallet/
|
|
92
|
+
* - Docs: https://docs.arkiv.network/ts-sdk/actions/wallet/patchEntity
|
|
97
93
|
* - JSON-RPC Methods: [`eth_sendRawTransaction`](https://docs.arkiv.network/dev/json-rpc-api/#mutateEntities)
|
|
98
94
|
*
|
|
99
|
-
* @param data - The entity
|
|
95
|
+
* @param data - The entity key and the mutations to apply
|
|
100
96
|
* @param txParams - Optional transaction parameters
|
|
101
|
-
* @returns The
|
|
97
|
+
* @returns The entity key and the transaction hash
|
|
102
98
|
*
|
|
103
|
-
* @throws {
|
|
104
|
-
*
|
|
105
|
-
* @throws {
|
|
106
|
-
*
|
|
99
|
+
* @throws {EmptyPatchError} If the patch has nothing to apply.
|
|
100
|
+
* @throws {ConflictingMutationError} If a name appears in both `set` and `unset`.
|
|
101
|
+
* @throws {InvalidValueError} If an attribute value does not fit the type it names.
|
|
102
|
+
* @throws {InvalidAttributeNameError} If a name violates the attribute-name grammar.
|
|
107
103
|
*
|
|
108
104
|
* @example
|
|
109
|
-
* import { createWalletClient,
|
|
110
|
-
* import {
|
|
105
|
+
* import { createWalletClient, jsonToPayload } from "@arkiv-network/sdk"
|
|
106
|
+
* import { i32 } from "@arkiv-network/sdk/attr"
|
|
107
|
+
* import { cheesecake } from "@arkiv-network/sdk/chains"
|
|
108
|
+
* import { http } from "viem"
|
|
111
109
|
*
|
|
112
110
|
* const client = createWalletClient({
|
|
113
|
-
* chain:
|
|
111
|
+
* chain: cheesecake,
|
|
114
112
|
* transport: http(),
|
|
115
113
|
* })
|
|
114
|
+
* // Publish the entity: one attribute changes, one goes away, the payload is replaced.
|
|
115
|
+
* const { txHash } = await client.patchEntity({
|
|
116
|
+
* entityKey,
|
|
117
|
+
* set: { status: "published", revision: i32(2) },
|
|
118
|
+
* unset: ["draft"],
|
|
119
|
+
* payload: jsonToPayload({ title: "Hello" }),
|
|
120
|
+
* })
|
|
116
121
|
*/
|
|
117
|
-
|
|
118
|
-
data:
|
|
122
|
+
patchEntity: (
|
|
123
|
+
data: PatchEntityParameters,
|
|
119
124
|
txParams?: TxParams,
|
|
120
|
-
) => Promise<
|
|
125
|
+
) => Promise<PatchEntityReturnType>
|
|
121
126
|
|
|
122
127
|
/**
|
|
123
128
|
* Deletes the entity with the given key.
|
|
@@ -130,20 +135,16 @@ export type WalletArkivActions<
|
|
|
130
135
|
* @returns The deleted entity with transaction hash
|
|
131
136
|
*
|
|
132
137
|
* @example
|
|
133
|
-
* import { createWalletClient
|
|
134
|
-
* import {
|
|
138
|
+
* import { createWalletClient } from "@arkiv-network/sdk"
|
|
139
|
+
* import { cheesecake } from "@arkiv-network/sdk/chains"
|
|
140
|
+
* import { http } from "viem"
|
|
135
141
|
*
|
|
136
142
|
* const client = createWalletClient({
|
|
137
|
-
* chain:
|
|
143
|
+
* chain: cheesecake,
|
|
138
144
|
* transport: http(),
|
|
139
145
|
* })
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
* console.log("txHash", txHash)
|
|
143
|
-
* // {
|
|
144
|
-
* // entityKey: "0x123",
|
|
145
|
-
* // txHash: "0x123",
|
|
146
|
-
* // }
|
|
146
|
+
* // entityKey is the bytes32 key returned by createEntity.
|
|
147
|
+
* const { txHash } = await client.deleteEntity({ entityKey })
|
|
147
148
|
*/
|
|
148
149
|
deleteEntity: (
|
|
149
150
|
data: DeleteEntityParameters,
|
|
@@ -151,35 +152,35 @@ export type WalletArkivActions<
|
|
|
151
152
|
) => Promise<DeleteEntityReturnType>
|
|
152
153
|
|
|
153
154
|
/**
|
|
154
|
-
*
|
|
155
|
+
* Sets a new expiry on the entity with the given key.
|
|
156
|
+
*
|
|
157
|
+
* The new lifetime is resolved the same way a create's is: a duration counts from now rather
|
|
158
|
+
* than adding to what the entity has left, and `atBlock` / `atDate` pin an absolute deadline.
|
|
159
|
+
* The engine rejects an extension that would not move the expiry later.
|
|
155
160
|
*
|
|
156
161
|
* - Docs: https://docs.arkiv.network/ts-sdk/actions/wallet/extendEntity
|
|
157
162
|
* - JSON-RPC Methods: [`eth_sendRawTransaction`](https://docs.arkiv.network/dev/json-rpc-api/#mutateEntities)
|
|
158
163
|
*
|
|
159
|
-
* @param data - The entity
|
|
164
|
+
* @param data - The entity key and its new lifetime
|
|
160
165
|
* @param txParams - Optional transaction parameters
|
|
161
|
-
* @returns The
|
|
166
|
+
* @returns The entity key, transaction hash, and the block it is now expected to expire at
|
|
162
167
|
*
|
|
163
|
-
* @throws {
|
|
164
|
-
*
|
|
168
|
+
* @throws {InvalidExpiryError} If the expiry is malformed, exceeds a protocol bound, or would
|
|
169
|
+
* leave the entity dead on arrival.
|
|
165
170
|
*
|
|
166
171
|
* @example
|
|
167
|
-
* import { createWalletClient,
|
|
168
|
-
* import {
|
|
172
|
+
* import { createWalletClient, ExpirationTime } from "@arkiv-network/sdk"
|
|
173
|
+
* import { cheesecake } from "@arkiv-network/sdk/chains"
|
|
174
|
+
* import { http } from "viem"
|
|
169
175
|
*
|
|
170
176
|
* const client = createWalletClient({
|
|
171
|
-
* chain:
|
|
177
|
+
* chain: cheesecake,
|
|
172
178
|
* transport: http(),
|
|
173
179
|
* })
|
|
174
|
-
* const {
|
|
175
|
-
*
|
|
180
|
+
* const { txHash, expiresAt } = await client.extendEntity({
|
|
181
|
+
* entityKey,
|
|
182
|
+
* expires: ExpirationTime.fromDays(30),
|
|
176
183
|
* })
|
|
177
|
-
* console.log("entityKey", entityKey)
|
|
178
|
-
* console.log("txHash", txHash)
|
|
179
|
-
* // {
|
|
180
|
-
* // entityKey: "0x123",
|
|
181
|
-
* // txHash: "0x123",
|
|
182
|
-
* // }
|
|
183
184
|
*/
|
|
184
185
|
extendEntity: (
|
|
185
186
|
data: ExtendEntityParameters,
|
|
@@ -207,54 +208,59 @@ export type WalletArkivActions<
|
|
|
207
208
|
* - Docs: https://docs.arkiv.network/ts-sdk/actions/wallet/mutateEntities
|
|
208
209
|
* - JSON-RPC Methods: [`eth_sendRawTransaction`](https://docs.arkiv.network/dev/json-rpc-api/#mutateEntities)
|
|
209
210
|
*
|
|
210
|
-
*
|
|
211
|
+
* Every operation lands in one transaction, so the whole batch applies or none of it does.
|
|
212
|
+
* At least one operation is required.
|
|
213
|
+
*
|
|
214
|
+
* @param data - The mutation parameters (creates, patches, deletes, extensions, ownershipChanges)
|
|
211
215
|
* @param txParams - Optional transaction parameters
|
|
212
216
|
* @returns The mutation result with transaction hash
|
|
213
217
|
*
|
|
214
|
-
* @throws {
|
|
215
|
-
*
|
|
216
|
-
* @throws {
|
|
217
|
-
* integer.
|
|
218
|
+
* @throws {InvalidExpiryError} If an expiry exceeds a protocol bound or would leave the entity
|
|
219
|
+
* dead on arrival.
|
|
220
|
+
* @throws {InvalidValueError} If an attribute value does not fit the type it names.
|
|
218
221
|
*
|
|
219
222
|
* @example
|
|
220
|
-
* import { createWalletClient,
|
|
221
|
-
* import {
|
|
223
|
+
* import { createWalletClient, ExpirationTime, jsonToPayload } from "@arkiv-network/sdk"
|
|
224
|
+
* import { cheesecake } from "@arkiv-network/sdk/chains"
|
|
225
|
+
* import { http } from "viem"
|
|
222
226
|
*
|
|
223
227
|
* const client = createWalletClient({
|
|
224
|
-
* chain:
|
|
228
|
+
* chain: cheesecake,
|
|
225
229
|
* transport: http(),
|
|
226
230
|
* })
|
|
227
|
-
* const {
|
|
231
|
+
* const { txHash, createdEntities } = await client.mutateEntities({
|
|
228
232
|
* creates: [{
|
|
229
|
-
* payload:
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
* updates: [{
|
|
234
|
-
* entityKey: "0x123",
|
|
235
|
-
* payload: toBytes(JSON.stringify({ entity: { entityType: "testType", entityId: "testId" } })),
|
|
236
|
-
* attributes: [{ key: "testKey", value: "testValue" }],
|
|
237
|
-
* expiresIn: 1000,
|
|
238
|
-
* }],
|
|
239
|
-
* deletes: [{
|
|
240
|
-
* entityKey: "0x321",
|
|
233
|
+
* payload: jsonToPayload({ entityType: "testType", entityId: "testId" }),
|
|
234
|
+
* contentType: "application/json",
|
|
235
|
+
* attributes: { testKey: "testValue" },
|
|
236
|
+
* expires: ExpirationTime.fromDays(30),
|
|
241
237
|
* }],
|
|
238
|
+
* patches: [{ entityKey: keyToRevise, set: { status: "archived" }, unset: ["draft"] }],
|
|
239
|
+
* deletes: [{ entityKey: staleKey }],
|
|
242
240
|
* extensions: [{
|
|
243
|
-
* entityKey:
|
|
244
|
-
*
|
|
241
|
+
* entityKey: keyToKeepAlive,
|
|
242
|
+
* expires: ExpirationTime.atBlock(1_200_000n),
|
|
245
243
|
* }],
|
|
244
|
+
* ownershipChanges: [{ entityKey: keyToHandOver, newOwner }],
|
|
246
245
|
* })
|
|
247
|
-
* console.log("entityKey", entityKey)
|
|
248
|
-
* console.log("txHash", txHash)
|
|
249
|
-
* // {
|
|
250
|
-
* // entityKey: "0x123",
|
|
251
|
-
* // txHash: "0x123",
|
|
252
|
-
* // }
|
|
253
246
|
*/
|
|
254
247
|
mutateEntities: (
|
|
255
248
|
data: MutateEntitiesParameters,
|
|
256
249
|
txParams?: TxParams,
|
|
257
250
|
) => Promise<MutateEntitiesReturnType>
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* The advanced path: build, send, ping and read mutation results as separate steps, each
|
|
254
|
+
* costing the minimum number of RPC calls. Use it when you are optimising your RPC budget;
|
|
255
|
+
* the everyday actions above remain the right default. {@link WalletAdvancedActions}
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* const { txHash } = await client.advanced.sendMutation({ creates: [entity] }) // no waiting
|
|
259
|
+
* // ... later, one eth_getTransactionReceipt on your own schedule:
|
|
260
|
+
* const result = await client.advanced.getMutationResult(txHash)
|
|
261
|
+
* if (result.status === "success") console.log(result.createdEntities)
|
|
262
|
+
*/
|
|
263
|
+
advanced: WalletAdvancedActions
|
|
258
264
|
}
|
|
259
265
|
|
|
260
266
|
export function walletArkivActions<
|
|
@@ -265,8 +271,8 @@ export function walletArkivActions<
|
|
|
265
271
|
return {
|
|
266
272
|
createEntity: (data: CreateEntityParameters, txParams?: TxParams) =>
|
|
267
273
|
createEntity(client, data, txParams),
|
|
268
|
-
|
|
269
|
-
|
|
274
|
+
patchEntity: (data: PatchEntityParameters, txParams?: TxParams) =>
|
|
275
|
+
patchEntity(client, data, txParams),
|
|
270
276
|
deleteEntity: (data: DeleteEntityParameters, txParams?: TxParams) =>
|
|
271
277
|
deleteEntity(client, data, txParams),
|
|
272
278
|
extendEntity: (data: ExtendEntityParameters, txParams?: TxParams) =>
|
|
@@ -275,5 +281,6 @@ export function walletArkivActions<
|
|
|
275
281
|
changeOwnership(client, data, txParams),
|
|
276
282
|
mutateEntities: (data: MutateEntitiesParameters, txParams?: TxParams) =>
|
|
277
283
|
mutateEntities(client, data, txParams),
|
|
284
|
+
advanced: walletAdvancedActions(client),
|
|
278
285
|
}
|
|
279
286
|
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test"
|
|
2
|
+
import { decodeAbiParameters, parseAbiParameters, toHex } from "viem"
|
|
3
|
+
import { encodeAttributes } from "../attr/attributes"
|
|
4
|
+
import { dec, i32, str, u256 } from "../attr/values"
|
|
5
|
+
import { InvalidCreationFlagsError } from "./errors"
|
|
6
|
+
import { decodeCreationFlags, encodeCreationFlags } from "./flags"
|
|
7
|
+
import { MAX_SALT, predictEntityKey, randomSalt, validateSalt } from "./key"
|
|
8
|
+
import { createOperation } from "./operations"
|
|
9
|
+
import { OperationType } from "./params"
|
|
10
|
+
|
|
11
|
+
const OWNER = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
|
|
12
|
+
|
|
13
|
+
const CREATE_PARAMS = parseAbiParameters(
|
|
14
|
+
"(uint128 salt, uint64 expiresAt, uint64 minLifetime, uint8 creationFlags, (bytes32 name, uint8 typeId, bytes value)[] attributes)",
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
/** Decodes an operation's payload back into the Create struct it encodes. */
|
|
18
|
+
function decodeCreate(operationData: `0x${string}`) {
|
|
19
|
+
const [create] = decodeAbiParameters(CREATE_PARAMS, operationData)
|
|
20
|
+
return create
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("creation flags", () => {
|
|
24
|
+
it("packs each flag into its documented bit", () => {
|
|
25
|
+
expect(encodeCreationFlags({})).toBe(0b00)
|
|
26
|
+
expect(encodeCreationFlags({ readonly: true })).toBe(0b01)
|
|
27
|
+
expect(encodeCreationFlags({ permissionlessExtension: true })).toBe(0b10)
|
|
28
|
+
expect(encodeCreationFlags({ readonly: true, permissionlessExtension: true })).toBe(0b11)
|
|
29
|
+
expect(encodeCreationFlags()).toBe(0)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it("round-trips through the byte", () => {
|
|
33
|
+
for (const readonly of [true, false]) {
|
|
34
|
+
for (const permissionlessExtension of [true, false]) {
|
|
35
|
+
const decoded = decodeCreationFlags(
|
|
36
|
+
encodeCreationFlags({ readonly, permissionlessExtension }),
|
|
37
|
+
)
|
|
38
|
+
expect(decoded.readonly).toBe(readonly)
|
|
39
|
+
expect(decoded.permissionlessExtension).toBe(permissionlessExtension)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it("refuses a value that is not a byte at all", () => {
|
|
45
|
+
// Malformed input
|
|
46
|
+
expect(() => decodeCreationFlags(256)).toThrow(InvalidCreationFlagsError)
|
|
47
|
+
expect(() => decodeCreationFlags(256)).toThrow(/not a byte/)
|
|
48
|
+
expect(() => decodeCreationFlags(-1)).toThrow(/not a byte/)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it("keeps the raw byte, so unknown state stays visible", () => {
|
|
52
|
+
expect(decodeCreationFlags(0b11).raw).toBe(3)
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
describe("salt", () => {
|
|
57
|
+
it("generates 128 bits within the wire field", () => {
|
|
58
|
+
for (let i = 0; i < 32; i++) {
|
|
59
|
+
const salt = randomSalt()
|
|
60
|
+
expect(salt).toBeGreaterThanOrEqual(0n)
|
|
61
|
+
expect(salt).toBeLessThanOrEqual(MAX_SALT)
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it("does not repeat", () => {
|
|
66
|
+
const seen = new Set(Array.from({ length: 64 }, () => randomSalt().toString()))
|
|
67
|
+
expect(seen.size).toBe(64)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it("bounds a caller-supplied salt to the uint128 field", () => {
|
|
71
|
+
expect(validateSalt(0n)).toBe(0n)
|
|
72
|
+
expect(validateSalt(MAX_SALT)).toBe(MAX_SALT)
|
|
73
|
+
expect(() => validateSalt(MAX_SALT + 1n)).toThrow(/uint128/)
|
|
74
|
+
expect(() => validateSalt(-1n)).toThrow(/uint128/)
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
describe("predictEntityKey", () => {
|
|
79
|
+
it("is deterministic in owner, nonce and salt", () => {
|
|
80
|
+
const base = { owner: OWNER, nonce: 0n, salt: 7n, chainId: 1 } as const
|
|
81
|
+
expect(predictEntityKey(base)).toBe(predictEntityKey(base))
|
|
82
|
+
expect(predictEntityKey({ ...base, nonce: 1n })).not.toBe(predictEntityKey(base))
|
|
83
|
+
expect(predictEntityKey({ ...base, salt: 8n })).not.toBe(predictEntityKey(base))
|
|
84
|
+
expect(
|
|
85
|
+
predictEntityKey({ ...base, owner: "0x1111111111111111111111111111111111111111" }),
|
|
86
|
+
).not.toBe(predictEntityKey(base))
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it("separates chains through the domain", () => {
|
|
90
|
+
const base = { owner: OWNER, nonce: 0n, salt: 0n } as const
|
|
91
|
+
expect(predictEntityKey({ ...base, chainId: 1 })).not.toBe(
|
|
92
|
+
predictEntityKey({ ...base, chainId: 2 }),
|
|
93
|
+
)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it("returns a 32-byte key", () => {
|
|
97
|
+
expect(predictEntityKey({ owner: OWNER, nonce: 0n, salt: 0n, chainId: 1 })).toMatch(
|
|
98
|
+
/^0x[0-9a-f]{64}$/,
|
|
99
|
+
)
|
|
100
|
+
})
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
describe("the Create operation", () => {
|
|
104
|
+
const build = (over: Partial<Parameters<typeof createOperation>[0]> = {}) =>
|
|
105
|
+
createOperation({
|
|
106
|
+
salt: 42n,
|
|
107
|
+
expiry: { expiresAt: 0n, minLifetime: 43_200n },
|
|
108
|
+
creationFlags: 0,
|
|
109
|
+
attributes: [],
|
|
110
|
+
...over,
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
it("carries the CREATE tag", () => {
|
|
114
|
+
expect(build().operation).toBe(OperationType.Create)
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it("round-trips its fields through the ABI", () => {
|
|
118
|
+
const create = decodeCreate(
|
|
119
|
+
build({
|
|
120
|
+
salt: 42n,
|
|
121
|
+
expiry: { expiresAt: 1_200_000n, minLifetime: 100n },
|
|
122
|
+
creationFlags: 0b11,
|
|
123
|
+
}).operationData,
|
|
124
|
+
)
|
|
125
|
+
expect(create.salt).toBe(42n)
|
|
126
|
+
expect(create.expiresAt).toBe(1_200_000n)
|
|
127
|
+
expect(create.minLifetime).toBe(100n)
|
|
128
|
+
expect(create.creationFlags).toBe(3)
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
it("carries attributes as (name, typeId, bytes), sorted ascending by name", () => {
|
|
132
|
+
const create = decodeCreate(
|
|
133
|
+
build({
|
|
134
|
+
attributes: encodeAttributes({ zebra: i32(1), apple: str("x"), mango: u256(2n) }),
|
|
135
|
+
}).operationData,
|
|
136
|
+
)
|
|
137
|
+
const names = create.attributes.map((a) => a.name)
|
|
138
|
+
expect(names).toEqual([...names].sort())
|
|
139
|
+
expect(create.attributes.map((a) => a.typeId)).toEqual([8, 4, 2]) // apple str, mango u256, zebra i32
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
it("sends the payload and content type as system cells, ahead of user attributes", () => {
|
|
143
|
+
const create = decodeCreate(
|
|
144
|
+
build({
|
|
145
|
+
attributes: encodeAttributes(
|
|
146
|
+
{ level: i32(10) },
|
|
147
|
+
{ payload: new Uint8Array([0xde, 0xad]), contentType: "application/json" },
|
|
148
|
+
),
|
|
149
|
+
}).operationData,
|
|
150
|
+
)
|
|
151
|
+
const byName = Object.fromEntries(create.attributes.map((a) => [a.name, a]))
|
|
152
|
+
|
|
153
|
+
// "$" sorts below every letter, so the system cells lead.
|
|
154
|
+
expect(create.attributes[0].name).toBe(toHex("$contentType", { size: 32 }))
|
|
155
|
+
expect(create.attributes[1].name).toBe(toHex("$payload", { size: 32 }))
|
|
156
|
+
|
|
157
|
+
expect(byName[toHex("$payload", { size: 32 })]).toMatchObject({ typeId: 7, value: "0xdead" })
|
|
158
|
+
expect(byName[toHex("$contentType", { size: 32 })].typeId).toBe(8)
|
|
159
|
+
expect(byName[toHex("level", { size: 32 })].typeId).toBe(2)
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
it("omits the system cells entirely when there is no payload or content type", () => {
|
|
163
|
+
const create = decodeCreate(
|
|
164
|
+
build({ attributes: encodeAttributes({ level: i32(10) }) }).operationData,
|
|
165
|
+
)
|
|
166
|
+
expect(create.attributes).toHaveLength(1)
|
|
167
|
+
expect(create.attributes[0].name).toBe(toHex("level", { size: 32 }))
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
it("encodes each value type at its documented width", () => {
|
|
171
|
+
const create = decodeCreate(
|
|
172
|
+
build({
|
|
173
|
+
attributes: encodeAttributes({ n: i32(-42), big: u256(1n), d: dec("1.5"), s: str("hi") }),
|
|
174
|
+
}).operationData,
|
|
175
|
+
)
|
|
176
|
+
const byName = Object.fromEntries(create.attributes.map((a) => [a.name, a.value]))
|
|
177
|
+
// Word types are exactly 32 bytes; i32 is sign-extended.
|
|
178
|
+
expect(byName[toHex("n", { size: 32 })]).toBe(`0x${"ff".repeat(31)}d6`)
|
|
179
|
+
expect(byName[toHex("big", { size: 32 })]).toBe(`0x${"00".repeat(31)}01`)
|
|
180
|
+
expect(BigInt(byName[toHex("d", { size: 32 })])).toBe(1_500_000_000_000_000_000n)
|
|
181
|
+
// str is raw UTF-8, not padded.
|
|
182
|
+
expect(byName[toHex("s", { size: 32 })]).toBe("0x6869")
|
|
183
|
+
})
|
|
184
|
+
})
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** An expiry could not be expressed, or would be rejected by the engine. */
|
|
2
|
+
export class InvalidExpiryError extends Error {
|
|
3
|
+
constructor(reason: string) {
|
|
4
|
+
super(`Invalid expiry: ${reason}`)
|
|
5
|
+
this.name = "InvalidExpiryError"
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** A `creationFlags` byte could not be built or read. */
|
|
10
|
+
export class InvalidCreationFlagsError extends Error {
|
|
11
|
+
constructor(reason: string) {
|
|
12
|
+
super(`Invalid creation flags: ${reason}`)
|
|
13
|
+
this.name = "InvalidCreationFlagsError"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** A key salt was outside the `uint128` the wire carries. */
|
|
18
|
+
export class InvalidSaltError extends Error {
|
|
19
|
+
constructor(salt: bigint) {
|
|
20
|
+
super(
|
|
21
|
+
`Invalid salt ${salt}. A salt is a uint128, so it must be between 0 and ` +
|
|
22
|
+
`${2n ** 128n - 1n}. Omit it to get 128 random bits, or pass 0 for a predictable key.`,
|
|
23
|
+
)
|
|
24
|
+
this.name = "InvalidSaltError"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** No cryptographic randomness was available to generate a salt. */
|
|
29
|
+
export class NoRandomSourceError extends Error {
|
|
30
|
+
constructor() {
|
|
31
|
+
super(
|
|
32
|
+
"No cryptographic random source is available (globalThis.crypto.getRandomValues is " +
|
|
33
|
+
"missing), so a key salt cannot be generated. Upgrade to Node 18+ or a modern browser, " +
|
|
34
|
+
"or pass an explicit salt.",
|
|
35
|
+
)
|
|
36
|
+
this.name = "NoRandomSourceError"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { parseAbi } from "viem"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The events the engine emits: one per applied operation, in application order, so an off-chain
|
|
5
|
+
* replica can replay a transaction operation by operation.
|
|
6
|
+
*/
|
|
7
|
+
export const ENTITY_EVENTS_ABI = parseAbi([
|
|
8
|
+
"event EntityCreated(bytes32 indexed entityKey, address indexed owner, uint64 expiresAt, uint8 creationFlags)",
|
|
9
|
+
"event EntityPatched(bytes32 indexed entityKey, address indexed owner)",
|
|
10
|
+
"event ExpiryExtended(bytes32 indexed entityKey, address indexed owner, uint64 expiresAt)",
|
|
11
|
+
"event OwnershipTransferred(bytes32 indexed entityKey, address indexed previousOwner, address indexed newOwner)",
|
|
12
|
+
"event EntityDeleted(bytes32 indexed entityKey, address indexed owner)",
|
|
13
|
+
])
|
|
14
|
+
|
|
15
|
+
/** The name of each event in {@link ENTITY_EVENTS_ABI}. */
|
|
16
|
+
export type EntityEventName = (typeof ENTITY_EVENTS_ABI)[number]["name"]
|