@fivenorth/loop-sdk 0.11.0 → 0.11.2

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 CHANGED
@@ -80,7 +80,7 @@ loop.connect();
80
80
  ```
81
81
 
82
82
  This will open a modal with a QR code for the user to scan with their Loop wallet.
83
- If you set `requestSigningMode` to `'popup'` (or `'tab'`), each signing/transaction request will also open the wallet dashboard and auto-close the popup once the wallet responds.
83
+ If you set `requestSigningMode` to `'popup'` (or `'tab'`), each signing/transaction request will also open the wallet dashboard. The SDK does not auto-close the popup/tab; wallet UI controls completion/close behavior.
84
84
 
85
85
  ### 3. Using the Provider
86
86
 
@@ -241,9 +241,70 @@ Coming soon
241
241
 
242
242
  Loop SDK also supports a server-side signing flow. Instead of a wallet popup, your backend signs and submits transactions directly using the user's private key.
243
243
 
244
+ ### Installation
245
+
246
+ For server-side usage, you need to install the SDK and `node-forge`:
247
+
248
+ ```bash
249
+ bun add @fivenorth/loop-sdk node-forge
250
+ # or
251
+ npm install @fivenorth/loop-sdk node-forge
252
+ ```
253
+
254
+ **Note:** `node-forge` is a peer dependency and must be installed manually when using the server SDK. It's not required for browser usage.
255
+
256
+ ### Usage
257
+
258
+ ```javascript
259
+ import { loop } from '@fivenorth/loop-sdk/server';
260
+
261
+ // Initialize with private key
262
+ loop.init({
263
+ privateKey: process.env.PRIVATE_KEY, // hex-encoded Ed25519 private key
264
+ partyId: process.env.PARTY_ID, // your party ID
265
+ network: 'local', // or 'devnet', 'mainnet'
266
+ walletUrl: process.env.WALLET_URL, // optional
267
+ apiUrl: process.env.API_URL, // optional
268
+ });
269
+
270
+ // Authenticate to get API access
271
+ await loop.authenticate();
272
+
273
+ // Get the provider to interact with the ledger
274
+ const provider = loop.getProvider();
275
+
276
+ // List holdings
277
+ const holdings = await provider.getHolding();
278
+ console.log(holdings);
279
+
280
+ // Get active contracts
281
+ const contracts = await provider.getActiveContracts({
282
+ templateId: '#splice-amulet:Splice.Amulet:Amulet'
283
+ });
284
+
285
+ // Transfer tokens
286
+ const preparedPayload = await provider.transfer(
287
+ 'recipient::partyId',
288
+ 1,
289
+ {
290
+ instrument_admin: '',
291
+ instrument_id: 'Amulet',
292
+ },
293
+ {
294
+ requestedAt: new Date(),
295
+ executeBefore: new Date(Date.now() + 24 * 60 * 60 * 1000),
296
+ }
297
+ );
298
+
299
+ // Execute the transaction
300
+ const result = await loop.executeTransaction(preparedPayload);
301
+ console.log('Transfer result:', result);
302
+ ```
303
+
244
304
  Example ideas:
245
305
  - List pending transfers
246
306
  - Accept a pending transfer
307
+ - Automated transaction processing
247
308
 
248
309
 
249
310
  # Development Guide
@@ -0,0 +1,290 @@
1
+ import { UnauthorizedError } from './errors';
2
+ import { generateRequestId } from './provider';
3
+ export class Connection {
4
+ walletUrl = 'https://cantonloop.com';
5
+ apiUrl = 'https://cantonloop.com';
6
+ ws = null;
7
+ network = 'main';
8
+ ticketId = null;
9
+ onMessageHandler = null;
10
+ reconnectPromise = null;
11
+ status = 'disconnected';
12
+ constructor({ network, walletUrl, apiUrl }) {
13
+ this.network = network || 'main';
14
+ // Set default common value based on network
15
+ switch (this.network) {
16
+ case 'local':
17
+ this.walletUrl = 'http://localhost:3000';
18
+ this.apiUrl = 'http://localhost:8080';
19
+ break;
20
+ case 'devnet':
21
+ case 'dev':
22
+ this.walletUrl = 'https://devnet.cantonloop.com';
23
+ this.apiUrl = 'https://devnet.cantonloop.com';
24
+ break;
25
+ case 'testnet':
26
+ case 'test':
27
+ this.walletUrl = 'https://testnet.cantonloop.com';
28
+ this.apiUrl = 'https://testnet.cantonloop.com';
29
+ break;
30
+ case 'mainnet':
31
+ case 'main':
32
+ this.walletUrl = 'https://cantonloop.com';
33
+ this.apiUrl = 'https://cantonloop.com';
34
+ break;
35
+ }
36
+ // More useful when developing locally
37
+ if (walletUrl) {
38
+ this.walletUrl = walletUrl;
39
+ }
40
+ if (apiUrl) {
41
+ this.apiUrl = apiUrl;
42
+ }
43
+ }
44
+ connectInProgress() {
45
+ return this.status === 'connecting' || this.status === 'connected';
46
+ }
47
+ async getTicket(appName, sessionId, version) {
48
+ const response = await fetch(`${this.apiUrl}/api/v1/.connect/pair/tickets`, {
49
+ method: 'POST',
50
+ headers: {
51
+ 'Content-Type': 'application/json',
52
+ },
53
+ body: JSON.stringify({
54
+ app_name: appName,
55
+ session_id: sessionId,
56
+ version: version,
57
+ }),
58
+ });
59
+ if (!response.ok) {
60
+ throw new Error('Failed to get ticket from server.');
61
+ }
62
+ return response.json();
63
+ }
64
+ async getHolding(authToken) {
65
+ const response = await fetch(`${this.apiUrl}/api/v1/.connect/pair/account/holding`, {
66
+ method: 'GET',
67
+ headers: {
68
+ 'Content-Type': 'application/json',
69
+ 'Authorization': `Bearer ${authToken}`,
70
+ },
71
+ });
72
+ if (!response.ok) {
73
+ throw new Error('Failed to get holdings. ' + await response.text());
74
+ }
75
+ return response.json();
76
+ }
77
+ async getActiveContracts(authToken, params) {
78
+ const url = new URL(`${this.apiUrl}/api/v1/.connect/pair/account/active-contracts`);
79
+ if (params?.templateId) {
80
+ url.searchParams.append('templateId', params.templateId);
81
+ }
82
+ if (params?.interfaceId) {
83
+ url.searchParams.append('interfaceId', params.interfaceId);
84
+ }
85
+ const response = await fetch(url.toString(), {
86
+ method: 'GET',
87
+ headers: {
88
+ 'Content-Type': 'application/json',
89
+ 'Authorization': `Bearer ${authToken}`,
90
+ },
91
+ });
92
+ if (!response.ok) {
93
+ throw new Error('Failed to get active contracts.');
94
+ }
95
+ return response.json();
96
+ }
97
+ async prepareTransfer(authToken, params) {
98
+ const payload = {
99
+ recipient: params.recipient,
100
+ amount: params.amount,
101
+ };
102
+ if (params.instrument) {
103
+ if (params.instrument.instrument_admin) {
104
+ payload.instrument_admin = params.instrument.instrument_admin;
105
+ }
106
+ if (params.instrument.instrument_id) {
107
+ payload.instrument_id = params.instrument.instrument_id;
108
+ }
109
+ }
110
+ if (params.requested_at) {
111
+ payload.requested_at = params.requested_at;
112
+ }
113
+ if (params.execute_before) {
114
+ payload.execute_before = params.execute_before;
115
+ }
116
+ if (params.memo) {
117
+ payload.memo = params.memo;
118
+ }
119
+ const response = await fetch(`${this.apiUrl}/api/v1/.connect/pair/transfer`, {
120
+ method: 'POST',
121
+ headers: {
122
+ 'Content-Type': 'application/json',
123
+ 'Authorization': `Bearer ${authToken}`,
124
+ },
125
+ body: JSON.stringify(payload),
126
+ });
127
+ if (!response.ok) {
128
+ console.error('Failed to prepare transfer.', await response.text());
129
+ throw new Error('Failed to prepare transfer.');
130
+ }
131
+ const data = await response.json();
132
+ return data.payload;
133
+ }
134
+ async verifySession(authToken) {
135
+ const response = await fetch(`${this.apiUrl}/api/v1/.connect/pair/account`, {
136
+ method: 'GET',
137
+ headers: {
138
+ 'Content-Type': 'application/json',
139
+ 'Authorization': `Bearer ${authToken}`,
140
+ },
141
+ });
142
+ if (!response.ok) {
143
+ if (response.status === 401 || response.status === 403) {
144
+ throw new UnauthorizedError();
145
+ }
146
+ throw new Error(`Session verification failed with status ${response.status}.`);
147
+ }
148
+ const data = await response.json();
149
+ const email = data?.email;
150
+ if (!data?.party_id || !data?.public_key) {
151
+ throw new Error('Invalid session verification response.');
152
+ }
153
+ // Map fields from the response to the account object, handling camelCase and snake_case.
154
+ const account = {
155
+ party_id: data?.party_id,
156
+ auth_token: authToken,
157
+ public_key: data?.public_key,
158
+ email,
159
+ has_preapproval: data?.has_preapproval,
160
+ has_merge_delegation: data?.has_merge_delegation,
161
+ usdc_bridge_access: data?.usdc_bridge_access,
162
+ };
163
+ return account;
164
+ }
165
+ connectWebSocket(ticketId, onMessage) {
166
+ if (this.ws &&
167
+ (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) &&
168
+ this.ticketId !== ticketId) {
169
+ // When connecting to a new ticket, we need to close the existing socket first
170
+ this.ws.close();
171
+ this.ws = null;
172
+ }
173
+ // prevent opening multiple sockets for same ticket
174
+ if (this.status === 'connecting' || this.status === 'connected') {
175
+ return;
176
+ }
177
+ // set the message handler and ticket id to re-use for reconnecting
178
+ this.onMessageHandler = onMessage;
179
+ this.ticketId = ticketId;
180
+ this.status = 'connecting';
181
+ this.attachWebSocket(ticketId, onMessage);
182
+ }
183
+ reconnect() {
184
+ if (!this.ticketId || !this.onMessageHandler) {
185
+ return Promise.reject(new Error('Cannot reconnect without a known ticket.'));
186
+ }
187
+ return new Promise((resolve, reject) => {
188
+ let opened = false;
189
+ this.attachWebSocket(this.ticketId, this.onMessageHandler, () => {
190
+ opened = true;
191
+ resolve();
192
+ }, () => {
193
+ if (opened) {
194
+ return;
195
+ }
196
+ reject(new Error('Failed to reconnect to ticket server.'));
197
+ }, () => {
198
+ if (opened) {
199
+ return;
200
+ }
201
+ reject(new Error('Failed to reconnect to ticket server.'));
202
+ });
203
+ });
204
+ }
205
+ // exchangeApiKey is used to exchange the API key for the public key and signature to use in a server session
206
+ async exchangeApiKey({ publicKey, signature, epoch }) {
207
+ const response = await fetch(`${this.apiUrl}/api/v1/.connect/pair/apikey`, {
208
+ method: 'POST',
209
+ headers: {
210
+ 'Content-Type': 'application/json',
211
+ },
212
+ body: JSON.stringify({
213
+ public_key: publicKey,
214
+ signature: signature,
215
+ epoch: epoch,
216
+ })
217
+ });
218
+ if (!response.ok) {
219
+ throw new Error('Failed to get API key from server.');
220
+ }
221
+ return response.json();
222
+ }
223
+ // send transaction to v2/interactive-submisison/prepare endpoint to get the prepared transaction
224
+ prepareTransaction(session, params) {
225
+ return fetch(`${this.apiUrl}/api/v1/.connect/tickets/prepare-transaction`, {
226
+ method: 'POST',
227
+ headers: {
228
+ 'Content-Type': 'application/json',
229
+ 'Authorization': `Bearer ${session.userApiKey}`,
230
+ },
231
+ body: JSON.stringify({
232
+ payload: params,
233
+ ticket_id: session.ticketId,
234
+ })
235
+ }).then(response => response.json());
236
+ }
237
+ // execute a signed transaction with v2/interactive-submisison/execute endpoint
238
+ async executeTransaction(session, params) {
239
+ if (!session.ticketId) {
240
+ throw new Error('Ticket ID is required');
241
+ }
242
+ const resp = fetch(`${this.apiUrl}/api/v1/.connect/tickets/execute-transaction`, {
243
+ method: 'POST',
244
+ headers: {
245
+ 'Content-Type': 'application/json',
246
+ 'Authorization': `Bearer ${session.userApiKey}`,
247
+ },
248
+ body: JSON.stringify({
249
+ ticket_id: session.ticketId,
250
+ request_id: generateRequestId(),
251
+ command_id: params.command_id,
252
+ signature: params.signature,
253
+ transaction_data: params.transaction_data,
254
+ }),
255
+ });
256
+ return (await resp).json();
257
+ }
258
+ websocketUrl(ticketId) {
259
+ return `${this.network === 'local' ? 'ws' : 'wss'}://${this.apiUrl.replace('https://', '').replace('http://', '')}/api/v1/.connect/pair/ws/${encodeURIComponent(ticketId)}`;
260
+ }
261
+ // attachWebSocket is a helper function to setup even handler on a websocket object and assign to our ws
262
+ attachWebSocket(ticketId, onMessage, onOpen, onError, onClose) {
263
+ const wsUrl = this.websocketUrl(ticketId);
264
+ const ws = new WebSocket(wsUrl);
265
+ ws.onmessage = onMessage;
266
+ ws.onopen = () => {
267
+ this.status = 'connected';
268
+ console.log('[LoopSDK] Connected to ticket server.');
269
+ onOpen?.();
270
+ };
271
+ ws.onclose = (event) => {
272
+ this.status = 'disconnected';
273
+ if (this.ws === ws) {
274
+ this.ws = null;
275
+ }
276
+ console.log('[LoopSDK] Disconnected from ticket server.');
277
+ onClose?.(event);
278
+ };
279
+ ws.onerror = (event) => {
280
+ // if it's already close, another close is a no-op
281
+ this.status = 'disconnected';
282
+ ws.close();
283
+ if (this.ws === ws) {
284
+ this.ws = null;
285
+ }
286
+ onError?.(event);
287
+ };
288
+ this.ws = ws;
289
+ }
290
+ }
package/dist/errors.d.ts CHANGED
@@ -2,7 +2,8 @@ export declare class RequestTimeoutError extends Error {
2
2
  constructor(timeout: number);
3
3
  }
