@arkiv-network/sdk 0.6.8-dev.5 → 0.7.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.
Files changed (75) hide show
  1. package/dist/chains/index.d.ts +25 -25
  2. package/dist/consts-Bz0LZQZY.js +7 -0
  3. package/dist/consts-Bz0LZQZY.js.map +1 -0
  4. package/dist/{consts-AUoL-v42.cjs → consts-CxT1-RXU.cjs} +1 -1
  5. package/dist/entity-BhSXaB23.cjs +81 -0
  6. package/dist/{entity-B6g_EPm1.d.cts → entity-CN41IOrq.d.cts} +53 -34
  7. package/dist/entity-CN41IOrq.d.cts.map +1 -0
  8. package/dist/entity-DGfVyB-a.js +71 -0
  9. package/dist/entity-DGfVyB-a.js.map +1 -0
  10. package/dist/{entity-qoLMAuuk.d.ts → entity-NnEVlePN.d.ts} +53 -34
  11. package/dist/entity-NnEVlePN.d.ts.map +1 -0
  12. package/dist/{index-DdspxNAA.d.ts → index-ClkpS6s_.d.ts} +2 -2
  13. package/dist/{index-DdspxNAA.d.ts.map → index-ClkpS6s_.d.ts.map} +1 -1
  14. package/dist/{index-Ds9dwqb5.d.cts → index-w4qop0Pe.d.cts} +2 -2
  15. package/dist/{index-Ds9dwqb5.d.cts.map → index-w4qop0Pe.d.cts.map} +1 -1
  16. package/dist/index.cjs +281 -264
  17. package/dist/index.d.cts +13 -4
  18. package/dist/index.d.cts.map +1 -1
  19. package/dist/index.d.ts +14 -5
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +279 -266
  22. package/dist/index.js.map +1 -1
  23. package/dist/{payload-Claf2jUO.js → payload-BpNUPOnY.js} +3 -3
  24. package/dist/payload-BpNUPOnY.js.map +1 -0
  25. package/dist/{payload-B2kFJyah.d.ts → payload-C2KHOUoj.d.ts} +1 -1
  26. package/dist/{payload-B2kFJyah.d.ts.map → payload-C2KHOUoj.d.ts.map} +1 -1
  27. package/dist/{payload-DpA5PA-w.cjs → payload-D8YLKcJj.cjs} +1 -1
  28. package/dist/query/index.cjs +3 -2
  29. package/dist/query/index.d.cts +2 -2
  30. package/dist/query/index.d.ts +2 -2
  31. package/dist/query/index.js +3 -2
  32. package/dist/query/index.js.map +1 -1
  33. package/dist/{queryBuilder-D2uwP9jI.js → queryBuilder-BE_XhLLa.js} +98 -67
  34. package/dist/queryBuilder-BE_XhLLa.js.map +1 -0
  35. package/dist/{queryBuilder-UW2MCaX4.cjs → queryBuilder-J37buGCi.cjs} +137 -64
  36. package/dist/types/index.cjs +4 -1
  37. package/dist/types/index.d.cts +2 -2
  38. package/dist/types/index.d.ts +2 -2
  39. package/dist/types/index.js +4 -1
  40. package/dist/utils/index.cjs +2 -2
  41. package/dist/utils/index.d.ts +1 -1
  42. package/dist/utils/index.js +2 -2
  43. package/package.json +1 -1
  44. package/src/actions/public/subscribeEntityEvents.ts +25 -51
  45. package/src/actions/wallet/changeOwnership.ts +6 -6
  46. package/src/actions/wallet/createEntity.ts +7 -4
  47. package/src/actions/wallet/deleteEntity.ts +2 -3
  48. package/src/actions/wallet/extendEntity.ts +3 -4
  49. package/src/actions/wallet/mutateEntities.ts +11 -54
  50. package/src/actions/wallet/updateEntity.ts +3 -4
  51. package/src/clients/decorators/arkivWallet.ts +5 -1
  52. package/src/consts.ts +2 -1
  53. package/src/errors.ts +29 -1
  54. package/src/query/engine.test.ts +45 -0
  55. package/src/query/engine.ts +6 -1
  56. package/src/query/selectQueryBuilder.test.ts +5 -2
  57. package/src/types/attributes.ts +17 -5
  58. package/src/types/entity.ts +12 -2
  59. package/src/types/events.ts +14 -16
  60. package/src/types/index.ts +1 -0
  61. package/src/types/rpcSchema.ts +7 -2
  62. package/src/utils/arkivTransactions.test.ts +234 -36
  63. package/src/utils/arkivTransactions.ts +255 -101
  64. package/src/utils/entities.ts +17 -7
  65. package/src/utils/payload.ts +4 -2
  66. package/src/utils/validation.test.ts +52 -6
  67. package/src/utils/validation.ts +54 -6
  68. package/dist/consts-BV4PR-de.js +0 -7
  69. package/dist/consts-BV4PR-de.js.map +0 -1
  70. package/dist/entity-B6g_EPm1.d.cts.map +0 -1
  71. package/dist/entity-qoLMAuuk.d.ts.map +0 -1
  72. package/dist/payload-Claf2jUO.js.map +0 -1
  73. package/dist/queryBuilder-D2uwP9jI.js.map +0 -1
  74. /package/dist/{types-H-TSmRpm.js → types-Ci4BRClw.js} +0 -0
  75. /package/dist/{types-o3zWarRp.cjs → types-a8gm_IaQ.cjs} +0 -0
