@aboutcircles/sdk-pathfinder 0.1.5 → 0.1.7

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.
@@ -1,6 +1,24 @@
1
- import type { FlowMatrix, TransferStep, Address } from '@aboutcircles/sdk-types';
1
+ import type { FlowMatrix, TransferStep, Address, Hex } from '@aboutcircles/sdk-types';
2
2
  /**
3
3
  * Create an ABI‑ready FlowMatrix object from a list of TransferSteps.
4
+ *
5
+ * @param from - Sender address
6
+ * @param to - Receiver address
7
+ * @param value - Total value to transfer
8
+ * @param transfers - List of transfer steps
4
9
  */
5
10
  export declare function createFlowMatrix(from: Address, to: Address, value: bigint, transfers: TransferStep[]): FlowMatrix;
11
+ /**
12
+ * Prepare flow matrix streams with hex-encoded data for ABI encoding
13
+ * Converts Uint8Array data to hex strings and adds optional txData to the first stream
14
+ *
15
+ * @param flowMatrix - The flow matrix to prepare
16
+ * @param txData - Optional transaction data to attach to the first stream
17
+ * @returns Array of streams with hex-encoded data ready for contract calls
18
+ */
19
+ export declare function prepareFlowMatrixStreams(flowMatrix: FlowMatrix, txData?: Hex | Uint8Array): Array<{
20
+ sourceCoordinate: number;
21
+ flowEdgeIds: readonly number[];
22
+ data: Hex;
23
+ }>;
6
24
  //# sourceMappingURL=flowMatrix.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"flowMatrix.d.ts","sourceRoot":"","sources":["../src/flowMatrix.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAgC,MAAM,yBAAyB,CAAC;AAG/G;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,OAAO,EACb,EAAE,EAAE,OAAO,EACX,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,YAAY,EAAE,GACxB,UAAU,CAmEZ"}