4
4
  export declare class RejectRequestError extends Error {
5
- constructor();
5
+ code?: string;
6
+ constructor(message?: string, code?: string);
6
7
  }
7
8
  export declare class UnauthorizedError extends Error {
8
9
  code?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,mBAAoB,SAAQ,KAAK;gBAC9B,OAAO,EAAE,MAAM;CAG9B;AAED,qBAAa,kBAAmB,SAAQ,KAAK;;CAI5C;AAED,qBAAa,iBAAkB,SAAQ,KAAK;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;gBACT,IAAI,CAAC,EAAE,MAAM;CAI5B;AAID,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI,CAQ5D;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,IAAI,MAAM,CAK5E"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,mBAAoB,SAAQ,KAAK;gBAC9B,OAAO,EAAE,MAAM;CAG9B;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;gBACT,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;CAI9C;AAED,qBAAa,iBAAkB,SAAQ,KAAK;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;gBACT,IAAI,CAAC,EAAE,MAAM;CAI5B;AAID,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI,CAQ5D;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,IAAI,MAAM,CAK5E"}
package/dist/errors.js ADDED
@@ -0,0 +1,35 @@
1
+ export class RequestTimeoutError extends Error {
2
+ constructor(timeout) {
3
+ super(`Request timed out after ${timeout}ms.`);
4
+ }
5
+ }
6
+ export class RejectRequestError extends Error {
7
+ code;
8
+ constructor(message, code) {
9
+ super(message || 'Request was rejected by the wallet.');
10
+ this.code = code;
11
+ }
12
+ }
13
+ export class UnauthorizedError extends Error {
14
+ code;
15
+ constructor(code) {
16
+ super(code || 'Unauthorized');
17
+ this.code = code;
18
+ }
19
+ }
20
+ const UNAUTH_CODES = new Set(['UNAUTHENTICATED', 'UNAUTHORIZED', 'SESSION_EXPIRED', 'LOGGED_OUT']);
21
+ export function extractErrorCode(message) {
22
+ if (typeof message?.error?.code === 'string' && message.error.code.length > 0) {
23
+ return message.error.code;
24
+ }
25
+ if (message?.type === 'unauthorized' && typeof message?.code === 'string') {
26
+ return message.code;
27
+ }
28
+ return null;
29
+ }
30
+ export function isUnauthCode(code) {
31
+ if (!code) {
32
+ return false;
33
+ }
34
+ return UNAUTH_CODES.has(code);
35
+ }
@@ -0,0 +1,52 @@
1
+ export class UsdcBridge {
2
+ getProvider;
3
+ constructor(getProvider) {
4
+ this.getProvider = getProvider;
5
+ }
6
+ requireProvider() {
7
+ const provider = this.getProvider();
8
+ if (!provider) {
9
+ throw new Error('SDK not connected. Call connect() and wait for acceptance first.');
10
+ }
11
+ return provider;
12
+ }
13
+ withdrawalUSDCxToEthereum(recipient, amount, options) {
14
+ const provider = this.requireProvider();
15
+ const amountStr = typeof amount === 'number' ? amount.toString() : amount;
16
+ const withdrawRequest = {
17
+ recipient,
18
+ amount: amountStr,
19
+ reference: options?.reference,
20
+ };
21
+ return prepareUsdcWithdraw(provider.connection, provider.getAuthToken(), withdrawRequest).then((preparedPayload) => provider.submitTransaction({
22
+ commands: preparedPayload.commands,
23
+ disclosedContracts: preparedPayload.disclosedContracts,
24
+ packageIdSelectionPreference: preparedPayload.packageIdSelectionPreference,
25
+ actAs: preparedPayload.actAs,
26
+ readAs: preparedPayload.readAs,
27
+ synchronizerId: preparedPayload.synchronizerId,
28
+ }, { requestTimeout: options?.requestTimeout, message: options?.message }));
29
+ }
30
+ }
31
+ export async function prepareUsdcWithdraw(connection, authToken, params) {
32
+ const payload = {
33
+ recipient: params.recipient,
34
+ amount: params.amount,
35
+ };
36
+ if (params.reference) {
37
+ payload.reference = params.reference;
38
+ }
39
+ const response = await fetch(`${connection.apiUrl}/api/v1/.connect/pair/usdc/withdraw`, {
40
+ method: 'POST',
41
+ headers: {
42
+ 'Content-Type': 'application/json',
43
+ 'Authorization': `Bearer ${authToken}`,
44
+ },
45
+ body: JSON.stringify(payload),
46
+ });
47
+ if (!response.ok) {
48
+ throw new Error('Failed to prepare USDC withdrawal.');
49
+ }
50
+ const data = await response.json();
51
+ return data.payload;
52
+ }
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.d.ts CHANGED
@@ -38,7 +38,6 @@ declare class LoopSDK {
38
38
  private buildConnectUrl;
39
39
  private buildDashboardUrl;
40
40
  private openRequestUi;
41
- private closePopupIfExists;
42
41
  private openWallet;
43
42
  private injectModalStyles;
44
43
  private showQrCode;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAqB,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEzD,OAAO,KAAK,EAGX,OAAO,EAEP,MAAM,EACN,sBAAsB,EACtB,MAAM,SAAS,CAAC;AAIjB,cAAM,OAAO;IACZ,OAAO,CAAC,OAAO,CAAmB;IAElC,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,kBAAkB,CAA4B;IACtD,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,WAAW,CAAC,CAAS;IAE7B,OAAO,CAAC,QAAQ,CAA+C;IAC/D,OAAO,CAAC,QAAQ,CAA6B;IAC3C,OAAO,CAAC,mBAAmB,CAA0E;IACvG,OAAO,CAAC,OAAO,CAA+B;IACvC,MAAM,EAAE,MAAM,CAAC;;IAMtB,IAAI,CAAC,EACJ,OAAO,EACP,OAAO,EACP,SAAS,EACT,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,mBAAmB,EACnB,OAAO,GACP,EAAE;QACF,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;QACxC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;QACtB,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE,sBAAsB,EAAE,OAAO,EAAE,GAAG,KAAK,IAAI,CAAC;QAC9E,OAAO,CAAC,EAAE;YACT,QAAQ,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;YAC3B,kBAAkB,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;YACrC,WAAW,CAAC,EAAE,MAAM,CAAC;SACrB,CAAC;KACF;YAiCa,eAAe;IA6CvB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IA8B5B,OAAO;IA2Cb,OAAO,CAAC,sBAAsB;IA8DvB,aAAa,IAAI,MAAM;IAO9B,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,aAAa;IAqBrB,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,UAAU;IAuClB,OAAO,CAAC,iBAAiB;IAyIzB,OAAO,CAAC,UAAU;IAoFlB,OAAO,CAAC,UAAU;IAOlB,MAAM;IAQN,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,mBAAmB;CAe3B;AAED,eAAO,MAAM,IAAI,SAAgB,CAAC;AAClC,cAAc,yBAAyB,CAAC;AACxC,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAqB,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEzD,OAAO,KAAK,EAGX,OAAO,EAEP,MAAM,EACN,sBAAsB,EACtB,MAAM,SAAS,CAAC;AAIjB,cAAM,OAAO;IACZ,OAAO,CAAC,OAAO,CAAoB;IAEnC,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,kBAAkB,CAA4B;IACtD,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,WAAW,CAAC,CAAS;IAE7B,OAAO,CAAC,QAAQ,CAA+C;IAC/D,OAAO,CAAC,QAAQ,CAA6B;IAC3C,OAAO,CAAC,mBAAmB,CAA0E;IACvG,OAAO,CAAC,OAAO,CAA+B;IACvC,MAAM,EAAE,MAAM,CAAC;;IAMtB,IAAI,CAAC,EACJ,OAAO,EACP,OAAO,EACP,SAAS,EACT,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,mBAAmB,EACnB,OAAO,GACP,EAAE;QACF,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;QACxC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;QACtB,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE,sBAAsB,EAAE,OAAO,EAAE,GAAG,KAAK,IAAI,CAAC;QAC9E,OAAO,CAAC,EAAE;YACT,QAAQ,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;YAC3B,kBAAkB,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;YACrC,WAAW,CAAC,EAAE,MAAM,CAAC;SACrB,CAAC;KACF;YAiCa,eAAe;IA6CvB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IA8B5B,OAAO;IA2Cb,OAAO,CAAC,sBAAsB;IA8DvB,aAAa,IAAI,MAAM;IAO9B,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,aAAa;IAqBrB,OAAO,CAAC,UAAU;IAuClB,OAAO,CAAC,iBAAiB;IAyIzB,OAAO,CAAC,UAAU;IAoFlB,OAAO,CAAC,UAAU;IAOlB,MAAM;IAQN,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,mBAAmB;CAO3B;AAED,eAAO,MAAM,IAAI,SAAgB,CAAC;AAClC,cAAc,yBAAyB,CAAC;AACxC,cAAc,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -2,51 +2,33 @@ 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;
6
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ function __accessProp(key) {
7
+ return this[key];
8
+ }
9
+ var __toESMCache_node;
10
+ var __toESMCache_esm;
7
11
  var __toESM = (mod, isNodeMode, target) => {
12
+ var canCache = mod != null && typeof mod === "object";
13
+ if (canCache) {
14
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
15
+ var cached = cache.get(mod);
16
+ if (cached)
17
+ return cached;
18
+ }
8
19
  target = mod != null ? __create(__getProtoOf(mod)) : {};
9
20
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
21
  for (let key of __getOwnPropNames(mod))
11
22
  if (!__hasOwnProp.call(to, key))
12
23
  __defProp(to, key, {
13
- get: () => mod[key],
24
+ get: __accessProp.bind(mod, key),
14
25
  enumerable: true
15
26
  });
27
+ if (canCache)
28
+ cache.set(mod, to);
16
29
  return to;
17
30
  };
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
- };
32
31
  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
