@fivenorth/loop-sdk 0.10.0 → 0.11.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/README.md +70 -0
- package/dist/connection.d.ts +40 -0
- package/dist/connection.d.ts.map +1 -0
- package/dist/connection.js +290 -0
- package/dist/errors.d.ts +13 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +33 -0
- package/dist/extensions/usdc/index.d.ts +11 -0
- package/dist/extensions/usdc/index.d.ts.map +1 -0
- package/dist/extensions/usdc/index.js +52 -0
- package/dist/extensions/usdc/types.d.ts +25 -0
- package/dist/extensions/usdc/types.d.ts.map +1 -0
- package/dist/extensions/usdc/types.js +1 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +284 -229
- package/dist/provider.d.ts +61 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +247 -0
- package/dist/server/index.d.ts +23 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +117 -0
- package/dist/server/signer.d.ts +15 -0
- package/dist/server/signer.d.ts.map +1 -0
- package/dist/server/signer.js +56 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +38 -0
- package/dist/session.d.ts +39 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +92 -0
- package/dist/types.d.ts +116 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/wallet.d.ts +10 -0
- package/dist/wallet.d.ts.map +1 -0
- package/dist/wallet.js +22 -0
- package/package.json +21 -4
package/dist/index.js
CHANGED
|
@@ -2092,232 +2092,6 @@ function isUnauthCode(code) {
|
|
|
2092
2092
|
return UNAUTH_CODES.has(code);
|
|
2093
2093
|
}
|
|
2094
2094
|
|
|
2095
|
-
// src/connection.ts
|
|
2096
|
-
class Connection {
|
|
2097
|
-
walletUrl = "https://cantonloop.com";
|
|
2098
|
-
apiUrl = "https://cantonloop.com";
|
|
2099
|
-
ws = null;
|
|
2100
|
-
network = "main";
|
|
2101
|
-
ticketId = null;
|
|
2102
|
-
onMessageHandler = null;
|
|
2103
|
-
reconnectPromise = null;
|
|
2104
|
-
status = "disconnected";
|
|
2105
|
-
constructor({ network, walletUrl, apiUrl }) {
|
|
2106
|
-
this.network = network || "main";
|
|
2107
|
-
switch (this.network) {
|
|
2108
|
-
case "local":
|
|
2109
|
-
this.walletUrl = "http://localhost:3000";
|
|
2110
|
-
this.apiUrl = "http://localhost:8080";
|
|
2111
|
-
break;
|
|
2112
|
-
case "devnet":
|
|
2113
|
-
case "dev":
|
|
2114
|
-
this.walletUrl = "https://devnet.cantonloop.com";
|
|
2115
|
-
this.apiUrl = "https://devnet.cantonloop.com";
|
|
2116
|
-
break;
|
|
2117
|
-
case "testnet":
|
|
2118
|
-
case "test":
|
|
2119
|
-
this.walletUrl = "https://testnet.cantonloop.com";
|
|
2120
|
-
this.apiUrl = "https://testnet.cantonloop.com";
|
|
2121
|
-
break;
|
|
2122
|
-
case "mainnet":
|
|
2123
|
-
case "main":
|
|
2124
|
-
this.walletUrl = "https://cantonloop.com";
|
|
2125
|
-
this.apiUrl = "https://cantonloop.com";
|
|
2126
|
-
break;
|
|
2127
|
-
}
|
|
2128
|
-
if (walletUrl) {
|
|
2129
|
-
this.walletUrl = walletUrl;
|
|
2130
|
-
}
|
|
2131
|
-
if (apiUrl) {
|
|
2132
|
-
this.apiUrl = apiUrl;
|
|
2133
|
-
}
|
|
2134
|
-
}
|
|
2135
|
-
connectInProgress() {
|
|
2136
|
-
return this.status === "connecting" || this.status === "connected";
|
|
2137
|
-
}
|
|
2138
|
-
async getTicket(appName, sessionId, version) {
|
|
2139
|
-
const response = await fetch(`${this.apiUrl}/api/v1/.connect/pair/tickets`, {
|
|
2140
|
-
method: "POST",
|
|
2141
|
-
headers: {
|
|
2142
|
-
"Content-Type": "application/json"
|
|
2143
|
-
},
|
|
2144
|
-
body: JSON.stringify({
|
|
2145
|
-
app_name: appName,
|
|
2146
|
-
session_id: sessionId,
|
|
2147
|
-
version
|
|
2148
|
-
})
|
|
2149
|
-
});
|
|
2150
|
-
if (!response.ok) {
|
|
2151
|
-
throw new Error("Failed to get ticket from server.");
|
|
2152
|
-
}
|
|
2153
|
-
return response.json();
|
|
2154
|
-
}
|
|
2155
|
-
async getHolding(authToken) {
|
|
2156
|
-
const response = await fetch(`${this.apiUrl}/api/v1/.connect/pair/account/holding`, {
|
|
2157
|
-
method: "GET",
|
|
2158
|
-
headers: {
|
|
2159
|
-
"Content-Type": "application/json",
|
|
2160
|
-
Authorization: `Bearer ${authToken}`
|
|
2161
|
-
}
|
|
2162
|
-
});
|
|
2163
|
-
if (!response.ok) {
|
|
2164
|
-
throw new Error("Failed to get holdings.");
|
|
2165
|
-
}
|
|
2166
|
-
return response.json();
|
|
2167
|
-
}
|
|
2168
|
-
async getActiveContracts(authToken, params) {
|
|
2169
|
-
const url = new URL(`${this.apiUrl}/api/v1/.connect/pair/account/active-contracts`);
|
|
2170
|
-
if (params?.templateId) {
|
|
2171
|
-
url.searchParams.append("templateId", params.templateId);
|
|
2172
|
-
}
|
|
2173
|
-
if (params?.interfaceId) {
|
|
2174
|
-
url.searchParams.append("interfaceId", params.interfaceId);
|
|
2175
|
-
}
|
|
2176
|
-
const response = await fetch(url.toString(), {
|
|
2177
|
-
method: "GET",
|
|
2178
|
-
headers: {
|
|
2179
|
-
"Content-Type": "application/json",
|
|
2180
|
-
Authorization: `Bearer ${authToken}`
|
|
2181
|
-
}
|
|
2182
|
-
});
|
|
2183
|
-
if (!response.ok) {
|
|
2184
|
-
throw new Error("Failed to get active contracts.");
|
|
2185
|
-
}
|
|
2186
|
-
return response.json();
|
|
2187
|
-
}
|
|
2188
|
-
async prepareTransfer(authToken, params) {
|
|
2189
|
-
const payload = {
|
|
2190
|
-
recipient: params.recipient,
|
|
2191
|
-
amount: params.amount
|
|
2192
|
-
};
|
|
2193
|
-
if (params.instrument) {
|
|
2194
|
-
if (params.instrument.instrument_admin) {
|
|
2195
|
-
payload.instrument_admin = params.instrument.instrument_admin;
|
|
2196
|
-
}
|
|
2197
|
-
if (params.instrument.instrument_id) {
|
|
2198
|
-
payload.instrument_id = params.instrument.instrument_id;
|
|
2199
|
-
}
|
|
2200
|
-
}
|
|
2201
|
-
if (params.requested_at) {
|
|
2202
|
-
payload.requested_at = params.requested_at;
|
|
2203
|
-
}
|
|
2204
|
-
if (params.execute_before) {
|
|
2205
|
-
payload.execute_before = params.execute_before;
|
|
2206
|
-
}
|
|
2207
|
-
if (params.memo) {
|
|
2208
|
-
payload.memo = params.memo;
|
|
2209
|
-
}
|
|
2210
|
-
const response = await fetch(`${this.apiUrl}/api/v1/.connect/pair/transfer`, {
|
|
2211
|
-
method: "POST",
|
|
2212
|
-
headers: {
|
|
2213
|
-
"Content-Type": "application/json",
|
|
2214
|
-
Authorization: `Bearer ${authToken}`
|
|
2215
|
-
},
|
|
2216
|
-
body: JSON.stringify(payload)
|
|
2217
|
-
});
|
|
2218
|
-
if (!response.ok) {
|
|
2219
|
-
throw new Error("Failed to prepare transfer.");
|
|
2220
|
-
}
|
|
2221
|
-
const data = await response.json();
|
|
2222
|
-
return data.payload;
|
|
2223
|
-
}
|
|
2224
|
-
async verifySession(authToken) {
|
|
2225
|
-
const response = await fetch(`${this.apiUrl}/api/v1/.connect/pair/account`, {
|
|
2226
|
-
method: "GET",
|
|
2227
|
-
headers: {
|
|
2228
|
-
"Content-Type": "application/json",
|
|
2229
|
-
Authorization: `Bearer ${authToken}`
|
|
2230
|
-
}
|
|
2231
|
-
});
|
|
2232
|
-
if (!response.ok) {
|
|
2233
|
-
if (response.status === 401 || response.status === 403) {
|
|
2234
|
-
throw new UnauthorizedError;
|
|
2235
|
-
}
|
|
2236
|
-
throw new Error(`Session verification failed with status ${response.status}.`);
|
|
2237
|
-
}
|
|
2238
|
-
const data = await response.json();
|
|
2239
|
-
const email = data?.email;
|
|
2240
|
-
if (!data?.party_id || !data?.public_key) {
|
|
2241
|
-
throw new Error("Invalid session verification response.");
|
|
2242
|
-
}
|
|
2243
|
-
const account = {
|
|
2244
|
-
party_id: data?.party_id,
|
|
2245
|
-
auth_token: authToken,
|
|
2246
|
-
public_key: data?.public_key,
|
|
2247
|
-
email,
|
|
2248
|
-
has_preapproval: data?.has_preapproval,
|
|
2249
|
-
has_merge_delegation: data?.has_merge_delegation,
|
|
2250
|
-
usdc_bridge_access: data?.usdc_bridge_access
|
|
2251
|
-
};
|
|
2252
|
-
return account;
|
|
2253
|
-
}
|
|
2254
|
-
connectWebSocket(ticketId, onMessage) {
|
|
2255
|
-
if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) && this.ticketId !== ticketId) {
|
|
2256
|
-
this.ws.close();
|
|
2257
|
-
this.ws = null;
|
|
2258
|
-
}
|
|
2259
|
-
if (this.status === "connecting" || this.status === "connected") {
|
|
2260
|
-
return;
|
|
2261
|
-
}
|
|
2262
|
-
this.onMessageHandler = onMessage;
|
|
2263
|
-
this.ticketId = ticketId;
|
|
2264
|
-
this.status = "connecting";
|
|
2265
|
-
this.attachWebSocket(ticketId, onMessage);
|
|
2266
|
-
}
|
|
2267
|
-
reconnect() {
|
|
2268
|
-
if (!this.ticketId || !this.onMessageHandler) {
|
|
2269
|
-
return Promise.reject(new Error("Cannot reconnect without a known ticket."));
|
|
2270
|
-
}
|
|
2271
|
-
return new Promise((resolve, reject) => {
|
|
2272
|
-
let opened = false;
|
|
2273
|
-
this.attachWebSocket(this.ticketId, this.onMessageHandler, () => {
|
|
2274
|
-
opened = true;
|
|
2275
|
-
resolve();
|
|
2276
|
-
}, () => {
|
|
2277
|
-
if (opened) {
|
|
2278
|
-
return;
|
|
2279
|
-
}
|
|
2280
|
-
reject(new Error("Failed to reconnect to ticket server."));
|
|
2281
|
-
}, () => {
|
|
2282
|
-
if (opened) {
|
|
2283
|
-
return;
|
|
2284
|
-
}
|
|
2285
|
-
reject(new Error("Failed to reconnect to ticket server."));
|
|
2286
|
-
});
|
|
2287
|
-
});
|
|
2288
|
-
}
|
|
2289
|
-
websocketUrl(ticketId) {
|
|
2290
|
-
return `${this.network === "local" ? "ws" : "wss"}://${this.apiUrl.replace("https://", "").replace("http://", "")}/api/v1/.connect/pair/ws/${encodeURIComponent(ticketId)}`;
|
|
2291
|
-
}
|
|
2292
|
-
attachWebSocket(ticketId, onMessage, onOpen, onError, onClose) {
|
|
2293
|
-
const wsUrl = this.websocketUrl(ticketId);
|
|
2294
|
-
const ws = new WebSocket(wsUrl);
|
|
2295
|
-
ws.onmessage = onMessage;
|
|
2296
|
-
ws.onopen = () => {
|
|
2297
|
-
this.status = "connected";
|
|
2298
|
-
console.log("[LoopSDK] Connected to ticket server.");
|
|
2299
|
-
onOpen?.();
|
|
2300
|
-
};
|
|
2301
|
-
ws.onclose = (event) => {
|
|
2302
|
-
this.status = "disconnected";
|
|
2303
|
-
if (this.ws === ws) {
|
|
2304
|
-
this.ws = null;
|
|
2305
|
-
}
|
|
2306
|
-
console.log("[LoopSDK] Disconnected from ticket server.");
|
|
2307
|
-
onClose?.(event);
|
|
2308
|
-
};
|
|
2309
|
-
ws.onerror = (event) => {
|
|
2310
|
-
this.status = "disconnected";
|
|
2311
|
-
ws.close();
|
|
2312
|
-
if (this.ws === ws) {
|
|
2313
|
-
this.ws = null;
|
|
2314
|
-
}
|
|
2315
|
-
onError?.(event);
|
|
2316
|
-
};
|
|
2317
|
-
this.ws = ws;
|
|
2318
|
-
}
|
|
2319
|
-
}
|
|
2320
|
-
|
|
2321
2095
|
// src/types.ts
|
|
2322
2096
|
var MessageType;
|
|
2323
2097
|
((MessageType2) => {
|
|
@@ -2400,10 +2174,12 @@ class Provider {
|
|
|
2400
2174
|
}
|
|
2401
2175
|
async submitTransaction(payload, options) {
|
|
2402
2176
|
const requestPayload = options?.estimateTraffic ? { ...payload, estimate_traffic: true } : payload;
|
|
2403
|
-
|
|
2177
|
+
const executionMode = options?.executionMode;
|
|
2178
|
+
const finalPayload = executionMode === "wait" ? { ...requestPayload, execution_mode: "wait" } : requestPayload;
|
|
2179
|
+
return this.sendRequest("run_transaction" /* RUN_TRANSACTION */, finalPayload, options);
|
|
2404
2180
|
}
|
|
2405
2181
|
async submitAndWaitForTransaction(payload, options) {
|
|
2406
|
-
const requestPayload = options?.estimateTraffic ? { ...payload,
|
|
2182
|
+
const requestPayload = options?.estimateTraffic ? { ...payload, estimate_traffic: true } : payload;
|
|
2407
2183
|
return this.sendRequest("run_transaction" /* RUN_TRANSACTION */, { ...requestPayload, execution_mode: "wait" }, options);
|
|
2408
2184
|
}
|
|
2409
2185
|
async transfer(recipient, amount, instrument, options) {
|
|
@@ -2559,6 +2335,283 @@ class Provider {
|
|
|
2559
2335
|
}
|
|
2560
2336
|
}
|
|
2561
2337
|
|
|
2338
|
+
// src/connection.ts
|
|
2339
|
+
class Connection {
|
|
2340
|
+
walletUrl = "https://cantonloop.com";
|
|
2341
|
+
apiUrl = "https://cantonloop.com";
|
|
2342
|
+
ws = null;
|
|
2343
|
+
network = "main";
|
|
2344
|
+
ticketId = null;
|
|
2345
|
+
onMessageHandler = null;
|
|
2346
|
+
reconnectPromise = null;
|
|
2347
|
+
status = "disconnected";
|
|
2348
|
+
constructor({ network, walletUrl, apiUrl }) {
|
|
2349
|
+
this.network = network || "main";
|
|
2350
|
+
switch (this.network) {
|
|
2351
|
+
case "local":
|
|
2352
|
+
this.walletUrl = "http://localhost:3000";
|
|
2353
|
+
this.apiUrl = "http://localhost:8080";
|
|
2354
|
+
break;
|
|
2355
|
+
case "devnet":
|
|
2356
|
+
case "dev":
|
|
2357
|
+
this.walletUrl = "https://devnet.cantonloop.com";
|
|
2358
|
+
this.apiUrl = "https://devnet.cantonloop.com";
|
|
2359
|
+
break;
|
|
2360
|
+
case "testnet":
|
|
2361
|
+
case "test":
|
|
2362
|
+
this.walletUrl = "https://testnet.cantonloop.com";
|
|
2363
|
+
this.apiUrl = "https://testnet.cantonloop.com";
|
|
2364
|
+
break;
|
|
2365
|
+
case "mainnet":
|
|
2366
|
+
case "main":
|
|
2367
|
+
this.walletUrl = "https://cantonloop.com";
|
|
2368
|
+
this.apiUrl = "https://cantonloop.com";
|
|
2369
|
+
break;
|
|
2370
|
+
}
|
|
2371
|
+
if (walletUrl) {
|
|
2372
|
+
this.walletUrl = walletUrl;
|
|
2373
|
+
}
|
|
2374
|
+
if (apiUrl) {
|
|
2375
|
+
this.apiUrl = apiUrl;
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
connectInProgress() {
|
|
2379
|
+
return this.status === "connecting" || this.status === "connected";
|
|
2380
|
+
}
|
|
2381
|
+
async getTicket(appName, sessionId, version) {
|
|
2382
|
+
const response = await fetch(`${this.apiUrl}/api/v1/.connect/pair/tickets`, {
|
|
2383
|
+
method: "POST",
|
|
2384
|
+
headers: {
|
|
2385
|
+
"Content-Type": "application/json"
|
|
2386
|
+
},
|
|
2387
|
+
body: JSON.stringify({
|
|
2388
|
+
app_name: appName,
|
|
2389
|
+
session_id: sessionId,
|
|
2390
|
+
version
|
|
2391
|
+
})
|
|
2392
|
+
});
|
|
2393
|
+
if (!response.ok) {
|
|
2394
|
+
throw new Error("Failed to get ticket from server.");
|
|
2395
|
+
}
|
|
2396
|
+
return response.json();
|
|
2397
|
+
}
|
|
2398
|
+
async getHolding(authToken) {
|
|
2399
|
+
const response = await fetch(`${this.apiUrl}/api/v1/.connect/pair/account/holding`, {
|
|
2400
|
+
method: "GET",
|
|
2401
|
+
headers: {
|
|
2402
|
+
"Content-Type": "application/json",
|
|
2403
|
+
Authorization: `Bearer ${authToken}`
|
|
2404
|
+
}
|
|
2405
|
+
});
|
|
2406
|
+
if (!response.ok) {
|
|
2407
|
+
throw new Error("Failed to get holdings. " + await response.text());
|
|
2408
|
+
}
|
|
2409
|
+
return response.json();
|
|
2410
|
+
}
|
|
2411
|
+
async getActiveContracts(authToken, params) {
|
|
2412
|
+
const url = new URL(`${this.apiUrl}/api/v1/.connect/pair/account/active-contracts`);
|
|
2413
|
+
if (params?.templateId) {
|
|
2414
|
+
url.searchParams.append("templateId", params.templateId);
|
|
2415
|
+
}
|
|
2416
|
+
if (params?.interfaceId) {
|
|
2417
|
+
url.searchParams.append("interfaceId", params.interfaceId);
|
|
2418
|
+
}
|
|
2419
|
+
const response = await fetch(url.toString(), {
|
|
2420
|
+
method: "GET",
|
|
2421
|
+
headers: {
|
|
2422
|
+
"Content-Type": "application/json",
|
|
2423
|
+
Authorization: `Bearer ${authToken}`
|
|
2424
|
+
}
|
|
2425
|
+
});
|
|
2426
|
+
if (!response.ok) {
|
|
2427
|
+
throw new Error("Failed to get active contracts.");
|
|
2428
|
+
}
|
|
2429
|
+
return response.json();
|
|
2430
|
+
}
|
|
2431
|
+
async prepareTransfer(authToken, params) {
|
|
2432
|
+
const payload = {
|
|
2433
|
+
recipient: params.recipient,
|
|
2434
|
+
amount: params.amount
|
|
2435
|
+
};
|
|
2436
|
+
if (params.instrument) {
|
|
2437
|
+
if (params.instrument.instrument_admin) {
|
|
2438
|
+
payload.instrument_admin = params.instrument.instrument_admin;
|
|
2439
|
+
}
|
|
2440
|
+
if (params.instrument.instrument_id) {
|
|
2441
|
+
payload.instrument_id = params.instrument.instrument_id;
|
|
2442
|
+
}
|
|
2443
|
+
}
|
|
2444
|
+
if (params.requested_at) {
|
|
2445
|
+
payload.requested_at = params.requested_at;
|
|
2446
|
+
}
|
|
2447
|
+
if (params.execute_before) {
|
|
2448
|
+
payload.execute_before = params.execute_before;
|
|
2449
|
+
}
|
|
2450
|
+
if (params.memo) {
|
|
2451
|
+
payload.memo = params.memo;
|
|
2452
|
+
}
|
|
2453
|
+
const response = await fetch(`${this.apiUrl}/api/v1/.connect/pair/transfer`, {
|
|
2454
|
+
method: "POST",
|
|
2455
|
+
headers: {
|
|
2456
|
+
"Content-Type": "application/json",
|
|
2457
|
+
Authorization: `Bearer ${authToken}`
|
|
2458
|
+
},
|
|
2459
|
+
body: JSON.stringify(payload)
|
|
2460
|
+
});
|
|
2461
|
+
if (!response.ok) {
|
|
2462
|
+
console.error("Failed to prepare transfer.", await response.text());
|
|
2463
|
+
throw new Error("Failed to prepare transfer.");
|
|
2464
|
+
}
|
|
2465
|
+
const data = await response.json();
|
|
2466
|
+
return data.payload;
|
|
2467
|
+
}
|
|
2468
|
+
async verifySession(authToken) {
|
|
2469
|
+
const response = await fetch(`${this.apiUrl}/api/v1/.connect/pair/account`, {
|
|
2470
|
+
method: "GET",
|
|
2471
|
+
headers: {
|
|
2472
|
+
"Content-Type": "application/json",
|
|
2473
|
+
Authorization: `Bearer ${authToken}`
|
|
2474
|
+
}
|
|
2475
|
+
});
|
|
2476
|
+
if (!response.ok) {
|
|
2477
|
+
if (response.status === 401 || response.status === 403) {
|
|
2478
|
+
throw new UnauthorizedError;
|
|
2479
|
+
}
|
|
2480
|
+
throw new Error(`Session verification failed with status ${response.status}.`);
|
|
2481
|
+
}
|
|
2482
|
+
const data = await response.json();
|
|
2483
|
+
const email = data?.email;
|
|
2484
|
+
if (!data?.party_id || !data?.public_key) {
|
|
2485
|
+
throw new Error("Invalid session verification response.");
|
|
2486
|
+
}
|
|
2487
|
+
const account = {
|
|
2488
|
+
party_id: data?.party_id,
|
|
2489
|
+
auth_token: authToken,
|
|
2490
|
+
public_key: data?.public_key,
|
|
2491
|
+
email,
|
|
2492
|
+
has_preapproval: data?.has_preapproval,
|
|
2493
|
+
has_merge_delegation: data?.has_merge_delegation,
|
|
2494
|
+
usdc_bridge_access: data?.usdc_bridge_access
|
|
2495
|
+
};
|
|
2496
|
+
return account;
|
|
2497
|
+
}
|
|
2498
|
+
connectWebSocket(ticketId, onMessage) {
|
|
2499
|
+
if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) && this.ticketId !== ticketId) {
|
|
2500
|
+
this.ws.close();
|
|
2501
|
+
this.ws = null;
|
|
2502
|
+
}
|
|
2503
|
+
if (this.status === "connecting" || this.status === "connected") {
|
|
2504
|
+
return;
|
|
2505
|
+
}
|
|
2506
|
+
this.onMessageHandler = onMessage;
|
|
2507
|
+
this.ticketId = ticketId;
|
|
2508
|
+
this.status = "connecting";
|
|
2509
|
+
this.attachWebSocket(ticketId, onMessage);
|
|
2510
|
+
}
|
|
2511
|
+
reconnect() {
|
|
2512
|
+
if (!this.ticketId || !this.onMessageHandler) {
|
|
2513
|
+
return Promise.reject(new Error("Cannot reconnect without a known ticket."));
|
|
2514
|
+
}
|
|
2515
|
+
return new Promise((resolve, reject) => {
|
|
2516
|
+
let opened = false;
|
|
2517
|
+
this.attachWebSocket(this.ticketId, this.onMessageHandler, () => {
|
|
2518
|
+
opened = true;
|
|
2519
|
+
resolve();
|
|
2520
|
+
}, () => {
|
|
2521
|
+
if (opened) {
|
|
2522
|
+
return;
|
|
2523
|
+
}
|
|
2524
|
+
reject(new Error("Failed to reconnect to ticket server."));
|
|
2525
|
+
}, () => {
|
|
2526
|
+
if (opened) {
|
|
2527
|
+
return;
|
|
2528
|
+
}
|
|
2529
|
+
reject(new Error("Failed to reconnect to ticket server."));
|
|
2530
|
+
});
|
|
2531
|
+
});
|
|
2532
|
+
}
|
|
2533
|
+
async exchangeApiKey({ publicKey, signature, epoch }) {
|
|
2534
|
+
const response = await fetch(`${this.apiUrl}/api/v1/.connect/pair/apikey`, {
|
|
2535
|
+
method: "POST",
|
|
2536
|
+
headers: {
|
|
2537
|
+
"Content-Type": "application/json"
|
|
2538
|
+
},
|
|
2539
|
+
body: JSON.stringify({
|
|
2540
|
+
public_key: publicKey,
|
|
2541
|
+
signature,
|
|
2542
|
+
epoch
|
|
2543
|
+
})
|
|
2544
|
+
});
|
|
2545
|
+
if (!response.ok) {
|
|
2546
|
+
throw new Error("Failed to get API key from server.");
|
|
2547
|
+
}
|
|
2548
|
+
return response.json();
|
|
2549
|
+
}
|
|
2550
|
+
prepareTransaction(session, params) {
|
|
2551
|
+
return fetch(`${this.apiUrl}/api/v1/.connect/tickets/prepare-transaction`, {
|
|
2552
|
+
method: "POST",
|
|
2553
|
+
headers: {
|
|
2554
|
+
"Content-Type": "application/json",
|
|
2555
|
+
Authorization: `Bearer ${session.userApiKey}`
|
|
2556
|
+
},
|
|
2557
|
+
body: JSON.stringify({
|
|
2558
|
+
payload: params,
|
|
2559
|
+
ticket_id: session.ticketId
|
|
2560
|
+
})
|
|
2561
|
+
}).then((response) => response.json());
|
|
2562
|
+
}
|
|
2563
|
+
async executeTransaction(session, params) {
|
|
2564
|
+
if (!session.ticketId) {
|
|
2565
|
+
throw new Error("Ticket ID is required");
|
|
2566
|
+
}
|
|
2567
|
+
const resp = fetch(`${this.apiUrl}/api/v1/.connect/tickets/execute-transaction`, {
|
|
2568
|
+
method: "POST",
|
|
2569
|
+
headers: {
|
|
2570
|
+
"Content-Type": "application/json",
|
|
2571
|
+
Authorization: `Bearer ${session.userApiKey}`
|
|
2572
|
+
},
|
|
2573
|
+
body: JSON.stringify({
|
|
2574
|
+
ticket_id: session.ticketId,
|
|
2575
|
+
request_id: generateRequestId(),
|
|
2576
|
+
command_id: params.command_id,
|
|
2577
|
+
signature: params.signature,
|
|
2578
|
+
transaction_data: params.transaction_data
|
|
2579
|
+
})
|
|
2580
|
+
});
|
|
2581
|
+
return (await resp).json();
|
|
2582
|
+
}
|
|
2583
|
+
websocketUrl(ticketId) {
|
|
2584
|
+
return `${this.network === "local" ? "ws" : "wss"}://${this.apiUrl.replace("https://", "").replace("http://", "")}/api/v1/.connect/pair/ws/${encodeURIComponent(ticketId)}`;
|
|
2585
|
+
}
|
|
2586
|
+
attachWebSocket(ticketId, onMessage, onOpen, onError, onClose) {
|
|
2587
|
+
const wsUrl = this.websocketUrl(ticketId);
|
|
2588
|
+
const ws = new WebSocket(wsUrl);
|
|
2589
|
+
ws.onmessage = onMessage;
|
|
2590
|
+
ws.onopen = () => {
|
|
2591
|
+
this.status = "connected";
|
|
2592
|
+
console.log("[LoopSDK] Connected to ticket server.");
|
|
2593
|
+
onOpen?.();
|
|
2594
|
+
};
|
|
2595
|
+
ws.onclose = (event) => {
|
|
2596
|
+
this.status = "disconnected";
|
|
2597
|
+
if (this.ws === ws) {
|
|
2598
|
+
this.ws = null;
|
|
2599
|
+
}
|
|
2600
|
+
console.log("[LoopSDK] Disconnected from ticket server.");
|
|
2601
|
+
onClose?.(event);
|
|
2602
|
+
};
|
|
2603
|
+
ws.onerror = (event) => {
|
|
2604
|
+
this.status = "disconnected";
|
|
2605
|
+
ws.close();
|
|
2606
|
+
if (this.ws === ws) {
|
|
2607
|
+
this.ws = null;
|
|
2608
|
+
}
|
|
2609
|
+
onError?.(event);
|
|
2610
|
+
};
|
|
2611
|
+
this.ws = ws;
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2614
|
+
|
|
2562
2615
|
// src/session.ts
|
|
2563
2616
|
var STORAGE_KEY_LOOP_CONNECT = "loop_connect";
|
|
2564
2617
|
|
|
@@ -2569,14 +2622,16 @@ class SessionInfo {
|
|
|
2569
2622
|
partyId;
|
|
2570
2623
|
publicKey;
|
|
2571
2624
|
email;
|
|
2625
|
+
userApiKey;
|
|
2572
2626
|
_isAuthorized = false;
|
|
2573
|
-
constructor({ sessionId, ticketId, authToken, partyId, publicKey, email }) {
|
|
2627
|
+
constructor({ sessionId, ticketId, authToken, partyId, publicKey, email, userApiKey }) {
|
|
2574
2628
|
this.sessionId = sessionId;
|
|
2575
2629
|
this.ticketId = ticketId;
|
|
2576
2630
|
this.authToken = authToken;
|
|
2577
2631
|
this.partyId = partyId;
|
|
2578
2632
|
this.publicKey = publicKey;
|
|
2579
2633
|
this.email = email;
|
|
2634
|
+
this.userApiKey = userApiKey;
|
|
2580
2635
|
}
|
|
2581
2636
|
setTicketId(ticketId) {
|
|
2582
2637
|
this.ticketId = ticketId;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Connection } from './connection';
|
|
2
|
+
import type { Holding, ActiveContract, TransferOptions, InstrumentSpec, RunTransactionResponse, TransactionPayload } from './types';
|
|
3
|
+
import { MessageType, type Account } from './types';
|
|
4
|
+
export declare const DEFAULT_REQUEST_TIMEOUT_MS = 300000;
|
|
5
|
+
export type RequestFinishStatus = 'success' | 'rejected' | 'timeout' | 'error';
|
|
6
|
+
export type RequestFinishArgs = {
|
|
7
|
+
status: RequestFinishStatus;
|
|
8
|
+
messageType: MessageType;
|
|
9
|
+
requestLabel?: string;
|
|
10
|
+
requestContext?: unknown;
|
|
11
|
+
errorCode?: string;
|
|
12
|
+
};
|
|
13
|
+
export type ProviderHooks = {
|
|
14
|
+
onRequestStart?: (messageType: MessageType, requestLabel?: string) => unknown | Promise<unknown>;
|
|
15
|
+
onRequestFinish?: (args: RequestFinishArgs) => void;
|
|
16
|
+
onTransactionUpdate?: (payload: RunTransactionResponse, message: any) => void;
|
|
17
|
+
};
|
|
18
|
+
type SubmitOptions = {
|
|
19
|
+
requestTimeout?: number;
|
|
20
|
+
message?: string;
|
|
21
|
+
requestLabel?: string;
|
|
22
|
+
estimateTraffic?: boolean;
|
|
23
|
+
executionMode?: 'async' | 'wait';
|
|
24
|
+
};
|
|
25
|
+
export declare function generateRequestId(): string;
|
|
26
|
+
export declare class Provider {
|
|
27
|
+
connection: Connection;
|
|
28
|
+
party_id: string;
|
|
29
|
+
public_key: string;
|
|
30
|
+
email?: string;
|
|
31
|
+
private auth_token;
|
|
32
|
+
private requests;
|
|
33
|
+
private requestTimeout;
|
|
34
|
+
private hooks?;
|
|
35
|
+
constructor({ connection, party_id, public_key, auth_token, email, hooks }: {
|
|
36
|
+
connection: Connection;
|
|
37
|
+
party_id: string;
|
|
38
|
+
public_key: string;
|
|
39
|
+
auth_token: string;
|
|
40
|
+
email?: string;
|
|
41
|
+
hooks?: ProviderHooks;
|
|
42
|
+
});
|
|
43
|
+
getAuthToken(): string;
|
|
44
|
+
handleResponse(message: any): void;
|
|
45
|
+
getHolding(): Promise<Holding[]>;
|
|
46
|
+
getAccount(): Promise<Account>;
|
|
47
|
+
getActiveContracts(params?: {
|
|
48
|
+
templateId?: string;
|
|
49
|
+
interfaceId?: string;
|
|
50
|
+
}): Promise<ActiveContract[]>;
|
|
51
|
+
submitTransaction(payload: TransactionPayload, options?: SubmitOptions): Promise<any>;
|
|
52
|
+
submitAndWaitForTransaction(payload: TransactionPayload, options?: SubmitOptions): Promise<any>;
|
|
53
|
+
transfer(recipient: string, amount: string | number, instrument?: InstrumentSpec, options?: TransferOptions & {
|
|
54
|
+
executionMode?: 'async' | 'wait';
|
|
55
|
+
}): Promise<any>;
|
|
56
|
+
signMessage(message: string): Promise<any>;
|
|
57
|
+
private ensureConnected;
|
|
58
|
+
private sendRequest;
|
|
59
|
+
}
|
|
60
|
+
export {};
|
|
61
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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"}
|