@@ -1 +1,4 @@
1
- import "../types-H-TSmRpm.js";
1
+ import { n as EntityOperationType } from "../entity-DGfVyB-a.js";
2
+ import "../types-Ci4BRClw.js";
3
+
4
+ export { EntityOperationType };
@@ -1,5 +1,5 @@
1
- const require_consts = require('../consts-AUoL-v42.cjs');
2
- const require_payload = require('../payload-DpA5PA-w.cjs');
1
+ const require_consts = require('../consts-CxT1-RXU.cjs');
2
+ const require_payload = require('../payload-D8YLKcJj.cjs');
3
3
 
4
4
  //#region src/utils/expirationTime.ts
5
5
  const ExpirationTime = {
@@ -1,4 +1,4 @@
1
- import { n as stringToPayload, t as jsonToPayload } from "../payload-B2kFJyah.js";
1
+ import { n as stringToPayload, t as jsonToPayload } from "../payload-C2KHOUoj.js";
2
2
 
3
3
  //#region src/utils/expirationTime.d.ts
4
4
  declare const ExpirationTime: {
@@ -1,5 +1,5 @@
1
- import { n as BLOCK_TIME } from "../consts-BV4PR-de.js";
2
- import { n as stringToPayload, t as jsonToPayload } from "../payload-Claf2jUO.js";
1
+ import { n as BLOCK_TIME } from "../consts-Bz0LZQZY.js";
2
+ import { n as stringToPayload, t as jsonToPayload } from "../payload-BpNUPOnY.js";
3
3
 
4
4
  //#region src/utils/expirationTime.ts
5
5
  const ExpirationTime = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkiv-network/sdk",
3
- "version": "0.6.8-dev.5",
3
+ "version": "0.7.0-dev.1",
4
4
  "description": "TypeScript client library for Arkiv's blockchains interactions",
5
5
  "type": "module",
6
6
  "target": "esnext",
@@ -1,6 +1,7 @@
1
- import { decodeEventLog, type Hex, parseAbi, toHex } from "viem"
1
+ import { decodeEventLog, type Hex } from "viem"
2
2
  import type { ArkivClient } from "../../clients/baseClient"
3
3
  import type { PublicArkivClient } from "../../clients/createPublicClient"
4
+ import { EntityOperationType } from "../../types/entity"
4
5
  import type {
5
6
  OnEntityCreatedEvent,
6
7
  OnEntityDeletedEvent,
@@ -9,18 +10,12 @@ import type {
9
10
  OnEntityOwnerChangedEvent,
10
11
  OnEntityUpdatedEvent,
11
12
  } from "../../types/events"
13
+ import { ENTITY_OPERATION_EVENT_ABI } from "../../utils/arkivTransactions"
12
14
  import { getLogger } from "../../utils/logger"
13
15
 
14
16
  const logger = getLogger("actions:public:subscribe-entity-events")
15
17
 
16
- export const arkivABI = parseAbi([
17
- "event ArkivEntityCreated(uint256 indexed entityKey, address indexed ownerAddress, uint256 expirationBlock, uint256 cost)",
18
- "event ArkivEntityUpdated(uint256 indexed entityKey, address indexed ownerAddress, uint256 oldExpirationBlock, uint256 newExpirationBlock, uint256 cost)",
19
- "event ArkivEntityExpired(uint256 indexed entityKey, address indexed ownerAddress)",
20
- "event ArkivEntityDeleted(uint256 indexed entityKey, address indexed ownerAddress)",
21
- "event ArkivEntityBTLExtended(uint256 indexed entityKey, address indexed ownerAddress, uint256 oldExpirationBlock, uint256 newExpirationBlock, uint256 cost)",
22
- "event ArkivEntityOwnerChanged(uint256 indexed entityKey, address indexed oldOwnerAddress, address indexed newOwnerAddress)",
23
- ])
18
+ export const arkivABI = ENTITY_OPERATION_EVENT_ABI
24
19
 
25
20
  export async function subscribeEntityEvents(
26
21
  client: ArkivClient,
@@ -57,54 +52,33 @@ export async function subscribeEntityEvents(
57
52
  data: log.data,
58
53
  })
59
54
  logger("event from subscribeEntityEvents %o", event)
60
- switch (event.eventName) {
61
- case "ArkivEntityCreated":
62
- onEntityCreated?.({
63
- entityKey: toHex(event.args.entityKey, { size: 32 }),
64
- owner: event.args.ownerAddress,
65
- expirationBlock: Number(event.args.expirationBlock),
66
- cost: event.args.cost,
67
- })
68
- break
69
- case "ArkivEntityUpdated":
70
- onEntityUpdated?.({
71
- entityKey: toHex(event.args.entityKey, { size: 32 }),
72
- owner: event.args.ownerAddress,
73
- oldExpirationBlock: Number(event.args.oldExpirationBlock),
74
- newExpirationBlock: Number(event.args.newExpirationBlock),
75
- cost: event.args.cost,
76
- })
55
+
56
+ if (event.eventName !== "EntityOperation") continue
57
+
58
+ const entityKey = event.args.entityKey as Hex
59
+ const owner = event.args.owner
60
+ const expiresAt = event.args.expiresAt
61
+ const entityHash = event.args.entityHash as Hex
62
+ const opType = Number(event.args.operationType)
63
+
64
+ switch (opType) {
65
+ case EntityOperationType.Create:
66
+ onEntityCreated?.({ entityKey, owner, expiresAt, entityHash })
77
67
  break
78
- case "ArkivEntityDeleted":
79
- onEntityDeleted?.({
80
- entityKey: toHex(event.args.entityKey, { size: 32 }),
81
- owner: event.args.ownerAddress,
82
- })
68
+ case EntityOperationType.Update:
69
+ onEntityUpdated?.({ entityKey, owner, expiresAt, entityHash })
83
70
  break
84
- case "ArkivEntityBTLExtended":
85
- onEntityExpiresInExtended?.({
86
- entityKey: toHex(event.args.entityKey, { size: 32 }),
87
- owner: event.args.ownerAddress,
88
- oldExpirationBlock: Number(event.args.oldExpirationBlock),
89
- newExpirationBlock: Number(event.args.newExpirationBlock),
90
- cost: event.args.cost,
91
- })
71
+ case EntityOperationType.Extend:
72
+ onEntityExpiresInExtended?.({ entityKey, owner, expiresAt, entityHash })
92
73
  break
93
- case "ArkivEntityExpired":
94
- onEntityExpired?.({
95
- entityKey: toHex(event.args.entityKey, { size: 32 }),
96
- owner: event.args.ownerAddress,
97
- })
74
+ case EntityOperationType.Transfer:
75
+ onEntityOwnerChanged?.({ entityKey, owner, entityHash })
98
76
  break
99
- case "ArkivEntityOwnerChanged":
100
- onEntityOwnerChanged?.({
101
- entityKey: toHex(event.args.entityKey, { size: 32 }),
102
- oldOwner: event.args.oldOwnerAddress,
103
- newOwner: event.args.newOwnerAddress,
104
- })
77
+ case EntityOperationType.Delete:
78
+ onEntityDeleted?.({ entityKey, owner })
105
79
  break
106
80
  default:
107
- console.warn("unknown event from subscribeEntityEvents", event)
81
+ onEntityExpired?.({ entityKey, owner })
108
82
  break
109
83
  }
110
84
  }
@@ -1,14 +1,15 @@
1
1
  import type { Hex } from "viem"
2
2
  import type { ArkivClient } from "../../clients/baseClient"
3
3
  import type { TxParams } from "../../types"
4
- import { opsToTxData, sendArkivTransaction } from "../../utils/arkivTransactions"
4
+ import { sendArkivTransaction } from "../../utils/arkivTransactions"
5
5
  import { getLogger } from "../../utils/logger"
6
6
 
7
7
  const logger = getLogger("actions:wallet:change-ownership")
8
8
 
9
9
  /**
10
- * Parameters for the deleteEntity function.
11
- * - entityKey: The key of the entity to delete.
10
+ * Parameters for the changeOwnership function.
11
+ * - entityKey: The key of the entity.
12
+ * - newOwner: The address of the new owner.
12
13
  */
13
14
  export type ChangeOwnershipParameters = {
14
15
  entityKey: Hex
@@ -16,7 +17,7 @@ export type ChangeOwnershipParameters = {
16
17
  }
17
18
 
18
19
  /**
19
- * Return type for the deleteEntity function.
20
+ * Return type for the changeOwnership function.
20
21
  * - entityKey: The key of the entity.
21
22
  * - txHash: The transaction hash.
22
23
  */
@@ -31,8 +32,7 @@ export async function changeOwnership(
31
32
  txParams?: TxParams,
32
33
  ): Promise<ChangeOwnershipReturnType> {
33
34
  logger("changeOwnership %o", data)
34
- const txData = opsToTxData({ ownershipChanges: [data] })
35
- const receipt = await sendArkivTransaction(client, txData, txParams)
35
+ const { receipt } = await sendArkivTransaction(client, { ownershipChanges: [data] }, txParams)
36
36
 
37
37
  logger("Receipt from changeOwnership %o", receipt)
38
38
 
@@ -1,7 +1,7 @@
1
1
  import type { Hash, Hex } from "viem"
2
2
  import type { ArkivClient } from "../../clients/baseClient"
3
3
  import type { Attribute, MimeType, TxParams } from "../../types"
4
- import { opsToTxData, sendArkivTransaction } from "../../utils/arkivTransactions"
4
+ import { sendArkivTransaction } from "../../utils/arkivTransactions"
5
5
  import { getLogger } from "../../utils/logger"
6
6
 
7
7
  const logger = getLogger("actions:wallet:create-entity")
@@ -46,13 +46,16 @@ export async function createEntity(
46
46
  txParams?: TxParams,
47
47
  ): Promise<CreateEntityReturnType> {
48
48
  logger("createEntity %o", data)
49
- const txData = opsToTxData({ creates: [data] })
50
- const receipt = await sendArkivTransaction(client, txData, txParams)
49
+ const { receipt, createdEntityKeys } = await sendArkivTransaction(
50
+ client,
51
+ { creates: [data] },
52
+ txParams,
53
+ )
51
54
 
52
55
  logger("Receipt from createEntity %o", receipt)
53
56
 
54
57
  return {
55
58
  txHash: receipt.transactionHash as Hash,
56
- entityKey: receipt.logs[0].topics[1] as Hex,
59
+ entityKey: createdEntityKeys[0],
57
60
  }
58
61
  }
@@ -1,7 +1,7 @@
1
1
  import type { Hash, Hex } from "viem"
2
2
  import type { ArkivClient } from "../../clients/baseClient"
3
3
  import type { TxParams } from "../../types"
4
- import { opsToTxData, sendArkivTransaction } from "../../utils/arkivTransactions"
4
+ import { sendArkivTransaction } from "../../utils/arkivTransactions"
5
5
  import { getLogger } from "../../utils/logger"
6
6
 
7
7
  const logger = getLogger("actions:wallet:delete-entity")
@@ -30,8 +30,7 @@ export async function deleteEntity(
30
30
  txParams?: TxParams,
31
31
  ): Promise<DeleteEntityReturnType> {
32
32
  logger("deleteEntity %o", data)
33
- const txData = opsToTxData({ deletes: [data] })
34
- const receipt = await sendArkivTransaction(client, txData, txParams)
33
+ const { receipt } = await sendArkivTransaction(client, { deletes: [data] }, txParams)
35
34
 
36
35
  logger("Receipt from deleteEntity %o", receipt)
37
36
 
@@ -1,7 +1,7 @@
1
1
  import type { Hash, Hex } from "viem"
2
2
  import type { ArkivClient } from "../../clients/baseClient"
3
3
  import type { TxParams } from "../../types"
4
- import { opsToTxData, sendArkivTransaction } from "../../utils/arkivTransactions"
4
+ import { sendArkivTransaction } from "../../utils/arkivTransactions"
5
5
  import { getLogger } from "../../utils/logger"
6
6
 
7
7
  const logger = getLogger("actions:wallet:extend-entity")
@@ -37,13 +37,12 @@ export async function extendEntity(
37
37
  txParams?: TxParams,
38
38
  ): Promise<ExtendEntityReturnType> {
39
39
  logger("extendEntity %o", data)
40
- const txData = opsToTxData({ extensions: [data] })
41
- const receipt = await sendArkivTransaction(client, txData, txParams)
40
+ const { receipt } = await sendArkivTransaction(client, { extensions: [data] }, txParams)
42
41
 
43
42
  logger("Receipt from extendEntity %o", receipt)
44
43
 
45
44
  return {
46
45
  txHash: receipt.transactionHash as Hash,
47
- entityKey: receipt.logs[0].topics[1] as Hex,
46
+ entityKey: data.entityKey,
48
47
  }
49
48
  }
@@ -1,17 +1,16 @@
1
- import type { Hash, Hex, TransactionReceipt } from "viem"
1
+ import type { Hash, Hex } from "viem"
2
2
  import type { ArkivClient } from "../../clients/baseClient"
3
3
  import type { TxParams } from "../../types"
4
- import { opsToTxData, sendArkivTransaction } from "../../utils/arkivTransactions"
4
+ import { sendArkivTransaction } from "../../utils/arkivTransactions"
5
5
  import { getLogger } from "../../utils/logger"
6
6
  import type { ChangeOwnershipParameters } from "./changeOwnership"
7
-
8
- const logger = getLogger("actions:wallet:mutate-entities")
9
-
10
7
  import type { CreateEntityParameters } from "./createEntity"
11
8
  import type { DeleteEntityParameters } from "./deleteEntity"
12
9
  import type { ExtendEntityParameters } from "./extendEntity"
13
10
  import type { UpdateEntityParameters } from "./updateEntity"
14
11
 
12
+ const logger = getLogger("actions:wallet:mutate-entities")
13
+
15
14
  /**
16
15
  * Parameters for the mutateEntities function.
17
16
  * - creates: The creates to perform.
@@ -27,39 +26,6 @@ export type MutateEntitiesParameters = {
27
26
  ownershipChanges?: ChangeOwnershipParameters[]
28
27
  }
29
28
 
30
- function parseReceipt(receipt: TransactionReceipt, params: MutateEntitiesParameters) {
31
- const createdEntities: Hex[] = []
32
- const updatedEntities: Hex[] = []
33
- const deletedEntities: Hex[] = []
34
- const extendedEntities: Hex[] = []
35
- const ownershipChanges: Hex[] = []
36
-
37
- const totalCreates = params.creates?.length ?? 0
38
- const totalUpdates = params.updates?.length ?? 0
39
- const totalDeletes = params.deletes?.length ?? 0
40
- const totalExtensions = params.extensions?.length ?? 0
41
-
42
- // iterate over all logs and parse the event
43
- // logs go in the following order: creates, deleted, updates, extends, ownership changes
44
- for (let index = 0; index < receipt.logs.length; index++) {
45
- const log = receipt.logs[index]
46
-
47
- if (index < totalCreates) {
48
- createdEntities.push(log.topics[1] as Hex)
49
- } else if (index < totalCreates + totalDeletes) {
50
- deletedEntities.push(log.topics[1] as Hex)
51
- } else if (index < totalCreates + totalUpdates + totalDeletes) {
52
- updatedEntities.push(log.topics[1] as Hex)
53
- } else if (index < totalCreates + totalUpdates + totalDeletes + totalExtensions) {
54
- extendedEntities.push(log.topics[1] as Hex)
55
- } else {
56
- ownershipChanges.push(log.topics[1] as Hex)
57
- }
58
- }
59
-
60
- return { createdEntities, updatedEntities, deletedEntities, extendedEntities, ownershipChanges }
61
- }
62
-
63
29
  /**
64
30
  * Return type for the mutateEntities function.
65
31
  * - txHash: The transaction hash.
@@ -77,6 +43,7 @@ export type MutateEntitiesReturnType = {
77
43
  extendedEntities: Hex[]
78
44
  ownershipChanges: Hex[]
79
45
  }
46
+
80
47
  export async function mutateEntities(
81
48
  client: ArkivClient,
82
49
  data: MutateEntitiesParameters,
@@ -86,26 +53,16 @@ export async function mutateEntities(
86
53
  throw new Error("No operations to perform")
87
54
  }
88
55
 
89
- const txData = opsToTxData({
90
- creates: data.creates ?? [],
91
- updates: data.updates ?? [],
92
- deletes: data.deletes ?? [],
93
- extensions: data.extensions ?? [],
94
- ownershipChanges: data.ownershipChanges ?? [],
95
- })
96
-
97
- const receipt = await sendArkivTransaction(client, txData, txParams)
56
+ const { receipt, createdEntityKeys } = await sendArkivTransaction(client, data, txParams)
98
57
 
99
58
  logger("Receipt from mutateEntities %o", receipt)
100
59
 
101
- const { createdEntities, updatedEntities, deletedEntities, extendedEntities, ownershipChanges } =
102
- parseReceipt(receipt, data)
103
60
  return {
104
61
  txHash: receipt.transactionHash as Hash,
105
- createdEntities,
106
- updatedEntities,
107
- deletedEntities,
108
- extendedEntities,
109
- ownershipChanges,
62
+ createdEntities: createdEntityKeys,
63
+ updatedEntities: (data.updates ?? []).map((u) => u.entityKey),
64
+ deletedEntities: (data.deletes ?? []).map((d) => d.entityKey),
65
+ extendedEntities: (data.extensions ?? []).map((e) => e.entityKey),
66
+ ownershipChanges: (data.ownershipChanges ?? []).map((o) => o.entityKey),
110
67
  }
111
68
  }
@@ -1,7 +1,7 @@
1
1
  import type { Hash, Hex } from "viem"
2
2
  import type { ArkivClient } from "../../clients/baseClient"
3
3
  import type { Attribute, MimeType, TxParams } from "../../types"
4
- import { opsToTxData, sendArkivTransaction } from "../../utils/arkivTransactions"
4
+ import { sendArkivTransaction } from "../../utils/arkivTransactions"
5
5
  import { getLogger } from "../../utils/logger"
6
6
 
7
7
  const logger = getLogger("actions:wallet:update-entity")
@@ -48,13 +48,12 @@ export async function updateEntity(
48
48
  txParams?: TxParams,
49
49
  ): Promise<UpdateEntityReturnType> {
50
50
  logger("updateEntity %o", data)
51
- const txData = opsToTxData({ updates: [data] })
52
- const receipt = await sendArkivTransaction(client, txData, txParams)
51
+ const { receipt } = await sendArkivTransaction(client, { updates: [data] }, txParams)
53
52
 
54
53
  logger("Receipt from updateEntity %o", receipt)
55
54
 
56
55
  return {
57
56
  txHash: receipt.transactionHash as Hash,
58
- entityKey: receipt.logs[0].topics[1] as Hex,
57
+ entityKey: data.entityKey,
59
58
  }
60
59
  }
@@ -35,7 +35,10 @@ export type WalletArkivActions<
35
35
  transport extends Transport = Transport,
36
36
  chain extends Chain | undefined = Chain | undefined,
37
37
  account extends Account | undefined = Account | undefined,
38
- > = Pick<PublicActions<transport, chain, account>, "waitForTransactionReceipt" | "call"> &
38
+ > = Pick<
39
+ PublicActions<transport, chain, account>,
40
+ "waitForTransactionReceipt" | "call" | "simulateContract" | "readContract" | "getBlockNumber"
41
+ > &
39
42
  Pick<
40
43
  WalletActions<chain, account>,
41
44
  | "addChain"
@@ -45,6 +48,7 @@ export type WalletArkivActions<
45
48
  | "sendRawTransaction"
46
49
  | "signMessage"
47
50
  | "signTransaction"
51
+ | "writeContract"
48
52
  > & {
49
53
  /**
50
54
  * Creates a new entity.
package/src/consts.ts CHANGED
@@ -1,2 +1,3 @@
1
- export const ARKIV_ADDRESS = "0x00000000000000000000000000000061726b6976" as `0x${string}`
1
+ //export const ARKIV_ADDRESS = "0x00000000000000000000000000000061726b6976" as `0x${string}`
2
+ export const ARKIV_ADDRESS = "0x4400000000000000000000000000000000000044" as `0x${string}`
2
3
  export const BLOCK_TIME = 2 // 2 seconds
package/src/errors.ts CHANGED
@@ -16,13 +16,32 @@ export class InvalidExpirationError extends Error {
16
16
  }
17
17
  export class InvalidAttributeError extends Error {
18
18
  constructor(key: string, value: number) {
19
+ const remedy = Number.isInteger(value)
20
+ ? `Offset it into the non-negative range (e.g. store ${String(value)} + OFFSET, subtracting OFFSET on read) to keep numeric ordering/range queries; otherwise store it as a string (e.g. "${String(value)}")`
21
+ : `To keep numeric ordering/range queries, scale it to an integer (e.g. Math.round(${String(value)} * 1000), dividing by 1000 on read); otherwise store it as a string (e.g. "${String(value)}")`
19
22
  super(
20
- `Invalid numeric value for attribute "${key}": ${String(value)}. Numeric attribute values must be integers. To keep numeric ordering/range queries, scale it to an integer (e.g. Math.round(${String(value)} * 1000), dividing by 1000 on read); otherwise store it as a string (e.g. "${String(value)}").`,
23
+ `Invalid numeric value for attribute "${key}": ${String(value)}. Numeric attribute values must be non-negative integers (stored on-chain as unsigned 256-bit). ${remedy}.`,
21
24
  )
22
25
  this.name = "InvalidAttributeError"
23
26
  }
24
27
  }
25
28
 
29
+ export class InvalidAttributeKeyError extends Error {
30
+ constructor(key: string, reason: string) {
31
+ super(
32
+ `Invalid attribute key "${key}": ${reason}. Keys must be 1-32 bytes, start with a lowercase letter (a-z), and contain only a-z, 0-9, ".", "-" or "_".`,
33
+ )
34
+ this.name = "InvalidAttributeKeyError"
35
+ }
36
+ }
37
+
38
+ export class DuplicateAttributeError extends Error {
39
+ constructor(key: string) {
40
+ super(`Duplicate attribute key "${key}". Attribute keys must be unique per entity.`)
41
+ this.name = "DuplicateAttributeError"
42
+ }
43
+ }
44
+
26
45
  export class NoMoreResultsError extends Error {
27
46
  constructor() {
28
47
  super("No more results")
@@ -43,3 +62,12 @@ export class NoEntityFoundError extends Error {
43
62
  this.name = "NoEntityFoundError"
44
63
  }
45
64
  }
65
+
66
+ export class InvalidContentTypeError extends Error {
67
+ constructor(contentType: string) {
68
+ super(
69
+ `Invalid content type "${contentType}". Must follow RFC 2045 MIME grammar and be lowercase only (e.g. "text/plain").`,
70
+ )
71
+ this.name = "InvalidContentTypeError"
72
+ }
73
+ }
@@ -47,6 +47,51 @@ describe("processQuery tests", () => {
47
47
  })
48
48
  })
49
49
 
50
+ it("should serialize 32-byte hex values as unquoted literals and other hex as strings", async () => {
51
+ const hexValue = "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
52
+ const predicates = [
53
+ { type: "eq" as const, key: "hexattr", value: hexValue },
54
+ { type: "eq" as const, key: "strattr", value: "value" },
55
+ // hex-looking but not 32 bytes — stored as strings, so compared quoted
56
+ { type: "eq" as const, key: "shorthex", value: "0xab" },
57
+ { type: "eq" as const, key: "addrhex", value: "0x6186b0dba9652262942d5a465d49686eb560834c" },
58
+ ]
59
+ await processQuery(client, {
60
+ predicates,
61
+ limit: undefined,
62
+ cursor: undefined,
63
+ ownedBy: undefined,
64
+ createdBy: undefined,
65
+ orderBy: undefined,
66
+ validAtBlock: undefined,
67
+ withAttributes: undefined,
68
+ withMetadata: undefined,
69
+ withPayload: undefined,
70
+ })
71
+
72
+ expect(client.request).lastCalledWith({
73
+ method: "arkiv_query",
74
+ params: [
75
+ `hexattr = ${hexValue} && strattr = "value" && shorthex = "0xab" && addrhex = "0x6186b0dba9652262942d5a465d49686eb560834c"`,
76
+ {
77
+ includeData: {
78
+ key: true,
79
+ attributes: false,
80
+ contentType: false,
81
+ payload: false,
82
+ expiration: false,
83
+ owner: false,
84
+ creator: false,
85
+ createdAtBlock: false,
86
+ lastModifiedAtBlock: false,
87
+ transactionIndexInBlock: false,
88
+ operationIndexInTransaction: false,
89
+ },
90
+ },
91
+ ],
92
+ })
93
+ })
94
+
50
95
  it("should process all simple predicates - flat", async () => {
51
96
  const predicates = [
52
97
  { type: "eq" as const, key: "key", value: "value" },
@@ -3,6 +3,7 @@ import { hexToNumber, numberToHex } from "viem"
3
3
  import type { ArkivClient } from "../clients/baseClient"
4
4
  import type { RpcIncludeData, RpcOrderByAttribute, RpcQueryOptions } from "../types/rpcSchema"
5
5
  import { getLogger } from "../utils/logger"
6
+ import { isEntityKey } from "../utils/validation"
6
7
  import type { Predicate } from "./predicate"
7
8
 
8
9
  const logger = getLogger("query:engine")
@@ -10,7 +11,11 @@ const logger = getLogger("query:engine")
10
11
  function processPredicates(predicates: Predicate[]): string {
11
12
  const processValue = (value: string | number) => {
12
13
  if (typeof value === "string") {
13
- return `"${value}"`
14
+ // 32-byte hex strings are stored as the EntityKey attribute type (see
15
+ // encodeAttribute), which the query language only matches against unquoted
16
+ // hex literals. All other strings — including shorter hex — are stored and
17
+ // compared as quoted strings.
18
+ return isEntityKey(value) ? value : `"${value}"`
14
19
  }
15
20
  return value
16
21
  }
@@ -1,6 +1,7 @@
1
1
  import { afterEach, beforeEach, describe, expect, jest, test } from "bun:test"
2
2
  import type { ArkivClient } from "../clients/baseClient"
3
3
  import type { Entity } from "../types/entity"
4
+ import { RpcAttributeValueType } from "../types/rpcSchema"
4
5
  import * as entitiesUtils from "../utils/entities"
5
6
  import * as engine from "./engine"
6
7
  import { eq, gte } from "./predicate"
@@ -150,8 +151,10 @@ describe("SelectQueryBuilder", () => {
150
151
  key: "0xabc",
151
152
  owner: "0xowner",
152
153
  value: "0x68656c6c6f", // "hello"
153
- stringAttributes: [{ key: "category", value: "docs" }],
154
- numericAttributes: [{ key: "score", value: "0x2a" }],
154
+ attributes: [
155
+ { key: "category", value: "docs", valueType: RpcAttributeValueType.String },
156
+ { key: "score", value: "0x2a", valueType: RpcAttributeValueType.Uint },
157
+ ],
155
158
  },
156
159
  ],
157
160
  cursor: "",
@@ -1,16 +1,28 @@
1
+ import type { Hex } from "viem"
2
+
1
3
  /**
2
4
  * An entity attribute (key/value pair).
3
5
  *
4
- * Arkiv supports both string and number values. Numeric values **must be
5
- * integers** — passing a non-integer number (e.g. `1.5`) throws an
6
- * {@link InvalidAttributeError} at mutation time. To store a non-integer value:
6
+ * Arkiv supports string, Hex and number values.
7
+ *
8
+ * Hex values are stored as the on-chain `EntityKey` type **only when they are
9
+ * exactly 32 bytes** (66 characters, e.g. an entity key). Hex-looking strings
10
+ * of any other length are stored as plain strings: they round-trip unchanged
11
+ * and compare lexicographically, not as hex.
12
+ *
13
+ * Numeric values **must be non-negative integers** (they are stored on-chain
14
+ * as unsigned 256-bit) — passing a non-integer (e.g. `1.5`) or negative number
15
+ * throws an {@link InvalidAttributeError} at mutation time. To store a
16
+ * non-integer value:
7
17
  * - Scale it to an integer (e.g. `1.5` -> `1500`, dividing by the same factor on
8
18
  * read) to keep numeric ordering and range queries working.
9
19
  * - Or pass it as a string (e.g. `"1.5"`), which sorts lexicographically and so
10
20
  * does not support numeric comparisons.
21
+ *
22
+ * To store a negative value, offset it into the non-negative range (subtracting
23
+ * the offset on read) or store it as a string.
11
24
  */
12
25
  export type Attribute = {
13
26
  key: string
14
- /** Attribute value. A `number` must be an integer (scale non-integers, e.g. `1.5` -> `1500`, or use a string). Throws {@link InvalidAttributeError} otherwise. */
15
- value: string | number
27
+ value: number | string | Hex
16
28
  }
@@ -1,10 +1,20 @@
1
1
  import { bytesToString, type Hex } from "viem"
2
+
3
+ export enum EntityOperationType {
4
+ Create = 1,
5
+ Update = 2,
6
+ Extend = 3,
7
+ Transfer = 4,
8
+ Delete = 5,
9
+ Expire = 6,
10
+ }
11
+
2
12
  import type { MimeType } from "../types"
3
13
  import type { Attribute } from "./attributes"
4
14
 
5
15
  export class Entity {
6
16
  key: Hex
7
- contentType: MimeType | undefined
17
+ contentType: MimeType | `${string}/${string}` | undefined
8
18
  owner: Hex | undefined
9
19
  creator: Hex | undefined
10
20
  expiresAtBlock: bigint | undefined
@@ -17,7 +27,7 @@ export class Entity {
17
27
 
18
28
  constructor(
19
29
  key: Hex,
20
- contentType: MimeType | undefined = undefined,
30
+ contentType: MimeType | `${string}/${string}` | undefined = undefined,
21
31
  owner: Hex | undefined = undefined,
22
32
  creator: Hex | undefined = undefined,
23
33
  expiresAtBlock: bigint | undefined = undefined,