- });
50
32
 
51
33
  // node_modules/qrcode/lib/can-promise.js
52
34
  var require_can_promise = __commonJS((exports, module) => {
@@ -2095,8 +2077,10 @@ class RequestTimeoutError extends Error {
2095
2077
  }
2096
2078
 
2097
2079
  class RejectRequestError extends Error {
2098
- constructor() {
2099
- super("Request was rejected by the wallet.");
2080
+ code;
2081
+ constructor(message, code) {
2082
+ super(message || "Request was rejected by the wallet.");
2083
+ this.code = code;
2100
2084
  }
2101
2085
  }
2102
2086
 
@@ -2330,13 +2314,15 @@ class Provider {
2330
2314
  return;
2331
2315
  }
2332
2316
  if (response.type === "reject_request" /* REJECT_REQUEST */) {
2317
+ const rejectMessage = response?.payload?.message;
2318
+ const rejectCode = response?.payload?.code;
2333
2319
  this.hooks?.onRequestFinish?.({
2334
2320
  status: "rejected",
2335
2321
  messageType,
2336
2322
  requestLabel: options?.requestLabel,
2337
2323
  requestContext
2338
2324
  });
2339
- reject(new RejectRequestError);
2325
+ reject(new RejectRequestError(rejectMessage, rejectCode));
2340
2326
  } else {
2341
2327
  this.hooks?.onRequestFinish?.({
2342
2328
  status: "success",
@@ -2800,7 +2786,7 @@ class LoopWallet {
2800
2786
 
2801
2787
  // src/index.ts
2802
2788
  class LoopSDK {
2803
- version = "0.7.6";
2789
+ version = "0.11.2";
2804
2790
  appName = "Unknown";
2805
2791
  connection = null;
2806
2792
  session = null;
@@ -3005,14 +2991,6 @@ class LoopSDK {
3005
2991
  }
3006
2992
  return null;
3007
2993
  }
3008
- closePopupIfExists() {
3009
- if (this.popupWindow && !this.popupWindow.closed) {
3010
- try {
3011
- this.popupWindow.close();
3012
- } catch {}
3013
- }
3014
- this.popupWindow = null;
3015
- }
3016
2994
  openWallet(url, mode) {
3017
2995
  if (typeof window === "undefined") {
3018
2996
  return null;
@@ -3253,13 +3231,8 @@ class LoopSDK {
3253
3231
  createProviderHooks() {
3254
3232
  return {
3255
3233
  onRequestStart: () => this.openRequestUi(),
3256
- onRequestFinish: ({ requestContext }) => {
3257
- const win = requestContext;
3258
- if (win) {
3259
- setTimeout(() => {
3260
- this.closePopupIfExists();
3261
- }, 800);
3262
- }
3234
+ onRequestFinish: () => {
3235
+ return;
3263
3236
  },
3264
3237
  onTransactionUpdate: this.onTransactionUpdate ?? undefined
3265
3238
  };
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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"}