@jack-kernel/sdk 1.0.0 → 1.2.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/cjs/index.js +125 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/lifi/chain-map.js +39 -0
- package/dist/cjs/lifi/chain-map.js.map +1 -0
- package/dist/cjs/lifi/fallback.js +135 -0
- package/dist/cjs/lifi/fallback.js.map +1 -0
- package/dist/cjs/lifi/index.js +34 -0
- package/dist/cjs/lifi/index.js.map +1 -0
- package/dist/cjs/lifi/lifi-provider.js +496 -0
- package/dist/cjs/lifi/lifi-provider.js.map +1 -0
- package/dist/cjs/lifi/token-map.js +75 -0
- package/dist/cjs/lifi/token-map.js.map +1 -0
- package/dist/cjs/lifi/types.js +3 -0
- package/dist/cjs/lifi/types.js.map +1 -0
- package/dist/cjs/lifi/utils.js +45 -0
- package/dist/cjs/lifi/utils.js.map +1 -0
- package/dist/cjs/yellow/channel-state-manager.js +167 -0
- package/dist/cjs/yellow/channel-state-manager.js.map +1 -0
- package/dist/cjs/yellow/clear-node-connection.js +390 -0
- package/dist/cjs/yellow/clear-node-connection.js.map +1 -0
- package/dist/cjs/yellow/event-mapper.js +254 -0
- package/dist/cjs/yellow/event-mapper.js.map +1 -0
- package/dist/cjs/yellow/serialization.js +130 -0
- package/dist/cjs/yellow/serialization.js.map +1 -0
- package/dist/cjs/yellow/session-key-manager.js +308 -0
- package/dist/cjs/yellow/session-key-manager.js.map +1 -0
- package/dist/cjs/yellow/types.js +12 -0
- package/dist/cjs/yellow/types.js.map +1 -0
- package/dist/cjs/yellow/yellow-provider.js +1545 -0
- package/dist/cjs/yellow/yellow-provider.js.map +1 -0
- package/dist/esm/index.js +102 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lifi/chain-map.js +35 -0
- package/dist/esm/lifi/chain-map.js.map +1 -0
- package/dist/esm/lifi/fallback.js +128 -0
- package/dist/esm/lifi/fallback.js.map +1 -0
- package/dist/esm/lifi/index.js +19 -0
- package/dist/esm/lifi/index.js.map +1 -0
- package/dist/esm/lifi/lifi-provider.js +492 -0
- package/dist/esm/lifi/lifi-provider.js.map +1 -0
- package/dist/esm/lifi/token-map.js +71 -0
- package/dist/esm/lifi/token-map.js.map +1 -0
- package/dist/esm/lifi/types.js +2 -0
- package/dist/esm/lifi/types.js.map +1 -0
- package/dist/esm/lifi/utils.js +41 -0
- package/dist/esm/lifi/utils.js.map +1 -0
- package/dist/esm/yellow/channel-state-manager.js +163 -0
- package/dist/esm/yellow/channel-state-manager.js.map +1 -0
- package/dist/esm/yellow/clear-node-connection.js +385 -0
- package/dist/esm/yellow/clear-node-connection.js.map +1 -0
- package/dist/esm/yellow/event-mapper.js +248 -0
- package/dist/esm/yellow/event-mapper.js.map +1 -0
- package/dist/esm/yellow/serialization.js +125 -0
- package/dist/esm/yellow/serialization.js.map +1 -0
- package/dist/esm/yellow/session-key-manager.js +302 -0
- package/dist/esm/yellow/session-key-manager.js.map +1 -0
- package/dist/esm/yellow/types.js +11 -0
- package/dist/esm/yellow/types.js.map +1 -0
- package/dist/esm/yellow/yellow-provider.js +1538 -0
- package/dist/esm/yellow/yellow-provider.js.map +1 -0
- package/dist/types/index.d.ts +104 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lifi/chain-map.d.ts +27 -0
- package/dist/types/lifi/chain-map.d.ts.map +1 -0
- package/dist/types/lifi/fallback.d.ts +58 -0
- package/dist/types/lifi/fallback.d.ts.map +1 -0
- package/dist/types/lifi/index.d.ts +18 -0
- package/dist/types/lifi/index.d.ts.map +1 -0
- package/dist/types/lifi/lifi-provider.d.ts +133 -0
- package/dist/types/lifi/lifi-provider.d.ts.map +1 -0
- package/dist/types/lifi/token-map.d.ts +34 -0
- package/dist/types/lifi/token-map.d.ts.map +1 -0
- package/dist/types/lifi/types.d.ts +52 -0
- package/dist/types/lifi/types.d.ts.map +1 -0
- package/dist/types/lifi/utils.d.ts +29 -0
- package/dist/types/lifi/utils.d.ts.map +1 -0
- package/dist/types/yellow/channel-state-manager.d.ts +106 -0
- package/dist/types/yellow/channel-state-manager.d.ts.map +1 -0
- package/dist/types/yellow/clear-node-connection.d.ts +202 -0
- package/dist/types/yellow/clear-node-connection.d.ts.map +1 -0
- package/dist/types/yellow/event-mapper.d.ts +74 -0
- package/dist/types/yellow/event-mapper.d.ts.map +1 -0
- package/dist/types/yellow/serialization.d.ts +52 -0
- package/dist/types/yellow/serialization.d.ts.map +1 -0
- package/dist/types/yellow/session-key-manager.d.ts +179 -0
- package/dist/types/yellow/session-key-manager.d.ts.map +1 -0
- package/dist/types/yellow/types.d.ts +177 -0
- package/dist/types/yellow/types.d.ts.map +1 -0
- package/dist/types/yellow/yellow-provider.d.ts +303 -0
- package/dist/types/yellow/yellow-provider.d.ts.map +1 -0
- package/package.json +4 -1
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Yellow Network Event-to-Status Mapper
|
|
3
|
+
*
|
|
4
|
+
* Maps Yellow Network events, channel statuses, and state intents to JACK
|
|
5
|
+
* ExecutionStatus values. These are pure functions with no side effects,
|
|
6
|
+
* extracted from the dashboard's route.ts mapping tables into SDK-level
|
|
7
|
+
* reusable functions.
|
|
8
|
+
*
|
|
9
|
+
* Requirements: 9.1, 9.2, 9.3, 9.4, 9.5, 9.6
|
|
10
|
+
*/
|
|
11
|
+
import { ExecutionStatus } from '../types.js';
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Terminal statuses — only SETTLED, ABORTED, and EXPIRED are terminal
|
|
14
|
+
// ============================================================================
|
|
15
|
+
const TERMINAL_STATUSES = new Set([
|
|
16
|
+
ExecutionStatus.SETTLED,
|
|
17
|
+
ExecutionStatus.ABORTED,
|
|
18
|
+
ExecutionStatus.EXPIRED,
|
|
19
|
+
]);
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Yellow Event Mapping Table
|
|
22
|
+
// ============================================================================
|
|
23
|
+
const EVENT_STATUS_MAP = {
|
|
24
|
+
quote_accepted: {
|
|
25
|
+
executionStatus: ExecutionStatus.QUOTED,
|
|
26
|
+
stepLabel: 'Solver Quote Accepted (Yellow Network)',
|
|
27
|
+
stepStatus: 'COMPLETED',
|
|
28
|
+
isTerminal: false,
|
|
29
|
+
},
|
|
30
|
+
solver_quoted: {
|
|
31
|
+
executionStatus: ExecutionStatus.QUOTED,
|
|
32
|
+
stepLabel: 'Solver Quote Received (Yellow Network)',
|
|
33
|
+
stepStatus: 'COMPLETED',
|
|
34
|
+
isTerminal: false,
|
|
35
|
+
},
|
|
36
|
+
execution_started: {
|
|
37
|
+
executionStatus: ExecutionStatus.EXECUTING,
|
|
38
|
+
stepLabel: 'Execution Started (Yellow Network)',
|
|
39
|
+
stepStatus: 'IN_PROGRESS',
|
|
40
|
+
isTerminal: false,
|
|
41
|
+
},
|
|
42
|
+
routing_started: {
|
|
43
|
+
executionStatus: ExecutionStatus.EXECUTING,
|
|
44
|
+
stepLabel: 'Cross-Chain Routing Started (Yellow Network)',
|
|
45
|
+
stepStatus: 'IN_PROGRESS',
|
|
46
|
+
isTerminal: false,
|
|
47
|
+
},
|
|
48
|
+
settlement_submitted: {
|
|
49
|
+
executionStatus: ExecutionStatus.SETTLING,
|
|
50
|
+
stepLabel: 'Settlement Submitted (Yellow Network)',
|
|
51
|
+
stepStatus: 'IN_PROGRESS',
|
|
52
|
+
isTerminal: false,
|
|
53
|
+
},
|
|
54
|
+
settled: {
|
|
55
|
+
executionStatus: ExecutionStatus.SETTLED,
|
|
56
|
+
stepLabel: 'Settlement Finalized (Yellow Network)',
|
|
57
|
+
stepStatus: 'COMPLETED',
|
|
58
|
+
isTerminal: true,
|
|
59
|
+
},
|
|
60
|
+
settlement_finalized: {
|
|
61
|
+
executionStatus: ExecutionStatus.SETTLED,
|
|
62
|
+
stepLabel: 'Settlement Finalized (Yellow Network)',
|
|
63
|
+
stepStatus: 'COMPLETED',
|
|
64
|
+
isTerminal: true,
|
|
65
|
+
},
|
|
66
|
+
failed: {
|
|
67
|
+
executionStatus: ExecutionStatus.ABORTED,
|
|
68
|
+
stepLabel: 'Execution Failed (Yellow Network)',
|
|
69
|
+
stepStatus: 'FAILED',
|
|
70
|
+
isTerminal: true,
|
|
71
|
+
},
|
|
72
|
+
execution_failed: {
|
|
73
|
+
executionStatus: ExecutionStatus.ABORTED,
|
|
74
|
+
stepLabel: 'Execution Failed (Yellow Network)',
|
|
75
|
+
stepStatus: 'FAILED',
|
|
76
|
+
isTerminal: true,
|
|
77
|
+
},
|
|
78
|
+
settlement_failed: {
|
|
79
|
+
executionStatus: ExecutionStatus.ABORTED,
|
|
80
|
+
stepLabel: 'Settlement Failed (Yellow Network)',
|
|
81
|
+
stepStatus: 'FAILED',
|
|
82
|
+
isTerminal: true,
|
|
83
|
+
},
|
|
84
|
+
expired: {
|
|
85
|
+
executionStatus: ExecutionStatus.EXPIRED,
|
|
86
|
+
stepLabel: 'Intent Expired (Yellow Network)',
|
|
87
|
+
stepStatus: 'FAILED',
|
|
88
|
+
isTerminal: true,
|
|
89
|
+
},
|
|
90
|
+
canceled: {
|
|
91
|
+
executionStatus: ExecutionStatus.ABORTED,
|
|
92
|
+
stepLabel: 'Intent Canceled (Yellow Network)',
|
|
93
|
+
stepStatus: 'FAILED',
|
|
94
|
+
isTerminal: true,
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
// ============================================================================
|
|
98
|
+
// Channel Status Mapping Table
|
|
99
|
+
// ============================================================================
|
|
100
|
+
const CHANNEL_STATUS_MAP = {
|
|
101
|
+
void: {
|
|
102
|
+
executionStatus: ExecutionStatus.CREATED,
|
|
103
|
+
stepLabel: 'Channel Status: VOID (ERC-7824)',
|
|
104
|
+
stepStatus: 'COMPLETED',
|
|
105
|
+
isTerminal: false,
|
|
106
|
+
},
|
|
107
|
+
initial: {
|
|
108
|
+
executionStatus: ExecutionStatus.QUOTED,
|
|
109
|
+
stepLabel: 'Channel Status: INITIAL (ERC-7824)',
|
|
110
|
+
stepStatus: 'IN_PROGRESS',
|
|
111
|
+
isTerminal: false,
|
|
112
|
+
},
|
|
113
|
+
active: {
|
|
114
|
+
executionStatus: ExecutionStatus.EXECUTING,
|
|
115
|
+
stepLabel: 'Channel Status: ACTIVE (ERC-7824)',
|
|
116
|
+
stepStatus: 'IN_PROGRESS',
|
|
117
|
+
isTerminal: false,
|
|
118
|
+
},
|
|
119
|
+
dispute: {
|
|
120
|
+
executionStatus: ExecutionStatus.EXECUTING,
|
|
121
|
+
stepLabel: 'Channel Status: DISPUTE (ERC-7824)',
|
|
122
|
+
stepStatus: 'IN_PROGRESS',
|
|
123
|
+
isTerminal: false,
|
|
124
|
+
},
|
|
125
|
+
final: {
|
|
126
|
+
executionStatus: ExecutionStatus.SETTLED,
|
|
127
|
+
stepLabel: 'Channel Status: FINAL (ERC-7824)',
|
|
128
|
+
stepStatus: 'COMPLETED',
|
|
129
|
+
isTerminal: true,
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
// ============================================================================
|
|
133
|
+
// State Intent Mapping Table
|
|
134
|
+
// ============================================================================
|
|
135
|
+
const STATE_INTENT_MAP = {
|
|
136
|
+
initialize: {
|
|
137
|
+
executionStatus: ExecutionStatus.QUOTED,
|
|
138
|
+
stepLabel: 'State Intent: INITIALIZE (ERC-7824)',
|
|
139
|
+
stepStatus: 'IN_PROGRESS',
|
|
140
|
+
isTerminal: false,
|
|
141
|
+
},
|
|
142
|
+
operate: {
|
|
143
|
+
executionStatus: ExecutionStatus.EXECUTING,
|
|
144
|
+
stepLabel: 'State Intent: OPERATE (ERC-7824)',
|
|
145
|
+
stepStatus: 'IN_PROGRESS',
|
|
146
|
+
isTerminal: false,
|
|
147
|
+
},
|
|
148
|
+
resize: {
|
|
149
|
+
executionStatus: ExecutionStatus.EXECUTING,
|
|
150
|
+
stepLabel: 'State Intent: RESIZE (ERC-7824)',
|
|
151
|
+
stepStatus: 'COMPLETED',
|
|
152
|
+
isTerminal: false,
|
|
153
|
+
},
|
|
154
|
+
finalize: {
|
|
155
|
+
executionStatus: ExecutionStatus.SETTLED,
|
|
156
|
+
stepLabel: 'State Intent: FINALIZE (ERC-7824)',
|
|
157
|
+
stepStatus: 'COMPLETED',
|
|
158
|
+
isTerminal: true,
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
// ============================================================================
|
|
162
|
+
// Normalization Helper
|
|
163
|
+
// ============================================================================
|
|
164
|
+
/**
|
|
165
|
+
* Normalizes an event/status/intent string to lowercase with underscores.
|
|
166
|
+
* Trims whitespace and replaces spaces and hyphens with underscores.
|
|
167
|
+
*/
|
|
168
|
+
function normalizeKey(value) {
|
|
169
|
+
return value.trim().toLowerCase().replace(/[\s-]+/g, '_');
|
|
170
|
+
}
|
|
171
|
+
// ============================================================================
|
|
172
|
+
// Public Mapping Functions
|
|
173
|
+
// ============================================================================
|
|
174
|
+
/**
|
|
175
|
+
* Map a Yellow Network event name to a JACK MappedEvent.
|
|
176
|
+
*
|
|
177
|
+
* Accepts event names in any casing; normalizes to lowercase with underscores.
|
|
178
|
+
* Returns undefined for unknown events.
|
|
179
|
+
*
|
|
180
|
+
* @param event - The Yellow Network event name (e.g., "quote_accepted", "settled")
|
|
181
|
+
* @returns The corresponding MappedEvent, or undefined if the event is unknown
|
|
182
|
+
*
|
|
183
|
+
* Requirements: 9.1, 9.2, 9.3, 9.4, 9.5
|
|
184
|
+
*/
|
|
185
|
+
export function mapYellowEvent(event) {
|
|
186
|
+
const key = normalizeKey(event);
|
|
187
|
+
return Object.hasOwn(EVENT_STATUS_MAP, key) ? EVENT_STATUS_MAP[key] : undefined;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Map a channel status to a JACK MappedEvent.
|
|
191
|
+
*
|
|
192
|
+
* Accepts channel statuses in any casing (e.g., "ACTIVE", "active", "Active").
|
|
193
|
+
* Returns undefined for unknown statuses.
|
|
194
|
+
*
|
|
195
|
+
* @param status - The ERC-7824 channel status (e.g., "VOID", "ACTIVE", "FINAL")
|
|
196
|
+
* @returns The corresponding MappedEvent, or undefined if the status is unknown
|
|
197
|
+
*
|
|
198
|
+
* Requirement: 9.6
|
|
199
|
+
*/
|
|
200
|
+
export function mapChannelStatus(status) {
|
|
201
|
+
const key = normalizeKey(status);
|
|
202
|
+
return Object.hasOwn(CHANNEL_STATUS_MAP, key) ? CHANNEL_STATUS_MAP[key] : undefined;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Map a state intent to a JACK MappedEvent.
|
|
206
|
+
*
|
|
207
|
+
* Accepts state intents in any casing (e.g., "FINALIZE", "finalize", "Finalize").
|
|
208
|
+
* Returns undefined for unknown intents.
|
|
209
|
+
*
|
|
210
|
+
* @param intent - The ERC-7824 state intent (e.g., "INITIALIZE", "OPERATE", "FINALIZE")
|
|
211
|
+
* @returns The corresponding MappedEvent, or undefined if the intent is unknown
|
|
212
|
+
*
|
|
213
|
+
* Requirement: 9.6
|
|
214
|
+
*/
|
|
215
|
+
export function mapStateIntent(intent) {
|
|
216
|
+
const key = normalizeKey(intent);
|
|
217
|
+
return Object.hasOwn(STATE_INTENT_MAP, key) ? STATE_INTENT_MAP[key] : undefined;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Infer the best mapping from a notification payload.
|
|
221
|
+
*
|
|
222
|
+
* Checks fields in priority order: event → channelStatus → stateIntent.
|
|
223
|
+
* Returns the first successful mapping, or undefined if no field matches.
|
|
224
|
+
*
|
|
225
|
+
* @param notification - An object with optional event, channelStatus, and stateIntent fields
|
|
226
|
+
* @returns The best matching MappedEvent, or undefined if no mapping is found
|
|
227
|
+
*
|
|
228
|
+
* Requirements: 9.1, 9.2, 9.3, 9.4, 9.5, 9.6
|
|
229
|
+
*/
|
|
230
|
+
export function inferMapping(notification) {
|
|
231
|
+
if (notification.event) {
|
|
232
|
+
const mapped = mapYellowEvent(notification.event);
|
|
233
|
+
if (mapped)
|
|
234
|
+
return mapped;
|
|
235
|
+
}
|
|
236
|
+
if (notification.channelStatus) {
|
|
237
|
+
const mapped = mapChannelStatus(notification.channelStatus);
|
|
238
|
+
if (mapped)
|
|
239
|
+
return mapped;
|
|
240
|
+
}
|
|
241
|
+
if (notification.stateIntent) {
|
|
242
|
+
const mapped = mapStateIntent(notification.stateIntent);
|
|
243
|
+
if (mapped)
|
|
244
|
+
return mapped;
|
|
245
|
+
}
|
|
246
|
+
return undefined;
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=event-mapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-mapper.js","sourceRoot":"","sources":["../../../src/yellow/event-mapper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Yellow Network Integration - BigInt Serialization Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides helpers to ensure all BigInt values from NitroliteClient responses
|
|
5
|
+
* are converted to string representations in public-facing types, making
|
|
6
|
+
* ChannelState and YellowQuote objects fully JSON-serializable via JSON.stringify.
|
|
7
|
+
*
|
|
8
|
+
* Requirements: 11.1, 11.2, 11.5
|
|
9
|
+
*/
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Core BigInt-to-string conversion
|
|
12
|
+
// ============================================================================
|
|
13
|
+
/**
|
|
14
|
+
* Recursively converts any BigInt values in an object (or nested objects/arrays)
|
|
15
|
+
* to their string representation. All other value types are left unchanged.
|
|
16
|
+
*
|
|
17
|
+
* This is the foundational utility used by the type-specific helpers below.
|
|
18
|
+
* It handles the case where NitroliteClient responses may contain raw BigInt
|
|
19
|
+
* values that would cause JSON.stringify to throw.
|
|
20
|
+
*
|
|
21
|
+
* @param value - Any value that may contain BigInt values at any nesting level
|
|
22
|
+
* @returns A new value with all BigInt instances replaced by their string form
|
|
23
|
+
*
|
|
24
|
+
* Requirement 11.5: Convert BigInt values to string representation for JSON compatibility
|
|
25
|
+
*/
|
|
26
|
+
export function serializeBigIntToString(value) {
|
|
27
|
+
if (typeof value === 'bigint') {
|
|
28
|
+
return value.toString();
|
|
29
|
+
}
|
|
30
|
+
if (value === null || value === undefined) {
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
if (Array.isArray(value)) {
|
|
34
|
+
return value.map((item) => serializeBigIntToString(item));
|
|
35
|
+
}
|
|
36
|
+
if (typeof value === 'object') {
|
|
37
|
+
const result = {};
|
|
38
|
+
for (const [key, val] of Object.entries(value)) {
|
|
39
|
+
result[key] = serializeBigIntToString(val);
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
// Primitive types (string, number, boolean) pass through unchanged
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
// ============================================================================
|
|
47
|
+
// Type-specific serialization helpers
|
|
48
|
+
// ============================================================================
|
|
49
|
+
/**
|
|
50
|
+
* Ensures a ChannelState object is fully JSON-serializable.
|
|
51
|
+
*
|
|
52
|
+
* Converts any BigInt values that may be present in the ChannelState
|
|
53
|
+
* (particularly in allocation amounts, challengePeriod, challengeExpiration,
|
|
54
|
+
* stateVersion, chainId, createdAt, updatedAt) to their appropriate
|
|
55
|
+
* JSON-compatible types (string for amounts, number for numeric fields).
|
|
56
|
+
*
|
|
57
|
+
* @param state - A ChannelState that may contain BigInt values from NitroliteClient
|
|
58
|
+
* @returns A new ChannelState with all values JSON-serializable
|
|
59
|
+
*
|
|
60
|
+
* Requirements: 11.1, 11.5
|
|
61
|
+
*/
|
|
62
|
+
export function toSerializableChannelState(state) {
|
|
63
|
+
return {
|
|
64
|
+
channelId: String(state.channelId),
|
|
65
|
+
status: state.status,
|
|
66
|
+
chainId: Number(state.chainId),
|
|
67
|
+
token: String(state.token),
|
|
68
|
+
allocations: state.allocations.map(toSerializableAllocation),
|
|
69
|
+
stateVersion: Number(state.stateVersion),
|
|
70
|
+
stateIntent: String(state.stateIntent),
|
|
71
|
+
stateHash: state.stateHash !== undefined ? String(state.stateHash) : undefined,
|
|
72
|
+
adjudicator: String(state.adjudicator),
|
|
73
|
+
challengePeriod: Number(state.challengePeriod),
|
|
74
|
+
challengeExpiration: state.challengeExpiration !== undefined ? Number(state.challengeExpiration) : undefined,
|
|
75
|
+
createdAt: Number(state.createdAt),
|
|
76
|
+
updatedAt: Number(state.updatedAt),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Ensures a ChannelAllocation object is fully JSON-serializable.
|
|
81
|
+
*
|
|
82
|
+
* The `amount` field is the most likely to contain a BigInt from NitroliteClient
|
|
83
|
+
* responses. This helper converts it to a string representation.
|
|
84
|
+
*
|
|
85
|
+
* @param allocation - A ChannelAllocation that may contain BigInt amount
|
|
86
|
+
* @returns A new ChannelAllocation with amount as string
|
|
87
|
+
*
|
|
88
|
+
* Requirement 11.5
|
|
89
|
+
*/
|
|
90
|
+
function toSerializableAllocation(allocation) {
|
|
91
|
+
return {
|
|
92
|
+
destination: String(allocation.destination),
|
|
93
|
+
token: String(allocation.token),
|
|
94
|
+
amount: typeof allocation.amount === 'bigint'
|
|
95
|
+
? allocation.amount.toString()
|
|
96
|
+
: String(allocation.amount),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Ensures a YellowQuote object is fully JSON-serializable.
|
|
101
|
+
*
|
|
102
|
+
* Converts any BigInt values that may be present in the YellowQuote
|
|
103
|
+
* (particularly amountIn and amountOut from solver responses) to their
|
|
104
|
+
* string representation.
|
|
105
|
+
*
|
|
106
|
+
* @param quote - A YellowQuote that may contain BigInt values from ClearNode
|
|
107
|
+
* @returns A new YellowQuote with all values JSON-serializable
|
|
108
|
+
*
|
|
109
|
+
* Requirement 11.2
|
|
110
|
+
*/
|
|
111
|
+
export function toSerializableYellowQuote(quote) {
|
|
112
|
+
return {
|
|
113
|
+
solverId: String(quote.solverId),
|
|
114
|
+
channelId: String(quote.channelId),
|
|
115
|
+
amountIn: typeof quote.amountIn === 'bigint'
|
|
116
|
+
? quote.amountIn.toString()
|
|
117
|
+
: String(quote.amountIn),
|
|
118
|
+
amountOut: typeof quote.amountOut === 'bigint'
|
|
119
|
+
? quote.amountOut.toString()
|
|
120
|
+
: String(quote.amountOut),
|
|
121
|
+
estimatedTime: Number(quote.estimatedTime),
|
|
122
|
+
timestamp: Number(quote.timestamp),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=serialization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialization.js","sourceRoot":"","sources":["../../../src/yellow/serialization.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Key Manager for Yellow Network ClearNode Authentication
|
|
3
|
+
*
|
|
4
|
+
* Handles session key generation, EIP-712 authentication flow, and session lifecycle.
|
|
5
|
+
*
|
|
6
|
+
* Authentication flow:
|
|
7
|
+
* 1. Generate session keypair via viem's generatePrivateKey + privateKeyToAccount
|
|
8
|
+
* 2. Send auth_request message with session key address, allowances, expiry, scope
|
|
9
|
+
* 3. Receive auth_challenge from ClearNode
|
|
10
|
+
* 4. Sign challenge with main wallet via EIP-712 typed data
|
|
11
|
+
* 5. Send auth_verify with signed challenge
|
|
12
|
+
* 6. Receive confirmation and store session state
|
|
13
|
+
*
|
|
14
|
+
* Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 2.6
|
|
15
|
+
*/
|
|
16
|
+
import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// Message Factory Functions (local stubs for @erc7824/nitrolite)
|
|
19
|
+
// ============================================================================
|
|
20
|
+
/**
|
|
21
|
+
* Create an auth_request message for ClearNode.
|
|
22
|
+
*
|
|
23
|
+
* This is a local implementation matching the @erc7824/nitrolite
|
|
24
|
+
* createAuthRequestMessage API. It constructs a JSON-RPC style message
|
|
25
|
+
* with the session key details and allowances.
|
|
26
|
+
*
|
|
27
|
+
* @param params - Auth request parameters
|
|
28
|
+
* @returns JSON string of the auth_request message
|
|
29
|
+
*/
|
|
30
|
+
export function createAuthRequestMessage(params) {
|
|
31
|
+
return JSON.stringify({
|
|
32
|
+
method: 'auth_request',
|
|
33
|
+
params: {
|
|
34
|
+
wallet: params.wallet,
|
|
35
|
+
participant: params.participant,
|
|
36
|
+
allowances: params.allowances,
|
|
37
|
+
expire: params.expire,
|
|
38
|
+
scope: params.scope,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Create an EIP-712 auth message signer using the provided wallet client.
|
|
44
|
+
*
|
|
45
|
+
* This is a local implementation matching the @erc7824/nitrolite
|
|
46
|
+
* createEIP712AuthMessageSigner API. It returns a function that signs
|
|
47
|
+
* a challenge string using EIP-712 typed data via the wallet client.
|
|
48
|
+
*
|
|
49
|
+
* The EIP-712 domain and types follow the Yellow Network auth protocol:
|
|
50
|
+
* - Domain: { name: "Yellow ClearNode", version: "1" }
|
|
51
|
+
* - Types: { Auth: [{ name: "challenge", type: "string" }] }
|
|
52
|
+
*
|
|
53
|
+
* @param walletClient - The viem WalletClient to sign with
|
|
54
|
+
* @returns A function that takes a challenge string and returns the EIP-712 signature
|
|
55
|
+
*/
|
|
56
|
+
export function createEIP712AuthMessageSigner(walletClient) {
|
|
57
|
+
return async (challenge) => {
|
|
58
|
+
const account = walletClient.account;
|
|
59
|
+
if (!account) {
|
|
60
|
+
throw new Error('WalletClient must have an account attached for EIP-712 signing');
|
|
61
|
+
}
|
|
62
|
+
const signature = await walletClient.signTypedData({
|
|
63
|
+
account,
|
|
64
|
+
domain: {
|
|
65
|
+
name: 'Yellow ClearNode',
|
|
66
|
+
version: '1',
|
|
67
|
+
},
|
|
68
|
+
types: {
|
|
69
|
+
Auth: [{ name: 'challenge', type: 'string' }],
|
|
70
|
+
},
|
|
71
|
+
primaryType: 'Auth',
|
|
72
|
+
message: {
|
|
73
|
+
challenge,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
return signature;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
// ============================================================================
|
|
80
|
+
// SessionKeyManager
|
|
81
|
+
// ============================================================================
|
|
82
|
+
/** Default session expiry: 1 hour in seconds */
|
|
83
|
+
const DEFAULT_SESSION_EXPIRY = 3600;
|
|
84
|
+
/** Default application scope */
|
|
85
|
+
const DEFAULT_SCOPE = 'jack-kernel';
|
|
86
|
+
/** Timeout for auth messages in milliseconds */
|
|
87
|
+
const AUTH_TIMEOUT = 30_000;
|
|
88
|
+
/**
|
|
89
|
+
* Manages session key generation, ClearNode authentication, and session lifecycle.
|
|
90
|
+
*
|
|
91
|
+
* The SessionKeyManager generates ephemeral session keypairs for signing offchain
|
|
92
|
+
* messages, authenticates them with ClearNode via EIP-712, and tracks session expiry
|
|
93
|
+
* to support automatic re-authentication when the session expires.
|
|
94
|
+
*
|
|
95
|
+
* Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 2.6
|
|
96
|
+
*/
|
|
97
|
+
export class SessionKeyManager {
|
|
98
|
+
walletClient;
|
|
99
|
+
connection;
|
|
100
|
+
sessionAccount = null;
|
|
101
|
+
sessionPrivateKey = null;
|
|
102
|
+
_sessionInfo = null;
|
|
103
|
+
lastAuthParams = null;
|
|
104
|
+
/**
|
|
105
|
+
* @param walletClient - The main wallet's viem WalletClient for EIP-712 signing
|
|
106
|
+
* @param connection - The ClearNodeConnection for sending/receiving auth messages
|
|
107
|
+
*/
|
|
108
|
+
constructor(walletClient, connection) {
|
|
109
|
+
this.walletClient = walletClient;
|
|
110
|
+
this.connection = connection;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Generate a session keypair and authenticate with ClearNode.
|
|
114
|
+
*
|
|
115
|
+
* Flow:
|
|
116
|
+
* 1. Generate session keypair (Requirement 2.1)
|
|
117
|
+
* 2. Send auth_request with session address, allowances, expiry, scope (Requirement 2.2)
|
|
118
|
+
* 3. Receive auth_challenge from ClearNode
|
|
119
|
+
* 4. Sign challenge with main wallet via EIP-712 (Requirement 2.3)
|
|
120
|
+
* 5. Send auth_verify with signed challenge
|
|
121
|
+
* 6. Receive confirmation and store session state (Requirement 2.4)
|
|
122
|
+
*
|
|
123
|
+
* @param params - Authentication parameters including allowances and optional expiry/scope
|
|
124
|
+
* @returns Session information including address, expiry, and authentication status
|
|
125
|
+
* @throws Error if authentication fails or times out (Requirement 2.5)
|
|
126
|
+
*/
|
|
127
|
+
async authenticate(params) {
|
|
128
|
+
// Store params for potential re-authentication (Requirement 2.6)
|
|
129
|
+
this.lastAuthParams = params;
|
|
130
|
+
// Step 1: Generate session keypair (Requirement 2.1)
|
|
131
|
+
this.sessionPrivateKey = generatePrivateKey();
|
|
132
|
+
this.sessionAccount = privateKeyToAccount(this.sessionPrivateKey);
|
|
133
|
+
const sessionAddress = this.sessionAccount.address;
|
|
134
|
+
const walletAddress = this.walletClient.account?.address;
|
|
135
|
+
if (!walletAddress) {
|
|
136
|
+
throw new Error('WalletClient must have an account attached for authentication');
|
|
137
|
+
}
|
|
138
|
+
const expiresAt = params.expiresAt ?? Math.floor(Date.now() / 1000) + DEFAULT_SESSION_EXPIRY;
|
|
139
|
+
const scope = params.scope ?? DEFAULT_SCOPE;
|
|
140
|
+
// Step 2: Send auth_request (Requirement 2.2)
|
|
141
|
+
const authRequestMsg = createAuthRequestMessage({
|
|
142
|
+
wallet: walletAddress,
|
|
143
|
+
participant: sessionAddress,
|
|
144
|
+
allowances: params.allowances,
|
|
145
|
+
expire: expiresAt,
|
|
146
|
+
scope,
|
|
147
|
+
});
|
|
148
|
+
let challengeResponse;
|
|
149
|
+
try {
|
|
150
|
+
challengeResponse = await this.connection.sendAndWait(authRequestMsg, 'auth_challenge', AUTH_TIMEOUT);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
154
|
+
throw new Error(`Authentication failed: could not receive auth_challenge - ${message}`);
|
|
155
|
+
}
|
|
156
|
+
// Step 3: Extract challenge and sign with main wallet via EIP-712 (Requirement 2.3)
|
|
157
|
+
const challenge = challengeResponse.challenge
|
|
158
|
+
?? challengeResponse.data?.challenge;
|
|
159
|
+
if (!challenge || typeof challenge !== 'string') {
|
|
160
|
+
throw new Error('Authentication failed: invalid auth_challenge response - missing challenge string');
|
|
161
|
+
}
|
|
162
|
+
const eip712Signer = createEIP712AuthMessageSigner(this.walletClient);
|
|
163
|
+
let signature;
|
|
164
|
+
try {
|
|
165
|
+
signature = await eip712Signer(challenge);
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
169
|
+
throw new Error(`Authentication failed: EIP-712 signing error - ${message}`);
|
|
170
|
+
}
|
|
171
|
+
// Step 4: Send auth_verify with signed challenge
|
|
172
|
+
const authVerifyMsg = JSON.stringify({
|
|
173
|
+
method: 'auth_verify',
|
|
174
|
+
params: {
|
|
175
|
+
participant: sessionAddress,
|
|
176
|
+
signature,
|
|
177
|
+
challenge,
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
let verifyResponse;
|
|
181
|
+
try {
|
|
182
|
+
verifyResponse = await this.connection.sendAndWait(authVerifyMsg, 'auth_verify', AUTH_TIMEOUT);
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
186
|
+
throw new Error(`Authentication failed: could not receive auth_verify confirmation - ${message}`);
|
|
187
|
+
}
|
|
188
|
+
// Step 5: Validate confirmation and store session state (Requirement 2.4)
|
|
189
|
+
const isConfirmed = verifyResponse.data?.authenticated === true
|
|
190
|
+
|| verifyResponse.status === 'ok'
|
|
191
|
+
|| verifyResponse.data?.status === 'ok'
|
|
192
|
+
|| verifyResponse.data?.status === 'authenticated';
|
|
193
|
+
if (!isConfirmed) {
|
|
194
|
+
throw new Error('Authentication failed: ClearNode rejected the auth_verify request');
|
|
195
|
+
}
|
|
196
|
+
this._sessionInfo = {
|
|
197
|
+
sessionAddress,
|
|
198
|
+
expiresAt,
|
|
199
|
+
authenticated: true,
|
|
200
|
+
};
|
|
201
|
+
return { ...this._sessionInfo };
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Check if the current session is valid and not expired.
|
|
205
|
+
*
|
|
206
|
+
* Returns false if:
|
|
207
|
+
* - No session has been established
|
|
208
|
+
* - The session has been invalidated
|
|
209
|
+
* - The session has expired (Requirement 2.6)
|
|
210
|
+
*/
|
|
211
|
+
get isAuthenticated() {
|
|
212
|
+
if (!this._sessionInfo || !this._sessionInfo.authenticated) {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
// Check expiry (Requirement 2.6)
|
|
216
|
+
const now = Math.floor(Date.now() / 1000);
|
|
217
|
+
if (now >= this._sessionInfo.expiresAt) {
|
|
218
|
+
// Session has expired - mark as not authenticated
|
|
219
|
+
this._sessionInfo.authenticated = false;
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Get the session signer function for signing offchain messages.
|
|
226
|
+
*
|
|
227
|
+
* The returned function signs arbitrary payloads using the session private key.
|
|
228
|
+
* This is used for signing state channel messages without exposing the main wallet.
|
|
229
|
+
*
|
|
230
|
+
* @throws Error if no authenticated session exists
|
|
231
|
+
*/
|
|
232
|
+
get sessionSigner() {
|
|
233
|
+
if (!this.sessionAccount) {
|
|
234
|
+
throw new Error('No authenticated session - call authenticate() first');
|
|
235
|
+
}
|
|
236
|
+
const account = this.sessionAccount;
|
|
237
|
+
return async (payload) => {
|
|
238
|
+
const signature = await account.signMessage({
|
|
239
|
+
message: { raw: payload },
|
|
240
|
+
});
|
|
241
|
+
return signature;
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Get the session key's Ethereum address.
|
|
246
|
+
*
|
|
247
|
+
* @throws Error if no session key has been generated
|
|
248
|
+
*/
|
|
249
|
+
get sessionAddress() {
|
|
250
|
+
if (!this.sessionAccount) {
|
|
251
|
+
throw new Error('No session key generated - call authenticate() first');
|
|
252
|
+
}
|
|
253
|
+
return this.sessionAccount.address;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Invalidate the current session.
|
|
257
|
+
*
|
|
258
|
+
* Clears all session state including the keypair and authentication status.
|
|
259
|
+
* After invalidation, a new authenticate() call is required.
|
|
260
|
+
*/
|
|
261
|
+
invalidate() {
|
|
262
|
+
this.sessionAccount = null;
|
|
263
|
+
this.sessionPrivateKey = null;
|
|
264
|
+
this._sessionInfo = null;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Re-authenticate using the last authentication parameters.
|
|
268
|
+
*
|
|
269
|
+
* This is called internally when a session has expired and a new operation
|
|
270
|
+
* requires an active session (Requirement 2.6).
|
|
271
|
+
*
|
|
272
|
+
* @returns Session information from the new authentication
|
|
273
|
+
* @throws Error if no previous auth params exist or re-authentication fails
|
|
274
|
+
*/
|
|
275
|
+
async reauthenticate() {
|
|
276
|
+
if (!this.lastAuthParams) {
|
|
277
|
+
throw new Error('Cannot re-authenticate: no previous authentication parameters available');
|
|
278
|
+
}
|
|
279
|
+
// Invalidate current session before re-authenticating
|
|
280
|
+
this.invalidate();
|
|
281
|
+
return this.authenticate(this.lastAuthParams);
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Ensure the session is authenticated, re-authenticating if expired.
|
|
285
|
+
*
|
|
286
|
+
* This is a convenience method for use by other components that need
|
|
287
|
+
* to ensure an active session before performing operations.
|
|
288
|
+
*
|
|
289
|
+
* Requirement 2.6: Auto-reauthentication on next operation when expired.
|
|
290
|
+
*
|
|
291
|
+
* @returns The current or newly created session info
|
|
292
|
+
* @throws Error if authentication fails
|
|
293
|
+
*/
|
|
294
|
+
async ensureAuthenticated() {
|
|
295
|
+
if (this.isAuthenticated && this._sessionInfo) {
|
|
296
|
+
return { ...this._sessionInfo };
|
|
297
|
+
}
|
|
298
|
+
// Session expired or not established - re-authenticate
|
|
299
|
+
return this.reauthenticate();
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
//# sourceMappingURL=session-key-manager.js.map
|