@0xio/sdk 2.4.0 → 2.4.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/CHANGELOG.md +32 -0
- package/README.md +12 -7
- package/dist/index.d.ts +17 -8
- package/dist/index.esm.js +111 -47
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +111 -47
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +111 -47
- package/dist/index.umd.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to the 0xio Wallet SDK will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [2.4.1] - 2026-04-14
|
|
6
|
+
|
|
7
|
+
### Security
|
|
8
|
+
- **[CRITICAL] postMessage origin validation**: Parent-frame messages now validated against a strict trusted origins set instead of accepting all origins. Prevents malicious pages from intercepting wallet requests via iframe embedding.
|
|
9
|
+
- **[CRITICAL] Removed auto-trust for iframes**: SDK no longer assumes any iframe parent is a wallet bridge. Must receive a `walletReady` signal from a trusted origin first.
|
|
10
|
+
- **[CRITICAL] Response binding**: Only responses with matching pending request IDs are processed. Forged responses from injected scripts are rejected.
|
|
11
|
+
- **[HIGH] Removed `simulateExtensionEvent`**: Dev utility that could be exploited on staging builds to inject fake wallet events has been removed.
|
|
12
|
+
- **[HIGH] No wildcard postMessage**: `postMessageToExtension` now uses specific trusted origins (`tauri://localhost`, etc.) instead of `'*'` for parent-frame communication.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
- **No retry on user rejection**: `retry()` detects rejection/denied/cancelled errors and throws immediately. Prevents double confirmation popups.
|
|
16
|
+
- **`withTimeout` timer leak**: Timer is now cleared via `.finally()` when the promise resolves, preventing 30s memory retention per request.
|
|
17
|
+
- **`retry` off-by-one**: `maxRetries=1` now correctly means 1 initial + 1 retry = 2 total (was 3).
|
|
18
|
+
- **Message listener cleanup**: `cleanup()` now removes the `window.addEventListener('message')` listener, preventing accumulation on re-instantiation.
|
|
19
|
+
- **Type compatibility**: Replaced `NodeJS.Timeout` with `ReturnType<typeof setTimeout>` for browser-only environments.
|
|
20
|
+
- **`process.env` guard**: `createLogger` now uses optional chaining for `process.env.NODE_ENV`, preventing ReferenceError when imported in browser without bundler.
|
|
21
|
+
- **Duplicate `isValidNetworkId`**: Removed duplicate export from `utils.ts`, canonical version in `config/networks.ts`.
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
- **`setTrustedOrigins(origins)`**: New method to configure allowed parent-frame origins for iframe/bridge communication.
|
|
25
|
+
|
|
26
|
+
### Documentation
|
|
27
|
+
- Fixed all event listener examples to use `event.data.xxx` (WalletEvent wrapper)
|
|
28
|
+
- Fixed `TransactionHistory` type (`totalCount`/`hasMore` instead of `total`/`limit`/`totalPages`)
|
|
29
|
+
- Fixed `retry()` docs (positional args, not options object)
|
|
30
|
+
- Fixed `formatZeroXIO` return value (no " OCT" suffix)
|
|
31
|
+
- Fixed `toMicroZeroXIO` return type (string, not number)
|
|
32
|
+
- Removed nonexistent `ConnectOptions.timeout`, `.requestPrivateAccess`
|
|
33
|
+
- Removed nonexistent `ConnectionInfo.permissions`
|
|
34
|
+
- Changed `ErrorCode.TIMEOUT` to `ErrorCode.NETWORK_ERROR`
|
|
35
|
+
- Updated mainnet privacy support to "Yes"
|
|
36
|
+
|
|
5
37
|
## [2.4.0] - 2026-03-24
|
|
6
38
|
|
|
7
39
|
### Added
|
package/README.md
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
# 0xio Wallet SDK
|
|
2
2
|
|
|
3
|
-
**Version:** 2.4.
|
|
3
|
+
**Version:** 2.4.1
|
|
4
4
|
|
|
5
5
|
Official TypeScript SDK for integrating DApps with 0xio Wallet on Octra Network.
|
|
6
6
|
|
|
7
|
-
## What's New in v2.4.
|
|
7
|
+
## What's New in v2.4.1
|
|
8
|
+
|
|
9
|
+
- **No retry on user rejection**: Transactions, contract calls, and sign requests rejected by the user no longer trigger automatic retry. Prevents double confirmation popups.
|
|
10
|
+
- **Type fixes**: Replaced `NodeJS.Timeout` with `ReturnType<typeof setTimeout>` for browser compatibility.
|
|
11
|
+
|
|
12
|
+
## v2.4.0
|
|
8
13
|
|
|
9
14
|
- **Desktop/Mobile DApp Bridge**: SDK now supports running inside iframes (0xio Desktop) and WebViews (0xio App). Requests are relayed to the parent frame automatically.
|
|
10
15
|
- **Auto Frame Detection**: When `window.parent !== window`, the SDK assumes a wallet bridge is available and marks the wallet as detected.
|
|
@@ -163,11 +168,11 @@ console.log('Signature:', signature);
|
|
|
163
168
|
### Events
|
|
164
169
|
|
|
165
170
|
```typescript
|
|
166
|
-
wallet.on('connect', (event) => console.log('Connected:', event.address));
|
|
171
|
+
wallet.on('connect', (event) => console.log('Connected:', event.data.address));
|
|
167
172
|
wallet.on('disconnect', (event) => console.log('Disconnected'));
|
|
168
|
-
wallet.on('balanceChanged', (event) => console.log('New balance:', event.newBalance.total));
|
|
169
|
-
wallet.on('accountChanged', (event) => console.log('Account changed:', event.newAddress));
|
|
170
|
-
wallet.on('networkChanged', (event) => console.log('Network:', event.newNetwork.name));
|
|
173
|
+
wallet.on('balanceChanged', (event) => console.log('New balance:', event.data.newBalance.total));
|
|
174
|
+
wallet.on('accountChanged', (event) => console.log('Account changed:', event.data.newAddress));
|
|
175
|
+
wallet.on('networkChanged', (event) => console.log('Network:', event.data.newNetwork.name));
|
|
171
176
|
```
|
|
172
177
|
|
|
173
178
|
## Error Handling
|
|
@@ -227,7 +232,7 @@ console.log(mainnet.supportsPrivacy); // true
|
|
|
227
232
|
|
|
228
233
|
| Network | Privacy (FHE) | Explorer |
|
|
229
234
|
|---------|:---:|---|
|
|
230
|
-
| Mainnet Alpha |
|
|
235
|
+
| Mainnet Alpha | Yes | [octrascan.io](https://octrascan.io) |
|
|
231
236
|
| Devnet | Yes | [devnet.octrascan.io](https://devnet.octrascan.io) |
|
|
232
237
|
|
|
233
238
|
### NetworkInfo Type
|
package/dist/index.d.ts
CHANGED
|
@@ -412,7 +412,7 @@ declare class ZeroXIOWallet extends EventEmitter {
|
|
|
412
412
|
* to ensure secure wallet interactions.
|
|
413
413
|
*
|
|
414
414
|
* @module communication
|
|
415
|
-
* @version 2.
|
|
415
|
+
* @version 2.4.1
|
|
416
416
|
* @license MIT
|
|
417
417
|
*/
|
|
418
418
|
|
|
@@ -452,6 +452,10 @@ declare class ExtensionCommunicator extends EventEmitter {
|
|
|
452
452
|
private extensionDetectionInterval;
|
|
453
453
|
/** Current extension availability state */
|
|
454
454
|
private isExtensionAvailableState;
|
|
455
|
+
/** Message listener reference for cleanup */
|
|
456
|
+
private messageListener;
|
|
457
|
+
/** Trusted parent origins for iframe communication */
|
|
458
|
+
private trustedOrigins;
|
|
455
459
|
/** Maximum number of concurrent pending requests */
|
|
456
460
|
private readonly MAX_CONCURRENT_REQUESTS;
|
|
457
461
|
/** Time window for rate limiting (milliseconds) */
|
|
@@ -465,7 +469,12 @@ declare class ExtensionCommunicator extends EventEmitter {
|
|
|
465
469
|
*
|
|
466
470
|
* @param {boolean} debug - Enable debug logging
|
|
467
471
|
*/
|
|
468
|
-
constructor(debug?: boolean);
|
|
472
|
+
constructor(debug?: boolean, trustedOrigins?: string[]);
|
|
473
|
+
/**
|
|
474
|
+
* Add trusted origins for iframe/bridge communication
|
|
475
|
+
* Call this before connecting if your dApp runs inside a trusted frame
|
|
476
|
+
*/
|
|
477
|
+
setTrustedOrigins(origins: string[]): void;
|
|
469
478
|
/**
|
|
470
479
|
* Initialize communication with the wallet extension
|
|
471
480
|
*
|
|
@@ -614,6 +623,10 @@ declare function getNetworkConfig(networkId?: string): NetworkInfo;
|
|
|
614
623
|
* Get all available networks
|
|
615
624
|
*/
|
|
616
625
|
declare function getAllNetworks(): NetworkInfo[];
|
|
626
|
+
/**
|
|
627
|
+
* Check if network ID is valid
|
|
628
|
+
*/
|
|
629
|
+
declare function isValidNetworkId(networkId: string): boolean;
|
|
617
630
|
|
|
618
631
|
/**
|
|
619
632
|
* Default balance structure
|
|
@@ -623,7 +636,7 @@ declare function createDefaultBalance(total?: number): Balance;
|
|
|
623
636
|
* SDK Configuration constants
|
|
624
637
|
*/
|
|
625
638
|
declare const SDK_CONFIG: {
|
|
626
|
-
readonly version: "2.
|
|
639
|
+
readonly version: "2.4.1";
|
|
627
640
|
readonly defaultNetworkId: "mainnet";
|
|
628
641
|
readonly communicationTimeout: 30000;
|
|
629
642
|
readonly retryAttempts: 3;
|
|
@@ -647,10 +660,6 @@ declare function isValidAddress(address: string): boolean;
|
|
|
647
660
|
* Validate transaction amount
|
|
648
661
|
*/
|
|
649
662
|
declare function isValidAmount(amount: number): boolean;
|
|
650
|
-
/**
|
|
651
|
-
* Validate network ID
|
|
652
|
-
*/
|
|
653
|
-
declare function isValidNetworkId(networkId: string): boolean;
|
|
654
663
|
/**
|
|
655
664
|
* Validate transaction message
|
|
656
665
|
*/
|
|
@@ -750,7 +759,7 @@ declare function createLogger(prefix: string, debug: boolean): {
|
|
|
750
759
|
groupEnd: () => void;
|
|
751
760
|
};
|
|
752
761
|
|
|
753
|
-
declare const SDK_VERSION = "2.
|
|
762
|
+
declare const SDK_VERSION = "2.4.1";
|
|
754
763
|
declare const MIN_EXTENSION_VERSION = "2.0.1";
|
|
755
764
|
declare const MIN_EXTENSION_VERSION_DEVNET = "2.2.1";
|
|
756
765
|
declare const SUPPORTED_EXTENSION_VERSIONS = "^2.0.1";
|
package/dist/index.esm.js
CHANGED
|
@@ -164,16 +164,6 @@ function isValidAmount(amount) {
|
|
|
164
164
|
Number.isFinite(amount) &&
|
|
165
165
|
amount <= Number.MAX_SAFE_INTEGER;
|
|
166
166
|
}
|
|
167
|
-
/**
|
|
168
|
-
* Validate network ID
|
|
169
|
-
*/
|
|
170
|
-
function isValidNetworkId(networkId) {
|
|
171
|
-
if (!networkId || typeof networkId !== 'string') {
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
const validNetworks = ['mainnet', 'devnet', 'custom'];
|
|
175
|
-
return validNetworks.includes(networkId.toLowerCase());
|
|
176
|
-
}
|
|
177
167
|
/**
|
|
178
168
|
* Validate transaction message
|
|
179
169
|
*/
|
|
@@ -317,14 +307,21 @@ function delay(ms) {
|
|
|
317
307
|
*/
|
|
318
308
|
async function retry(operation, maxRetries = 3, baseDelay = 1000) {
|
|
319
309
|
let lastError;
|
|
320
|
-
|
|
310
|
+
// maxRetries = number of retries AFTER the first attempt
|
|
311
|
+
// Total attempts = 1 (initial) + maxRetries
|
|
312
|
+
for (let attempt = 0; attempt < 1 + maxRetries; attempt++) {
|
|
321
313
|
try {
|
|
322
314
|
return await operation();
|
|
323
315
|
}
|
|
324
316
|
catch (error) {
|
|
325
317
|
lastError = error;
|
|
326
|
-
|
|
327
|
-
|
|
318
|
+
// Never retry user rejections — these are intentional
|
|
319
|
+
const msg = lastError.message?.toLowerCase() || '';
|
|
320
|
+
if (msg.includes('rejected') || msg.includes('denied') || msg.includes('cancelled') || msg.includes('user refused')) {
|
|
321
|
+
throw lastError;
|
|
322
|
+
}
|
|
323
|
+
if (attempt >= maxRetries) {
|
|
324
|
+
break; // All retries exhausted
|
|
328
325
|
}
|
|
329
326
|
// Exponential backoff: 1s, 2s, 4s, etc.
|
|
330
327
|
const delayMs = baseDelay * Math.pow(2, attempt);
|
|
@@ -337,12 +334,15 @@ async function retry(operation, maxRetries = 3, baseDelay = 1000) {
|
|
|
337
334
|
* Timeout wrapper for promises
|
|
338
335
|
*/
|
|
339
336
|
function withTimeout(promise, timeoutMs, timeoutMessage = 'Operation timed out') {
|
|
337
|
+
let timer;
|
|
340
338
|
const timeoutPromise = new Promise((_, reject) => {
|
|
341
|
-
setTimeout(() => {
|
|
339
|
+
timer = setTimeout(() => {
|
|
342
340
|
reject(new ZeroXIOWalletError(ErrorCode.NETWORK_ERROR, timeoutMessage));
|
|
343
341
|
}, timeoutMs);
|
|
344
342
|
});
|
|
345
|
-
return Promise.race([promise, timeoutPromise])
|
|
343
|
+
return Promise.race([promise, timeoutPromise]).finally(() => {
|
|
344
|
+
clearTimeout(timer);
|
|
345
|
+
});
|
|
346
346
|
}
|
|
347
347
|
// ===================
|
|
348
348
|
// BROWSER UTILITIES
|
|
@@ -409,7 +409,8 @@ function generateMockData() {
|
|
|
409
409
|
* Create development logger
|
|
410
410
|
*/
|
|
411
411
|
function createLogger(prefix, debug) {
|
|
412
|
-
const isDevelopment = typeof window !== 'undefined' && (
|
|
412
|
+
const isDevelopment = typeof window !== 'undefined' && ((typeof process !== 'undefined' && process.env?.NODE_ENV === 'development') ||
|
|
413
|
+
window.location.hostname === 'localhost' ||
|
|
413
414
|
window.location.hostname === '127.0.0.1' ||
|
|
414
415
|
window.__OCTRA_SDK_DEBUG__);
|
|
415
416
|
// Only enable logging in development mode AND when debug is explicitly enabled
|
|
@@ -467,7 +468,7 @@ function createLogger(prefix, debug) {
|
|
|
467
468
|
* to ensure secure wallet interactions.
|
|
468
469
|
*
|
|
469
470
|
* @module communication
|
|
470
|
-
* @version 2.
|
|
471
|
+
* @version 2.4.1
|
|
471
472
|
* @license MIT
|
|
472
473
|
*/
|
|
473
474
|
/**
|
|
@@ -499,7 +500,7 @@ class ExtensionCommunicator extends EventEmitter {
|
|
|
499
500
|
*
|
|
500
501
|
* @param {boolean} debug - Enable debug logging
|
|
501
502
|
*/
|
|
502
|
-
constructor(debug = false) {
|
|
503
|
+
constructor(debug = false, trustedOrigins = []) {
|
|
503
504
|
super(debug);
|
|
504
505
|
/** Legacy request counter (deprecated, kept for fallback) */
|
|
505
506
|
this.requestId = 0;
|
|
@@ -511,6 +512,10 @@ class ExtensionCommunicator extends EventEmitter {
|
|
|
511
512
|
this.extensionDetectionInterval = null;
|
|
512
513
|
/** Current extension availability state */
|
|
513
514
|
this.isExtensionAvailableState = false;
|
|
515
|
+
/** Message listener reference for cleanup */
|
|
516
|
+
this.messageListener = null;
|
|
517
|
+
/** Trusted parent origins for iframe communication */
|
|
518
|
+
this.trustedOrigins = [];
|
|
514
519
|
// Rate limiting configuration
|
|
515
520
|
/** Maximum number of concurrent pending requests */
|
|
516
521
|
this.MAX_CONCURRENT_REQUESTS = 50;
|
|
@@ -521,9 +526,17 @@ class ExtensionCommunicator extends EventEmitter {
|
|
|
521
526
|
/** Timestamps of recent requests for rate limiting */
|
|
522
527
|
this.requestTimestamps = [];
|
|
523
528
|
this.logger = createLogger('ExtensionCommunicator', debug);
|
|
529
|
+
this.trustedOrigins = trustedOrigins;
|
|
524
530
|
this.setupMessageListener();
|
|
525
531
|
this.startExtensionDetection();
|
|
526
532
|
}
|
|
533
|
+
/**
|
|
534
|
+
* Add trusted origins for iframe/bridge communication
|
|
535
|
+
* Call this before connecting if your dApp runs inside a trusted frame
|
|
536
|
+
*/
|
|
537
|
+
setTrustedOrigins(origins) {
|
|
538
|
+
this.trustedOrigins = origins;
|
|
539
|
+
}
|
|
527
540
|
/**
|
|
528
541
|
* Initialize communication with the wallet extension
|
|
529
542
|
*
|
|
@@ -649,34 +662,51 @@ class ExtensionCommunicator extends EventEmitter {
|
|
|
649
662
|
return; // Not in browser environment
|
|
650
663
|
}
|
|
651
664
|
const allowedOrigin = window.location.origin;
|
|
652
|
-
|
|
653
|
-
|
|
665
|
+
// Store allowed origins for parent frame communication
|
|
666
|
+
// Desktop (Tauri): tauri://localhost or https://tauri.localhost
|
|
667
|
+
// Mobile (Expo): about:blank or custom scheme
|
|
668
|
+
const trustedParentOrigins = new Set([
|
|
669
|
+
allowedOrigin,
|
|
670
|
+
'tauri://localhost',
|
|
671
|
+
'https://tauri.localhost',
|
|
672
|
+
'http://localhost',
|
|
673
|
+
'https://localhost',
|
|
674
|
+
]);
|
|
675
|
+
// Allow dApps to register additional trusted origins
|
|
676
|
+
if (this.trustedOrigins) {
|
|
677
|
+
for (const origin of this.trustedOrigins) {
|
|
678
|
+
trustedParentOrigins.add(origin);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
this.messageListener = (event) => {
|
|
682
|
+
// Strict origin validation
|
|
654
683
|
const isFromSameOrigin = event.origin === allowedOrigin;
|
|
655
|
-
const
|
|
656
|
-
|
|
684
|
+
const isFromTrustedParent = event.source === window.parent
|
|
685
|
+
&& window.parent !== window
|
|
686
|
+
&& trustedParentOrigins.has(event.origin);
|
|
687
|
+
if (!isFromSameOrigin && !isFromTrustedParent) {
|
|
657
688
|
return;
|
|
658
689
|
}
|
|
659
|
-
//
|
|
690
|
+
// Only accept from same window (extension content script) or trusted parent frame
|
|
660
691
|
if (event.source !== window && event.source !== window.parent) {
|
|
661
692
|
return;
|
|
662
693
|
}
|
|
663
|
-
//
|
|
694
|
+
// Verify message structure
|
|
664
695
|
if (!event.data || event.data.source !== '0xio-sdk-bridge') {
|
|
665
696
|
return;
|
|
666
697
|
}
|
|
667
|
-
//
|
|
698
|
+
// Validate response has a pending request (prevents forged responses)
|
|
668
699
|
if (event.data.response) {
|
|
669
|
-
// Regular request/response
|
|
670
700
|
const response = event.data.response;
|
|
671
|
-
if (response && response.id) {
|
|
701
|
+
if (response && response.id && this.pendingRequests.has(response.id)) {
|
|
672
702
|
this.handleExtensionResponse(response);
|
|
673
703
|
}
|
|
674
704
|
}
|
|
675
705
|
else if (event.data.event) {
|
|
676
|
-
// Event notification from extension
|
|
677
706
|
this.handleExtensionEvent(event.data.event);
|
|
678
707
|
}
|
|
679
|
-
}
|
|
708
|
+
};
|
|
709
|
+
window.addEventListener('message', this.messageListener);
|
|
680
710
|
this.logger.log('Message listener setup complete');
|
|
681
711
|
}
|
|
682
712
|
/**
|
|
@@ -732,9 +762,28 @@ class ExtensionCommunicator extends EventEmitter {
|
|
|
732
762
|
const msg = { source: '0xio-sdk-request', request };
|
|
733
763
|
// Post to same window (extension content script picks it up)
|
|
734
764
|
window.postMessage(msg, window.location.origin);
|
|
735
|
-
// Also post to parent frame if in an iframe (desktop/mobile bridge
|
|
765
|
+
// Also post to parent frame if in an iframe (desktop/mobile bridge)
|
|
766
|
+
// Use specific origin instead of wildcard to prevent interception
|
|
736
767
|
if (window.parent !== window) {
|
|
737
|
-
|
|
768
|
+
try {
|
|
769
|
+
// Try same-origin first (works for Tauri, same-domain iframes)
|
|
770
|
+
window.parent.postMessage(msg, window.location.origin);
|
|
771
|
+
}
|
|
772
|
+
catch {
|
|
773
|
+
// Cross-origin parent (e.g. tauri://localhost) — use known trusted origins only
|
|
774
|
+
const trustedOrigins = ['tauri://localhost', 'https://tauri.localhost'];
|
|
775
|
+
if (this.trustedOrigins) {
|
|
776
|
+
trustedOrigins.push(...this.trustedOrigins);
|
|
777
|
+
}
|
|
778
|
+
for (const origin of trustedOrigins) {
|
|
779
|
+
try {
|
|
780
|
+
window.parent.postMessage(msg, origin);
|
|
781
|
+
}
|
|
782
|
+
catch {
|
|
783
|
+
// Origin not matching, skip
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
738
787
|
}
|
|
739
788
|
}
|
|
740
789
|
/**
|
|
@@ -830,17 +879,26 @@ class ExtensionCommunicator extends EventEmitter {
|
|
|
830
879
|
this.logger.log('Received octraWalletReady event');
|
|
831
880
|
this.isExtensionAvailableState = true;
|
|
832
881
|
});
|
|
833
|
-
// Listen for desktop/mobile bridge walletReady via postMessage
|
|
882
|
+
// Listen for desktop/mobile bridge walletReady via postMessage (with origin validation)
|
|
834
883
|
window.addEventListener('message', (event) => {
|
|
835
884
|
if (event.data?.source === '0xio-sdk-bridge' && event.data?.event?.type === 'walletReady') {
|
|
836
|
-
|
|
837
|
-
|
|
885
|
+
const isSameOrigin = event.origin === window.location.origin;
|
|
886
|
+
const isTrusted = this.trustedOrigins.includes(event.origin)
|
|
887
|
+
|| event.origin === 'tauri://localhost'
|
|
888
|
+
|| event.origin === 'https://tauri.localhost';
|
|
889
|
+
if (isSameOrigin || isTrusted) {
|
|
890
|
+
this.logger.log('Received walletReady via postMessage from trusted origin');
|
|
891
|
+
this.isExtensionAvailableState = true;
|
|
892
|
+
}
|
|
893
|
+
else {
|
|
894
|
+
this.logger.warn(`Ignored walletReady from untrusted origin: ${event.origin}`);
|
|
895
|
+
}
|
|
838
896
|
}
|
|
839
897
|
});
|
|
840
|
-
//
|
|
898
|
+
// If running inside a frame, do NOT auto-trust the parent.
|
|
899
|
+
// Wait for a walletReady message from a trusted origin instead.
|
|
841
900
|
if (window.parent !== window) {
|
|
842
|
-
this.logger.log('Running inside a frame —
|
|
843
|
-
this.isExtensionAvailableState = true;
|
|
901
|
+
this.logger.log('Running inside a frame — waiting for trusted walletReady signal');
|
|
844
902
|
}
|
|
845
903
|
// Initial check (in case extension was already injected)
|
|
846
904
|
this.checkExtensionAvailability();
|
|
@@ -977,6 +1035,11 @@ class ExtensionCommunicator extends EventEmitter {
|
|
|
977
1035
|
this.pendingRequests.clear();
|
|
978
1036
|
this.isInitialized = false;
|
|
979
1037
|
this.isExtensionAvailableState = false;
|
|
1038
|
+
// Remove message listener to prevent accumulation
|
|
1039
|
+
if (this.messageListener) {
|
|
1040
|
+
window.removeEventListener('message', this.messageListener);
|
|
1041
|
+
this.messageListener = null;
|
|
1042
|
+
}
|
|
980
1043
|
// Call parent cleanup
|
|
981
1044
|
this.removeAllListeners();
|
|
982
1045
|
this.logger.log('Communication cleanup complete');
|
|
@@ -1050,6 +1113,12 @@ function getNetworkConfig(networkId = DEFAULT_NETWORK_ID) {
|
|
|
1050
1113
|
function getAllNetworks() {
|
|
1051
1114
|
return Object.values(NETWORKS);
|
|
1052
1115
|
}
|
|
1116
|
+
/**
|
|
1117
|
+
* Check if network ID is valid
|
|
1118
|
+
*/
|
|
1119
|
+
function isValidNetworkId(networkId) {
|
|
1120
|
+
return networkId in NETWORKS;
|
|
1121
|
+
}
|
|
1053
1122
|
|
|
1054
1123
|
/**
|
|
1055
1124
|
* SDK Configuration
|
|
@@ -1069,7 +1138,7 @@ function createDefaultBalance(total = 0) {
|
|
|
1069
1138
|
* SDK Configuration constants
|
|
1070
1139
|
*/
|
|
1071
1140
|
const SDK_CONFIG = {
|
|
1072
|
-
version: '2.
|
|
1141
|
+
version: '2.4.1',
|
|
1073
1142
|
defaultNetworkId: DEFAULT_NETWORK_ID,
|
|
1074
1143
|
communicationTimeout: 30000, // 30 seconds
|
|
1075
1144
|
retryAttempts: 3,
|
|
@@ -1770,7 +1839,7 @@ var wallet = /*#__PURE__*/Object.freeze({
|
|
|
1770
1839
|
*/
|
|
1771
1840
|
// Main exports
|
|
1772
1841
|
// Version information
|
|
1773
|
-
const SDK_VERSION = '2.
|
|
1842
|
+
const SDK_VERSION = '2.4.1';
|
|
1774
1843
|
const MIN_EXTENSION_VERSION = '2.0.1'; // Mainnet Alpha
|
|
1775
1844
|
const MIN_EXTENSION_VERSION_DEVNET = '2.2.1'; // Devnet (contract calls, privacy)
|
|
1776
1845
|
const SUPPORTED_EXTENSION_VERSIONS = '^2.0.1'; // Supports all versions >= 2.0.1
|
|
@@ -1825,7 +1894,8 @@ if (typeof window !== 'undefined') {
|
|
|
1825
1894
|
window.__OCTRA_SDK_VERSION__ = SDK_VERSION;
|
|
1826
1895
|
window.__ZEROXIO_SDK_VERSION__ = SDK_VERSION;
|
|
1827
1896
|
// Development mode detection
|
|
1828
|
-
const isDevelopment =
|
|
1897
|
+
const isDevelopment = (typeof globalThis !== 'undefined' && globalThis.process?.env?.NODE_ENV === 'development') ||
|
|
1898
|
+
window.location.hostname === 'localhost' ||
|
|
1829
1899
|
window.location.hostname === '127.0.0.1';
|
|
1830
1900
|
if (isDevelopment) {
|
|
1831
1901
|
// Set debug flag but don't automatically log
|
|
@@ -1850,13 +1920,7 @@ if (typeof window !== 'undefined') {
|
|
|
1850
1920
|
debugMode: !!window.__ZEROXIO_SDK_DEBUG__,
|
|
1851
1921
|
environment: isDevelopment ? 'development' : 'production'
|
|
1852
1922
|
}),
|
|
1853
|
-
simulateExtensionEvent
|
|
1854
|
-
window.postMessage({
|
|
1855
|
-
source: '0xio-sdk-bridge',
|
|
1856
|
-
event: { type: eventType, data }
|
|
1857
|
-
}, window.location.origin);
|
|
1858
|
-
console.log('[0xio SDK] Simulated extension event:', eventType, data);
|
|
1859
|
-
},
|
|
1923
|
+
// simulateExtensionEvent removed for security — could be exploited on staging builds
|
|
1860
1924
|
showWelcome: () => {
|
|
1861
1925
|
console.log(`[0xio SDK] Development mode - SDK v${SDK_VERSION}`);
|
|
1862
1926
|
console.log('[0xio SDK] Debug utilities available at window.__ZEROXIO_SDK_UTILS__');
|