Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: detect metamask version to force upgrade #353

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
7 changes: 7 additions & 0 deletions packages/get-starknet/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ module.exports = {
'import/no-nodejs-modules': 'off',
},
},

{
files: ['src/wallet.ts'],
rules: {
'no-restricted-globals': ['off', 'document', 'window'] // Disable rule for document and window
},
},
],

ignorePatterns: ['!.eslintrc.js', 'dist/', '**/test', '.nyc_output/', 'coverage/'],
Expand Down
2 changes: 1 addition & 1 deletion packages/get-starknet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"build": "webpack --config webpack.config.build.js",
"prettier": "prettier --write \"src/**/*.ts\"",
"lint": "eslint 'src/*.{js,ts,tsx}' --max-warnings 0 -f json -o eslint-report.json",
"lint:fix": "eslint '**/*.{js,ts,tsx}' --fix",
"lint:fix": "eslint 'src/*.{js,ts,tsx}' --fix",
"test:unit": ""
},
"keywords": [],
Expand Down
33 changes: 33 additions & 0 deletions packages/get-starknet/src/snap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,39 @@ export class MetaMaskSnap {
this.#version = version;
}

async isUpgradeRequired(minRequiredVersion = '13.0.0'): Promise<boolean> {
const version = await this.#getVersionNumber();
const parts = version.split('.').map(Number);
const requiredParts = minRequiredVersion.split('.').map(Number);

for (let i = 0; i < 3; i++) {
if (parts[i] < requiredParts[i]) {
return true; // current version is smaller, upgrade required
} else if (parts[i] > requiredParts[i]) {
return false; // current version is greater or equal, no upgrade required
}
}

return false; // If both versions are equal
}

async #getVersionNumber(): Promise<string> {
// Requesting the client version from the provider
const clientVersion: string = (await this.#provider.request({
method: 'web3_clientVersion',
params: [],
})) as string;

// Extracting the version number (xx.yy.zz) using a regular expression
const versionMatch = clientVersion.match(/(\d+\.\d+\.\d+)/u);

// If a match is found, return it; otherwise, return a default value or throw an error
if (versionMatch) {
return versionMatch[0]; // The version number (xx.yy.zz)
}
throw new Error('Version number not found in client version');
}

async getPubKey(userAddress: string): Promise<string> {
return (await this.#provider.request({
method: 'wallet_invokeSnap',
Expand Down
132 changes: 132 additions & 0 deletions packages/get-starknet/src/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export class MetaMaskSnapWallet implements IStarknetWindowObject {

metamaskProvider: MetaMaskProvider;

isPopupVisible: boolean;

static readonly #cairoVersion = '0';

// eslint-disable-next-line @typescript-eslint/naming-convention, no-restricted-globals
Expand All @@ -53,6 +55,7 @@ export class MetaMaskSnapWallet implements IStarknetWindowObject {
this.account = undefined;
this.selectedAddress = undefined;
this.isConnected = false;
this.isPopupVisible = false;
this.snap = new MetaMaskSnap(MetaMaskSnapWallet.#SNAPI_ID, snapVersion, this.metamaskProvider);
}

Expand Down Expand Up @@ -128,6 +131,16 @@ export class MetaMaskSnapWallet implements IStarknetWindowObject {
}

async enable() {
const minRequiredVersion = '12.0.0';
if (await this.snap.isUpgradeRequired(minRequiredVersion)) {
if (typeof document !== 'undefined') {
// Safe to use document
this.#showPopup();
}

throw new Error('MetaMask upgrade required');
}

await this.snap.installIfNot();
this.isConnected = true;
const network = await this.#getNetwork();
Expand Down Expand Up @@ -158,4 +171,123 @@ export class MetaMaskSnapWallet implements IStarknetWindowObject {
off<Event extends WalletEvents>() {
throw new Error('Method not supported');
}

// Function to dynamically create and show the pop-up
// Function to dynamically create and show the pop-up
#showPopup() {
if (this.isPopupVisible) {
return;
} // Prevent multiple pop-ups
this.isPopupVisible = true;

const backdrop = document.createElement('div');
Object.assign(backdrop.style, {
position: 'fixed',
top: '0',
left: '0',
width: '100%',
height: '100%',
backgroundColor: 'rgba(0, 0, 0, 0.25)',
backdropFilter: 'blur(5px)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
zIndex: '1000',
});
backdrop.id = 'popupBackdrop';

const popup = document.createElement('div');
Object.assign(popup.style, {
position: 'relative',
backgroundColor: '#ffffff',
borderRadius: '8px',
padding: '20px',
maxWidth: '400px',
width: '100%',
boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',
display: 'flex', // Flexbox to handle vertical centering
flexDirection: 'column',
alignItems: 'center', // Center content horizontally
justifyContent: 'center', // Center content vertically
height: '300px', // Ensure enough height to center the button in the middle of the pop-up
textAlign: 'center',
});

const closeButton = document.createElement('button');
Object.assign(closeButton.style, {
position: 'absolute',
top: '10px',
right: '10px',
fontSize: '1.5rem',
border: 'none',
background: 'none',
cursor: 'pointer',
});
closeButton.innerHTML = '&times;';
closeButton.onclick = () => {
document.body.removeChild(backdrop);
this.isPopupVisible = false;
};

const title = document.createElement('h2');
title.innerText = 'Update MetaMask';
Object.assign(title.style, {
fontSize: '1.5rem',
marginBottom: '16px',
});

const message = document.createElement('p');
message.innerText = 'Please update your MetaMask to the latest version for the best experience.';
Object.assign(message.style, {
fontSize: '1rem',
marginBottom: '16px',
});

// Center the button using margin and block-level display
const updateButton = document.createElement('button');
Object.assign(updateButton.style, {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
gap: '10px',
padding: '10px 20px',
backgroundColor: '#f0f0f0',
border: 'none',
borderRadius: '5px',
color: '#333333',
cursor: 'pointer',
fontSize: '1rem',
marginTop: '20px',
});

const logoImg = document.createElement('img');
Object.assign(logoImg.style, {
width: '30px',
height: '30px',
});
logoImg.src = 'https://metamask.io/assets/icon.svg';
logoImg.alt = 'MetaMask Logo';

const buttonText = document.createElement('span');
buttonText.innerText = 'Update MetaMask';

updateButton.onclick = () => {
window.open('https://metamask.io/', '_blank');
};

updateButton.appendChild(logoImg);
updateButton.appendChild(buttonText);

// Append elements to the pop-up
popup.appendChild(closeButton);
popup.appendChild(title);
popup.appendChild(message);
popup.appendChild(updateButton);

// Append the pop-up to the backdrop
backdrop.appendChild(popup);

// Append the backdrop (with the pop-up inside) to the body
document.body.appendChild(backdrop);
}
}
Loading