Skip to main content
Building Arkognito on @arkiv-network/sdk 0.8.1 and the Tiramisu testnet surfaced several behaviours every Arkiv builder should know. Each has a reproduction script in the repository’s arkiv/friction.md.

Expiry hides an entity but does not erase it

After an entity expires, getEntity throws and normal queries return nothing. But a query at an earlier block (.atBlock(<creation block>)) still returns it with its payload, and the payload bytes are readable in the creating transaction’s calldata. Consequence: expiry is not a privacy tool. In Arkognito: private content uses encrypt: true.

Uppercase attribute names are rejected by the node

The SDK’s isValidAttributeName("minBatch") returns true and the SDK sends it, but the node reverts: an attribute name holds “B” (0x42) at byte 3, which is outside the name charset (“A”-“Z”, “a”-“z”, …). The message lists “A”-“Z” as allowed while rejecting it. In an executeBatch, one bad name reverts every operation in the batch. In Arkognito: the client and the relayer both enforce ^[a-z][a-z0-9._-]*$ before a record can join a batch, and a failed batch is split and retried so one bad record cannot sink the others.

The SDK’s page iterator breaks when a block lands mid-page

Arkiv cursors are tied to the block they were read at. The SDK’s async iterator reads page 1 at the head and page 2 at the new head, so a page-through over more than 200 entities fails intermittently with cursor belongs to a different query, block or select. In Arkognito: every page-through is pinned with .atBlock(await client.getBlockNumber()).

The SDK refuses $createdAt filters the node supports

eq("$createdAt", u64(n)) throws in the SDK (carries no index, so it cannot be filtered on), while the same filter sent as a raw query works. In Arkognito: whole-batch fetches, which let a client read its record without naming it, use client.query("… AND $createdAt = u64(<block>) AND $creator = addr(<relayer>)").

Stale key predictions fail with a misleading message

predictEntityKeys is only valid while nothing else from that owner is in flight. A batch built on a stale prediction fails with no entity 0x… — it may have been deleted, or have expired, which points at the wrong cause. The revert is atomic. In Arkognito: one writer per relayer wallet, predict immediately before sending, and re-predict on this error.

The wallet client’s type hides signing methods

The SDK’s createWalletClient extends viem’s wallet actions at runtime, but its declared type omits signTypedData and signMessage, so TypeScript rejects code that signs with it. In Arkognito: any object with an account is accepted; signing methods are checked at runtime.

Smaller notes

  • npm install @arkiv-network/sdk@0.8.1 works; some docs still say to use the @dev tag.
  • The Tiramisu explorer is https://indexer.tiramisu.db-chain.testnet.arkiv.network.
  • executeBatch applies creates before ownership changes, which is what lets a relayer create a record and hand it to its one-time owner in one transaction.
Last modified on October 12, 2026