@canton-network/core-tx-parser 0.1.0

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/index.cjs ADDED
@@ -0,0 +1,1019 @@
1
+ 'use strict';
2
+
3
+ var coreTokenStandard = require('@canton-network/core-token-standard');
4
+ var coreLedgerClientTypes = require('@canton-network/core-ledger-client-types');
5
+ var BigNumber = require('bignumber.js');
6
+
7
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
+
9
+ var BigNumber__default = /*#__PURE__*/_interopDefault(BigNumber);
10
+
11
+ var __defProp = Object.defineProperty;
12
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
13
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
14
+ function splitInterfaceId(interfaceId) {
15
+ const regExp = /^#?([^:]+):([^:]+):([^:]+)$/;
16
+ const match = regExp.exec(interfaceId);
17
+ if (!match) return null;
18
+ const [, packageName, moduleName, entityName] = match;
19
+ return {
20
+ packageName,
21
+ moduleName,
22
+ entityName
23
+ };
24
+ }
25
+ function matchInterfaceIds(a, b) {
26
+ const aParts = splitInterfaceId(a);
27
+ const bParts = splitInterfaceId(b);
28
+ return aParts !== null && bParts !== null && aParts.moduleName === bParts.moduleName && aParts.entityName === bParts.entityName;
29
+ }
30
+ var TokenStandardTransactionInterfaces = [
31
+ coreTokenStandard.HOLDING_INTERFACE_ID,
32
+ coreTokenStandard.TRANSFER_FACTORY_INTERFACE_ID,
33
+ coreTokenStandard.TRANSFER_INSTRUCTION_INTERFACE_ID,
34
+ coreTokenStandard.ALLOCATION_FACTORY_INTERFACE_ID,
35
+ coreTokenStandard.ALLOCATION_INSTRUCTION_INTERFACE_ID,
36
+ coreTokenStandard.ALLOCATION_INTERFACE_ID,
37
+ coreTokenStandard.ALLOCATION_REQUEST_INTERFACE_ID
38
+ ];
39
+ var SpliceMetaKeyPrefix = "splice.lfdecentralizedtrust.org/";
40
+ var TxKindMetaKey = `${SpliceMetaKeyPrefix}tx-kind`;
41
+ var SenderMetaKey = `${SpliceMetaKeyPrefix}sender`;
42
+ var ReasonMetaKey = `${SpliceMetaKeyPrefix}reason`;
43
+ var BurnedMetaKey = `${SpliceMetaKeyPrefix}burned`;
44
+ var AllKnownMetaKeys = [
45
+ TxKindMetaKey,
46
+ SenderMetaKey,
47
+ ReasonMetaKey,
48
+ BurnedMetaKey
49
+ ];
50
+ function hasInterface(interfaceId, event) {
51
+ return (event.implementedInterfaces || []).some(
52
+ (id) => matchInterfaceIds(id, interfaceId)
53
+ );
54
+ }
55
+ function getInterfaceView(createdEvent) {
56
+ const interfaceViews = createdEvent.interfaceViews || null;
57
+ return interfaceViews && interfaceViews[0] || null;
58
+ }
59
+ function getKnownInterfaceView(createdEvent) {
60
+ const interfaceView = getInterfaceView(createdEvent);
61
+ if (!interfaceView) {
62
+ return null;
63
+ } else if (matchInterfaceIds(coreTokenStandard.HOLDING_INTERFACE_ID, interfaceView.interfaceId)) {
64
+ return {
65
+ type: "Holding",
66
+ viewValue: interfaceView.viewValue
67
+ };
68
+ } else if (matchInterfaceIds(
69
+ coreTokenStandard.TRANSFER_INSTRUCTION_INTERFACE_ID,
70
+ interfaceView.interfaceId
71
+ )) {
72
+ return {
73
+ type: "TransferInstruction",
74
+ viewValue: interfaceView.viewValue
75
+ };
76
+ } else {
77
+ return null;
78
+ }
79
+ }
80
+ function ensureInterfaceViewIsPresent(createdEvent, interfaceId) {
81
+ const interfaceView = getInterfaceView(createdEvent);
82
+ if (!interfaceView) {
83
+ throw new Error(
84
+ `Expected to have interface views, but didn't: ${JSON.stringify(
85
+ createdEvent
86
+ )}`
87
+ );
88
+ }
89
+ if (!matchInterfaceIds(interfaceId, interfaceView.interfaceId)) {
90
+ throw new Error(
91
+ `Not a ${interfaceId} but a ${interfaceView.interfaceId}: ${JSON.stringify(createdEvent)}`
92
+ );
93
+ }
94
+ return interfaceView;
95
+ }
96
+ function mergeMetas(event, extra) {
97
+ const choiceArgument = event.choiceArgument;
98
+ const lastWriteWins = [
99
+ choiceArgument?.transfer?.meta,
100
+ choiceArgument?.extraArgs?.meta,
101
+ choiceArgument?.meta,
102
+ extra,
103
+ event.exerciseResult?.meta
104
+ ];
105
+ const result = {};
106
+ lastWriteWins.forEach((meta) => {
107
+ const values = meta?.values || {};
108
+ Object.entries(values).forEach(([k, v]) => {
109
+ result[k] = v;
110
+ });
111
+ });
112
+ if (Object.keys(result).length === 0) {
113
+ return void 0;
114
+ } else {
115
+ return { values: result };
116
+ }
117
+ }
118
+ function getMetaKeyValue(key, meta) {
119
+ return (meta?.values || {})[key] || null;
120
+ }
121
+ function removeParsedMetaKeys(meta) {
122
+ return {
123
+ values: Object.fromEntries(
124
+ Object.entries(meta?.values || {}).filter(
125
+ ([k]) => !AllKnownMetaKeys.includes(k)
126
+ )
127
+ )
128
+ };
129
+ }
130
+
131
+ // src/types.ts
132
+ var renderTransaction = (t) => {
133
+ return { ...t, events: t.events.map(renderTransactionEvent) };
134
+ };
135
+ var renderTransactionEvent = (e) => {
136
+ const lockedHoldingsChangeSummaries = e.lockedHoldingsChangeSummaries.map(renderHoldingsChangeSummary).filter((s) => s !== null);
137
+ const unlockedHoldingsChangeSummaries = e.unlockedHoldingsChangeSummaries.map(renderHoldingsChangeSummary).filter((s) => s !== null);
138
+ const lockedHoldingsChange = renderHoldingsChange(e.lockedHoldingsChange);
139
+ const unlockedHoldingsChange = renderHoldingsChange(
140
+ e.unlockedHoldingsChange
141
+ );
142
+ return {
143
+ ...e,
144
+ lockedHoldingsChange,
145
+ unlockedHoldingsChange,
146
+ lockedHoldingsChangeSummaries,
147
+ // Deprecated
148
+ lockedHoldingsChangeSummary: renderHoldingsChangeSummary(
149
+ e.lockedHoldingsChangeSummary
150
+ ),
151
+ unlockedHoldingsChangeSummaries,
152
+ // Deprecated
153
+ unlockedHoldingsChangeSummary: renderHoldingsChangeSummary(
154
+ e.unlockedHoldingsChangeSummary
155
+ )
156
+ };
157
+ };
158
+ var renderHoldingsChangeSummary = (s) => {
159
+ if (s.numInputs === 0 && s.numOutputs === 0 && s.inputAmount === "0" && s.outputAmount === "0" && s.amountChange === "0") {
160
+ return null;
161
+ }
162
+ return {
163
+ ...(s.instrumentId.admin !== "" || s.instrumentId.id !== "") && {
164
+ instrumentId: s.instrumentId
165
+ },
166
+ ...s.numInputs !== 0 && { numInputs: s.numInputs },
167
+ ...s.inputAmount !== "0" && { inputAmount: s.inputAmount },
168
+ ...s.numOutputs !== 0 && { numOutputs: s.numOutputs },
169
+ ...s.outputAmount !== "0" && { outputAmount: s.outputAmount },
170
+ ...s.amountChange !== "0" && { amountChange: s.amountChange }
171
+ };
172
+ };
173
+ var renderHoldingsChange = (c) => {
174
+ if (c.creates.length === 0 && c.archives.length === 0) {
175
+ return null;
176
+ }
177
+ return {
178
+ ...c.creates.length !== 0 && { creates: c.creates },
179
+ ...c.archives.length !== 0 && { archives: c.archives }
180
+ };
181
+ };
182
+
183
+ // src/instrumentmap.ts
184
+ var InstrumentMap = class {
185
+ constructor() {
186
+ __publicField(this, "map");
187
+ this.map = /* @__PURE__ */ new Map();
188
+ }
189
+ encodeKey(instrumentId) {
190
+ return JSON.stringify([instrumentId.admin, instrumentId.id]);
191
+ }
192
+ decodeKey(key) {
193
+ const [admin, id] = JSON.parse(key);
194
+ return { admin, id };
195
+ }
196
+ set(key, value) {
197
+ this.map.set(this.encodeKey(key), value);
198
+ }
199
+ get(key) {
200
+ return this.map.get(this.encodeKey(key));
201
+ }
202
+ has(key) {
203
+ return this.map.has(this.encodeKey(key));
204
+ }
205
+ delete(key) {
206
+ return this.map.delete(this.encodeKey(key));
207
+ }
208
+ *entries() {
209
+ for (const [key, value] of this.map.entries()) {
210
+ yield [this.decodeKey(key), value];
211
+ }
212
+ }
213
+ };
214
+ function currentStatusFromChoiceOrResult(choice, resultTag) {
215
+ if (resultTag === "TransferInstructionResult_Failed") return "Failed";
216
+ if (resultTag === "TransferInstructionResult_Completed") return "Completed";
217
+ switch (choice) {
218
+ case "TransferInstruction_Reject":
219
+ return "Rejected";
220
+ case "TransferInstruction_Withdraw":
221
+ return "Withdrawn";
222
+ case "TransferInstruction_Accept":
223
+ case "TransferInstruction_Update":
224
+ return "Pending";
225
+ default:
226
+ return "Pending";
227
+ }
228
+ }
229
+ function getCorrelationIdFromTransferInstruction(currentInstructionCid, originalInstructionCid) {
230
+ return originalInstructionCid ?? currentInstructionCid;
231
+ }
232
+ function getPendingTransferInstructionCid(exercisedEvent) {
233
+ const output = exercisedEvent.exerciseResult?.output;
234
+ if (output?.tag !== "TransferInstructionResult_Pending") return void 0;
235
+ const cid = output.value?.transferInstructionCid;
236
+ return cid ?? void 0;
237
+ }
238
+ function isTransferObject(value) {
239
+ if (!value || typeof value !== "object") return false;
240
+ const v = value;
241
+ const instrumentId = v.instrumentId;
242
+ const meta = v.meta;
243
+ return typeof v.sender === "string" && typeof v.receiver === "string" && typeof v.amount === "string" && typeof v.requestedAt === "string" && typeof v.executeBefore === "string" && Array.isArray(v.inputHoldingCids) && v.inputHoldingCids.every((cid) => typeof cid === "string") && !!instrumentId && typeof instrumentId.admin === "string" && typeof instrumentId.id === "string" && !!meta && typeof meta.values === "object" && meta.values !== null;
244
+ }
245
+ var TransactionParser = class {
246
+ constructor(transaction, ledgerClient, partyId, isMasterUser) {
247
+ __publicField(this, "ledgerClient");
248
+ __publicField(this, "partyId");
249
+ __publicField(this, "transaction");
250
+ __publicField(this, "isMasterUser");
251
+ this.ledgerClient = ledgerClient;
252
+ this.partyId = partyId;
253
+ this.transaction = transaction;
254
+ this.isMasterUser = isMasterUser;
255
+ }
256
+ async parseTransaction() {
257
+ const tx = this.transaction;
258
+ const events = await this.parseEvents([...tx.events || []].reverse());
259
+ return {
260
+ updateId: tx.updateId,
261
+ offset: tx.offset,
262
+ recordTime: tx.recordTime,
263
+ synchronizerId: tx.synchronizerId,
264
+ events
265
+ };
266
+ }
267
+ async parseTransferObjects() {
268
+ const eventsStack = [...this.transaction.events || []].reverse();
269
+ const results = await this.fetchTransferObjectChoice(eventsStack);
270
+ return results;
271
+ }
272
+ async fetchTransferObjectChoice(eventsStack) {
273
+ const result = [];
274
+ while (eventsStack.length > 0) {
275
+ const currentEvent = eventsStack.pop();
276
+ const { exercisedEvent } = getNodeIdAndEvent(currentEvent);
277
+ if (exercisedEvent && (exercisedEvent.choice === "TransferFactory_Transfer" || exercisedEvent.choice === "TransferRule_Transfer")) {
278
+ const { choiceArgument } = exercisedEvent;
279
+ if (choiceArgument && typeof choiceArgument === "object" && "transfer" in choiceArgument) {
280
+ const transfer = choiceArgument.transfer;
281
+ if (isTransferObject(transfer)) {
282
+ result.push(transfer);
283
+ }
284
+ }
285
+ }
286
+ }
287
+ return result;
288
+ }
289
+ async parseEvents(eventsStack) {
290
+ let callStack = [];
291
+ let continueAfterNodeId = -1;
292
+ const result = [];
293
+ while (eventsStack.length > 0) {
294
+ const currentEvent = eventsStack.pop();
295
+ const { nodeId, createdEvent, archivedEvent, exercisedEvent } = getNodeIdAndEvent(currentEvent);
296
+ callStack = callStack.filter((s) => s.untilNodeId <= nodeId);
297
+ const parentChoice = callStack[callStack.length - 1] && callStack[callStack.length - 1].parentChoiceName || "none (root node)";
298
+ let parsed;
299
+ if (nodeId <= continueAfterNodeId) {
300
+ parsed = null;
301
+ } else if (createdEvent) {
302
+ parsed = this.parseRawCreate(createdEvent, parentChoice);
303
+ } else if (archivedEvent) {
304
+ parsed = await this.parseRawArchive(archivedEvent, parentChoice);
305
+ } else if (exercisedEvent) {
306
+ parsed = await this.parseExercise(exercisedEvent);
307
+ } else {
308
+ throw new Error(
309
+ `Impossible event: ${JSON.stringify(currentEvent)}`
310
+ );
311
+ }
312
+ if (parsed && isLeafEventNode(parsed)) {
313
+ if (holdingChangesNonEmpty(parsed.event)) {
314
+ result.push({
315
+ ...parsed.event,
316
+ label: {
317
+ ...parsed.event.label,
318
+ meta: removeParsedMetaKeys(parsed.event.label.meta)
319
+ }
320
+ });
321
+ }
322
+ continueAfterNodeId = parsed.continueAfterNodeId;
323
+ } else if (parsed) {
324
+ callStack.push({
325
+ parentChoiceName: parsed.parentChoiceName,
326
+ untilNodeId: parsed.lastDescendantNodeId
327
+ });
328
+ }
329
+ }
330
+ return result;
331
+ }
332
+ parseRawCreate(create, parentChoice) {
333
+ return this.buildRawEvent(create, create.nodeId, (result) => {
334
+ return {
335
+ // TODO: this code currently only looks at the first instrument
336
+ // to determine the type of the Event.
337
+ type: Number(
338
+ result.lockedHoldingsChangeSummaries[0]?.amountChange
339
+ ) > 0 ? "Lock" : "Create",
340
+ parentChoice,
341
+ contractId: create.contractId,
342
+ offset: create.offset,
343
+ templateId: create.templateId,
344
+ payload: result.payload,
345
+ packageName: create.packageName,
346
+ meta: void 0
347
+ };
348
+ });
349
+ }
350
+ async parseRawArchive(archive, parentChoice) {
351
+ const events = await this.getEventsForArchive(archive);
352
+ if (!events) {
353
+ return null;
354
+ }
355
+ return this.buildRawEvent(
356
+ events.created.createdEvent,
357
+ archive.nodeId,
358
+ (result) => {
359
+ return {
360
+ type: "Archive",
361
+ parentChoice,
362
+ contractId: archive.contractId,
363
+ offset: archive.offset,
364
+ templateId: archive.templateId,
365
+ packageName: archive.packageName,
366
+ actingParties: archive.actingParties || [],
367
+ payload: result.payload,
368
+ meta: void 0
369
+ };
370
+ }
371
+ );
372
+ }
373
+ buildRawEvent(originalCreate, nodeId, buildLabel) {
374
+ const view = getKnownInterfaceView(originalCreate);
375
+ let result;
376
+ switch (view?.type) {
377
+ case "Holding": {
378
+ const holdingView = view.viewValue;
379
+ if (this.partyId !== holdingView.owner) {
380
+ result = null;
381
+ } else {
382
+ const isLocked = !!holdingView.lock;
383
+ const summary = {
384
+ instrumentId: holdingView.instrumentId,
385
+ amountChange: holdingView.amount,
386
+ numInputs: 0,
387
+ inputAmount: "0",
388
+ numOutputs: 1,
389
+ outputAmount: holdingView.amount
390
+ };
391
+ const lockedHoldingsChangeSummaries = isLocked ? [summary] : [];
392
+ const unlockedHoldingsChangeSummaries = isLocked ? [] : [summary];
393
+ result = {
394
+ payload: holdingView,
395
+ unlockedHoldingsChange: {
396
+ creates: isLocked ? [] : [holdingView],
397
+ archives: []
398
+ },
399
+ lockedHoldingsChange: {
400
+ creates: isLocked ? [holdingView] : [],
401
+ archives: []
402
+ },
403
+ lockedHoldingsChangeSummaries,
404
+ lockedHoldingsChangeSummary: lockedHoldingsChangeSummaries[0] ?? emptyHoldingsChangeSummary,
405
+ unlockedHoldingsChangeSummaries,
406
+ unlockedHoldingsChangeSummary: unlockedHoldingsChangeSummaries[0] ?? emptyHoldingsChangeSummary,
407
+ transferInstruction: null
408
+ };
409
+ }
410
+ break;
411
+ }
412
+ case "TransferInstruction": {
413
+ const transferInstructionView = view.viewValue;
414
+ if (![
415
+ transferInstructionView.transfer.sender,
416
+ transferInstructionView.transfer.receiver
417
+ ].some((stakeholder) => stakeholder === this.partyId)) {
418
+ result = null;
419
+ } else {
420
+ const multiStepCorrelationId = getCorrelationIdFromTransferInstruction(
421
+ originalCreate.contractId,
422
+ transferInstructionView.originalInstructionCid ?? null
423
+ );
424
+ result = {
425
+ payload: transferInstructionView,
426
+ transferInstruction: {
427
+ originalInstructionCid: transferInstructionView.originalInstructionCid,
428
+ transfer: transferInstructionView.transfer,
429
+ meta: transferInstructionView.meta,
430
+ status: {
431
+ before: transferInstructionView.status,
432
+ // raw DAML pending sub-state
433
+ current: { tag: "Pending", value: {} }
434
+ // normalized
435
+ },
436
+ multiStepCorrelationId
437
+ },
438
+ unlockedHoldingsChange: { creates: [], archives: [] },
439
+ lockedHoldingsChange: { creates: [], archives: [] },
440
+ unlockedHoldingsChangeSummaries: [],
441
+ unlockedHoldingsChangeSummary: emptyHoldingsChangeSummary,
442
+ lockedHoldingsChangeSummaries: [],
443
+ lockedHoldingsChangeSummary: emptyHoldingsChangeSummary
444
+ };
445
+ }
446
+ break;
447
+ }
448
+ default:
449
+ result = null;
450
+ }
451
+ return result && {
452
+ continueAfterNodeId: nodeId,
453
+ event: {
454
+ label: buildLabel(result),
455
+ unlockedHoldingsChange: result.unlockedHoldingsChange,
456
+ lockedHoldingsChange: result.lockedHoldingsChange,
457
+ lockedHoldingsChangeSummaries: result.lockedHoldingsChangeSummaries,
458
+ lockedHoldingsChangeSummary: result.lockedHoldingsChangeSummary,
459
+ unlockedHoldingsChangeSummaries: result.unlockedHoldingsChangeSummaries,
460
+ unlockedHoldingsChangeSummary: result.unlockedHoldingsChangeSummary,
461
+ transferInstruction: result.transferInstruction
462
+ }
463
+ };
464
+ }
465
+ async parseExercise(exercise) {
466
+ let result = null;
467
+ const tokenStandardChoice = {
468
+ name: exercise.choice,
469
+ choiceArgument: exercise.choiceArgument,
470
+ exerciseResult: exercise.exerciseResult
471
+ };
472
+ switch (exercise.choice) {
473
+ case "TransferRule_Transfer":
474
+ case "TransferFactory_Transfer":
475
+ result = await this.buildTransfer(exercise, tokenStandardChoice);
476
+ break;
477
+ case "TransferInstruction_Accept":
478
+ case "TransferInstruction_Reject":
479
+ case "TransferInstruction_Withdraw":
480
+ case "TransferInstruction_Update":
481
+ result = await this.buildFromTransferInstructionExercise(
482
+ exercise,
483
+ tokenStandardChoice
484
+ );
485
+ break;
486
+ case "BurnMintFactory_BurnMint":
487
+ result = await this.buildMergeSplit(
488
+ exercise,
489
+ tokenStandardChoice
490
+ );
491
+ break;
492
+ default: {
493
+ const meta = mergeMetas(exercise);
494
+ const txKind = getMetaKeyValue(TxKindMetaKey, meta);
495
+ if (txKind) {
496
+ result = await this.parseViaTxKind(exercise, txKind);
497
+ }
498
+ break;
499
+ }
500
+ }
501
+ if (!result) {
502
+ return {
503
+ lastDescendantNodeId: exercise.lastDescendantNodeId,
504
+ parentChoiceName: exercise.choice
505
+ };
506
+ } else {
507
+ const lockedHoldingsChange = {
508
+ creates: result.children.creates.filter(
509
+ (h) => !!h.lock && h.owner === this.partyId
510
+ ),
511
+ archives: result.children.archives.filter(
512
+ (h) => !!h.lock && h.owner === this.partyId
513
+ )
514
+ };
515
+ const unlockedHoldingsChange = {
516
+ creates: result.children.creates.filter(
517
+ (h) => !h.lock && h.owner === this.partyId
518
+ ),
519
+ archives: result.children.archives.filter(
520
+ (h) => !h.lock && h.owner === this.partyId
521
+ )
522
+ };
523
+ const lockedHoldingsChangeSummaries = computeSummaries(
524
+ lockedHoldingsChange,
525
+ this.partyId
526
+ );
527
+ const unlockedHoldingsChangeSummaries = computeSummaries(
528
+ unlockedHoldingsChange,
529
+ this.partyId
530
+ );
531
+ return {
532
+ event: {
533
+ label: result.label,
534
+ lockedHoldingsChange,
535
+ lockedHoldingsChangeSummaries,
536
+ lockedHoldingsChangeSummary: lockedHoldingsChangeSummaries[0] ?? emptyHoldingsChangeSummary,
537
+ unlockedHoldingsChange,
538
+ unlockedHoldingsChangeSummaries,
539
+ unlockedHoldingsChangeSummary: unlockedHoldingsChangeSummaries[0] ?? emptyHoldingsChangeSummary,
540
+ transferInstruction: result.transferInstruction
541
+ },
542
+ continueAfterNodeId: exercise.lastDescendantNodeId
543
+ };
544
+ }
545
+ }
546
+ async parseViaTxKind(exercisedEvent, txKind) {
547
+ switch (txKind) {
548
+ case "transfer":
549
+ return await this.buildTransfer(exercisedEvent, null);
550
+ case "merge-split":
551
+ case "burn":
552
+ case "mint":
553
+ return await this.buildMergeSplit(exercisedEvent, null);
554
+ case "unlock":
555
+ return await this.buildBasic(exercisedEvent, "Unlock", null);
556
+ case "expire-dust":
557
+ return await this.buildBasic(exercisedEvent, "ExpireDust", null);
558
+ default:
559
+ throw new Error(
560
+ `Unknown tx-kind '${txKind}' in ${JSON.stringify(exercisedEvent)}`
561
+ );
562
+ }
563
+ }
564
+ async buildTransfer(exercisedEvent, tokenStandardChoice, transferInstructions) {
565
+ const meta = mergeMetas(
566
+ exercisedEvent,
567
+ transferInstructions?.transfer?.meta
568
+ );
569
+ const reason = getMetaKeyValue(ReasonMetaKey, meta);
570
+ const choiceArgumentTransfer = exercisedEvent.choiceArgument.transfer;
571
+ const sender = transferInstructions?.transfer?.sender || getMetaKeyValue(SenderMetaKey, meta) || choiceArgumentTransfer.sender;
572
+ if (!sender) {
573
+ console.error(
574
+ `Malformed transfer didn't contain sender. Will instead attempt to parse the children.
575
+ Transfer: ${JSON.stringify(exercisedEvent)}`
576
+ );
577
+ return null;
578
+ }
579
+ const resultTag = exercisedEvent.exerciseResult?.output?.tag || void 0;
580
+ const pendingCid = getPendingTransferInstructionCid(exercisedEvent);
581
+ const currentTag = currentStatusFromChoiceOrResult(
582
+ exercisedEvent.choice,
583
+ resultTag
584
+ );
585
+ const children = await this.getChildren(exercisedEvent);
586
+ const receiverAmounts = /* @__PURE__ */ new Map();
587
+ children.creates.filter((h) => h.owner !== sender).forEach(
588
+ (holding) => receiverAmounts.set(
589
+ holding.owner,
590
+ (receiverAmounts.get(holding.owner) || BigNumber__default.default("0")).plus(
591
+ BigNumber__default.default(holding.amount)
592
+ )
593
+ )
594
+ );
595
+ const amountChanges = computeAmountChanges(children, meta, this.partyId);
596
+ let label;
597
+ if (receiverAmounts.size === 0) {
598
+ label = {
599
+ ...amountChanges,
600
+ type: "MergeSplit",
601
+ tokenStandardChoice,
602
+ reason,
603
+ meta
604
+ };
605
+ } else if (sender === this.partyId) {
606
+ label = {
607
+ ...amountChanges,
608
+ type: "TransferOut",
609
+ receiverAmounts: [...receiverAmounts].map(([k, v]) => {
610
+ return { receiver: k, amount: v.toString() };
611
+ }),
612
+ tokenStandardChoice,
613
+ reason,
614
+ meta
615
+ };
616
+ } else {
617
+ label = {
618
+ type: "TransferIn",
619
+ // for Transfers, the burn/mint is always 0 for the receiving party (i.e., 0 for TransferIn)
620
+ burnAmount: "0",
621
+ mintAmount: "0",
622
+ sender,
623
+ tokenStandardChoice,
624
+ reason,
625
+ meta
626
+ };
627
+ }
628
+ if (transferInstructions) {
629
+ transferInstructions.status.current = transferInstructions.status.current || { tag: currentTag, value: {} };
630
+ return {
631
+ label,
632
+ children,
633
+ transferInstruction: transferInstructions
634
+ };
635
+ }
636
+ const transferInstruction = {
637
+ originalInstructionCid: null,
638
+ ...choiceArgumentTransfer !== void 0 && {
639
+ transfer: choiceArgumentTransfer
640
+ },
641
+ status: {
642
+ before: null,
643
+ current: { tag: currentTag, value: {} }
644
+ },
645
+ meta: null,
646
+ ...pendingCid ? { multiStepCorrelationId: pendingCid } : {}
647
+ };
648
+ return {
649
+ label,
650
+ children,
651
+ transferInstruction
652
+ };
653
+ }
654
+ async buildMergeSplit(exercisedEvent, tokenStandardChoice) {
655
+ let type;
656
+ const meta = mergeMetas(exercisedEvent);
657
+ switch (getMetaKeyValue(TxKindMetaKey, meta)) {
658
+ case "burn":
659
+ type = "Burn";
660
+ break;
661
+ case "mint":
662
+ type = "Mint";
663
+ break;
664
+ default:
665
+ type = "MergeSplit";
666
+ }
667
+ const reason = getMetaKeyValue(ReasonMetaKey, meta);
668
+ const children = await this.getChildren(exercisedEvent);
669
+ const amountChanges = computeAmountChanges(children, meta, this.partyId);
670
+ const label = {
671
+ ...amountChanges,
672
+ type,
673
+ tokenStandardChoice,
674
+ reason,
675
+ meta
676
+ };
677
+ return {
678
+ label,
679
+ children,
680
+ transferInstruction: null
681
+ };
682
+ }
683
+ async buildFromTransferInstructionExercise(exercisedEvent, tokenStandardChoice) {
684
+ const instructionCid = exercisedEvent.contractId;
685
+ const transferInstructionEvents = await this.getEventsForArchive(exercisedEvent);
686
+ if (!transferInstructionEvents) {
687
+ return null;
688
+ }
689
+ const transferInstructionView = ensureInterfaceViewIsPresent(
690
+ transferInstructionEvents.created.createdEvent,
691
+ coreTokenStandard.TRANSFER_INSTRUCTION_INTERFACE_ID
692
+ ).viewValue;
693
+ const multiStepCorrelationId = getCorrelationIdFromTransferInstruction(
694
+ instructionCid,
695
+ transferInstructionView.originalInstructionCid ?? null
696
+ );
697
+ const resultTag = exercisedEvent.exerciseResult?.output?.tag || void 0;
698
+ const currentTag = currentStatusFromChoiceOrResult(
699
+ exercisedEvent.choice,
700
+ resultTag
701
+ );
702
+ const transferInstruction = {
703
+ originalInstructionCid: transferInstructionView.originalInstructionCid,
704
+ multiStepCorrelationId,
705
+ transfer: transferInstructionView.transfer,
706
+ meta: transferInstructionView.meta,
707
+ status: {
708
+ before: transferInstructionView.status,
709
+ current: { tag: currentTag, value: {} }
710
+ }
711
+ };
712
+ const exerciseResultOutputTag = resultTag;
713
+ let result = null;
714
+ switch (exerciseResultOutputTag) {
715
+ case "TransferInstructionResult_Failed":
716
+ case "TransferInstructionResult_Pending":
717
+ result = await this.buildMergeSplit(
718
+ exercisedEvent,
719
+ tokenStandardChoice
720
+ );
721
+ break;
722
+ case "TransferInstructionResult_Completed":
723
+ result = await this.buildTransfer(
724
+ exercisedEvent,
725
+ tokenStandardChoice,
726
+ transferInstruction
727
+ );
728
+ break;
729
+ default:
730
+ throw new Error(
731
+ `Unknown TransferInstructionResult: ${exerciseResultOutputTag}`
732
+ );
733
+ }
734
+ return result && {
735
+ ...result,
736
+ transferInstruction
737
+ };
738
+ }
739
+ async buildBasic(exercisedEvent, type, tokenStandardChoice) {
740
+ const children = await this.getChildren(exercisedEvent);
741
+ const meta = mergeMetas(exercisedEvent);
742
+ const amountChanges = computeAmountChanges(children, meta, this.partyId);
743
+ const reason = getMetaKeyValue(ReasonMetaKey, meta);
744
+ return {
745
+ label: {
746
+ ...amountChanges,
747
+ type,
748
+ tokenStandardChoice,
749
+ reason,
750
+ meta
751
+ },
752
+ children,
753
+ transferInstruction: null
754
+ };
755
+ }
756
+ async getChildren(exercisedEvent) {
757
+ const mutatingResult = { creates: [], archives: [] };
758
+ const childrenEventsSlice = (this.transaction.events || []).map(getNodeIdAndEvent).filter(
759
+ ({ nodeId }) => nodeId > exercisedEvent.nodeId && nodeId <= exercisedEvent.lastDescendantNodeId
760
+ );
761
+ if (exercisedEvent.consuming && hasInterface(coreTokenStandard.HOLDING_INTERFACE_ID, exercisedEvent)) {
762
+ const selfEvent = await this.getEventsForArchive(exercisedEvent);
763
+ if (selfEvent) {
764
+ const holdingView = ensureInterfaceViewIsPresent(
765
+ selfEvent.created.createdEvent,
766
+ coreTokenStandard.HOLDING_INTERFACE_ID
767
+ ).viewValue;
768
+ mutatingResult.archives.push({
769
+ amount: holdingView.amount,
770
+ instrumentId: holdingView.instrumentId,
771
+ contractId: exercisedEvent.contractId,
772
+ owner: holdingView.owner,
773
+ meta: holdingView.meta,
774
+ lock: holdingView.lock
775
+ });
776
+ }
777
+ }
778
+ for (const {
779
+ createdEvent,
780
+ archivedEvent,
781
+ exercisedEvent: exercisedEvent2
782
+ } of childrenEventsSlice) {
783
+ if (createdEvent) {
784
+ const interfaceView = getInterfaceView(createdEvent);
785
+ if (interfaceView && matchInterfaceIds(
786
+ coreTokenStandard.HOLDING_INTERFACE_ID,
787
+ interfaceView.interfaceId
788
+ )) {
789
+ const holdingView = interfaceView.viewValue;
790
+ mutatingResult.creates.push({
791
+ amount: holdingView.amount,
792
+ instrumentId: holdingView.instrumentId,
793
+ contractId: createdEvent.contractId,
794
+ owner: holdingView.owner,
795
+ meta: holdingView.meta,
796
+ lock: holdingView.lock
797
+ });
798
+ }
799
+ } else if (archivedEvent && hasInterface(coreTokenStandard.HOLDING_INTERFACE_ID, archivedEvent) || exercisedEvent2 && exercisedEvent2.consuming && hasInterface(coreTokenStandard.HOLDING_INTERFACE_ID, exercisedEvent2)) {
800
+ const contractEvents = await this.getEventsForArchive(
801
+ archivedEvent || exercisedEvent2
802
+ );
803
+ if (contractEvents) {
804
+ const holdingView = ensureInterfaceViewIsPresent(
805
+ contractEvents.created?.createdEvent,
806
+ coreTokenStandard.HOLDING_INTERFACE_ID
807
+ ).viewValue;
808
+ mutatingResult.archives.push({
809
+ amount: holdingView.amount,
810
+ instrumentId: holdingView.instrumentId,
811
+ contractId: archivedEvent?.contractId || exercisedEvent2.contractId,
812
+ owner: holdingView.owner,
813
+ meta: holdingView.meta,
814
+ lock: holdingView.lock
815
+ });
816
+ }
817
+ }
818
+ }
819
+ return {
820
+ // remove transient contracts
821
+ creates: mutatingResult.creates.filter(
822
+ (create) => !mutatingResult.archives.some(
823
+ (archive) => create.contractId === archive.contractId
824
+ )
825
+ ),
826
+ archives: mutatingResult.archives.filter(
827
+ (archive) => !mutatingResult.creates.some(
828
+ (create) => create.contractId === archive.contractId
829
+ )
830
+ )
831
+ };
832
+ }
833
+ async getEventsForArchive(archivedEvent) {
834
+ if (!(archivedEvent.witnessParties || []).includes(this.partyId)) {
835
+ return null;
836
+ }
837
+ const basePayload = {
838
+ contractId: archivedEvent.contractId,
839
+ eventFormat: coreLedgerClientTypes.EventFilterBySetup({
840
+ interfaceIds: [
841
+ coreTokenStandard.HOLDING_INTERFACE_ID,
842
+ coreTokenStandard.TRANSFER_INSTRUCTION_INTERFACE_ID
843
+ ],
844
+ isMasterUser: this.isMasterUser,
845
+ partyId: this.partyId,
846
+ verbose: true
847
+ })
848
+ };
849
+ const payload = this.ledgerClient.getCurrentClientVersion() === "3.3" ? { ...basePayload, requestingParties: [] } : basePayload;
850
+ const events = await this.ledgerClient.postWithRetry("/v2/events/events-by-contract-id", payload).catch((err) => {
851
+ if (err.code === "CONTRACT_EVENTS_NOT_FOUND") {
852
+ return null;
853
+ } else {
854
+ throw err;
855
+ }
856
+ });
857
+ if (!events) {
858
+ return null;
859
+ }
860
+ const created = events.created;
861
+ const archived = events.archived;
862
+ if (!created || !archived) {
863
+ throw new Error(
864
+ `Archival of ${archivedEvent.contractId} does not have a corresponding create/archive event: ${JSON.stringify(
865
+ events
866
+ )}`
867
+ );
868
+ }
869
+ return { created, archived };
870
+ }
871
+ };
872
+ function isLeafEventNode(result) {
873
+ return !!result.event;
874
+ }
875
+ function getNodeIdAndEvent(event) {
876
+ if ("ExercisedEvent" in event) {
877
+ if (event.ExercisedEvent.choice === "Archive") {
878
+ return {
879
+ nodeId: event.ExercisedEvent.nodeId,
880
+ archivedEvent: event.ExercisedEvent
881
+ };
882
+ } else {
883
+ return {
884
+ nodeId: event.ExercisedEvent.nodeId,
885
+ exercisedEvent: event.ExercisedEvent
886
+ };
887
+ }
888
+ } else if ("CreatedEvent" in event) {
889
+ return {
890
+ nodeId: event.CreatedEvent.nodeId,
891
+ createdEvent: event.CreatedEvent
892
+ };
893
+ } else if ("ArchivedEvent" in event) {
894
+ return {
895
+ nodeId: event.ArchivedEvent.nodeId,
896
+ archivedEvent: event.ArchivedEvent
897
+ };
898
+ } else {
899
+ throw new Error(`Impossible event type: ${event}`);
900
+ }
901
+ }
902
+ function sumHoldingsChange(change, filter) {
903
+ return sumHoldings(
904
+ change.creates.filter((create) => filter(create.owner, create.lock))
905
+ ).minus(
906
+ sumHoldings(
907
+ change.archives.filter(
908
+ (archive) => filter(archive.owner, archive.lock)
909
+ )
910
+ )
911
+ );
912
+ }
913
+ function sumHoldings(holdings) {
914
+ if (holdings.length > 0) {
915
+ const instrumentId = holdings[0].instrumentId;
916
+ for (const holding of holdings) {
917
+ if (holding.instrumentId.admin !== instrumentId.admin || holding.instrumentId.id !== instrumentId.id) {
918
+ throw new Error(
919
+ `Attempted to call sumHoldings on heterogeneous instruments: ${JSON.stringify(instrumentId)} != ${JSON.stringify(holding.instrumentId)}`
920
+ );
921
+ }
922
+ }
923
+ }
924
+ return BigNumber__default.default.sum(
925
+ ...holdings.map((h) => h.amount).concat(["0"])
926
+ // avoid NaN
927
+ );
928
+ }
929
+ function computeAmountChanges(children, meta, partyId) {
930
+ const burnAmount = BigNumber__default.default(getMetaKeyValue(BurnedMetaKey, meta) || "0");
931
+ const partyHoldingAmountChange = sumHoldingsChange(
932
+ children,
933
+ (owner) => owner === partyId
934
+ );
935
+ const otherPartiesHoldingAmountChange = sumHoldingsChange(
936
+ children,
937
+ (owner) => owner !== partyId
938
+ );
939
+ const mintAmount = partyHoldingAmountChange.plus(burnAmount).plus(otherPartiesHoldingAmountChange);
940
+ return {
941
+ burnAmount: burnAmount.toString(),
942
+ mintAmount: mintAmount.toString()
943
+ };
944
+ }
945
+ function computeSummary(instrumentId, changes, partyId) {
946
+ const amountChange = sumHoldingsChange(
947
+ changes,
948
+ (owner) => owner === partyId
949
+ );
950
+ const outputAmount = sumHoldings(changes.creates);
951
+ const inputAmount = sumHoldings(changes.archives);
952
+ return {
953
+ instrumentId,
954
+ amountChange: amountChange.toString(),
955
+ numOutputs: changes.creates.length,
956
+ outputAmount: outputAmount.toString(),
957
+ numInputs: changes.archives.length,
958
+ inputAmount: inputAmount.toString()
959
+ };
960
+ }
961
+ function holdingsChangeByInstrument(changes) {
962
+ const map = new InstrumentMap();
963
+ for (const create of changes.creates) {
964
+ if (map.has(create.instrumentId)) {
965
+ map.get(create.instrumentId).creates.push(create);
966
+ } else {
967
+ map.set(create.instrumentId, { creates: [create], archives: [] });
968
+ }
969
+ }
970
+ for (const archive of changes.archives) {
971
+ if (map.has(archive.instrumentId)) {
972
+ map.get(archive.instrumentId).archives.push(archive);
973
+ } else {
974
+ map.set(archive.instrumentId, { creates: [], archives: [archive] });
975
+ }
976
+ }
977
+ return map;
978
+ }
979
+ function computeSummaries(changes, partyId) {
980
+ const byInstrument = holdingsChangeByInstrument(changes);
981
+ return [...byInstrument.entries()].map(
982
+ ([instrumentId, change]) => computeSummary(instrumentId, change, partyId)
983
+ );
984
+ }
985
+ function holdingChangesNonEmpty(event) {
986
+ return event.unlockedHoldingsChange.creates.length > 0 || event.unlockedHoldingsChange.archives.length > 0 || event.lockedHoldingsChange.creates.length > 0 || event.lockedHoldingsChange.archives.length > 0;
987
+ }
988
+ var emptyHoldingsChangeSummary = {
989
+ // This is obviously incorrect, but the field was introduced at the same
990
+ // time at which we introduced the more correct per-instrument summaries,
991
+ // so we know that old code couldn't use this (broken) field, and new code
992
+ // should use the correct summaries.
993
+ instrumentId: { admin: "", id: "" },
994
+ numInputs: 0,
995
+ numOutputs: 0,
996
+ inputAmount: "0",
997
+ outputAmount: "0",
998
+ amountChange: "0"
999
+ };
1000
+
1001
+ exports.AllKnownMetaKeys = AllKnownMetaKeys;
1002
+ exports.BurnedMetaKey = BurnedMetaKey;
1003
+ exports.ReasonMetaKey = ReasonMetaKey;
1004
+ exports.SenderMetaKey = SenderMetaKey;
1005
+ exports.TokenStandardTransactionInterfaces = TokenStandardTransactionInterfaces;
1006
+ exports.TransactionParser = TransactionParser;
1007
+ exports.TxKindMetaKey = TxKindMetaKey;
1008
+ exports.ensureInterfaceViewIsPresent = ensureInterfaceViewIsPresent;
1009
+ exports.getInterfaceView = getInterfaceView;
1010
+ exports.getKnownInterfaceView = getKnownInterfaceView;
1011
+ exports.getMetaKeyValue = getMetaKeyValue;
1012
+ exports.hasInterface = hasInterface;
1013
+ exports.matchInterfaceIds = matchInterfaceIds;
1014
+ exports.mergeMetas = mergeMetas;
1015
+ exports.removeParsedMetaKeys = removeParsedMetaKeys;
1016
+ exports.renderTransaction = renderTransaction;
1017
+ exports.splitInterfaceId = splitInterfaceId;
1018
+ //# sourceMappingURL=index.cjs.map
1019
+ //# sourceMappingURL=index.cjs.map