@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.
- package/dist/chains/index.d.ts +25 -25
- package/dist/consts-Bz0LZQZY.js +7 -0
- package/dist/consts-Bz0LZQZY.js.map +1 -0
- package/dist/{consts-AUoL-v42.cjs → consts-CxT1-RXU.cjs} +1 -1
- package/dist/entity-BhSXaB23.cjs +81 -0
- package/dist/{entity-B6g_EPm1.d.cts → entity-CN41IOrq.d.cts} +53 -34
- package/dist/entity-CN41IOrq.d.cts.map +1 -0
- package/dist/entity-DGfVyB-a.js +71 -0
- package/dist/entity-DGfVyB-a.js.map +1 -0
- package/dist/{entity-qoLMAuuk.d.ts → entity-NnEVlePN.d.ts} +53 -34
- package/dist/entity-NnEVlePN.d.ts.map +1 -0
- package/dist/{index-DdspxNAA.d.ts → index-ClkpS6s_.d.ts} +2 -2
- package/dist/{index-DdspxNAA.d.ts.map → index-ClkpS6s_.d.ts.map} +1 -1
- package/dist/{index-Ds9dwqb5.d.cts → index-w4qop0Pe.d.cts} +2 -2
- package/dist/{index-Ds9dwqb5.d.cts.map → index-w4qop0Pe.d.cts.map} +1 -1
- package/dist/index.cjs +281 -264
- package/dist/index.d.cts +13 -4
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +14 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +279 -266
- package/dist/index.js.map +1 -1
- package/dist/{payload-Claf2jUO.js → payload-BpNUPOnY.js} +3 -3
- package/dist/payload-BpNUPOnY.js.map +1 -0
- package/dist/{payload-B2kFJyah.d.ts → payload-C2KHOUoj.d.ts} +1 -1
- package/dist/{payload-B2kFJyah.d.ts.map → payload-C2KHOUoj.d.ts.map} +1 -1
- package/dist/{payload-DpA5PA-w.cjs → payload-D8YLKcJj.cjs} +1 -1
- package/dist/query/index.cjs +3 -2
- package/dist/query/index.d.cts +2 -2
- package/dist/query/index.d.ts +2 -2
- package/dist/query/index.js +3 -2
- package/dist/query/index.js.map +1 -1
- package/dist/{queryBuilder-D2uwP9jI.js → queryBuilder-BE_XhLLa.js} +98 -67
- package/dist/queryBuilder-BE_XhLLa.js.map +1 -0
- package/dist/{queryBuilder-UW2MCaX4.cjs → queryBuilder-J37buGCi.cjs} +137 -64
- package/dist/types/index.cjs +4 -1
- package/dist/types/index.d.cts +2 -2
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.js +4 -1
- package/dist/utils/index.cjs +2 -2
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +2 -2
- package/package.json +1 -1
- package/src/actions/public/subscribeEntityEvents.ts +25 -51
- package/src/actions/wallet/changeOwnership.ts +6 -6
- package/src/actions/wallet/createEntity.ts +7 -4
- package/src/actions/wallet/deleteEntity.ts +2 -3
- package/src/actions/wallet/extendEntity.ts +3 -4
- package/src/actions/wallet/mutateEntities.ts +11 -54
- package/src/actions/wallet/updateEntity.ts +3 -4
- package/src/clients/decorators/arkivWallet.ts +5 -1
- package/src/consts.ts +2 -1
- package/src/errors.ts +29 -1
- package/src/query/engine.test.ts +45 -0
- package/src/query/engine.ts +6 -1
- package/src/query/selectQueryBuilder.test.ts +5 -2
- package/src/types/attributes.ts +17 -5
- package/src/types/entity.ts +12 -2
- package/src/types/events.ts +14 -16
- package/src/types/index.ts +1 -0
- package/src/types/rpcSchema.ts +7 -2
- package/src/utils/arkivTransactions.test.ts +234 -36
- package/src/utils/arkivTransactions.ts +255 -101
- package/src/utils/entities.ts +17 -7
- package/src/utils/payload.ts +4 -2
- package/src/utils/validation.test.ts +52 -6
- package/src/utils/validation.ts +54 -6
- package/dist/consts-BV4PR-de.js +0 -7
- package/dist/consts-BV4PR-de.js.map +0 -1
- package/dist/entity-B6g_EPm1.d.cts.map +0 -1
- package/dist/entity-qoLMAuuk.d.ts.map +0 -1
- package/dist/payload-Claf2jUO.js.map +0 -1
- package/dist/queryBuilder-D2uwP9jI.js.map +0 -1
- /package/dist/{types-H-TSmRpm.js → types-Ci4BRClw.js} +0 -0
- /package/dist/{types-o3zWarRp.cjs → types-a8gm_IaQ.cjs} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { t as chains_exports } from "./chains-CrtkVbBh.js";
|
|
2
|
-
import { c as
|
|
3
|
-
import { n as BLOCK_TIME, t as ARKIV_ADDRESS } from "./consts-
|
|
4
|
-
import "./
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
2
|
+
import { S as getLogger, _ as InvalidContentTypeError, b as NoEntityFoundError, c as isEntityKey, d as entityFromRpcResult, f as RpcAttributeValueType, g as InvalidAttributeKeyError, h as InvalidAttributeError, l as validateAttribute, m as EntityMutationError, n as QueryBuilder, p as DuplicateAttributeError, r as SelectQueryBuilder, u as validateExpiresIn, v as InvalidExpirationError, x as NoMoreResultsError, y as NoCursorOrLimitError } from "./queryBuilder-BE_XhLLa.js";
|
|
3
|
+
import { n as BLOCK_TIME, t as ARKIV_ADDRESS } from "./consts-Bz0LZQZY.js";
|
|
4
|
+
import { n as EntityOperationType } from "./entity-DGfVyB-a.js";
|
|
5
|
+
import "./types-Ci4BRClw.js";
|
|
6
|
+
import { n as stringToPayload, t as jsonToPayload } from "./payload-BpNUPOnY.js";
|
|
7
|
+
import { ContractFunctionExecutionError, ContractFunctionRevertedError, TransactionExecutionError, bytesToHex, createClient, decodeEventLog, encodePacked, hexToBytes, keccak256, numberToHex, parseAbi, publicActions, stringToBytes, toBytes, toHex, walletActions } from "viem";
|
|
7
8
|
|
|
8
9
|
//#region src/actions/public/getBlockTiming.ts
|
|
9
|
-
const logger$
|
|
10
|
+
const logger$8 = getLogger("actions:public:get-block-timing");
|
|
10
11
|
async function getBlockTiming(client) {
|
|
11
12
|
const blockTiming = await client.request({
|
|
12
13
|
method: "arkiv_getBlockTiming",
|
|
13
14
|
params: []
|
|
14
15
|
});
|
|
15
|
-
logger$
|
|
16
|
+
logger$8("Block timing %o", blockTiming);
|
|
16
17
|
return {
|
|
17
18
|
currentBlock: BigInt(blockTiming.current_block),
|
|
18
19
|
currentBlockTime: blockTiming.current_block_time,
|
|
@@ -98,78 +99,289 @@ async function query(client, query$1, queryOptions) {
|
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
//#endregion
|
|
101
|
-
//#region src/
|
|
102
|
-
const logger$
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
102
|
+
//#region src/utils/arkivTransactions.ts
|
|
103
|
+
const logger$7 = getLogger("utils:arkiv-transactions");
|
|
104
|
+
const MIME_REGEX = /^[a-z][a-z0-9!#$&\-^_]*\/[a-z0-9][a-z0-9!#$&\-^_.+]*$/;
|
|
105
|
+
function validateContentType(contentType) {
|
|
106
|
+
if (!MIME_REGEX.test(contentType)) throw new InvalidContentTypeError(contentType);
|
|
107
|
+
}
|
|
108
|
+
const ENTITY_EXECUTE_ABI = parseAbi(["function execute((uint8 operationType, bytes32 entityKey, bytes payload, (bytes32[4] data) contentType, (bytes32 name, uint8 valueType, bytes32[4] value)[] attributes, uint32 expiresIn, address newOwner)[] ops) external"]);
|
|
109
|
+
const ENTITY_OPERATION_EVENT_ABI = parseAbi(["event EntityOperation(bytes32 indexed entityKey, uint8 indexed operationType, address indexed owner, uint32 expiresAt, bytes32 entityHash)"]);
|
|
110
|
+
const ENTITY_ERRORS_ABI = parseAbi([
|
|
111
|
+
"error EmptyBatch()",
|
|
112
|
+
"error AttributesNotSorted()",
|
|
113
|
+
"error InvalidValueType(bytes32 name, uint8 valueType)",
|
|
114
|
+
"error InvalidOpType(uint8 operationType)",
|
|
115
|
+
"error ExpiryInPast(uint32 expiresAt, uint32 currentBlock)",
|
|
116
|
+
"error TooManyAttributes(uint256 count, uint256 maxCount)",
|
|
117
|
+
"error EntityNotFound(bytes32 entityKey)",
|
|
118
|
+
"error NotOwner(bytes32 entityKey, address caller, address owner)",
|
|
119
|
+
"error EntityExpired(bytes32 entityKey, uint32 expiresAt)",
|
|
120
|
+
"error ExpiryNotExtended(bytes32 entityKey, uint32 newExpiresAt, uint32 currentExpiresAt)",
|
|
121
|
+
"error TransferToZeroAddress(bytes32 entityKey)",
|
|
122
|
+
"error TransferToSelf(bytes32 entityKey)",
|
|
123
|
+
"error EntityNotExpired(bytes32 entityKey, uint32 expiresAt)",
|
|
124
|
+
"error Ident32Empty()",
|
|
125
|
+
"error Ident32TooLong(uint256 length)",
|
|
126
|
+
"error Ident32InvalidByte(uint256 position, bytes1 value)",
|
|
127
|
+
"error MimeEmpty()",
|
|
128
|
+
"error MimeTooLong(uint256 length, uint256 maxLength)",
|
|
129
|
+
"error MimeInvalidByte(uint256 position, bytes1 value)",
|
|
130
|
+
"error MimeIncomplete()"
|
|
110
131
|
]);
|
|
132
|
+
const EXECUTE_ABI = [...ENTITY_EXECUTE_ABI, ...ENTITY_ERRORS_ABI];
|
|
133
|
+
const ENTITY_NONCE_ABI = parseAbi(["function nonces(address owner) view returns (uint32)"]);
|
|
134
|
+
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
135
|
+
const ZERO_32 = `0x${"00".repeat(32)}`;
|
|
136
|
+
const EMPTY_BYTES128 = [
|
|
137
|
+
ZERO_32,
|
|
138
|
+
ZERO_32,
|
|
139
|
+
ZERO_32,
|
|
140
|
+
ZERO_32
|
|
141
|
+
];
|
|
142
|
+
function encodeBytes128(data) {
|
|
143
|
+
const padded = new Uint8Array(128);
|
|
144
|
+
padded.set(data.slice(0, 128));
|
|
145
|
+
return [
|
|
146
|
+
toHex(padded.slice(0, 32)),
|
|
147
|
+
toHex(padded.slice(32, 64)),
|
|
148
|
+
toHex(padded.slice(64, 96)),
|
|
149
|
+
toHex(padded.slice(96, 128))
|
|
150
|
+
];
|
|
151
|
+
}
|
|
152
|
+
function encodeMime128(contentType) {
|
|
153
|
+
return { data: contentType ? encodeBytes128(stringToBytes(contentType)) : EMPTY_BYTES128 };
|
|
154
|
+
}
|
|
155
|
+
function encodeAttribute(attr) {
|
|
156
|
+
validateAttribute(attr);
|
|
157
|
+
const name = toHex(attr.key, { size: 32 });
|
|
158
|
+
if (typeof attr.value === "string") {
|
|
159
|
+
if (isEntityKey(attr.value)) return {
|
|
160
|
+
name,
|
|
161
|
+
valueType: RpcAttributeValueType.EntityKey,
|
|
162
|
+
value: [
|
|
163
|
+
toHex(toBytes(attr.value), { size: 32 }),
|
|
164
|
+
ZERO_32,
|
|
165
|
+
ZERO_32,
|
|
166
|
+
ZERO_32
|
|
167
|
+
]
|
|
168
|
+
};
|
|
169
|
+
return {
|
|
170
|
+
name,
|
|
171
|
+
valueType: RpcAttributeValueType.String,
|
|
172
|
+
value: encodeBytes128(stringToBytes(attr.value))
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
name,
|
|
177
|
+
valueType: RpcAttributeValueType.Uint,
|
|
178
|
+
value: [
|
|
179
|
+
toHex(BigInt(attr.value), { size: 32 }),
|
|
180
|
+
ZERO_32,
|
|
181
|
+
ZERO_32,
|
|
182
|
+
ZERO_32
|
|
183
|
+
]
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function encodeAttributes(attrs) {
|
|
187
|
+
const encoded = attrs.map((attr) => ({
|
|
188
|
+
key: attr.key,
|
|
189
|
+
...encodeAttribute(attr)
|
|
190
|
+
})).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
191
|
+
for (let i = 1; i < encoded.length; i++) if (encoded[i].name === encoded[i - 1].name) throw new DuplicateAttributeError(encoded[i].key);
|
|
192
|
+
return encoded.map(({ key: _,...attr }) => attr);
|
|
193
|
+
}
|
|
194
|
+
function toBTL(expiresIn) {
|
|
195
|
+
validateExpiresIn(expiresIn);
|
|
196
|
+
return Math.ceil(expiresIn / BLOCK_TIME);
|
|
197
|
+
}
|
|
198
|
+
function deriveEntityKey(chainId, owner, nonce) {
|
|
199
|
+
return keccak256(encodePacked([
|
|
200
|
+
"uint256",
|
|
201
|
+
"address",
|
|
202
|
+
"address",
|
|
203
|
+
"uint32"
|
|
204
|
+
], [
|
|
205
|
+
BigInt(chainId),
|
|
206
|
+
ARKIV_ADDRESS,
|
|
207
|
+
owner,
|
|
208
|
+
Number(nonce)
|
|
209
|
+
]));
|
|
210
|
+
}
|
|
211
|
+
async function sendArkivTransaction(client, ops, txParams) {
|
|
212
|
+
if (!client.account) throw new Error("Account required");
|
|
213
|
+
if (!client.chain) throw new Error("Chain required");
|
|
214
|
+
const walletClient = client;
|
|
215
|
+
const { creates, updates, deletes, extensions, ownershipChanges } = ops;
|
|
216
|
+
const owner = client.account.address;
|
|
217
|
+
const ownerNonce = creates?.length ? BigInt(await walletClient.readContract({
|
|
218
|
+
address: ARKIV_ADDRESS,
|
|
219
|
+
abi: ENTITY_NONCE_ABI,
|
|
220
|
+
functionName: "nonces",
|
|
221
|
+
args: [owner]
|
|
222
|
+
})) : 0n;
|
|
223
|
+
const createdEntityKeys = (creates ?? []).map((_, i) => deriveEntityKey(client.chain.id, owner, ownerNonce + BigInt(i)));
|
|
224
|
+
for (const item of creates ?? []) validateContentType(item.contentType);
|
|
225
|
+
for (const item of updates ?? []) validateContentType(item.contentType);
|
|
226
|
+
const operations = [
|
|
227
|
+
...(creates ?? []).map((item, i) => ({
|
|
228
|
+
operationType: EntityOperationType.Create,
|
|
229
|
+
entityKey: createdEntityKeys[i],
|
|
230
|
+
payload: toHex(item.payload),
|
|
231
|
+
contentType: encodeMime128(item.contentType),
|
|
232
|
+
attributes: encodeAttributes(item.attributes),
|
|
233
|
+
expiresIn: toBTL(item.expiresIn),
|
|
234
|
+
newOwner: ZERO_ADDRESS
|
|
235
|
+
})),
|
|
236
|
+
...(updates ?? []).map((item) => ({
|
|
237
|
+
operationType: EntityOperationType.Update,
|
|
238
|
+
entityKey: item.entityKey,
|
|
239
|
+
payload: toHex(item.payload),
|
|
240
|
+
contentType: encodeMime128(item.contentType),
|
|
241
|
+
attributes: encodeAttributes(item.attributes),
|
|
242
|
+
expiresIn: 0,
|
|
243
|
+
newOwner: ZERO_ADDRESS
|
|
244
|
+
})),
|
|
245
|
+
...(deletes ?? []).map((item) => ({
|
|
246
|
+
operationType: EntityOperationType.Delete,
|
|
247
|
+
entityKey: item.entityKey,
|
|
248
|
+
payload: "0x",
|
|
249
|
+
contentType: encodeMime128(""),
|
|
250
|
+
attributes: [],
|
|
251
|
+
expiresIn: 0,
|
|
252
|
+
newOwner: ZERO_ADDRESS
|
|
253
|
+
})),
|
|
254
|
+
...(extensions ?? []).map((item) => ({
|
|
255
|
+
operationType: EntityOperationType.Extend,
|
|
256
|
+
entityKey: item.entityKey,
|
|
257
|
+
payload: "0x",
|
|
258
|
+
contentType: encodeMime128(""),
|
|
259
|
+
attributes: [],
|
|
260
|
+
expiresIn: toBTL(item.expiresIn),
|
|
261
|
+
newOwner: ZERO_ADDRESS
|
|
262
|
+
})),
|
|
263
|
+
...(ownershipChanges ?? []).map((item) => ({
|
|
264
|
+
operationType: EntityOperationType.Transfer,
|
|
265
|
+
entityKey: item.entityKey,
|
|
266
|
+
payload: "0x",
|
|
267
|
+
contentType: encodeMime128(""),
|
|
268
|
+
attributes: [],
|
|
269
|
+
expiresIn: 0,
|
|
270
|
+
newOwner: item.newOwner
|
|
271
|
+
}))
|
|
272
|
+
];
|
|
273
|
+
logger$7("Sending execute with %d operations %s", operations.length, JSON.stringify(operations));
|
|
274
|
+
try {
|
|
275
|
+
const txHash = await walletClient.writeContract({
|
|
276
|
+
address: ARKIV_ADDRESS,
|
|
277
|
+
abi: EXECUTE_ABI,
|
|
278
|
+
functionName: "execute",
|
|
279
|
+
args: [operations],
|
|
280
|
+
account: client.account,
|
|
281
|
+
chain: client.chain,
|
|
282
|
+
...txParams
|
|
283
|
+
});
|
|
284
|
+
const receipt = await walletClient.waitForTransactionReceipt({ hash: txHash });
|
|
285
|
+
logger$7("Tx receipt %o", receipt);
|
|
286
|
+
if (receipt.status === "reverted") {
|
|
287
|
+
try {
|
|
288
|
+
await walletClient.simulateContract({
|
|
289
|
+
address: ARKIV_ADDRESS,
|
|
290
|
+
abi: EXECUTE_ABI,
|
|
291
|
+
functionName: "execute",
|
|
292
|
+
args: [operations],
|
|
293
|
+
account: client.account,
|
|
294
|
+
chain: client.chain
|
|
295
|
+
});
|
|
296
|
+
} catch (err) {
|
|
297
|
+
const error = err;
|
|
298
|
+
const reason = error.shortMessage ?? error.cause?.details ?? "No reason provided by backend.";
|
|
299
|
+
throw new EntityMutationError(`Transaction ${receipt.transactionHash} reverted. Reason: ${reason}`);
|
|
300
|
+
}
|
|
301
|
+
throw new EntityMutationError(`Transaction ${receipt.transactionHash} reverted. No reason provided by backend.`);
|
|
302
|
+
}
|
|
303
|
+
return {
|
|
304
|
+
receipt,
|
|
305
|
+
createdEntityKeys
|
|
306
|
+
};
|
|
307
|
+
} catch (error) {
|
|
308
|
+
let message = "Transaction failed";
|
|
309
|
+
if (error instanceof TransactionExecutionError) message += `: ${error.details}`;
|
|
310
|
+
else if (error instanceof ContractFunctionExecutionError) {
|
|
311
|
+
logger$7("Contract function execution error data:", error.shortMessage);
|
|
312
|
+
if (error.cause instanceof ContractFunctionRevertedError) message += `: ${error.cause.message}`;
|
|
313
|
+
else message += ": Execution error without revert data";
|
|
314
|
+
} else if (error instanceof EntityMutationError) throw error;
|
|
315
|
+
throw new EntityMutationError(message);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
//#endregion
|
|
320
|
+
//#region src/actions/public/subscribeEntityEvents.ts
|
|
321
|
+
const logger$6 = getLogger("actions:public:subscribe-entity-events");
|
|
322
|
+
const arkivABI = ENTITY_OPERATION_EVENT_ABI;
|
|
111
323
|
async function subscribeEntityEvents(client, { onError, onEntityCreated, onEntityUpdated, onEntityDeleted, onEntityExpired, onEntityExpiresInExtended, onEntityOwnerChanged }, pollingInterval, fromBlock) {
|
|
112
324
|
return client.watchEvent({
|
|
113
325
|
pollingInterval: pollingInterval ?? 1e3,
|
|
114
326
|
fromBlock,
|
|
115
327
|
events: arkivABI,
|
|
116
328
|
onLogs: (logs) => {
|
|
117
|
-
logger$
|
|
329
|
+
logger$6("logs from subscribeEntityEvents %o", logs);
|
|
118
330
|
for (const log of logs) {
|
|
119
331
|
const event = decodeEventLog({
|
|
120
332
|
abi: arkivABI,
|
|
121
333
|
topics: log.topics,
|
|
122
334
|
data: log.data
|
|
123
335
|
});
|
|
124
|
-
logger$
|
|
125
|
-
|
|
126
|
-
|
|
336
|
+
logger$6("event from subscribeEntityEvents %o", event);
|
|
337
|
+
if (event.eventName !== "EntityOperation") continue;
|
|
338
|
+
const entityKey = event.args.entityKey;
|
|
339
|
+
const owner = event.args.owner;
|
|
340
|
+
const expiresAt = event.args.expiresAt;
|
|
341
|
+
const entityHash = event.args.entityHash;
|
|
342
|
+
switch (Number(event.args.operationType)) {
|
|
343
|
+
case EntityOperationType.Create:
|
|
127
344
|
onEntityCreated?.({
|
|
128
|
-
entityKey
|
|
129
|
-
owner
|
|
130
|
-
|
|
131
|
-
|
|
345
|
+
entityKey,
|
|
346
|
+
owner,
|
|
347
|
+
expiresAt,
|
|
348
|
+
entityHash
|
|
132
349
|
});
|
|
133
350
|
break;
|
|
134
|
-
case
|
|
351
|
+
case EntityOperationType.Update:
|
|
135
352
|
onEntityUpdated?.({
|
|
136
|
-
entityKey
|
|
137
|
-
owner
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
cost: event.args.cost
|
|
353
|
+
entityKey,
|
|
354
|
+
owner,
|
|
355
|
+
expiresAt,
|
|
356
|
+
entityHash
|
|
141
357
|
});
|
|
142
358
|
break;
|
|
143
|
-
case
|
|
144
|
-
onEntityDeleted?.({
|
|
145
|
-
entityKey: toHex(event.args.entityKey, { size: 32 }),
|
|
146
|
-
owner: event.args.ownerAddress
|
|
147
|
-
});
|
|
148
|
-
break;
|
|
149
|
-
case "ArkivEntityBTLExtended":
|
|
359
|
+
case EntityOperationType.Extend:
|
|
150
360
|
onEntityExpiresInExtended?.({
|
|
151
|
-
entityKey
|
|
152
|
-
owner
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
cost: event.args.cost
|
|
361
|
+
entityKey,
|
|
362
|
+
owner,
|
|
363
|
+
expiresAt,
|
|
364
|
+
entityHash
|
|
156
365
|
});
|
|
157
366
|
break;
|
|
158
|
-
case
|
|
159
|
-
|
|
160
|
-
entityKey
|
|
161
|
-
owner
|
|
367
|
+
case EntityOperationType.Transfer:
|
|
368
|
+
onEntityOwnerChanged?.({
|
|
369
|
+
entityKey,
|
|
370
|
+
owner,
|
|
371
|
+
entityHash
|
|
162
372
|
});
|
|
163
373
|
break;
|
|
164
|
-
case
|
|
165
|
-
|
|
166
|
-
entityKey
|
|
167
|
-
|
|
168
|
-
newOwner: event.args.newOwnerAddress
|
|
374
|
+
case EntityOperationType.Delete:
|
|
375
|
+
onEntityDeleted?.({
|
|
376
|
+
entityKey,
|
|
377
|
+
owner
|
|
169
378
|
});
|
|
170
379
|
break;
|
|
171
380
|
default:
|
|
172
|
-
|
|
381
|
+
onEntityExpired?.({
|
|
382
|
+
entityKey,
|
|
383
|
+
owner
|
|
384
|
+
});
|
|
173
385
|
break;
|
|
174
386
|
}
|
|
175
387
|
}
|
|
@@ -232,178 +444,12 @@ function createPublicClient(parameters) {
|
|
|
232
444
|
}).extend(publicActions).extend(publicArkivActions);
|
|
233
445
|
}
|
|
234
446
|
|
|
235
|
-
//#endregion
|
|
236
|
-
//#region src/utils/compression.ts
|
|
237
|
-
const logger$7 = getLogger("utils:compression");
|
|
238
|
-
const isNode = typeof process !== "undefined" && process.versions?.node != null;
|
|
239
|
-
let zlib = null;
|
|
240
|
-
let brotli = null;
|
|
241
|
-
async function getZlib() {
|
|
242
|
-
if (!isNode) return null;
|
|
243
|
-
if (!zlib) try {
|
|
244
|
-
zlib = await import("zlib");
|
|
245
|
-
} catch (error) {
|
|
246
|
-
console.error("Error importing zlib", error);
|
|
247
|
-
return null;
|
|
248
|
-
}
|
|
249
|
-
return zlib;
|
|
250
|
-
}
|
|
251
|
-
async function getBrotli() {
|
|
252
|
-
if (brotli) return brotli;
|
|
253
|
-
try {
|
|
254
|
-
const brotliModule = await import("brotli-wasm");
|
|
255
|
-
brotli = brotliModule.default ? await brotliModule.default : brotliModule;
|
|
256
|
-
} catch (error) {
|
|
257
|
-
console.error("Error importing brotli-wasm", error);
|
|
258
|
-
return null;
|
|
259
|
-
}
|
|
260
|
-
return brotli;
|
|
261
|
-
}
|
|
262
|
-
async function compress(data) {
|
|
263
|
-
logger$7("Compressing data size %d", data.length);
|
|
264
|
-
if (isNode) {
|
|
265
|
-
const zlibModule = await getZlib();
|
|
266
|
-
if (zlibModule) try {
|
|
267
|
-
const buffer = Buffer.from(data);
|
|
268
|
-
const compressed = zlibModule.brotliCompressSync(buffer);
|
|
269
|
-
const result = new Uint8Array(compressed);
|
|
270
|
-
logger$7("Brotli compressed with zlib size %d", result.length);
|
|
271
|
-
return result;
|
|
272
|
-
} catch (error) {
|
|
273
|
-
console.warn("zlib compression failed, falling back to brotli-wasm", error);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
const brotliInstance = await getBrotli();
|
|
277
|
-
if (!brotliInstance) {
|
|
278
|
-
console.warn("Brotli instance not found, not compressing data");
|
|
279
|
-
return data;
|
|
280
|
-
}
|
|
281
|
-
const brotliCompressed = brotliInstance.compress(data);
|
|
282
|
-
logger$7("Brotli compressed with wasm size %d", brotliCompressed.length);
|
|
283
|
-
return brotliCompressed;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
//#endregion
|
|
287
|
-
//#region src/utils/validation.ts
|
|
288
|
-
/**
|
|
289
|
-
* Expiration on Arkiv is measured in blocks (1 block =
|
|
290
|
-
* 2 seconds), so the value must be a positive integer that is
|
|
291
|
-
* a multiple of the block time.
|
|
292
|
-
*
|
|
293
|
-
* @param expiresIn - The expiration in seconds.
|
|
294
|
-
* @throws {InvalidExpirationError} If the value is not a positive integer that
|
|
295
|
-
* is a multiple of the block time.
|
|
296
|
-
*/
|
|
297
|
-
function validateExpiresIn(expiresIn) {
|
|
298
|
-
if (!Number.isInteger(expiresIn) || expiresIn <= 0 || expiresIn % BLOCK_TIME !== 0) throw new InvalidExpirationError(expiresIn);
|
|
299
|
-
}
|
|
300
|
-
/**
|
|
301
|
-
* Validates a single attribute. Arkiv supports string and number attribute
|
|
302
|
-
* values, but numeric values must be integers.
|
|
303
|
-
*
|
|
304
|
-
* @param attribute - The attribute to validate.
|
|
305
|
-
* @throws {InvalidAttributeError} If the attribute has a non-integer numeric
|
|
306
|
-
* value.
|
|
307
|
-
*/
|
|
308
|
-
function validateAttribute(attribute) {
|
|
309
|
-
if (typeof attribute.value === "number" && !Number.isInteger(attribute.value)) throw new InvalidAttributeError(attribute.key, attribute.value);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
//#endregion
|
|
313
|
-
//#region src/utils/arkivTransactions.ts
|
|
314
|
-
const logger$6 = getLogger("utils:arkiv-transactions");
|
|
315
|
-
function opsToTxData({ creates, updates, deletes, extensions, ownershipChanges }) {
|
|
316
|
-
function formatAttributes(attribute) {
|
|
317
|
-
return [toHex(attribute.key), toHex(typeof attribute.value === "number" && attribute.value === 0 ? "" : attribute.value)];
|
|
318
|
-
}
|
|
319
|
-
const payload = [
|
|
320
|
-
(creates ?? []).map((item) => {
|
|
321
|
-
validateExpiresIn(item.expiresIn);
|
|
322
|
-
item.attributes.forEach(validateAttribute);
|
|
323
|
-
return [
|
|
324
|
-
toHex(item.expiresIn / BLOCK_TIME),
|
|
325
|
-
toHex(item.contentType),
|
|
326
|
-
toHex(item.payload),
|
|
327
|
-
item.attributes.filter((attribute) => typeof attribute.value === "string").map(formatAttributes),
|
|
328
|
-
item.attributes.filter((attribute) => typeof attribute.value === "number").map(formatAttributes)
|
|
329
|
-
];
|
|
330
|
-
}),
|
|
331
|
-
(updates ?? []).map((item) => {
|
|
332
|
-
validateExpiresIn(item.expiresIn);
|
|
333
|
-
item.attributes.forEach(validateAttribute);
|
|
334
|
-
return [
|
|
335
|
-
item.entityKey,
|
|
336
|
-
toHex(item.contentType),
|
|
337
|
-
toHex(item.expiresIn / BLOCK_TIME),
|
|
338
|
-
toHex(item.payload),
|
|
339
|
-
item.attributes.filter((attribute) => typeof attribute.value === "string").map(formatAttributes),
|
|
340
|
-
item.attributes.filter((attribute) => typeof attribute.value === "number").map(formatAttributes)
|
|
341
|
-
];
|
|
342
|
-
}),
|
|
343
|
-
(deletes ?? []).map((item) => item.entityKey),
|
|
344
|
-
(extensions ?? []).map((item) => {
|
|
345
|
-
validateExpiresIn(item.expiresIn);
|
|
346
|
-
return [item.entityKey, toHex(item.expiresIn / BLOCK_TIME)];
|
|
347
|
-
}),
|
|
348
|
-
(ownershipChanges ?? []).map((item) => [item.entityKey, item.newOwner])
|
|
349
|
-
];
|
|
350
|
-
logger$6("txData to send as RLP %o length %d", payload, payload.length);
|
|
351
|
-
return toRlp(payload);
|
|
352
|
-
}
|
|
353
|
-
async function sendArkivTransaction(client, data, txParams) {
|
|
354
|
-
if (!client.account) throw new Error("Account required");
|
|
355
|
-
const walletClient = client;
|
|
356
|
-
logger$6("Sending transaction %o", {
|
|
357
|
-
account: client.account,
|
|
358
|
-
chain: client.chain,
|
|
359
|
-
to: ARKIV_ADDRESS,
|
|
360
|
-
value: 0n,
|
|
361
|
-
data,
|
|
362
|
-
...txParams
|
|
363
|
-
});
|
|
364
|
-
try {
|
|
365
|
-
const compressed = await compress(toBytes(data));
|
|
366
|
-
const txHash = await walletClient.sendTransaction({
|
|
367
|
-
account: client.account,
|
|
368
|
-
chain: client.chain,
|
|
369
|
-
to: ARKIV_ADDRESS,
|
|
370
|
-
value: 0n,
|
|
371
|
-
data: toHex(compressed),
|
|
372
|
-
...txParams
|
|
373
|
-
});
|
|
374
|
-
const receipt = await walletClient.waitForTransactionReceipt({ hash: txHash });
|
|
375
|
-
logger$6("Tx receipt %o", receipt);
|
|
376
|
-
if (receipt.status === "reverted") try {
|
|
377
|
-
const callResult = await walletClient.call({
|
|
378
|
-
account: client.account,
|
|
379
|
-
to: ARKIV_ADDRESS,
|
|
380
|
-
value: 0n,
|
|
381
|
-
data: toHex(compressed),
|
|
382
|
-
...txParams
|
|
383
|
-
});
|
|
384
|
-
throw new EntityMutationError(`Transaction ${receipt.transactionHash} reverted. Please make sure the data for entities doesn't contain invalid characters or invalid data types.
|
|
385
|
-
Reason: ${callResult.data ? hexToString(callResult.data) : "No reason provided by backend."}`);
|
|
386
|
-
} catch (err) {
|
|
387
|
-
const reason = err.cause?.details ?? "No reason provided by backend.";
|
|
388
|
-
logger$6("Error while calling to get more details about reverted transaction. Reason: %s", reason);
|
|
389
|
-
throw new EntityMutationError(`Transaction ${receipt.transactionHash} reverted. Reason: ${reason}`);
|
|
390
|
-
}
|
|
391
|
-
return receipt;
|
|
392
|
-
} catch (error) {
|
|
393
|
-
let message = "Transaction failed";
|
|
394
|
-
if (error instanceof TransactionExecutionError) message += `: ${error.details}`;
|
|
395
|
-
else if (error instanceof EntityMutationError) throw error;
|
|
396
|
-
logger$6("%s Detailed error stack: %o", message, error);
|
|
397
|
-
throw new EntityMutationError(message);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
447
|
//#endregion
|
|
402
448
|
//#region src/actions/wallet/changeOwnership.ts
|
|
403
449
|
const logger$5 = getLogger("actions:wallet:change-ownership");
|
|
404
450
|
async function changeOwnership(client, data, txParams) {
|
|
405
451
|
logger$5("changeOwnership %o", data);
|
|
406
|
-
const receipt = await sendArkivTransaction(client,
|
|
452
|
+
const { receipt } = await sendArkivTransaction(client, { ownershipChanges: [data] }, txParams);
|
|
407
453
|
logger$5("Receipt from changeOwnership %o", receipt);
|
|
408
454
|
return {
|
|
409
455
|
txHash: receipt.transactionHash,
|
|
@@ -416,11 +462,11 @@ async function changeOwnership(client, data, txParams) {
|
|
|
416
462
|
const logger$4 = getLogger("actions:wallet:create-entity");
|
|
417
463
|
async function createEntity(client, data, txParams) {
|
|
418
464
|
logger$4("createEntity %o", data);
|
|
419
|
-
const receipt = await sendArkivTransaction(client,
|
|
465
|
+
const { receipt, createdEntityKeys } = await sendArkivTransaction(client, { creates: [data] }, txParams);
|
|
420
466
|
logger$4("Receipt from createEntity %o", receipt);
|
|
421
467
|
return {
|
|
422
468
|
txHash: receipt.transactionHash,
|
|
423
|
-
entityKey:
|
|
469
|
+
entityKey: createdEntityKeys[0]
|
|
424
470
|
};
|
|
425
471
|
}
|
|
426
472
|
|
|
@@ -429,7 +475,7 @@ async function createEntity(client, data, txParams) {
|
|
|
429
475
|
const logger$3 = getLogger("actions:wallet:delete-entity");
|
|
430
476
|
async function deleteEntity(client, data, txParams) {
|
|
431
477
|
logger$3("deleteEntity %o", data);
|
|
432
|
-
const receipt = await sendArkivTransaction(client,
|
|
478
|
+
const { receipt } = await sendArkivTransaction(client, { deletes: [data] }, txParams);
|
|
433
479
|
logger$3("Receipt from deleteEntity %o", receipt);
|
|
434
480
|
return {
|
|
435
481
|
txHash: receipt.transactionHash,
|
|
@@ -442,61 +488,28 @@ async function deleteEntity(client, data, txParams) {
|
|
|
442
488
|
const logger$2 = getLogger("actions:wallet:extend-entity");
|
|
443
489
|
async function extendEntity(client, data, txParams) {
|
|
444
490
|
logger$2("extendEntity %o", data);
|
|
445
|
-
const receipt = await sendArkivTransaction(client,
|
|
491
|
+
const { receipt } = await sendArkivTransaction(client, { extensions: [data] }, txParams);
|
|
446
492
|
logger$2("Receipt from extendEntity %o", receipt);
|
|
447
493
|
return {
|
|
448
494
|
txHash: receipt.transactionHash,
|
|
449
|
-
entityKey:
|
|
495
|
+
entityKey: data.entityKey
|
|
450
496
|
};
|
|
451
497
|
}
|
|
452
498
|
|
|
453
499
|
//#endregion
|
|
454
500
|
//#region src/actions/wallet/mutateEntities.ts
|
|
455
501
|
const logger$1 = getLogger("actions:wallet:mutate-entities");
|
|
456
|
-
function parseReceipt(receipt, params) {
|
|
457
|
-
const createdEntities = [];
|
|
458
|
-
const updatedEntities = [];
|
|
459
|
-
const deletedEntities = [];
|
|
460
|
-
const extendedEntities = [];
|
|
461
|
-
const ownershipChanges = [];
|
|
462
|
-
const totalCreates = params.creates?.length ?? 0;
|
|
463
|
-
const totalUpdates = params.updates?.length ?? 0;
|
|
464
|
-
const totalDeletes = params.deletes?.length ?? 0;
|
|
465
|
-
const totalExtensions = params.extensions?.length ?? 0;
|
|
466
|
-
for (let index = 0; index < receipt.logs.length; index++) {
|
|
467
|
-
const log = receipt.logs[index];
|
|
468
|
-
if (index < totalCreates) createdEntities.push(log.topics[1]);
|
|
469
|
-
else if (index < totalCreates + totalDeletes) deletedEntities.push(log.topics[1]);
|
|
470
|
-
else if (index < totalCreates + totalUpdates + totalDeletes) updatedEntities.push(log.topics[1]);
|
|
471
|
-
else if (index < totalCreates + totalUpdates + totalDeletes + totalExtensions) extendedEntities.push(log.topics[1]);
|
|
472
|
-
else ownershipChanges.push(log.topics[1]);
|
|
473
|
-
}
|
|
474
|
-
return {
|
|
475
|
-
createdEntities,
|
|
476
|
-
updatedEntities,
|
|
477
|
-
deletedEntities,
|
|
478
|
-
extendedEntities,
|
|
479
|
-
ownershipChanges
|
|
480
|
-
};
|
|
481
|
-
}
|
|
482
502
|
async function mutateEntities(client, data, txParams) {
|
|
483
503
|
if (!data.creates && !data.updates && !data.deletes && !data.extensions) throw new Error("No operations to perform");
|
|
484
|
-
const receipt = await sendArkivTransaction(client,
|
|
485
|
-
creates: data.creates ?? [],
|
|
486
|
-
updates: data.updates ?? [],
|
|
487
|
-
deletes: data.deletes ?? [],
|
|
488
|
-
extensions: data.extensions ?? [],
|
|
489
|
-
ownershipChanges: data.ownershipChanges ?? []
|
|
490
|
-
}), txParams);
|
|
504
|
+
const { receipt, createdEntityKeys } = await sendArkivTransaction(client, data, txParams);
|
|
491
505
|
logger$1("Receipt from mutateEntities %o", receipt);
|
|
492
|
-
const { createdEntities, updatedEntities, deletedEntities, extendedEntities, ownershipChanges } = parseReceipt(receipt, data);
|
|
493
506
|
return {
|
|
494
507
|
txHash: receipt.transactionHash,
|
|
495
|
-
createdEntities,
|
|
496
|
-
updatedEntities,
|
|
497
|
-
deletedEntities,
|
|
498
|
-
extendedEntities,
|
|
499
|
-
ownershipChanges
|
|
508
|
+
createdEntities: createdEntityKeys,
|
|
509
|
+
updatedEntities: (data.updates ?? []).map((u) => u.entityKey),
|
|
510
|
+
deletedEntities: (data.deletes ?? []).map((d) => d.entityKey),
|
|
511
|
+
extendedEntities: (data.extensions ?? []).map((e) => e.entityKey),
|
|
512
|
+
ownershipChanges: (data.ownershipChanges ?? []).map((o) => o.entityKey)
|
|
500
513
|
};
|
|
501
514
|
}
|
|
502
515
|
|
|
@@ -505,11 +518,11 @@ async function mutateEntities(client, data, txParams) {
|
|
|
505
518
|
const logger = getLogger("actions:wallet:update-entity");
|
|
506
519
|
async function updateEntity(client, data, txParams) {
|
|
507
520
|
logger("updateEntity %o", data);
|
|
508
|
-
const receipt = await sendArkivTransaction(client,
|
|
521
|
+
const { receipt } = await sendArkivTransaction(client, { updates: [data] }, txParams);
|
|
509
522
|
logger("Receipt from updateEntity %o", receipt);
|
|
510
523
|
return {
|
|
511
524
|
txHash: receipt.transactionHash,
|
|
512
|
-
entityKey:
|
|
525
|
+
entityKey: data.entityKey
|
|
513
526
|
};
|
|
514
527
|
}
|
|
515
528
|
|
|
@@ -572,5 +585,5 @@ function chainFromName(name) {
|
|
|
572
585
|
}
|
|
573
586
|
|
|
574
587
|
//#endregion
|
|
575
|
-
export { EntityMutationError, InvalidAttributeError, InvalidExpirationError, NoCursorOrLimitError, NoEntityFoundError, NoMoreResultsError, chainFromName, createPublicClient, createWalletClient, jsonToPayload, stringToPayload };
|
|
588
|
+
export { DuplicateAttributeError, EntityMutationError, EntityOperationType, InvalidAttributeError, InvalidAttributeKeyError, InvalidContentTypeError, InvalidExpirationError, NoCursorOrLimitError, NoEntityFoundError, NoMoreResultsError, chainFromName, createPublicClient, createWalletClient, jsonToPayload, stringToPayload };
|
|
576
589
|
//# sourceMappingURL=index.js.map
|