chore: changes for 1.3.9

This commit is contained in:
Andrei O 2024-06-27 00:18:36 +03:00
parent 8b624ea8a2
commit d3aeecc7a1
No known key found for this signature in database
GPG Key ID: B961E5B68389457E
20 changed files with 862 additions and 807 deletions

View File

@ -1,5 +1,15 @@
# Changelog # Changelog
## Manifest Version 1.3.9
- add an additional throttle on 'eth_chainId' to prevent websites from spamming the wallet with requests
- change inject throttle to only affect UI requests
- updated some core dependencies
- optimized performance for json rpc calls
- disabled assets fetch until new provider is found before yup.io was used
- simplified wallet switching
- added sonarCloud badge to README.md
## Manifest Version 1.3.8 ## Manifest Version 1.3.8
- improved sign message display to better accomodate SIWE & other messages - improved sign message display to better accomodate SIWE & other messages

View File

@ -12,6 +12,10 @@ For more info you can check [docs website](https://clear-wallet.flashsoft.eu)
[![Clear EVM Wallet (CLW) - Open source EVM wallet that implements meta mask API. | Product Hunt](https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=381026&theme=dark)](https://www.producthunt.com/posts/clear-evm-wallet-clw?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-clear-evm-wallet-clw) [![Clear EVM Wallet (CLW) - Open source EVM wallet that implements meta mask API. | Product Hunt](https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=381026&theme=dark)](https://www.producthunt.com/posts/clear-evm-wallet-clw?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-clear-evm-wallet-clw)
### Badges
[![Quality gate](https://sonarcloud.io/api/project_badges/quality_gate?project=andrei0x309_clear-wallet)](https://sonarcloud.io/summary/new_code?id=andrei0x309_clear-wallet)
### Extended article about this repo ### Extended article about this repo
[Article on Mirror](https://mirror.xyz/andrei0x309.eth/9nc8UXrGIGOvz694ZY2gouS1JM9L8-Z8ITLNtirqD6Q) [Article on Mirror](https://mirror.xyz/andrei0x309.eth/9nc8UXrGIGOvz694ZY2gouS1JM9L8-Z8ITLNtirqD6Q)

View File

@ -1,13 +1,29 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en" style="width:400px;height:500px">
<head> <head>
<meta charset="utf-8" />
<title>Clear Wallet SandBox</title>
<base href="/" />
<meta name="color-scheme" content="light dark" />
<meta
name="viewport"
content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<meta name="format-detection" content="telephone=no" />
<meta name="msapplication-tap-highlight" content="no" />
<!-- add to homescreen for ios -->
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-title" content="Clear Wallet" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
</head> </head>
<body> <body>
<h1>Eval Sandbox</h1> <h1>Eval Sandbox</h1>
<script> <script>
// console.log('sandbox loaded'); console.info('sandbox loaded');
window.addEventListener('message', function (event) { window.addEventListener('message', function (event) {
// console.log('message received', event);
const data = event.data; const data = event.data;
const execFunc = new Function( const execFunc = new Function(
'return ' + data.code 'return ' + data.code

View File

@ -16,39 +16,38 @@
"pub": "yarn build && yarn release && yarn tsx ./release-scripts/create-release.ts" "pub": "yarn build && yarn release && yarn tsx ./release-scripts/create-release.ts"
}, },
"dependencies": { "dependencies": {
"@ionic/vue": "^7.2.3", "@ionic/vue": "^7.8.6",
"@ionic/vue-router": "^7.2.3", "@ionic/vue-router": "^7.8.6",
"core-js": "^3.32.0", "core-js": "^3.37.1",
"ethers": "^6.11.1", "ethers": "^6.13.1",
"vue": "^3.3.4", "vue": "^3.4.29",
"vue-router": "^4.2.4" "vue-router": "^4.3.3"
}, },
"devDependencies": { "devDependencies": {
"@capacitor/cli": "^5.2.3", "@capacitor/cli": "^5.2.3",
"@crxjs/vite-plugin": "^2.0.0-beta.23", "@crxjs/vite-plugin": "^2.0.0-beta.23",
"@types/archiver": "^5.3.2", "@types/archiver": "^5.3.4",
"@types/chrome": "^0.0.243", "@types/chrome": "^0.0.268",
"@types/jest": "^29.5.3", "@types/jest": "^29.5.3",
"@types/node": "^20.5.0", "@types/node": "^20.14.5",
"@typescript-eslint/eslint-plugin": "^6.3.0", "@typescript-eslint/eslint-plugin": "^7.13.0",
"@typescript-eslint/parser": "^6.3.0", "@typescript-eslint/parser": "^7.13.1",
"@vitejs/plugin-vue": "^5.0.4", "@vitejs/plugin-vue": "^5.0.5",
"@vue/eslint-config-typescript": "^11.0.3", "@vue/eslint-config-typescript": "^13.0.0",
"archiver": "^5.3.1", "archiver": "^5.3.1",
"eslint": "^8.47.0", "eslint": "^8.56.0",
"eslint-plugin-vue": "^9.17.0", "eslint-plugin-vue": "^9.26.0",
"http-browserify": "^1.7.0", "http-browserify": "^1.7.0",
"https-browserify": "^1.0.0", "https-browserify": "^1.0.0",
"jest": "^29.6.2", "jest": "^29.6.2",
"rollup-plugin-polyfill-node": "^0.12.0", "sass": "^1.77.6",
"sass": "^1.65.1",
"stream-browserify": "^3.0.0", "stream-browserify": "^3.0.0",
"ts-jest": "^29.1.1", "ts-jest": "^29.1.1",
"tsx": "^4.8.0", "tsx": "^4.15.6",
"typescript": "^5.1.6", "typescript": "^5.4.5",
"util": "^0.12.5", "util": "^0.12.5",
"vite": "^5.2.10", "vite": "^5.3.1",
"vue-tsc": "^1.8.8", "vue-tsc": "^2.0.21",
"yarn-upgrade-all": "^0.7.2" "yarn-upgrade-all": "^0.7.2"
}, },
"disabledNativeDependencies": { "disabledNativeDependencies": {

View File

@ -14,8 +14,6 @@
<meta name="format-detection" content="telephone=no" /> <meta name="format-detection" content="telephone=no" />
<meta name="msapplication-tap-highlight" content="no" /> <meta name="msapplication-tap-highlight" content="no" />
<!-- <link rel="shortcut icon" type="image/png" href="<%= BASE_URL %>assets/icon/favicon.png" /> -->
<!-- add to homescreen for ios --> <!-- add to homescreen for ios -->
<meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-title" content="Clear Wallet" /> <meta name="apple-mobile-web-app-title" content="Clear Wallet" />

View File

@ -47,7 +47,6 @@ async function ghRelease(changes: string[]) {
const p = cps.spawn('gh', ['release', 'create', `v${pkg.version}`, `./${outputPath}`, '-F', `./${changeLogPath}`], { const p = cps.spawn('gh', ['release', 'create', `v${pkg.version}`, `./${outputPath}`, '-F', `./${changeLogPath}`], {
shell: true, shell: true,
}); });
// const p = spawn('pwd');
let result = ''; let result = '';
p.stdout.on('data', (data) => (result += data.toString())); p.stdout.on('data', (data) => (result += data.toString()));
p.stderr.on('data', (data) => (result += data.toString())); p.stderr.on('data', (data) => (result += data.toString()));

View File

@ -65,8 +65,10 @@ window.addEventListener("message", (event) => {
params: event?.data?.data?.data?.params ?? [], params: event?.data?.data?.data?.params ?? [],
}, },
} }
if(event?.data?.data?.data?.method !== 'eth_chainId') {
// console.info('data out', data) // console.info('data out', data)
}
window.postMessage(data, "*"); window.postMessage(data, "*");
}) })
} }

View File

@ -1,5 +1,5 @@
interface RequestArguments { interface RequestArguments {
id?: string | undefined id?: string
method: string; method: string;
params?: unknown[] | object; params?: unknown[] | object;
} }
@ -18,8 +18,6 @@ const ProviderInfo: EIP6963ProviderInfo = {
rdns: 'clear-wallet.flashsoft.eu/', rdns: 'clear-wallet.flashsoft.eu/',
} }
const THROTTLE_LEVEL = 20;
const THROTTLE_TIMEOUT = 500;
const MAX_PROMISES = 50 const MAX_PROMISES = 50
function loadEIP1193Provider(provider: any) { function loadEIP1193Provider(provider: any) {
@ -74,16 +72,18 @@ const getListnersCount = (): number => {
} }
const sendMessage = (args: RequestArguments, ping = false, from = 'request'): Promise<unknown> => { const sendMessage = (args: RequestArguments, ping = false, from = 'request'): Promise<unknown> => {
return new Promise(async (resolve, reject) => { return new Promise((resolve, reject) => {
if(promResolvers.size < MAX_PROMISES && promResolvers.size > THROTTLE_LEVEL) { const p = [ "eth_signTypedData", "eth_signTypedData_v3", "eth_signTypedData_v4"]
await new Promise((res) => setTimeout(res, THROTTLE_TIMEOUT)) const throttledMethods = [...p, 'eth_sign', 'personal_sign', 'eth_sendTransaction']
} else if(promResolvers.size > MAX_PROMISES) {
if(promResolvers.size > MAX_PROMISES && throttledMethods.includes(args.method)) {
reject({code: -32000, message: 'ClearWallet: Too many requests', error: true }) reject({code: -32000, message: 'ClearWallet: Too many requests', error: true })
return
} }
const resId = [...`${Math.random().toString(16) + Date.now().toString(16)}`].slice(2).join('') const resId = [...`${Math.random().toString(16) + Date.now().toString(16)}`].slice(2).join('')
promResolvers.set(resId, { resolve, reject }) promResolvers.set(resId, { resolve, reject })
const p = [ "eth_signTypedData", "eth_signTypedData_v3", "eth_signTypedData_v4"]
const method = args.method const method = args.method
if (p.includes(args.method)) { if (p.includes(args.method)) {
args.method = undefined as any args.method = undefined as any
@ -100,11 +100,13 @@ const sendMessage = (args: RequestArguments, ping = false, from = 'request'): Pr
if (ping) { if (ping) {
data.type = 'CLWALLET_PING' data.type = 'CLWALLET_PING'
} }
if(method!== 'eth_chainId') {
// console.info('data in', data) // console.info('data in', data)
window.postMessage(data, "*"); }
window.postMessage(data, "*");
}) })
} }
class MetaMaskAPI { class MetaMaskAPI {
@ -187,30 +189,27 @@ class MetaMaskAPI {
} }
if (arg2 === undefined) { if (arg2 === undefined) {
if( typeof arg1 === 'string' ) { if( typeof arg1 === 'string' ) {
return resultFmt(sendMessage({ return resultFmt(sendMessage({
method: arg1, method: arg1,
params: undefined params: undefined
}, false, 'send')) }, false, 'send'))
} else {
return resultFmt(sendMessage(arg1 as RequestArguments, false, 'send'))
} }
return resultFmt(sendMessage(arg1 as RequestArguments, false, 'send'))
} else if (typeof arg1 === 'object') { } else if (typeof arg1 === 'object') {
if( typeof arg1 === 'string' ) { if( typeof arg1 === 'string' ) {
return resultFmt(sendMessage(arg1 as RequestArguments, false, 'send')) return resultFmt(sendMessage({
} else { method: arg1,
return resultFmt(sendMessage(arg1 as RequestArguments, false, 'send')) params: undefined
}, false, 'send'))
} }
return resultFmt(sendMessage(arg1 as RequestArguments, false, 'send'))
}else if( typeof arg1 === 'string' ) { }else if( typeof arg1 === 'string' ) {
return resultFmt( sendMessage({ return resultFmt( sendMessage({
method: arg1, method: arg1,
params: arg2 as object params: arg2 as object
}, false, 'send')) }, false, 'send'))
}else if (typeof arg2 === 'function'){
return resultFmt( sendMessage(arg1 as RequestArguments, false, 'send'))
} else {
return resultFmt(sendMessage(arg1 as RequestArguments , false, 'send'))
} }
return resultFmt(sendMessage(arg1 as RequestArguments, false, 'send'))
} }
on (eventName: string, callback: () => void) { on (eventName: string, callback: () => void) {
this.addListener(eventName, callback) this.addListener(eventName, callback)
@ -405,16 +404,16 @@ const web3Shim = {
__isMetaMaskShim__: true __isMetaMaskShim__: true
} }
const injectWallet = (win: any) => { const injectWallet = () => {
const ethKey = 'ethereum' const ethKey = 'ethereum'
if (win[ethKey]?.isClWallet) { if ((window as any)[ethKey]?.isClWallet) {
return; return;
} }
Object.defineProperty(win, ethKey, { Object.defineProperty((window as any), ethKey, {
value: eth, value: eth,
}); });
Object.defineProperty(win, 'web3', { Object.defineProperty((window as any), 'web3', {
value: web3Shim value: web3Shim
}); });
sendMessage({ sendMessage({
@ -422,12 +421,52 @@ sendMessage({
}, true) }, true)
} }
injectWallet(this); injectWallet();
loadEIP1193Provider(eth) loadEIP1193Provider(eth)
// HELPERS TO CLONE METAMASK API // HELPERS TO CLONE METAMASK API
// const MMReflect = async () => {
// await new Promise((resolve) => setTimeout(resolve, 2000))
// const originalRequest = (window as any).ethereum.request
// const originalSend = (window as any).ethereum.send
// const originalSendAsync = (window as any).ethereum.sendAsync
// const methods = [originalRequest, originalSend, originalSendAsync]
// const originalMethods = ['request', 'send', 'sendAsync']
// for(const [index, method] of methods.entries()) {
// const methodName = originalMethods[index];
// (window as any).ethereum[methodName] = new Proxy(method, {
// apply(target, thisArg, argsList) {
// const isEthChainId = argsList[0]?.method === 'eth_chainId'
// const result = Reflect.apply(target, thisArg, argsList) as Promise<unknown>
// const resultCLW = Reflect.apply(sendMessage, thisArg, argsList) as Promise<unknown>
// if(!isEthChainId) {
// result?.then((res: any) => {
// resultCLW?.then((resCLW: any) => {
// console.log(`window.ethereum.${methodName} ${JSON.stringify(argsList, null, 2)} result:`, res, resCLW);
// })
// })
// }
// return result;
// }
// });
// }
// console.log('Reflecting Metamask API')
// }
// MMReflect()
// window.addEventListener("message" , (event) => { // window.addEventListener("message" , (event) => {
// console.log('event', JSON.stringify(event?.data?.data, null, 2), JSON.stringify(event?.data, null, 2)) // console.log('event', JSON.stringify(event?.data?.data, null, 2), JSON.stringify(event?.data, null, 2))
// }) // })
@ -449,52 +488,52 @@ loadEIP1193Provider(eth)
// }, 5000) // }, 5000)
// setTimeout(async () => { // setTimeout(async () => {
// console.log('Metamask clone test'); // console.log('Metamask clone test');
// (<any>window).ethereum.request({method: 'eth_requestAccounts', params: Array(0)}).then((res: any) => { console.log(res, 'MT: eth_requestAccounts')}); // // (<any>window).ethereum.request({method: 'eth_requestAccounts', params: Array(0)}).then((res: any) => { console.log(res, 'MT: eth_requestAccounts')});
// (<any>window).ethereum2.request({method: 'eth_requestAccounts', params: Array(0)}).then((res: any) => { console.log(res, 'CW: eth_requestAccounts')}); // // (<any>window).ethereum2.request({method: 'eth_requestAccounts', params: Array(0)}).then((res: any) => { console.log(res, 'CW: eth_requestAccounts')});
// await new Promise((resolve) => setTimeout(resolve, 1000)); // // await new Promise((resolve) => setTimeout(resolve, 1000));
// (<any>window).ethereum.request({method: 'eth_accounts', params: Array(0)}).then((res: any) => { console.log(res, 'MT: eth_accounts')}); // // (<any>window).ethereum.request({method: 'eth_accounts', params: Array(0)}).then((res: any) => { console.log(res, 'MT: eth_accounts')});
// (<any>window).ethereum2.request({method: 'eth_accounts', params: Array(0)}).then((res: any) => { console.log(res, 'CW: eth_accounts')}); // // (<any>window).ethereum2.request({method: 'eth_accounts', params: Array(0)}).then((res: any) => { console.log(res, 'CW: eth_accounts')});
// await new Promise((resolve) => setTimeout(resolve, 1000)); // // await new Promise((resolve) => setTimeout(resolve, 1000));
// (<any>window).ethereum.request({method: 'eth_chainId', params: Array(0)}).then((res: any) => { console.log(res, 'MT: eth_chainId')}); // (<any>window).ethereum.request({method: 'eth_chainId', params: Array(0)}).then((res: any) => { console.log(res, 'MT: eth_chainId')});
// (<any>window).ethereum2.request({method: 'eth_chainId', params: Array(0)}).then((res: any) => { console.log(res, 'CW: eth_chainId')}); // (<any>window).ethereum2.request({method: 'eth_chainId', params: Array(0)}).then((res: any) => { console.log(res, 'CW: eth_chainId')});
// await new Promise((resolve) => setTimeout(resolve, 1000)); // // await new Promise((resolve) => setTimeout(resolve, 1000));
// (<any>window).ethereum.request({method: 'eth_blockNumber', params: Array(0)}).then((res: any) => { console.log(res, 'MT: eth_chainId')}); // // (<any>window).ethereum.request({method: 'eth_blockNumber', params: Array(0)}).then((res: any) => { console.log(res, 'MT: eth_chainId')});
// (<any>window).ethereum2.request({method: 'eth_blockNumber', params: Array(0)}).then((res: any) => { console.log(res, 'CW: eth_chainId')}); // // (<any>window).ethereum2.request({method: 'eth_blockNumber', params: Array(0)}).then((res: any) => { console.log(res, 'CW: eth_chainId')});
// await new Promise((resolve) => setTimeout(resolve, 1000)); // // await new Promise((resolve) => setTimeout(resolve, 1000));
// (<any>window).ethereum.request({method: 'wallet_requestPermissions', params: [{eth_accounts: {}}]}).then((res: any) => { console.log(res, 'MT: wallet_requestPermissions')}); // // (<any>window).ethereum.request({method: 'wallet_requestPermissions', params: [{eth_accounts: {}}]}).then((res: any) => { console.log(res, 'MT: wallet_requestPermissions')});
// (<any>window).ethereum2.request({method: 'wallet_requestPermissions', params: [{eth_accounts: {}}]}).then((res: any) => { console.log(res, 'CW: wallet_requestPermissions')}); // // (<any>window).ethereum2.request({method: 'wallet_requestPermissions', params: [{eth_accounts: {}}]}).then((res: any) => { console.log(res, 'CW: wallet_requestPermissions')});
// await new Promise((resolve) => setTimeout(resolve, 1000)); // // await new Promise((resolve) => setTimeout(resolve, 1000));
// (<any>window).ethereum.request({method: 'net_version', params: []}).then((res: any) => { console.log(res, 'MT: net_version')}); // // (<any>window).ethereum.request({method: 'net_version', params: []}).then((res: any) => { console.log(res, 'MT: net_version')});
// (<any>window).ethereum2.request({method: 'net_version', params: []}).then((res: any) => { console.log(res, 'CW: net_version')}); // // (<any>window).ethereum2.request({method: 'net_version', params: []}).then((res: any) => { console.log(res, 'CW: net_version')});
// await new Promise((resolve) => setTimeout(resolve, 1000)); // // await new Promise((resolve) => setTimeout(resolve, 1000));
// (<any>window).ethereum.request({method: 'wallet_switchEthereumChain', params: [{chainId: "0x89"}]}).then((res: any) => { console.log(res, 'MT: wallet_switchEthereumChain')}); // // (<any>window).ethereum.request({method: 'wallet_switchEthereumChain', params: [{chainId: "0x89"}]}).then((res: any) => { console.log(res, 'MT: wallet_switchEthereumChain')});
// (<any>window).ethereum2.request({method: 'wallet_switchEthereumChain', params: [{chainId: "0x89"}]}).then((res: any) => { console.log(res, 'CW: wallet_switchEthereumChain')}); // // (<any>window).ethereum2.request({method: 'wallet_switchEthereumChain', params: [{chainId: "0x89"}]}).then((res: any) => { console.log(res, 'CW: wallet_switchEthereumChain')});
// await new Promise((resolve) => setTimeout(resolve, 1000)); // // await new Promise((resolve) => setTimeout(resolve, 1000));
// (<any>window).ethereum.on('connect', ((a: any, b: any) => console.log('connect MT', a, b))); // // (<any>window).ethereum.on('connect', ((a: any, b: any) => console.log('connect MT', a, b)));
// (<any>window).ethereum.on('accountsChanged', ((a: any, b: any) => console.log('accountsChanged MT', a, b))); // // (<any>window).ethereum.on('accountsChanged', ((a: any, b: any) => console.log('accountsChanged MT', a, b)));
// (<any>window).ethereum.on('chainChanged', ((a: any) => console.log('chainChanged MT', a, typeof a))); // // (<any>window).ethereum.on('chainChanged', ((a: any) => console.log('chainChanged MT', a, typeof a)));
// await new Promise((resolve) => setTimeout(resolve, 1000)); // // await new Promise((resolve) => setTimeout(resolve, 1000));
// (<any>window).ethereum2.on('connect', ((a: any, b: any) => console.log('connect CW', a, b))); // // (<any>window).ethereum2.on('connect', ((a: any, b: any) => console.log('connect CW', a, b)));
// (<any>window).ethereum2.on('accountsChanged', ((a: any, b: any) => console.log('accountsChanged CW', a, b))); // // (<any>window).ethereum2.on('accountsChanged', ((a: any, b: any) => console.log('accountsChanged CW', a, b)));
// (<any>window).ethereum2.on('chainChanged', ((a: any) => console.log('chainChanged CW', a, typeof a))); // // (<any>window).ethereum2.on('chainChanged', ((a: any) => console.log('chainChanged CW', a, typeof a)));
// }, 3500) // }, 3500)

View File

@ -3,8 +3,8 @@
"name": "__MSG_appName__", "name": "__MSG_appName__",
"description": "__MSG_appDesc__", "description": "__MSG_appDesc__",
"default_locale": "en", "default_locale": "en",
"version": "1.3.8", "version": "1.3.9",
"version_name": "1.3.8", "version_name": "1.3.9",
"icons": { "icons": {
"16": "assets/extension-icon/wallet_16.png", "16": "assets/extension-icon/wallet_16.png",
"32": "assets/extension-icon/wallet_32.png", "32": "assets/extension-icon/wallet_32.png",

View File

@ -44,6 +44,8 @@ import { allTemplateNets } from '@/utils/networks'
let notificationUrl: string let notificationUrl: string
const chainIdThrottle: {[key: string]: number} = {}
chrome.runtime.onInstalled.addListener(() => { chrome.runtime.onInstalled.addListener(() => {
enableRightClickVote() enableRightClickVote()
console.info('Service worker installed'); console.info('Service worker installed');
@ -149,6 +151,30 @@ if (!chrome.notifications.onButtonClicked.hasListener(viewTxListner)){
chrome.notifications.onButtonClicked.addListener(viewTxListner) chrome.notifications.onButtonClicked.addListener(viewTxListner)
} }
const chainIdThrottleFn = async (website: string) => {
let urlKey
try {
const url = new URL(website)
urlKey = url.hostname
} catch {
urlKey = 'invalid'
}
if(chainIdThrottle[urlKey] === undefined) {
chainIdThrottle[urlKey] = 0
}
chainIdThrottle[urlKey] += 1
if( chainIdThrottle[urlKey] > 3) {
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(null)
}, 450)
})
// console.log('throttling', chainIdThrottle)
}
return urlKey
}
const mainListner = (message: RequestArguments, sender:any, sendResponse: (a: any) => any) => { const mainListner = (message: RequestArguments, sender:any, sendResponse: (a: any) => any) => {
if (chrome.runtime.lastError) { if (chrome.runtime.lastError) {
console.info("Error receiving message:", chrome.runtime.lastError); console.info("Error receiving message:", chrome.runtime.lastError);
@ -158,6 +184,8 @@ const mainListner = (message: RequestArguments, sender:any, sendResponse: (a: an
} }
(async () => { (async () => {
// console.info('Message:', message)
if (!(message?.method)) { if (!(message?.method)) {
sendResponse({ sendResponse({
code: 500, code: 500,
@ -354,11 +382,16 @@ const mainListner = (message: RequestArguments, sender:any, sendResponse: (a: an
} }
break break
} }
case 'eth_chainId': { case 'eth_chainId':
case 'net_version':
{
try { try {
const isNetVersion = message.method === 'net_version'
const urlKey = await chainIdThrottleFn(message?.website ?? '')
const network = await getSelectedNetwork() const network = await getSelectedNetwork()
const chainId = network?.chainId ?? 0 const chainId = network?.chainId ?? 1
sendResponse(`0x${chainId.toString(16)}`) sendResponse(isNetVersion ? chainId.toString() : `0x${chainId.toString(16)}`)
chainIdThrottle[urlKey] -= 1
} catch (e) { } catch (e) {
sendResponse({ sendResponse({
error: true, error: true,
@ -711,7 +744,7 @@ const mainListner = (message: RequestArguments, sender:any, sendResponse: (a: an
try { try {
chrome.windows.remove(sender.tab?.windowId ?? 0) chrome.windows.remove(sender.tab?.windowId ?? 0)
}catch (e) { }catch (e) {
console.log(e) console.info(e)
// ignore // ignore
} }
break break

View File

@ -48,7 +48,6 @@ export const saveNetwork = async (network: Network): Promise<void> => {
export const getSelectedNetwork = async (): Promise<Network > => { export const getSelectedNetwork = async (): Promise<Network > => {
console.info('network', (await (storageGet('selectedNetwork')))?.selectedNetwork)
return (await storageGet('selectedNetwork'))?.selectedNetwork ?? null as unknown as Network return (await storageGet('selectedNetwork'))?.selectedNetwork ?? null as unknown as Network
} }

View File

@ -1,6 +1,21 @@
import { getSelectedAccount, getSelectedNetwork, numToHexStr } from '@/utils/platform'; import { getSelectedAccount, getSelectedNetwork, numToHexStr } from '@/utils/platform';
import { ethers } from "ethers" import { ethers } from "ethers"
let provider: ethers.JsonRpcProvider | null = null
export const getCurrentProvider = async () => {
const network = await getSelectedNetwork()
if (provider) {
// check if the network has changed
if (provider._getConnection().url !== network.rpc) {
provider = new ethers.JsonRpcProvider(network.rpc, ethers.Network.from(network.chainId), { staticNetwork: true, batchMaxCount: 6, polling: false })
}
return {provider, network}
}
provider = new ethers.JsonRpcProvider(network.rpc, ethers.Network.from(network.chainId), { staticNetwork: true, batchMaxCount: 6, polling: false })
return {provider, network}
}
const convertReceipt = (receipt: ethers.TransactionReceipt | null) => { const convertReceipt = (receipt: ethers.TransactionReceipt | null) => {
if(!receipt) return null if(!receipt) return null
const newReceipt = {...receipt} as any const newReceipt = {...receipt} as any
@ -49,34 +64,29 @@ export const signTypedData = async (msg: string) => {
export const getBalance = async () =>{ export const getBalance = async () =>{
const account = await getSelectedAccount() const account = await getSelectedAccount()
const network = await getSelectedNetwork() const { provider } = await getCurrentProvider()
const provider = new ethers.JsonRpcProvider(network.rpc)
return await provider.getBalance(account.address) return await provider.getBalance(account.address)
} }
export const getGasPrice = async () => { export const getGasPrice = async () => {
const network = await getSelectedNetwork() const { provider } = await getCurrentProvider()
const provider = new ethers.JsonRpcProvider(network.rpc)
const feed = await provider.getFeeData() const feed = await provider.getFeeData()
const gasPrice = feed.maxFeePerGas ?? feed.gasPrice ?? 0n const gasPrice = feed.maxFeePerGas ?? feed.gasPrice ?? 0n
return Number(gasPrice) / 1e9 return Number(gasPrice) / 1e9
} }
export const getBlockNumber = async () => { export const getBlockNumber = async () => {
const network = await getSelectedNetwork() const { provider } = await getCurrentProvider()
const provider = new ethers.JsonRpcProvider(network.rpc)
return await provider.getBlockNumber() return await provider.getBlockNumber()
} }
export const getBlockByNumber = async (blockNum: number) => { export const getBlockByNumber = async (blockNum: number) => {
const network = await getSelectedNetwork() const { provider } = await getCurrentProvider()
const provider = new ethers.JsonRpcProvider(network.rpc)
return await provider.getBlock(blockNum) return await provider.getBlock(blockNum)
} }
export const estimateGas = async ({to = '', from = '', data = '', value = '0x0' }: {to: string, from: string, data: string, value: string}) => { export const estimateGas = async ({to = '', from = '', data = '', value = '0x0' }: {to: string, from: string, data: string, value: string}) => {
const network = await getSelectedNetwork() const { provider } = await getCurrentProvider()
const provider = new ethers.JsonRpcProvider(network.rpc)
return await provider.estimateGas({to, from, data, value}) return await provider.estimateGas({to, from, data, value})
} }
@ -94,23 +104,20 @@ export const evmCall = async (params: any[]) => {
tx.blockTag = 'latest' tx.blockTag = 'latest'
} }
const network = await getSelectedNetwork() const { provider } = await getCurrentProvider()
const provider = new ethers.JsonRpcProvider(network.rpc)
const result = await provider.call(tx) const result = await provider.call(tx)
return result return result
} }
export const getTxByHash = async (hash: string) => { export const getTxByHash = async (hash: string) => {
const network = await getSelectedNetwork() const { provider } = await getCurrentProvider()
const provider = new ethers.JsonRpcProvider(network.rpc)
return await provider.getTransaction(hash) return await provider.getTransaction(hash)
} }
export const getTxReceipt = async (hash: string) => { export const getTxReceipt = async (hash: string) => {
try { try {
if (!hash) return null if (!hash) return null
const network = await getSelectedNetwork() const { provider } = await getCurrentProvider()
const provider = new ethers.JsonRpcProvider(network.rpc)
const receipt = await provider.getTransactionReceipt(hash) const receipt = await provider.getTransactionReceipt(hash)
return convertReceipt(receipt) return convertReceipt(receipt)
@ -121,8 +128,7 @@ export const getTxReceipt = async (hash: string) => {
} }
export const getCode = async (addr: string) => { export const getCode = async (addr: string) => {
const network = await getSelectedNetwork() const { provider } = await getCurrentProvider()
const provider = new ethers.JsonRpcProvider(network.rpc)
return await provider.getCode(addr) return await provider.getCode(addr)
} }
@ -134,8 +140,7 @@ export const getFromMnemonic = (mnemonic: string, index: number) => {
} }
export const getTxCount = async (addr: string, block: null | string = null) => { export const getTxCount = async (addr: string, block: null | string = null) => {
const network = await getSelectedNetwork() const { provider } = await getCurrentProvider()
const provider = new ethers.JsonRpcProvider(network.rpc)
if(block){ if(block){
return await provider.getTransactionCount(addr, block) return await provider.getTransactionCount(addr, block)
} else { } else {
@ -147,16 +152,11 @@ export const getRandomPk = () => {
return ethers.Wallet.createRandom().privateKey return ethers.Wallet.createRandom().privateKey
} }
export const getCurrentProvider = async () => {
const network = await getSelectedNetwork()
return new ethers.JsonRpcProvider(network.rpc)
}
export const sendTransaction = async ({ data= '', gas='0x0', to='', from='', value='', gasPrice='0x0'}: export const sendTransaction = async ({ data= '', gas='0x0', to='', from='', value='', gasPrice='0x0'}:
{to: string, from: string, data: string, value: string, gas: string, gasPrice: string}) => { {to: string, from: string, data: string, value: string, gas: string, gasPrice: string}) => {
const account = await getSelectedAccount() const account = await getSelectedAccount()
const network = await getSelectedNetwork() const { provider } = await getCurrentProvider()
const wallet = new ethers.Wallet(account.pk, new ethers.JsonRpcProvider(network.rpc)) const wallet = new ethers.Wallet(account.pk, provider)
const gasPriceInt = BigInt(gasPrice) const gasPriceInt = BigInt(gasPrice)
const gasInt = BigInt(gas) const gasInt = BigInt(gas)

View File

@ -76,7 +76,7 @@
</ion-item> </ion-item>
<ion-item> <ion-item>
<ion-textarea <ion-textarea
style="overflow-y: scroll" style="overflow-y: scroll; width: 100%"
aria-label="Enter mnemonic" aria-label="Enter mnemonic"
:rows="10" :rows="10"
:cols="10" :cols="10"
@ -263,7 +263,7 @@ export default defineComponent({
if (settings.enableStorageEnctyption) { if (settings.enableStorageEnctyption) {
const pass = await openModal(); const pass = await openModal();
if (!pass) { if (!pass) {
alertMsg.value = "Cannot add account with encryption password."; alertMsg.value = "Cannot add account without encryption password.";
alertOpen.value = true; alertOpen.value = true;
return; return;
} }
@ -278,7 +278,8 @@ export default defineComponent({
} else { } else {
if (accounts.find((account) => account.address === wallet.address)) { if (accounts.find((account) => account.address === wallet.address)) {
alertMsg.value = "Account already exists."; alertMsg.value = "Account already exists.";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
} }
const p2 = saveAccount({ const p2 = saveAccount({
@ -299,7 +300,8 @@ export default defineComponent({
} else { } else {
if (accounts.find((account) => account.address === wallet.address)) { if (accounts.find((account) => account.address === wallet.address)) {
alertMsg.value = "Account already exists."; alertMsg.value = "Account already exists.";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
} }
const p2 = saveAccount({ const p2 = saveAccount({

View File

@ -229,22 +229,26 @@ export default defineComponent({
const onAddNetwork = async () => { const onAddNetwork = async () => {
if (Number(chainId.value) < 1) { if (Number(chainId.value) < 1) {
alertMsg.value = "Chain Id must be a valid decimal integer"; alertMsg.value = "Chain Id must be a valid decimal integer";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
if (name.value.length < 2) { if (name.value.length < 2) {
alertMsg.value = "Name must have at least 2 characters"; alertMsg.value = "Name must have at least 2 characters";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
if (name.value.length > 99) { if (name.value.length > 99) {
alertMsg.value = "Name must be less than 100 characters"; alertMsg.value = "Name must be less than 100 characters";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
if (name.value.length > 99) { if (name.value.length > 99) {
try { try {
new URL(rpc.value); new URL(rpc.value);
} catch { } catch {
alertMsg.value = "RPC must be a valid URL"; alertMsg.value = "RPC must be a valid URL";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
} }
let p1 = Promise.resolve(); let p1 = Promise.resolve();
@ -270,7 +274,8 @@ export default defineComponent({
} else { } else {
if (chainId.value in networks && !isEdit) { if (chainId.value in networks && !isEdit) {
alertMsg.value = "Network already exists."; alertMsg.value = "Network already exists.";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
} }
networks[chainId.value] = network; networks[chainId.value] = network;

View File

@ -35,10 +35,14 @@
conectivity issues. conectivity issues.
</template> </template>
<template v-else-if="noAssets"> <template v-else-if="noAssets">
<p class="padding: 1rem;"> <!-- <p class="padding: 1rem;">
No know assets found for this wallet address. No know assets found for this wallet address.
</p></template </p> -->
> <p class="padding: 1rem;">
Assets view temporarily disabled until finding better provider. As old
provider(yup.io) is no longer available.
</p>
</template>
<template v-else> <template v-else>
<template v-if="ethTokens.length || polyTokens.length"> <template v-if="ethTokens.length || polyTokens.length">
<template v-if="ethTokens.length"> <template v-if="ethTokens.length">

View File

@ -367,12 +367,13 @@ export default defineComponent({
const findIndex = accounts.value.findIndex((a) => a.address == address); const findIndex = accounts.value.findIndex((a) => a.address == address);
if (findIndex > -1) { if (findIndex > -1) {
selectedAccount.value = accounts.value[findIndex]; selectedAccount.value = accounts.value[findIndex];
await saveSelectedAccount(selectedAccount.value); accounts.value = accounts.value.filter((a) => a.address !== address);
// console.log(({ [address]: accounts.value[address], ...accounts.value})) accounts.value.unshift(selectedAccount.value);
accounts.value.splice(findIndex, 1);
accounts.value.splice(0, 0, selectedAccount.value);
const newAccounts = [...accounts.value]; const newAccounts = [...accounts.value];
await replaceAccounts(newAccounts); await Promise.all([
saveSelectedAccount(selectedAccount.value),
replaceAccounts(newAccounts),
]);
triggerListner("accountsChanged", [newAccounts.map((a) => a.address)?.[0]]); triggerListner("accountsChanged", [newAccounts.map((a) => a.address)?.[0]]);
} }
accountsModal.value = false; accountsModal.value = false;

View File

@ -121,6 +121,7 @@
></ion-alert> ></ion-alert>
<iframe <iframe
title="eval-sandbox"
@load="sandboxLoaded = true" @load="sandboxLoaded = true"
ref="evalFrame" ref="evalFrame"
src="eval-sandbox.html" src="eval-sandbox.html"
@ -285,7 +286,8 @@ export default defineComponent({
if (!content) { if (!content) {
alertMsg.value = alertMsg.value =
"Abi not found in storage, be sure Abi with name " + data.abi + " exists."; "Abi not found in storage, be sure Abi with name " + data.abi + " exists.";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
abiContent.value = content; abiContent.value = content;
@ -304,15 +306,18 @@ export default defineComponent({
const saveActionInStorage = () => { const saveActionInStorage = () => {
if (!functionName.value) { if (!functionName.value) {
alertMsg.value = "Function Name is required"; alertMsg.value = "Function Name is required";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
if (!contractAddress.value) { if (!contractAddress.value) {
alertMsg.value = "Contract Address is required"; alertMsg.value = "Contract Address is required";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
if (abiContent.value === "") { if (abiContent.value === "") {
alertMsg.value = "Abi is required"; alertMsg.value = "Abi is required";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
saveActionModal.value = true; saveActionModal.value = true;
}; };
@ -320,22 +325,26 @@ export default defineComponent({
const executeAction = async () => { const executeAction = async () => {
if (sandboxLoaded.value === false) { if (sandboxLoaded.value === false) {
alertMsg.value = "Sandbox for eval not loaded yet, please wait"; alertMsg.value = "Sandbox for eval not loaded yet, please wait";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
if (!contractAddress.value) { if (!contractAddress.value) {
alertMsg.value = "Contract Address is required"; alertMsg.value = "Contract Address is required";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
if (!functionName.value) { if (!functionName.value) {
alertMsg.value = "Function Name is required"; alertMsg.value = "Function Name is required";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
if (!parsedAbi) { if (!parsedAbi) {
alertMsg.value = "Abi is required"; alertMsg.value = "Abi is required";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
alertHeader.value = "Error"; alertHeader.value = "Error";
@ -350,7 +359,8 @@ export default defineComponent({
); );
} catch { } catch {
alertMsg.value = "Error parsing params, check params types"; alertMsg.value = "Error parsing params, check params types";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
try { try {
@ -362,14 +372,16 @@ export default defineComponent({
.map((param) => param.trim()); .map((param) => param.trim());
if (paramsTypes.length !== evalParams.length) { if (paramsTypes.length !== evalParams.length) {
alertMsg.value = "Params count mismatch"; alertMsg.value = "Params count mismatch";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
encodeParamsTypes.push(...paramsTypes); encodeParamsTypes.push(...paramsTypes);
} }
} catch { } catch {
alertMsg.value = alertMsg.value =
"Function Siganture wrong format (ex: 'functionName(uint256,string)')"; "Function Siganture wrong format (ex: 'functionName(uint256,string)')";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
const fnName = functionName.value.includes("(") const fnName = functionName.value.includes("(")
@ -384,17 +396,20 @@ export default defineComponent({
alertMsg.value = "Value from contract fetched check result area!"; alertMsg.value = "Value from contract fetched check result area!";
alertHeader.value = "OK"; alertHeader.value = "OK";
return (alertOpen.value = true); alertOpen.value = true;
return;
} catch (e) { } catch (e) {
alertMsg.value = "Function call failed, check params, contract address and ABI"; alertMsg.value = "Function call failed, check params, contract address and ABI";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
}; };
const saveAction = async () => { const saveAction = async () => {
if (!name.value) { if (!name.value) {
alertMsg.value = "Name is required"; alertMsg.value = "Name is required";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
const action = { const action = {
name: name.value, name: name.value,
@ -408,7 +423,8 @@ export default defineComponent({
saveActionModal.value = false; saveActionModal.value = false;
alertMsg.value = "Action saved successfully"; alertMsg.value = "Action saved successfully";
alertHeader.value = "OK"; alertHeader.value = "OK";
return (alertOpen.value = true); alertOpen.value = true;
return;
}; };
const messageHandler = (event: any) => { const messageHandler = (event: any) => {

View File

@ -53,11 +53,14 @@ import {
modalController, modalController,
onIonViewWillEnter, onIonViewWillEnter,
} from "@ionic/vue"; } from "@ionic/vue";
// import { ethers } from "ethers";
import { hexTostr } from "@/utils/platform";
import { approve, walletPing } from "@/extension/userRequest"; import { approve, walletPing } from "@/extension/userRequest";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { getSelectedAccount, unBlockLockout, blockLockout } from "@/utils/platform"; import {
getSelectedAccount,
unBlockLockout,
blockLockout,
hexTostr,
} from "@/utils/platform";
import UnlockModal from "@/views/UnlockModal.vue"; import UnlockModal from "@/views/UnlockModal.vue";
export default defineComponent({ export default defineComponent({

View File

@ -113,6 +113,7 @@
/> />
<iframe <iframe
title="eval-sandbox"
@load="sandboxLoaded = true" @load="sandboxLoaded = true"
ref="evalFrame" ref="evalFrame"
src="eval-sandbox.html" src="eval-sandbox.html"
@ -279,7 +280,8 @@ export default defineComponent({
if (!content) { if (!content) {
alertMsg.value = alertMsg.value =
"Abi not found in storage, be sure Abi with name " + data.abi + " exists."; "Abi not found in storage, be sure Abi with name " + data.abi + " exists.";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
abiContent.value = content; abiContent.value = content;
@ -297,15 +299,18 @@ export default defineComponent({
const saveActionInStorage = () => { const saveActionInStorage = () => {
if (!functionName.value) { if (!functionName.value) {
alertMsg.value = "Function Name is required"; alertMsg.value = "Function Name is required";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
if (!contractAddress.value) { if (!contractAddress.value) {
alertMsg.value = "Contract Address is required"; alertMsg.value = "Contract Address is required";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
if (abiContent.value === "") { if (abiContent.value === "") {
alertMsg.value = "Abi is required"; alertMsg.value = "Abi is required";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
saveActionModal.value = true; saveActionModal.value = true;
}; };
@ -313,22 +318,26 @@ export default defineComponent({
const executeAction = async () => { const executeAction = async () => {
if (sandboxLoaded.value === false) { if (sandboxLoaded.value === false) {
alertMsg.value = "Sandbox for eval not loaded yet, please wait"; alertMsg.value = "Sandbox for eval not loaded yet, please wait";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
if (!contractAddress.value) { if (!contractAddress.value) {
alertMsg.value = "Contract Address is required"; alertMsg.value = "Contract Address is required";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
if (!functionName.value) { if (!functionName.value) {
alertMsg.value = "Function Name is required"; alertMsg.value = "Function Name is required";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
if (!parsedAbi) { if (!parsedAbi) {
alertMsg.value = "Abi is required"; alertMsg.value = "Abi is required";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
alertHeader.value = "Error"; alertHeader.value = "Error";
@ -348,14 +357,16 @@ export default defineComponent({
.map((param) => param.trim()); .map((param) => param.trim());
if (paramsTypes.length !== evalParams.length) { if (paramsTypes.length !== evalParams.length) {
alertMsg.value = "Params count mismatch"; alertMsg.value = "Params count mismatch";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
encodeParamsTypes.push(...paramsTypes); encodeParamsTypes.push(...paramsTypes);
} }
} catch { } catch {
alertMsg.value = alertMsg.value =
"Function Siganture wrong format (ex: 'functionName(uint256,string)')"; "Function Siganture wrong format (ex: 'functionName(uint256,string)')";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
const fnName = functionName.value.includes("(") const fnName = functionName.value.includes("(")
@ -396,7 +407,8 @@ export default defineComponent({
alertMsg.value = "Function call failed, check params, contract address and ABI"; alertMsg.value = "Function call failed, check params, contract address and ABI";
loadingSend.value = false; loadingSend.value = false;
loading.value = false; loading.value = false;
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
loadingSend.value = false; loadingSend.value = false;
loading.value = false; loading.value = false;
@ -405,7 +417,8 @@ export default defineComponent({
const saveAction = async () => { const saveAction = async () => {
if (!name.value) { if (!name.value) {
alertMsg.value = "Name is required"; alertMsg.value = "Name is required";
return (alertOpen.value = true); alertOpen.value = true;
return;
} }
const action = { const action = {
name: name.value, name: name.value,
@ -419,7 +432,7 @@ export default defineComponent({
saveActionModal.value = false; saveActionModal.value = false;
alertMsg.value = "Action saved successfully"; alertMsg.value = "Action saved successfully";
alertHeader.value = "OK"; alertHeader.value = "OK";
return (alertOpen.value = true); alertOpen.value = true;
}; };
const messageHandler = (event: any) => { const messageHandler = (event: any) => {

1188
yarn.lock

File diff suppressed because it is too large Load Diff