Mutating Data
Learn how to create, update, delete, and extend entities on Arkiv using the TypeScript SDK’s wallet client.
WalletClient Setup
Section titled “WalletClient Setup”All write operations require a wallet client:
import { createWalletClient, http } from "@arkiv-network/sdk"import { privateKeyToAccount } from "@arkiv-network/sdk/accounts"import { kaolin } from "@arkiv-network/sdk/chains"
const walletClient = createWalletClient({ chain: kaolin, transport: http(), account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`),})Payload Helpers
Section titled “Payload Helpers”Convert data to Arkiv payloads before storing:
import { jsonToPayload, stringToPayload, payloadToString } from "@arkiv-network/sdk/utils"
// JSON dataconst jsonPayload = jsonToPayload({ title: "My Note", content: "Hello!" })
// Plain textconst textPayload = stringToPayload("Hello Arkiv!")
// Reading backconst text = payloadToString(entity.payload)const data = entity.toJson()Create Entity
Section titled “Create Entity”import { jsonToPayload, ExpirationTime } from "@arkiv-network/sdk/utils"
const { entityKey, txHash } = await walletClient.createEntity({ payload: jsonToPayload({ title: "My Note", content: "Hello Arkiv!" }), contentType: "application/json", attributes: [ { key: "type", value: "note" }, { key: "id", value: crypto.randomUUID() }, { key: "created", value: Date.now() }, ], expiresIn: ExpirationTime.fromHours(12),})
console.log("Created:", entityKey)Parameters
Section titled “Parameters”| Field | Type | Description |
|---|---|---|
payload | Uint8Array | Entity data (use jsonToPayload or stringToPayload) |
contentType | string | MIME type (application/json, text/plain, etc.) |
attributes | Array | Key-value pairs for querying |
expiresIn | number | Lifetime in seconds (use ExpirationTime helpers) |
Returns
Section titled “Returns”| Field | Type | Description |
|---|---|---|
entityKey | string | Unique identifier for the entity |
txHash | string | Transaction hash on the chain |
Update Entity
Section titled “Update Entity”Replace an entity’s payload, attributes, and expiration:
const { txHash } = await walletClient.updateEntity({ entityKey: entityKey, payload: jsonToPayload({ title: "Updated Note", content: "New content" }), contentType: "application/json", attributes: [ { key: "type", value: "note" }, { key: "updated", value: Date.now() }, ], expiresIn: ExpirationTime.fromHours(24),})Delete Entity
Section titled “Delete Entity”const { txHash } = await walletClient.deleteEntity({ entityKey: entityKey,})Change Ownership
Section titled “Change Ownership”Transfer an entity to a new owner:
const { entityKey, txHash } = await walletClient.changeOwnership({ entityKey: entityKey, newOwner: "0x1234567890abcdef1234567890abcdef12345678",})Parameters
Section titled “Parameters”| Field | Type | Description |
|---|---|---|
entityKey | Hex | Key of the entity to transfer |
newOwner | Hex | Address of the new owner |
Returns
Section titled “Returns”| Field | Type | Description |
|---|---|---|
entityKey | Hex | Key of the transferred entity |
txHash | string | Transaction hash on the chain |
Extend Expiration
Section titled “Extend Expiration”Add more time to an entity before it expires:
const { txHash } = await walletClient.extendEntity({ entityKey: entityKey, expiresIn: ExpirationTime.fromHours(1),})Batch Operations
Section titled “Batch Operations”Create multiple entities in a single transaction using mutateEntities():
await walletClient.mutateEntities({ creates: [ { payload: jsonToPayload({ content: "Item 1" }), contentType: "application/json", attributes: [{ key: "type", value: "item" }], expiresIn: ExpirationTime.fromMinutes(30), }, { payload: jsonToPayload({ content: "Item 2" }), contentType: "application/json", attributes: [{ key: "type", value: "item" }], expiresIn: ExpirationTime.fromMinutes(30), }, ],})Batch with Dynamic Data
Section titled “Batch with Dynamic Data”const items = ["frontend", "backend", "devops"]
await walletClient.mutateEntities({ creates: items.map((skill) => ({ payload: jsonToPayload({ profileId: "alice-123", skill }), contentType: "application/json", attributes: [ { key: "type", value: "skill" }, { key: "profileId", value: "alice-123" }, { key: "skill", value: skill }, ], expiresIn: ExpirationTime.fromDays(30), })),})ExpirationTime Reference
Section titled “ExpirationTime Reference”Always use the helper instead of raw numbers:
import { ExpirationTime } from "@arkiv-network/sdk/utils"
ExpirationTime.fromMinutes(30) // 1800 secondsExpirationTime.fromHours(1) // 3600 secondsExpirationTime.fromHours(12) // 43200 secondsExpirationTime.fromHours(24) // 86400 secondsExpirationTime.fromDays(7) // 604800 secondsBrowser Usage with MetaMask
Section titled “Browser Usage with MetaMask”In browser applications, use MetaMask as the transport instead of a private key:
import { createWalletClient, custom } from "@arkiv-network/sdk"import { kaolin } from "@arkiv-network/sdk/chains"
// Request wallet connectionawait window.ethereum.request({ method: 'eth_requestAccounts' })
// Use MetaMask as transportconst walletClient = createWalletClient({ chain: kaolin, transport: custom(window.ethereum),})See the MetaMask Sketch App tutorial for a complete browser example.
Error Handling
Section titled “Error Handling”The SDK does not retry on failure — all methods throw on error. Wrap write operations in try/catch:
try { const { entityKey, txHash } = await walletClient.createEntity({ payload: jsonToPayload({ title: "My Post" }), contentType: "application/json", attributes: [{ key: "type", value: "post" }], expiresIn: ExpirationTime.fromHours(12), })} catch (error) { // Common failures: // - User rejected the transaction (MetaMask popup dismissed) // - Insufficient funds / gas // - Network error (RPC unreachable) // - Entity already expired (for update/extend) console.error("Transaction failed:", error)}