1
+ {"version":3,"file":"flowMatrix.d.ts","sourceRoot":"","sources":["../src/flowMatrix.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAgC,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAsDpH;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,OAAO,EACb,EAAE,EAAE,OAAO,EACX,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,YAAY,EAAE,GACxB,UAAU,CAiEZ;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,UAAU,EACtB,MAAM,CAAC,EAAE,GAAG,GAAG,UAAU,GACxB,KAAK,CAAC;IAAE,gBAAgB,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,GAAG,CAAA;CAAE,CAAC,CAiBhF"}
@@ -1,30 +1,73 @@
1
1
  import { packCoordinates, transformToFlowVertices } from './packing';
2
+ import { bytesToHex } from '@aboutcircles/sdk-utils/bytes';
3
+ /**
4
+ * Detect terminal edges using graph analysis
5
+ *
6
+ * Terminal edge detection algorithm:
7
+ * 1. Identify all edges that deliver value to the receiver
8
+ * 2. Check if there's a self-loop at the receiver (aggregate pattern)
9
+ * 3. If self-loop exists: it's the ONLY terminal edge (aggregates all incoming flows)
10
+ * 4. If no self-loop: all edges TO receiver are terminal (standard multi-path flow)
11
+ *
12
+ * This handles:
13
+ * - Aggregate mode: receiver collects tokens, then self-transfers to consolidate
14
+ * - Standard mode: multiple paths deliver directly to receiver
15
+ * - Mixed scenarios: correctly identifies final delivery point
16
+ */
17
+ function detectTerminalEdges(transfers, receiver) {
18
+ const terminalEdges = new Set();
19
+ // Build adjacency info: track edges TO receiver and self-loops
20
+ const edgesToReceiver = [];
21
+ let selfLoopIndex = null;
22
+ transfers.forEach((t, index) => {
23
+ const fromLower = t.from.toLowerCase();
24
+ const toLower = t.to.toLowerCase();
25
+ // Check if this is a self-loop at the receiver
26
+ if (fromLower === receiver && toLower === receiver) {
27
+ selfLoopIndex = index;
28
+ }
29
+ // Check if this edge delivers to receiver
30
+ else if (toLower === receiver) {
31
+ edgesToReceiver.push(index);
32
+ }
33
+ });
34
+ // Decision logic:
35
+ // If self-loop exists, it's the aggregation edge (ONLY terminal)
36
+ // Otherwise, all edges delivering to receiver are terminal
37
+ if (selfLoopIndex !== null) {
38
+ terminalEdges.add(selfLoopIndex);
39
+ }
40
+ else {
41
+ edgesToReceiver.forEach(idx => terminalEdges.add(idx));
42
+ }
43
+ return terminalEdges;
44
+ }
2
45
  /**
3
46
  * Create an ABI‑ready FlowMatrix object from a list of TransferSteps.
47
+ *
48
+ * @param from - Sender address
49
+ * @param to - Receiver address
50
+ * @param value - Total value to transfer
51
+ * @param transfers - List of transfer steps
4
52
  */
5
53
  export function createFlowMatrix(from, to, value, transfers) {
6
54
  const sender = from.toLowerCase();
7
55
  const receiver = to.toLowerCase();
8
56
  const { sorted: flowVertices, idx } = transformToFlowVertices(transfers, sender, receiver);
9
- const flowEdges = transfers.map((t) => {
10
- const isTerminal = t.to.toLowerCase() === receiver;
57
+ // Use graph analysis to detect terminal edges
58
+ const terminalEdgeIndices = detectTerminalEdges(transfers, receiver);
59
+ const flowEdges = transfers.map((t, index) => {
60
+ const isTerminal = terminalEdgeIndices.has(index);
11
61
  return {
12
62
  streamSinkId: isTerminal ? 1 : 0,
13
63
  amount: t.value
14
64
  };
15
65
  });
16
- // Ensure at least one terminal edge
17
- const hasTerminalEdge = flowEdges.some((e) => e.streamSinkId === 1);
18
- if (!hasTerminalEdge) {
19
- const lastEdgeIndex = transfers
20
- .map((t) => t.to.toLowerCase())
21
- .lastIndexOf(receiver);
22
- const fallbackIndex = lastEdgeIndex === -1 ? flowEdges.length - 1 : lastEdgeIndex;
23
- flowEdges[fallbackIndex].streamSinkId = 1;
66
+ // Validation: ensure at least one terminal edge exists
67
+ if (terminalEdgeIndices.size === 0) {
68
+ throw new Error(`No terminal edges detected. Flow must have at least one edge delivering to receiver ${receiver}`);
24
69
  }
25
- const termEdgeIds = flowEdges
26
- .map((e, i) => (e.streamSinkId === 1 ? i : -1))
27
- .filter((i) => i !== -1);
70
+ const termEdgeIds = Array.from(terminalEdgeIndices);
28
71
  const streams = [
29
72
  {
30
73
  sourceCoordinate: idx[sender],
@@ -55,3 +98,27 @@ export function createFlowMatrix(from, to, value, transfers) {
55
98
  sourceCoordinate: idx[sender]
56
99
  };
57
100
  }
101
+ /**
102
+ * Prepare flow matrix streams with hex-encoded data for ABI encoding
103
+ * Converts Uint8Array data to hex strings and adds optional txData to the first stream
104
+ *
105
+ * @param flowMatrix - The flow matrix to prepare
106
+ * @param txData - Optional transaction data to attach to the first stream
107
+ * @returns Array of streams with hex-encoded data ready for contract calls
108
+ */
109
+ export function prepareFlowMatrixStreams(flowMatrix, txData) {
110
+ const streams = flowMatrix.streams.map((stream) => ({
111
+ sourceCoordinate: stream.sourceCoordinate,
112
+ flowEdgeIds: stream.flowEdgeIds,
113
+ data: stream.data instanceof Uint8Array
114
+ ? bytesToHex(stream.data)
115
+ : stream.data,
116
+ }));
117
+ // Attach txData to the first stream if provided
118
+ if (txData && streams.length > 0) {
119
+ streams[0].data = txData instanceof Uint8Array
120
+ ? bytesToHex(txData)
121
+ : txData;
122
+ }
123
+ return streams;
124
+ }