@fivenorth/loop-sdk 0.10.0 → 0.11.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/README.md +9 -0
- package/dist/connection.d.ts +40 -0
- package/dist/connection.d.ts.map +1 -0
- package/dist/errors.d.ts +13 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/extensions/usdc/index.d.ts +11 -0
- package/dist/extensions/usdc/index.d.ts.map +1 -0
- package/dist/extensions/usdc/types.d.ts +25 -0
- package/dist/extensions/usdc/types.d.ts.map +1 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +316 -229
- package/dist/provider.d.ts +61 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/server/index.d.ts +23 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +35344 -0
- package/dist/server/signer.d.ts +15 -0
- package/dist/server/signer.d.ts.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/session.d.ts +39 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/types.d.ts +116 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/wallet.d.ts +10 -0
- package/dist/wallet.d.ts.map +1 -0
- package/package.json +17 -3
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ var __create = Object.create;
|
|
|
2
2
|
var __getProtoOf = Object.getPrototypeOf;
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
7
|
var __toESM = (mod, isNodeMode, target) => {
|
|
7
8
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
@@ -14,7 +15,38 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
14
15
|
});
|
|
15
16
|
return to;
|
|
16
17
|
};
|
|
18
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
19
|
+
var __toCommonJS = (from) => {
|
|
20
|
+
var entry = __moduleCache.get(from), desc;
|
|
21
|
+
if (entry)
|
|
22
|
+
return entry;
|
|
23
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
24
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
25
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
26
|
+
get: () => from[key],
|
|
27
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
28
|
+
}));
|
|
29
|
+
__moduleCache.set(from, entry);
|
|
30
|
+
return entry;
|
|
31
|
+
};
|
|
17
32
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
33
|
+
var __export = (target, all) => {
|
|
34
|
+
for (var name in all)
|
|
35
|
+
__defProp(target, name, {
|
|
36
|
+
get: all[name],
|
|
37
|
+
enumerable: true,
|
|
38
|
+
configurable: true,
|
|
39
|
+
set: (newValue) => all[name] = () => newValue
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
43
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
44
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
45
|
+
}) : x)(function(x) {
|
|
46
|
+
if (typeof require !== "undefined")
|
|
47
|
+
return require.apply(this, arguments);
|
|
48
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
49
|
+
});
|
|
18
50
|
|
|
19
51
|
// node_modules/qrcode/lib/can-promise.js
|
|
20
52
|
var require_can_promise = __commonJS((exports, module) => {
|
|
@@ -2092,232 +2124,6 @@ function isUnauthCode(code) {
|
|
|
2092
2124
|
return UNAUTH_CODES.has(code);
|
|
2093
2125
|
}
|
|
2094
2126
|
|
|
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
2127
|
// src/types.ts
|
|
2322
2128
|
var MessageType;
|
|
2323
2129
|
((MessageType2) => {
|
|
@@ -2400,10 +2206,12 @@ class Provider {
|
|
|
2400
2206
|
}
|
|
2401
2207
|
async submitTransaction(payload, options) {
|
|
2402
2208
|
const requestPayload = options?.estimateTraffic ? { ...payload, estimate_traffic: true } : payload;
|
|
2403
|
-
|
|
2209
|
+
const executionMode = options?.executionMode;
|
|
2210
|
+
const finalPayload = executionMode === "wait" ? { ...requestPayload, execution_mode: "wait" } : requestPayload;
|
|
2211
|
+
return this.sendRequest("run_transaction" /* RUN_TRANSACTION */, finalPayload, options);
|
|
2404
2212
|
}
|
|
2405
2213
|
async submitAndWaitForTransaction(payload, options) {
|
|
2406
|
-
const requestPayload = options?.estimateTraffic ? { ...payload,
|
|
2214
|
+
const requestPayload = options?.estimateTraffic ? { ...payload, estimate_traffic: true } : payload;
|
|
2407
2215
|
return this.sendRequest("run_transaction" /* RUN_TRANSACTION */, { ...requestPayload, execution_mode: "wait" }, options);
|
|
2408
2216
|
}
|
|
2409
2217
|
async transfer(recipient, amount, instrument, options) {
|
|
@@ -2559,6 +2367,283 @@ class Provider {
|
|
|
2559
2367
|
}
|
|
2560
2368
|
}
|
|
2561
2369
|
|
|
2370
|
+
// src/connection.ts
|
|
2371
|
+
class Connection {
|
|
2372
|
+
walletUrl = "https://cantonloop.com";
|
|
2373
|
+
apiUrl = "https://cantonloop.com";
|
|
2374
|
+
ws = null;
|
|
2375
|
+
network = "main";
|
|
2376
|
+
ticketId = null;
|
|
2377
|
+
onMessageHandler = null;
|
|
2378
|
+
reconnectPromise = null;
|
|
2379
|
+
status = "disconnected";
|
|
2380
|
+
constructor({ network, walletUrl, apiUrl }) {
|
|
2381
|
+
this.network = network || "main";
|
|
2382
|
+
switch (this.network) {
|
|
2383
|
+
case "local":
|
|
2384
|
+
this.walletUrl = "http://localhost:3000";
|
|
2385
|
+
this.apiUrl = "http://localhost:8080";
|
|
2386
|
+
break;
|
|
2387
|
+
case "devnet":
|
|
2388
|
+
case "dev":
|
|
2389
|
+
this.walletUrl = "https://devnet.cantonloop.com";
|
|
2390
|
+
this.apiUrl = "https://devnet.cantonloop.com";
|
|
2391
|
+
break;
|
|
2392
|
+
case "testnet":
|
|
2393
|
+
case "test":
|
|
2394
|
+
this.walletUrl = "https://testnet.cantonloop.com";
|
|
2395
|
+
this.apiUrl = "https://testnet.cantonloop.com";
|
|
2396
|
+
break;
|
|
2397
|
+
case "mainnet":
|
|
2398
|
+
case "main":
|
|
2399
|
+
this.walletUrl = "https://cantonloop.com";
|
|
2400
|
+
this.apiUrl = "https://cantonloop.com";
|
|
2401
|
+
break;
|
|
2402
|
+
}
|
|
2403
|
+
if (walletUrl) {
|
|
2404
|
+
this.walletUrl = walletUrl;
|
|
2405
|
+
}
|
|
2406
|
+
if (apiUrl) {
|
|
2407
|
+
this.apiUrl = apiUrl;
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2410
|
+
connectInProgress() {
|
|
2411
|
+
return this.status === "connecting" || this.status === "connected";
|
|
2412
|
+
}
|
|
2413
|
+
async getTicket(appName, sessionId, version) {
|
|
2414
|
+
const response = await fetch(`${this.apiUrl}/api/v1/.connect/pair/tickets`, {
|
|
2415
|
+
method: "POST",
|
|
2416
|
+
headers: {
|
|
2417
|
+
"Content-Type": "application/json"
|
|
2418
|
+
},
|
|
2419
|
+
body: JSON.stringify({
|
|
2420
|
+
app_name: appName,
|
|
2421
|
+
session_id: sessionId,
|
|
2422
|
+
version
|
|
2423
|
+
})
|
|
2424
|
+
});
|
|
2425
|
+
if (!response.ok) {
|
|
2426
|
+
throw new Error("Failed to get ticket from server.");
|
|
2427
|
+
}
|
|
2428
|
+
return response.json();
|
|
2429
|
+
}
|
|
2430
|
+
async getHolding(authToken) {
|
|
2431
|
+
const response = await fetch(`${this.apiUrl}/api/v1/.connect/pair/account/holding`, {
|
|
2432
|
+
method: "GET",
|
|
2433
|
+
headers: {
|
|
2434
|
+
"Content-Type": "application/json",
|
|
2435
|
+
Authorization: `Bearer ${authToken}`
|
|
2436
|
+
}
|
|
2437
|
+
});
|
|
2438
|
+
if (!response.ok) {
|
|
2439
|
+
throw new Error("Failed to get holdings. " + await response.text());
|
|
2440
|
+
}
|
|
2441
|
+
return response.json();
|
|
2442
|
+
}
|
|
2443
|
+
async getActiveContracts(authToken, params) {
|
|
2444
|
+
const url = new URL(`${this.apiUrl}/api/v1/.connect/pair/account/active-contracts`);
|
|
2445
|
+
if (params?.templateId) {
|
|
2446
|
+
url.searchParams.append("templateId", params.templateId);
|
|
2447
|
+
}
|
|
2448
|
+
if (params?.interfaceId) {
|
|
2449
|
+
url.searchParams.append("interfaceId", params.interfaceId);
|
|
2450
|
+
}
|
|
2451
|
+
const response = await fetch(url.toString(), {
|
|
2452
|
+
method: "GET",
|
|
2453
|
+
headers: {
|
|
2454
|
+
"Content-Type": "application/json",
|
|
2455
|
+
Authorization: `Bearer ${authToken}`
|
|
2456
|
+
}
|
|
2457
|
+
});
|
|
2458
|
+
if (!response.ok) {
|
|
2459
|
+
throw new Error("Failed to get active contracts.");
|
|
2460
|
+
}
|
|
2461
|
+
return response.json();
|
|
2462
|
+
}
|
|
2463
|
+
async prepareTransfer(authToken, params) {
|
|
2464
|
+
const payload = {
|
|
2465
|
+
recipient: params.recipient,
|
|
2466
|
+
amount: params.amount
|
|
2467
|
+
};
|
|
2468
|
+
if (params.instrument) {
|
|
2469
|
+
if (params.instrument.instrument_admin) {
|
|
2470
|
+
payload.instrument_admin = params.instrument.instrument_admin;
|
|
2471
|
+
}
|
|
2472
|
+
if (params.instrument.instrument_id) {
|
|
2473
|
+
payload.instrument_id = params.instrument.instrument_id;
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
if (params.requested_at) {
|
|
2477
|
+
payload.requested_at = params.requested_at;
|
|
2478
|
+
}
|
|
2479
|
+
if (params.execute_before) {
|
|
2480
|
+
payload.execute_before = params.execute_before;
|
|
2481
|
+
}
|
|
2482
|
+
if (params.memo) {
|
|
2483
|
+
payload.memo = params.memo;
|
|
2484
|
+
}
|
|
2485
|
+
const response = await fetch(`${this.apiUrl}/api/v1/.connect/pair/transfer`, {
|
|
2486
|
+
method: "POST",
|
|
2487
|
+
headers: {
|
|
2488
|
+
"Content-Type": "application/json",
|
|
2489
|
+
Authorization: `Bearer ${authToken}`
|
|
2490
|
+
},
|
|
2491
|
+
body: JSON.stringify(payload)
|
|
2492
|
+
});
|
|
2493
|
+
if (!response.ok) {
|
|
2494
|
+
console.error("Failed to prepare transfer.", await response.text());
|
|
2495
|
+
throw new Error("Failed to prepare transfer.");
|
|
2496
|
+
}
|
|
2497
|
+
const data = await response.json();
|
|
2498
|
+
return data.payload;
|
|
2499
|
+
}
|
|
2500
|
+
async verifySession(authToken) {
|
|
2501
|
+
const response = await fetch(`${this.apiUrl}/api/v1/.connect/pair/account`, {
|
|
2502
|
+
method: "GET",
|
|
2503
|
+
headers: {
|
|
2504
|
+
"Content-Type": "application/json",
|
|
2505
|
+
Authorization: `Bearer ${authToken}`
|
|
2506
|
+
}
|
|
2507
|
+
});
|
|
2508
|
+
if (!response.ok) {
|
|
2509
|
+
if (response.status === 401 || response.status === 403) {
|
|
2510
|
+
throw new UnauthorizedError;
|
|
2511
|
+
}
|
|
2512
|
+
throw new Error(`Session verification failed with status ${response.status}.`);
|
|
2513
|
+
}
|
|
2514
|
+
const data = await response.json();
|
|
2515
|
+
const email = data?.email;
|
|
2516
|
+
if (!data?.party_id || !data?.public_key) {
|
|
2517
|
+
throw new Error("Invalid session verification response.");
|
|
2518
|
+
}
|
|
2519
|
+
const account = {
|
|
2520
|
+
party_id: data?.party_id,
|
|
2521
|
+
auth_token: authToken,
|
|
2522
|
+
public_key: data?.public_key,
|
|
2523
|
+
email,
|
|
2524
|
+
has_preapproval: data?.has_preapproval,
|
|
2525
|
+
has_merge_delegation: data?.has_merge_delegation,
|
|
2526
|
+
usdc_bridge_access: data?.usdc_bridge_access
|
|
2527
|
+
};
|
|
2528
|
+
return account;
|
|
2529
|
+
}
|
|
2530
|
+
connectWebSocket(ticketId, onMessage) {
|
|
2531
|
+
if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) && this.ticketId !== ticketId) {
|
|
2532
|
+
this.ws.close();
|
|
2533
|
+
this.ws = null;
|
|
2534
|
+
}
|
|
2535
|
+
if (this.status === "connecting" || this.status === "connected") {
|
|
2536
|
+
return;
|
|
2537
|
+
}
|
|
2538
|
+
this.onMessageHandler = onMessage;
|
|
2539
|
+
this.ticketId = ticketId;
|
|
2540
|
+
this.status = "connecting";
|
|
2541
|
+
this.attachWebSocket(ticketId, onMessage);
|
|
2542
|
+
}
|
|
2543
|
+
reconnect() {
|
|
2544
|
+
if (!this.ticketId || !this.onMessageHandler) {
|
|
2545
|
+
return Promise.reject(new Error("Cannot reconnect without a known ticket."));
|
|
2546
|
+
}
|
|
2547
|
+
return new Promise((resolve, reject) => {
|
|
2548
|
+
let opened = false;
|
|
2549
|
+
this.attachWebSocket(this.ticketId, this.onMessageHandler, () => {
|
|
2550
|
+
opened = true;
|
|
2551
|
+
resolve();
|
|
2552
|
+
}, () => {
|
|
2553
|
+
if (opened) {
|
|
2554
|
+
return;
|
|
2555
|
+
}
|
|
2556
|
+
reject(new Error("Failed to reconnect to ticket server."));
|
|
2557
|
+
}, () => {
|
|
2558
|
+
if (opened) {
|
|
2559
|
+
return;
|
|
2560
|
+
}
|
|
2561
|
+
reject(new Error("Failed to reconnect to ticket server."));
|
|
2562
|
+
});
|
|
2563
|
+
});
|
|
2564
|
+
}
|
|
2565
|
+
async exchangeApiKey({ publicKey, signature, epoch }) {
|
|
2566
|
+
const response = await fetch(`${this.apiUrl}/api/v1/.connect/pair/apikey`, {
|
|
2567
|
+
method: "POST",
|
|
2568
|
+
headers: {
|
|
2569
|
+
"Content-Type": "application/json"
|
|
2570
|
+
},
|
|
2571
|
+
body: JSON.stringify({
|
|
2572
|
+
public_key: publicKey,
|
|
2573
|
+
signature,
|
|
2574
|
+
epoch
|
|
2575
|
+
})
|
|
2576
|
+
});
|
|
2577
|
+
if (!response.ok) {
|
|
2578
|
+
throw new Error("Failed to get API key from server.");
|
|
2579
|
+
}
|
|
2580
|
+
return response.json();
|
|
2581
|
+
}
|
|
2582
|
+
prepareTransaction(session, params) {
|
|
2583
|
+
return fetch(`${this.apiUrl}/api/v1/.connect/tickets/prepare-transaction`, {
|
|
2584
|
+
method: "POST",
|
|
2585
|
+
headers: {
|
|
2586
|
+
"Content-Type": "application/json",
|
|
2587
|
+
Authorization: `Bearer ${session.userApiKey}`
|
|
2588
|
+
},
|
|
2589
|
+
body: JSON.stringify({
|
|
2590
|
+
payload: params,
|
|
2591
|
+
ticket_id: session.ticketId
|
|
2592
|
+
})
|
|
2593
|
+
}).then((response) => response.json());
|
|
2594
|
+
}
|
|
2595
|
+
async executeTransaction(session, params) {
|
|
2596
|
+
if (!session.ticketId) {
|
|
2597
|
+
throw new Error("Ticket ID is required");
|
|
2598
|
+
}
|
|
2599
|
+
const resp = fetch(`${this.apiUrl}/api/v1/.connect/tickets/execute-transaction`, {
|
|
2600
|
+
method: "POST",
|
|
2601
|
+
headers: {
|
|
2602
|
+
"Content-Type": "application/json",
|
|
2603
|
+
Authorization: `Bearer ${session.userApiKey}`
|
|
2604
|
+
},
|
|
2605
|
+
body: JSON.stringify({
|
|
2606
|
+
ticket_id: session.ticketId,
|
|
2607
|
+
request_id: generateRequestId(),
|
|
2608
|
+
command_id: params.command_id,
|
|
2609
|
+
signature: params.signature,
|
|
2610
|
+
transaction_data: params.transaction_data
|
|
2611
|
+
})
|
|
2612
|
+
});
|
|
2613
|
+
return (await resp).json();
|
|
2614
|
+
}
|
|
2615
|
+
websocketUrl(ticketId) {
|
|
2616
|
+
return `${this.network === "local" ? "ws" : "wss"}://${this.apiUrl.replace("https://", "").replace("http://", "")}/api/v1/.connect/pair/ws/${encodeURIComponent(ticketId)}`;
|
|
2617
|
+
}
|
|
2618
|
+
attachWebSocket(ticketId, onMessage, onOpen, onError, onClose) {
|
|
2619
|
+
const wsUrl = this.websocketUrl(ticketId);
|
|
2620
|
+
const ws = new WebSocket(wsUrl);
|
|
2621
|
+
ws.onmessage = onMessage;
|
|
2622
|
+
ws.onopen = () => {
|
|
2623
|
+
this.status = "connected";
|
|
2624
|
+
console.log("[LoopSDK] Connected to ticket server.");
|
|
2625
|
+
onOpen?.();
|
|
2626
|
+
};
|
|
2627
|
+
ws.onclose = (event) => {
|
|
2628
|
+
this.status = "disconnected";
|
|
2629
|
+
if (this.ws === ws) {
|
|
2630
|
+
this.ws = null;
|
|
2631
|
+
}
|
|
2632
|
+
console.log("[LoopSDK] Disconnected from ticket server.");
|
|
2633
|
+
onClose?.(event);
|
|
2634
|
+
};
|
|
2635
|
+
ws.onerror = (event) => {
|
|
2636
|
+
this.status = "disconnected";
|
|
2637
|
+
ws.close();
|
|
2638
|
+
if (this.ws === ws) {
|
|
2639
|
+
this.ws = null;
|
|
2640
|
+
}
|
|
2641
|
+
onError?.(event);
|
|
2642
|
+
};
|
|
2643
|
+
this.ws = ws;
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
|
|
2562
2647
|
// src/session.ts
|
|
2563
2648
|
var STORAGE_KEY_LOOP_CONNECT = "loop_connect";
|
|
2564
2649
|
|
|
@@ -2569,14 +2654,16 @@ class SessionInfo {
|
|
|
2569
2654
|
partyId;
|
|
2570
2655
|
publicKey;
|
|
2571
2656
|
email;
|
|
2657
|
+
userApiKey;
|
|
2572
2658
|
_isAuthorized = false;
|
|
2573
|
-
constructor({ sessionId, ticketId, authToken, partyId, publicKey, email }) {
|
|
2659
|
+
constructor({ sessionId, ticketId, authToken, partyId, publicKey, email, userApiKey }) {
|
|
2574
2660
|
this.sessionId = sessionId;
|
|
2575
2661
|
this.ticketId = ticketId;
|
|
2576
2662
|
this.authToken = authToken;
|
|
2577
2663
|
this.partyId = partyId;
|
|
2578
2664
|
this.publicKey = publicKey;
|
|
2579
2665
|
this.email = email;
|
|
2666
|
+
this.userApiKey = userApiKey;
|
|
2580
2667
|
}
|
|
2581
2668
|
setTicketId(ticketId) {
|
|
2582
2669
|
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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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Provider } from '../provider';
|
|
2
|
+
import type { Network, TransactionPayload } from '../types';
|
|
3
|
+
import { Signer } from './signer';
|
|
4
|
+
export declare class LoopSDK {
|
|
5
|
+
private signer?;
|
|
6
|
+
private provider?;
|
|
7
|
+
private connection?;
|
|
8
|
+
private isAuthenticated;
|
|
9
|
+
private session?;
|
|
10
|
+
init({ privateKey, partyId, network, walletUrl, apiUrl }: {
|
|
11
|
+
privateKey: string;
|
|
12
|
+
partyId: string;
|
|
13
|
+
network?: Network;
|
|
14
|
+
walletUrl?: string;
|
|
15
|
+
apiUrl?: string;
|
|
16
|
+
}): void;
|
|
17
|
+
authenticate(): Promise<void>;
|
|
18
|
+
getSigner(): Signer;
|
|
19
|
+
getProvider(): Provider;
|
|
20
|
+
executeTransaction(payload: TransactionPayload): Promise<any>;
|
|
21
|
+
}
|
|
22
|
+
export declare const loop: LoopSDK;
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAsB,MAAM,aAAa,CAAC;AAG3D,OAAO,KAAK,EAAE,OAAO,EAAyE,kBAAkB,EAAyD,MAAM,UAAU,CAAC;AAE1L,OAAO,EAAa,MAAM,EAAE,MAAM,UAAU,CAAC;AA4C7C,qBAAa,OAAO;IAChB,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,CAAc;IAC/B,OAAO,CAAC,UAAU,CAAC,CAAa;IAChC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,OAAO,CAAC,CAAc;IAE9B,IAAI,CAAC,EAAC,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAC;IASzI,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAoCnC,SAAS,IAAI,MAAM;IAOnB,WAAW,IAAI,QAAQ;IAOjB,kBAAkB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,GAAG,CAAC;CAuB7E;AAED,eAAO,MAAM,IAAI,SAAgB,CAAC"}
|