Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/sdk-multichain/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"@metamask/auto-changelog": "^3.4.3",
"@react-native-async-storage/async-storage": "^1.23.1",
"@types/jsdom": "^21.1.7",
"@types/pako": "^2.0.4",
"@types/ws": "^8.18.1",
"@vitest/coverage-v8": "^3.2.4",
"esbuild-plugin-umd-wrapper": "^3.0.0",
Expand Down Expand Up @@ -66,6 +67,7 @@
"cross-fetch": "^4.1.0",
"eciesjs": "^0.4.15",
"eventemitter3": "^5.0.1",
"pako": "^2.1.0",
"uuid": "^11.1.0",
"ws": "^8.18.3"
}
Expand Down
29 changes: 29 additions & 0 deletions packages/sdk-multichain/src/multichain/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,38 @@
import { deflate } from 'pako';
import { type CaipAccountId, type CaipChainId, parseCaipAccountId, parseCaipChainId } from '@metamask/utils';
import packageJson from '../../../package.json';
import { type DappSettings, getInfuraRpcUrls, getPlatformType, type MultichainOptions, PlatformType, type Scope, type SessionData } from '../../domain';

export type OptionalScopes = Record<Scope, SessionData['sessionScopes'][Scope]>;

/**
* Cross-platform base64 encoding
* Works in browser, Node.js, and React Native environments
*/
function base64Encode(str: string): string {
if (typeof btoa !== 'undefined') {
// Browser and React Native with polyfills
return btoa(str);
} else if (typeof Buffer !== 'undefined') {
// Node.js
return Buffer.from(str).toString('base64');
}
throw new Error('No base64 encoding method available');
}

/**
* Compress a string using pako (deflateRaw)
* Returns a base64-encoded compressed string
*/
export function compressString(str: string): string {
const compressed = deflate(str);

// Convert Uint8Array to string for base64 encoding
const binaryString = String.fromCharCode.apply(null, Array.from(compressed));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: String Compression Fails on Large Data

The compressString function can fail with a "Maximum call stack size exceeded" error when processing large compressed data. This occurs because String.fromCharCode.apply() exceeds the JavaScript engine's argument limit, causing the function to crash.

Fix in Cursor Fix in Web

return base64Encode(binaryString);
}


export function getDappId(dapp?: DappSettings) {
if (typeof window === 'undefined' || typeof window.location === 'undefined') {
return dapp?.name ?? dapp?.url ?? 'N/A';
Expand Down
13 changes: 8 additions & 5 deletions packages/sdk-multichain/src/ui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import MetaMaskOnboarding from '@metamask/onboarding';
import { type ConnectionRequest, getPlatformType, getVersion, type Modal, type OTPCode, PlatformType } from '../domain';
import type { FactoryModals, ModalTypes } from './modals/types';
import type { AbstractOTPCodeModal } from './modals/base/AbstractOTPModal';
import { compressString } from '../multichain/utils';
import { METAMASK_CONNECT_BASE_URL, METAMASK_DEEPLINK_BASE } from 'src/config';

// @ts-ignore
Expand Down Expand Up @@ -90,15 +91,17 @@ export class ModalFactory<T extends FactoryModals = FactoryModals> {
}

createDeeplink(connectionRequest: ConnectionRequest) {
const json = JSON.stringify(connectionRequest);
const urlEncoded = encodeURIComponent(json);
return `${METAMASK_DEEPLINK_BASE}/mwp?p=${urlEncoded}`;
const json = JSON.stringify(connectionRequest);
const compressed = compressString(json);
const urlEncoded = encodeURIComponent(compressed);
return `${METAMASK_DEEPLINK_BASE}/mwp?p=${urlEncoded}&c=1`;
}

createUniversalLink(connectionRequest: ConnectionRequest) {
const json = JSON.stringify(connectionRequest);
const urlEncoded = encodeURIComponent(json);
return `${METAMASK_CONNECT_BASE_URL}/mwp?p=${urlEncoded}`;
const compressed = compressString(json);
const urlEncoded = encodeURIComponent(compressed);
return `${METAMASK_CONNECT_BASE_URL}/mwp?p=${urlEncoded}&c=1`;
}

private async onCloseModal(shouldTerminate = true) {
Expand Down
16 changes: 16 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11583,6 +11583,7 @@ __metadata:
"@paulmillr/qr": ^0.2.1
"@react-native-async-storage/async-storage": ^1.23.1
"@types/jsdom": ^21.1.7
"@types/pako": ^2.0.4
"@types/ws": ^8.18.1
"@vitest/coverage-v8": ^3.2.4
bowser: ^2.11.0
Expand All @@ -11593,6 +11594,7 @@ __metadata:
fake-indexeddb: ^6.0.1
jsdom: ^26.1.0
nock: ^14.0.4
pako: ^2.1.0
prettier: ^3.3.3
tsup: ^8.5.0
typescript: ^5.8.3
Expand Down Expand Up @@ -20236,6 +20238,13 @@ __metadata:
languageName: node
linkType: hard

"@types/pako@npm:^2.0.4":
version: 2.0.4
resolution: "@types/pako@npm:2.0.4"
checksum: 7e7b090c27cdbed4a8c21f7dfa466ad1c6b5c29afbcaaa24b35e83803d2b6b6cd552060060d8832058cf3809787baaab47a6a974b69d75a2a2dc59d21b607ee8
languageName: node
linkType: hard

"@types/parse-json@npm:^4.0.0":
version: 4.0.0
resolution: "@types/parse-json@npm:4.0.0"
Expand Down Expand Up @@ -44907,6 +44916,13 @@ __metadata:
languageName: node
linkType: hard

"pako@npm:^2.1.0":
version: 2.1.0
resolution: "pako@npm:2.1.0"
checksum: 71666548644c9a4d056bcaba849ca6fd7242c6cf1af0646d3346f3079a1c7f4a66ffec6f7369ee0dc88f61926c10d6ab05da3e1fca44b83551839e89edd75a3e
languageName: node
linkType: hard

"pako@npm:~0.2.0":
version: 0.2.9
resolution: "pako@npm:0.2.9"
Expand Down
Loading