mirror of
https://github.com/andrei0x309/clear-wallet.git
synced 2024-10-04 22:50:54 +00:00
chore: changes for 1.3.0
This commit is contained in:
parent
b52ddd02f0
commit
fe8e4c273b
16
CHANGELOG.md
16
CHANGELOG.md
@ -1,5 +1,21 @@
|
||||
# Changelog
|
||||
|
||||
## Manifest Version 1.3.0
|
||||
|
||||
- refactored the wallet to use etheres V6
|
||||
- implemented EIP6963Provider
|
||||
- updated all dependencies
|
||||
- added ability to send native tokens
|
||||
- added ability to manage ABIs
|
||||
- added ability to perfrom arbitrary read calls to contracts
|
||||
- added ability to perfrom arbitrary write calls to contracts
|
||||
- added ability to save read or write calls for later use
|
||||
- added sandbox to be able to evaluate JS code in order to pass complex parameters to read or write calls
|
||||
- added base Network to templates class
|
||||
- added Icon for base network
|
||||
- added ability to add contacts and load them in Read contract and Write and Send token pages
|
||||
- added ability to paste current selected address to both webpages and insde wallet itself
|
||||
|
||||
## Manifest Version 1.2.8
|
||||
|
||||
- better support for estimate gas
|
||||
|
20
eval-sandbox.html
Normal file
20
eval-sandbox.html
Normal file
@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Eval Sandbox</h1>
|
||||
<script>
|
||||
// console.log('sandbox loaded');
|
||||
window.addEventListener('message', function (event) {
|
||||
// console.log('message received', event);
|
||||
const data = event.data;
|
||||
const execFunc = new Function(
|
||||
'return ' + data.code
|
||||
);
|
||||
const result = execFunc();
|
||||
event.source.postMessage({ result }, event.origin);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" style="width:400px;height:450px">
|
||||
<html lang="en" style="width:400px;height:500px">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Clear Wallet</title>
|
||||
|
@ -1,10 +1,11 @@
|
||||
{
|
||||
"name": "clear-wallet",
|
||||
"version": "1.2.8",
|
||||
"version": "1.2.9",
|
||||
"private": true,
|
||||
"description": "Clear Wallet (CLW) is a wallet that helps you manage your Ethereum assets and interact with Ethereum dApps and contracts with the main focus on absolute privacy.",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"inject": "tsc --outFile src/extension/inject.js src/extension/inject.ts",
|
||||
"inject": "tsc --downlevelIteration --outFile src/extension/inject.js src/extension/inject.ts",
|
||||
"content": "tsc --outFile src/extension/content.js src/extension/content.ts",
|
||||
"post-build": "ts-node ./release-scripts/post-build.ts",
|
||||
"build": "yarn inject && yarn content && vue-tsc --noEmit && vite build && yarn post-build",
|
||||
@ -53,6 +54,5 @@
|
||||
"vite": "^4.4.9",
|
||||
"vue-tsc": "^1.8.8",
|
||||
"yarn-upgrade-all": "^0.7.2"
|
||||
},
|
||||
"description": "An Ionic project"
|
||||
}
|
||||
}
|
||||
|
BIN
public/assets/chain-icons/base.webp
Normal file
BIN
public/assets/chain-icons/base.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 260 B |
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" style="width:400px;height:450px">
|
||||
<html lang="en" style="width:400px;height:500px">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Clear Wallet</title>
|
||||
|
@ -1,16 +1,15 @@
|
||||
|
||||
(async () => {
|
||||
const CONTENT_BUILD_PATH = 'src/extension/content.js'
|
||||
const METAMASK_STUB_PATH = 'src/extension/metamask-stub.js'
|
||||
const METAMASK_INJECT_PATH = 'src/extension/inject.js'
|
||||
const fs = (await import('fs')).default
|
||||
const path = (await import('path')).default
|
||||
const pkg = JSON.parse(fs.readFileSync('dist/manifest.json').toString());
|
||||
pkg.content_scripts[0].js[0] = CONTENT_BUILD_PATH
|
||||
pkg.content_scripts[1].js[0] = METAMASK_STUB_PATH
|
||||
pkg.content_scripts[1].js[0] = METAMASK_INJECT_PATH
|
||||
fs.writeFileSync('dist/manifest.json', JSON.stringify(pkg, null, 2))
|
||||
// fs.writeFileSync('dist/rules.js', fs.readFileSync('rules.json').toString())
|
||||
fs.writeFileSync('dist/'+ CONTENT_BUILD_PATH, fs.readFileSync('src/extension/content.js').toString())
|
||||
fs.writeFileSync('dist/'+ METAMASK_STUB_PATH, fs.readFileSync('src/extension/metamask-stub.js').toString())
|
||||
fs.writeFileSync('dist/'+ METAMASK_INJECT_PATH, fs.readFileSync('src/extension/inject.js').toString())
|
||||
const directory = 'dist/assets/';
|
||||
fs.readdir(directory, (err, files) => {
|
||||
files.forEach(file => {
|
||||
|
60
src/App.vue
60
src/App.vue
@ -6,9 +6,11 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { IonApp, IonRouterOutlet } from "@ionic/vue";
|
||||
import { defineComponent, onBeforeMount, onMounted } from "vue";
|
||||
import { defineComponent, onBeforeMount, onMounted, onUnmounted } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { getSettings } from "@/utils/platform";
|
||||
import { getSelectedAddress } from "@/utils/wallet";
|
||||
import type { RequestArguments } from "@/extension/types";
|
||||
|
||||
export default defineComponent({
|
||||
name: "App",
|
||||
@ -21,6 +23,51 @@ export default defineComponent({
|
||||
const router = useRouter();
|
||||
const { param, rid } = route.query;
|
||||
|
||||
const pageListener = (
|
||||
message: RequestArguments,
|
||||
sender: any,
|
||||
sendResponse: (a: any) => any
|
||||
) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.info("Error receiving message:", chrome.runtime.lastError);
|
||||
}
|
||||
if (message?.type !== "CLWALLET_PAGE_MSG") {
|
||||
return true;
|
||||
}
|
||||
|
||||
console.info("page listener:", message);
|
||||
|
||||
(async () => {
|
||||
if (!message?.method) {
|
||||
sendResponse({
|
||||
code: 500,
|
||||
message: "Invalid request method",
|
||||
});
|
||||
} else {
|
||||
// ETH API
|
||||
switch (message.method) {
|
||||
case "paste": {
|
||||
const currentAddress = (await getSelectedAddress()) as string[];
|
||||
if (currentAddress.length > 0) {
|
||||
document.execCommand("insertText", false, currentAddress[0]);
|
||||
}
|
||||
sendResponse(true);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
sendResponse({
|
||||
error: true,
|
||||
message:
|
||||
"ClearWallet: Invalid PAGE request method " + message?.method ?? "",
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
return true;
|
||||
};
|
||||
|
||||
onBeforeMount(() => {
|
||||
getSettings().then((settings) => {
|
||||
if (settings.theme !== "system") {
|
||||
@ -28,6 +75,17 @@ export default defineComponent({
|
||||
document.body.classList.add(settings.theme);
|
||||
}
|
||||
});
|
||||
if (chrome?.runtime?.onMessage) {
|
||||
chrome.runtime.onMessage.addListener(pageListener);
|
||||
console.info("page listener set");
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (chrome?.runtime?.onMessage) {
|
||||
chrome.runtime.onMessage.removeListener(pageListener);
|
||||
console.info("page listener removed");
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
|
@ -1,23 +1,24 @@
|
||||
|
||||
(() =>{
|
||||
try {
|
||||
const container = document.documentElement;
|
||||
const script = document.createElement('script');
|
||||
script.setAttribute('async', "false")
|
||||
script.setAttribute('fetchpriority', "high")
|
||||
script.src = chrome.runtime.getURL('src/extension/inject.js')
|
||||
container.prepend(script)
|
||||
script.addEventListener('load', () => { container.removeChild(script) } )
|
||||
} catch (error) {
|
||||
console.error('MetaMask: Provider injection failed.', error);
|
||||
}
|
||||
(() => {
|
||||
// Not needed anymore since injection is done with MAIN_WORLD context
|
||||
// try {
|
||||
// const container = document.documentElement;
|
||||
// const script = document.createElement('script');
|
||||
// script.setAttribute('async', "false")
|
||||
// script.setAttribute('fetchpriority', "high")
|
||||
// script.src = chrome.runtime.getURL('src/extension/inject.js')
|
||||
// container.prepend(script)
|
||||
// script.addEventListener('load', () => { container.removeChild(script) })
|
||||
// } catch (error) {
|
||||
// console.info('Error: MetaMask: Provider injection failed.', error);
|
||||
// }
|
||||
})()
|
||||
|
||||
const allowedMethods = {
|
||||
'eth_accounts': true,
|
||||
'eth_requestAccounts' : true,
|
||||
'eth_requestAccounts': true,
|
||||
'eth_chainId': true,
|
||||
'personal_sign' : true,
|
||||
'personal_sign': true,
|
||||
'wallet_requestPermissions': true,
|
||||
'eth_gasPrice': true,
|
||||
'eth_getBlockByNumber': true,
|
||||
@ -50,42 +51,51 @@ const allowedMethods = {
|
||||
|
||||
window.addEventListener("message", (event) => {
|
||||
if (event.source != window)
|
||||
return;
|
||||
// console.log(event)
|
||||
if (event.data.type && (event.data.type === "CLWALLET_CONTENT")) {
|
||||
return;
|
||||
if (event?.data?.type === "CLWALLET_CONTENT") {
|
||||
event.data.data.resId = event.data.resId
|
||||
event.data.data.type = "CLWALLET_CONTENT_MSG"
|
||||
event.data.data.website = document?.location?.href ?? ''
|
||||
if((event?.data?.data?.method ?? 'x') in allowedMethods) {
|
||||
chrome.runtime.sendMessage(event.data.data, (res) => {
|
||||
const data = { type: "CLWALLET_PAGE", data: res, resId: event.data.resId };
|
||||
// console.log('data back', data)
|
||||
event.data.data.website = document?.location?.href ?? ''
|
||||
if ((event?.data?.data?.method ?? 'x') in allowedMethods) {
|
||||
chrome.runtime.sendMessage(event.data.data, (res) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.warn("LOC1: Error sending message:", chrome.runtime.lastError);
|
||||
}
|
||||
|
||||
const data = { type: "CLWALLET_PAGE", data: res, resId: event.data.resId };
|
||||
// console.info('data out', data)
|
||||
window.postMessage(data, "*");
|
||||
})
|
||||
}
|
||||
else {
|
||||
const data = { type: "CLWALLET_PAGE", data: { error: true, message: 'ClearWallet: Unknown method requested ' + event?.data?.data?.method ?? '' }, resId: event.data.resId };
|
||||
window.postMessage(data, "*");
|
||||
})
|
||||
}
|
||||
else {
|
||||
const data = { type: "CLWALLET_PAGE", data: { error: true, message: 'ClearWallet: Unknown method requested ' + event?.data?.data?.method ?? ''}, resId: event.data.resId };
|
||||
window.postMessage(data, "*");
|
||||
}
|
||||
} else if (event.data.type && (event.data.type === "CLWALLET_PING")) {
|
||||
}
|
||||
} else if (event?.data?.type === "CLWALLET_PING") {
|
||||
event.data.data.resId = event.data.resId
|
||||
event.data.data.type = "CLWALLET_CONTENT_MSG"
|
||||
event.data.data.method = "wallet_connect"
|
||||
event.data.data.params = Array(0)
|
||||
chrome.runtime.sendMessage(event.data.data , async (res) => {
|
||||
window.postMessage(res, "*");
|
||||
|
||||
event.data.data.params = Array(0)
|
||||
chrome.runtime.sendMessage(event.data.data, async (res) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.warn("LOC2: Error sending message:", chrome.runtime.lastError);
|
||||
}
|
||||
window.postMessage(res, "*");
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
chrome.runtime.onMessage.addListener((message: any , sender, sendResponse) => {
|
||||
if(message.type === "CLWALLET_EXT_LISTNER") {
|
||||
const data = { type: "CLWALLET_PAGE_LISTENER", data: message.data };
|
||||
chrome.runtime.onMessage.addListener((message: any, sender, sendResponse) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.warn("Error receiving message:", chrome.runtime.lastError);
|
||||
}
|
||||
if (message.type === "CLWALLET_EXT_LISTNER") {
|
||||
const data = { type: "CLWALLET_PAGE_LISTENER", data: message.data };
|
||||
// console.log('data listner', data)
|
||||
window.postMessage(data, "*");
|
||||
}
|
||||
return true
|
||||
|
||||
});
|
||||
|
||||
|
@ -4,6 +4,42 @@ interface RequestArguments {
|
||||
params?: unknown[] | object;
|
||||
}
|
||||
|
||||
interface EIP6963ProviderInfo {
|
||||
uuid: string;
|
||||
name: string;
|
||||
icon: string;
|
||||
rdns: string;
|
||||
}
|
||||
|
||||
const ProviderInfo: EIP6963ProviderInfo = {
|
||||
uuid: '1fa914a1-f8c9-4c74-8d84-4aa93dc90eec',
|
||||
name: 'Clear Wallet',
|
||||
icon: 'data:image/png;base64,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',
|
||||
rdns: 'clear-wallet.flashsoft.eu/',
|
||||
}
|
||||
|
||||
function loadEIP1193Provider(provider: any) {
|
||||
|
||||
function announceProvider() {
|
||||
const info: EIP6963ProviderInfo = ProviderInfo
|
||||
window.dispatchEvent(
|
||||
new CustomEvent("eip6963:announceProvider", {
|
||||
detail: Object.freeze({ info, provider }),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
window.addEventListener(
|
||||
"eip6963:requestProvider",
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
(event: any) => {
|
||||
announceProvider();
|
||||
}
|
||||
);
|
||||
|
||||
announceProvider();
|
||||
}
|
||||
|
||||
const listners = {
|
||||
accountsChanged: new Set<(p?: any) => void>(),
|
||||
connect: new Set<(p?: any) => void>(),
|
||||
@ -36,13 +72,13 @@ const getListnersCount = (): number => {
|
||||
const sendMessage = (args: RequestArguments, ping = false) => {
|
||||
if(Object.values(promResolvers).filter(r=> r).length < 10 ) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const resId = crypto.randomUUID()
|
||||
const resId = [...`${Math.random().toString(16) + Date.now().toString(16)}`].slice(2).join('')
|
||||
promResolvers.set(resId, { resolve, reject })
|
||||
const data = { type: "CLWALLET_CONTENT", data: args, resId};
|
||||
if (ping) {
|
||||
data.type = 'CLWALLET_PING'
|
||||
}
|
||||
// console.log('data in', data)
|
||||
// console.info('data in', data)
|
||||
window.postMessage(data, "*");
|
||||
})
|
||||
} else {
|
||||
@ -80,7 +116,7 @@ class MetaMaskAPI {
|
||||
_events: {}, _eventsCount: 0, _maxListeners: undefined, _middleware: Array(4)
|
||||
}
|
||||
isConnected() {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
// for maximum compatibility since is cloning the same API
|
||||
|
||||
@ -129,7 +165,7 @@ class MetaMaskAPI {
|
||||
} else if (typeof arg1 === 'object') {
|
||||
return sendMessage(arg1 as RequestArguments)
|
||||
} else {
|
||||
console.error('Clear Wallet: faulty request')
|
||||
console.info('ERROR: Clear Wallet: faulty request')
|
||||
}
|
||||
}else if( typeof arg1 === 'string' ) {
|
||||
return sendMessage({
|
||||
@ -272,37 +308,22 @@ class MetaMaskAPI {
|
||||
_handleStreamDisconnect() { return true }
|
||||
_handleUnlockStateChanged() { return true }
|
||||
_sendSync () {
|
||||
console.error('Clear Wallet: Sync calling is deprecated and not supported')
|
||||
console.info('ERROR: Clear Wallet: Sync calling is deprecated and not supported')
|
||||
}
|
||||
}
|
||||
|
||||
const eth = new Proxy( new MetaMaskAPI(), {
|
||||
// set: () => { return true },
|
||||
// get: function(target, name, receiver) {
|
||||
// if (typeof (<any>target)[name] == 'function') {
|
||||
// return function (...args: any) {
|
||||
// console.dir({ call: [name, ...args] });
|
||||
// return undefined;
|
||||
// }
|
||||
// }
|
||||
|
||||
// let check = true
|
||||
// setTimeout(() => check = false, 400)
|
||||
// while(check){
|
||||
// // igmore
|
||||
// }
|
||||
// },
|
||||
deleteProperty: () => { return true },
|
||||
})
|
||||
|
||||
const listner = function(event: any) {
|
||||
if (event.source != window) return;
|
||||
|
||||
if (event.data.type && (event.data.type === "CLWALLET_PAGE")) {
|
||||
if (event?.data?.type === "CLWALLET_PAGE") {
|
||||
try {
|
||||
if(event?.data?.data?.error){
|
||||
promResolvers.get(event.data.resId)?.reject(event.data.data);
|
||||
console.error(event?.data?.data)
|
||||
console.info('Error: ', event?.data?.data)
|
||||
}else {
|
||||
promResolvers.get(event.data.resId)?.resolve(event.data.data);
|
||||
}
|
||||
@ -310,7 +331,7 @@ const listner = function(event: any) {
|
||||
} catch (e) {
|
||||
// console.log('Failed to connect resolve msg', e)
|
||||
}
|
||||
} else if( event.data.type && (event.data.type === "CLWALLET_PAGE_LISTENER")) {
|
||||
} else if(event?.data?.type === "CLWALLET_PAGE_LISTENER") {
|
||||
if((event?.data?.data?.listner ?? 'x') in listners ) {
|
||||
try {
|
||||
const listnerName = event?.data?.data?.listner as ('accountsChanged' | 'connect' | 'disconnect' | 'chainChanged')
|
||||
@ -320,7 +341,7 @@ const listner = function(event: any) {
|
||||
(<any>eth).selectedAddress = event?.data?.data?.address ?? null;
|
||||
(<any>eth).isConnected = () => true;
|
||||
} else if( listnerName === 'chainChanged' ) {
|
||||
// console.log(event?.data?.data?.data);
|
||||
// console.info(event?.data?.data?.data);
|
||||
(<any>eth).networkVersion = event?.data?.data?.data.toString(10) ?? '137';
|
||||
(<any>eth).chainId = event?.data?.data?.data ?? '0x89';
|
||||
} else if ( listnerName === 'accountsChanged' ) {
|
||||
@ -332,7 +353,7 @@ const listner = function(event: any) {
|
||||
listners.once[listnerName].delete(listner)
|
||||
});
|
||||
} catch (e) {
|
||||
// console.error(e)
|
||||
// console.info(e)
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
@ -341,43 +362,46 @@ const listner = function(event: any) {
|
||||
|
||||
window.addEventListener("message",listner)
|
||||
|
||||
// const proxy1 = new Proxy({
|
||||
// // on: (event: any, callback:any) => { if (event === 'message') {
|
||||
// // debugger;
|
||||
// // callback(true, true)
|
||||
// // } }
|
||||
// }, {
|
||||
// get: function(target, name, receiver) {
|
||||
// if (typeof (<any>target)[name] == 'function') {
|
||||
// return function (...args: any) {
|
||||
// console.dir({ call: [name, ...args] });
|
||||
// }
|
||||
// }
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const proxy1 = new Proxy(new MetaMaskAPI(), {
|
||||
get: function (target: any, prop: any) {
|
||||
// Intercept method calls and log them
|
||||
if (typeof target[prop] === 'function') {
|
||||
return function (...args: any[]) {
|
||||
console.log(`Calling ${prop} with arguments:`, args);
|
||||
// eslint-disable-next-line prefer-spread
|
||||
const result = target[prop].apply(target, args);
|
||||
console.log(`${prop} returned:`, result);
|
||||
return result;
|
||||
};
|
||||
} else {
|
||||
console.log(`Reading ${prop}`);
|
||||
return target[prop];
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
// console.log('ETH', name.toString() , target, receiver);
|
||||
// return undefined
|
||||
// }
|
||||
// })
|
||||
|
||||
const web3Shim = {
|
||||
currentProvider: eth,
|
||||
__isMetaMaskShim__: true
|
||||
}
|
||||
// const web3Shim = {
|
||||
// currentProvider: eth,
|
||||
// __isMetaMaskShim__: true
|
||||
// }
|
||||
|
||||
const injectWallet = (win: any) => {
|
||||
Object.defineProperty(win, 'ethereum', {
|
||||
value: eth,
|
||||
});
|
||||
Object.defineProperty(win, 'web3', {
|
||||
value: web3Shim
|
||||
value: eth
|
||||
});
|
||||
sendMessage({
|
||||
method: 'wallet_ready'
|
||||
}, true)
|
||||
// console.log('Clear wallet injected', (window as any).ethereum, win)
|
||||
console.log('Clear wallet injected', (window as any).ethereum, win)
|
||||
}
|
||||
|
||||
injectWallet(this);
|
||||
loadEIP1193Provider(eth)
|
||||
|
||||
// setTimeout(() => {
|
||||
// // console.log('Metamask clone test');
|
||||
|
@ -3,8 +3,8 @@
|
||||
"name": "__MSG_appName__",
|
||||
"description": "__MSG_appDesc__",
|
||||
"default_locale": "en",
|
||||
"version": "1.2.8",
|
||||
"version_name": "1.2.8",
|
||||
"version": "1.3.0",
|
||||
"version_name": "1.3.0",
|
||||
"icons": {
|
||||
"16": "assets/extension-icon/wallet_16.png",
|
||||
"32": "assets/extension-icon/wallet_32.png",
|
||||
@ -23,11 +23,14 @@
|
||||
"minimum_chrome_version": "103",
|
||||
"permissions": [
|
||||
"notifications",
|
||||
"activeTab",
|
||||
"storage",
|
||||
"alarms",
|
||||
"unlimitedStorage",
|
||||
"clipboardRead",
|
||||
"clipboardWrite"
|
||||
"clipboardWrite",
|
||||
"contextMenus",
|
||||
"scripting"
|
||||
],
|
||||
"host_permissions": [
|
||||
"*://*/*"
|
||||
@ -53,12 +56,17 @@
|
||||
],
|
||||
"all_frames": true,
|
||||
"run_at": "document_start",
|
||||
"js": ["/src/extension/metamask-stub.js"],
|
||||
"js": ["/src/extension/inject.ts"],
|
||||
"world": "MAIN"
|
||||
}
|
||||
],
|
||||
"web_accessible_resources": [{
|
||||
"resources": ["src/extension/inject.js"],
|
||||
"matches": ["<all_urls>"]
|
||||
}]
|
||||
}],
|
||||
"sandbox": {
|
||||
"pages": [
|
||||
"eval-sandbox.html"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,40 @@
|
||||
import { getSelectedAccount, getSelectedNetwork, smallRandomString, getSettings, clearPk, openTab, getUrl, addToHistory, getNetworks, strToHex, numToHexStr } from '@/utils/platform';
|
||||
import { userApprove, userReject, rIdWin, rIdData } from '@/extension/userRequest'
|
||||
import { signMsg, getBalance, getBlockNumber, estimateGas, sendTransaction, getGasPrice, getBlockByNumber, evmCall, getTxByHash, getTxReceipt, signTypedData, getCode, getTxCount } from '@/utils/wallet'
|
||||
import {
|
||||
CLW_CONTEXT_MENU_ID,
|
||||
getSelectedAccount,
|
||||
getSelectedNetwork,
|
||||
smallRandomString,
|
||||
getSettings,
|
||||
clearPk,
|
||||
openTab,
|
||||
getUrl,
|
||||
addToHistory,
|
||||
getNetworks,
|
||||
strToHex,
|
||||
numToHexStr,
|
||||
enableRightClickVote,
|
||||
} from '@/utils/platform';
|
||||
import {
|
||||
userApprove,
|
||||
userReject,
|
||||
rIdWin,
|
||||
rIdData,
|
||||
} from '@/extension/userRequest'
|
||||
import {
|
||||
signMsg,
|
||||
getBalance,
|
||||
getBlockNumber,
|
||||
estimateGas,
|
||||
sendTransaction,
|
||||
getGasPrice,
|
||||
getBlockByNumber,
|
||||
evmCall,
|
||||
getTxByHash,
|
||||
getTxReceipt,
|
||||
signTypedData,
|
||||
getCode,
|
||||
getTxCount,
|
||||
getSelectedAddress
|
||||
} from '@/utils/wallet'
|
||||
import type { RequestArguments } from '@/extension/types'
|
||||
import { rpcError } from '@/extension/rpcConstants'
|
||||
import { updatePrices } from '@/utils/gecko'
|
||||
@ -9,23 +43,58 @@ import { mainNets, testNets } from '@/utils/networks'
|
||||
let notificationUrl: string
|
||||
|
||||
chrome.runtime.onInstalled.addListener(() => {
|
||||
console.log('Service worker installed');
|
||||
enableRightClickVote()
|
||||
console.info('Service worker installed');
|
||||
})
|
||||
|
||||
chrome.runtime.onStartup.addListener(() => {
|
||||
console.log('Service worker startup');
|
||||
console.info('Service worker startup');
|
||||
enableRightClickVote();
|
||||
if(chrome.runtime.lastError) {
|
||||
console.warn("Whoops.. " + chrome.runtime.lastError.message);
|
||||
}
|
||||
})
|
||||
|
||||
chrome.runtime.onSuspend.addListener(() => {
|
||||
console.log('Service worker suspend');
|
||||
console.info('Service worker suspend');
|
||||
if(chrome.runtime.lastError) {
|
||||
console.warn("Whoops.. " + chrome.runtime.lastError.message);
|
||||
}
|
||||
})
|
||||
|
||||
async function pasteAddress() {
|
||||
const currentAddress = (await (window as any).ethereum?.request({
|
||||
method: 'eth_accounts',
|
||||
params: []
|
||||
}))
|
||||
if(currentAddress.length > 0) {
|
||||
document.execCommand("insertText", false, currentAddress[0]);
|
||||
}
|
||||
}
|
||||
|
||||
chrome.contextMenus.onClicked.addListener(async (info, tab) => {
|
||||
const extensionId = chrome.runtime.id
|
||||
const isOwnExtension = info?.pageUrl?.startsWith(`chrome-extension://${extensionId}`)
|
||||
|
||||
if (info.menuItemId === CLW_CONTEXT_MENU_ID && tab?.id && !isOwnExtension) {
|
||||
try {
|
||||
await chrome.scripting.executeScript({
|
||||
target: { tabId: tab.id },
|
||||
world: 'MAIN',
|
||||
func: pasteAddress
|
||||
});
|
||||
} catch {
|
||||
// igonre
|
||||
}
|
||||
} else if(isOwnExtension) {
|
||||
chrome.runtime.sendMessage({ method: 'paste', type: 'CLWALLET_PAGE_MSG' }, (r) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.warn("LOC3: Error sending message:", chrome.runtime.lastError);
|
||||
}
|
||||
return r
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
chrome.alarms.create('updatePrices', {
|
||||
periodInMinutes: 1
|
||||
@ -34,7 +103,9 @@ chrome.alarms.create('updatePrices', {
|
||||
chrome.alarms.onAlarm.addListener((alarm) => {
|
||||
if(alarm.name === 'updatePrices') {
|
||||
updatePrices().then(() => {
|
||||
console.log('Prices updated')
|
||||
console.info('Prices updated')
|
||||
}).catch((err) => {
|
||||
console.warn('Prices update failed', err)
|
||||
})
|
||||
}
|
||||
getSettings().then((settings) => {
|
||||
@ -77,9 +148,15 @@ if (!chrome.notifications.onButtonClicked.hasListener(viewTxListner)){
|
||||
}
|
||||
|
||||
const mainListner = (message: RequestArguments, sender:any, sendResponse: (a: any) => any) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.info("Error receiving message:", chrome.runtime.lastError);
|
||||
}
|
||||
if(message?.type !== "CLWALLET_CONTENT_MSG") {
|
||||
return true
|
||||
}
|
||||
|
||||
console.info('main listener', message);
|
||||
|
||||
(async () => {
|
||||
if (!(message?.method)) {
|
||||
sendResponse({
|
||||
@ -154,7 +231,7 @@ const mainListner = (message: RequestArguments, sender:any, sendResponse: (a: an
|
||||
}
|
||||
case 'eth_gasPrice': {
|
||||
try {
|
||||
sendResponse(strToHex(String(await getGasPrice() ?? 0)))
|
||||
sendResponse(numToHexStr(BigInt(Math.trunc(await getGasPrice() * 1e9))))
|
||||
} catch {
|
||||
sendResponse({
|
||||
error: true,
|
||||
@ -166,7 +243,9 @@ const mainListner = (message: RequestArguments, sender:any, sendResponse: (a: an
|
||||
}
|
||||
case 'eth_getBalance': {
|
||||
try {
|
||||
sendResponse(await getBalance())
|
||||
const balance = await getBalance()
|
||||
const balanceHex = numToHexStr(balance ?? 0n)
|
||||
sendResponse(balanceHex)
|
||||
} catch {
|
||||
sendResponse({
|
||||
error: true,
|
||||
@ -217,7 +296,7 @@ const mainListner = (message: RequestArguments, sender:any, sendResponse: (a: an
|
||||
data: params?.data ?? '',
|
||||
value: params?.value ?? '0x0'
|
||||
})
|
||||
const gasHex = strToHex(String(gas ?? 0))
|
||||
const gasHex = numToHexStr(gas ?? 0n)
|
||||
sendResponse(gasHex)
|
||||
} catch(err) {
|
||||
if(String(err).includes('UNPREDICTABLE_GAS_LIMIT')) {
|
||||
@ -244,10 +323,7 @@ const mainListner = (message: RequestArguments, sender:any, sendResponse: (a: an
|
||||
case 'eth_requestAccounts':
|
||||
case 'eth_accounts': {
|
||||
try {
|
||||
// give only the selected address for better privacy
|
||||
const account = await getSelectedAccount()
|
||||
const address = account?.address ? [account?.address] : []
|
||||
sendResponse(address)
|
||||
sendResponse(await getSelectedAddress())
|
||||
} catch {
|
||||
sendResponse({
|
||||
error: true,
|
||||
@ -303,13 +379,6 @@ const mainListner = (message: RequestArguments, sender:any, sendResponse: (a: an
|
||||
}
|
||||
params.from = account.address
|
||||
const serializeParams = strToHex(JSON.stringify(params)) ?? ''
|
||||
const pEstimateGas = estimateGas({
|
||||
to: params?.to ?? '',
|
||||
from: params?.from ?? '',
|
||||
data: params?.data ?? '',
|
||||
value: params?.value ?? '0x0'
|
||||
})
|
||||
const pGasPrice = getGasPrice()
|
||||
let gWin: any
|
||||
await new Promise((resolve, reject) => {
|
||||
chrome.windows.create({
|
||||
@ -327,7 +396,9 @@ const mainListner = (message: RequestArguments, sender:any, sendResponse: (a: an
|
||||
|
||||
})
|
||||
try {
|
||||
const tx = await sendTransaction({...params, ...(rIdData?.[String(gWin?.id ?? 0)] ?? {}) }, pEstimateGas, pGasPrice )
|
||||
// console.log('waiting for user to approve or reject')
|
||||
// console.log(rIdData?.[String(gWin?.id ?? 0)])
|
||||
const tx = await sendTransaction({...params, ...(rIdData?.[String(gWin?.id ?? 0)] ?? {}) } )
|
||||
sendResponse(tx.hash)
|
||||
const buttons = {} as any
|
||||
const network = await getSelectedNetwork()
|
||||
@ -452,7 +523,7 @@ const mainListner = (message: RequestArguments, sender:any, sendResponse: (a: an
|
||||
clearPk()
|
||||
}
|
||||
} catch (e) {
|
||||
// console.error(e)
|
||||
// console.info(e)
|
||||
sendResponse({
|
||||
error: true,
|
||||
code: rpcError.USER_REJECTED,
|
||||
@ -570,7 +641,7 @@ const mainListner = (message: RequestArguments, sender:any, sendResponse: (a: an
|
||||
})
|
||||
sendResponse(null)
|
||||
} catch (err) {
|
||||
console.log('err')
|
||||
console.error('err')
|
||||
sendResponse({
|
||||
error: true,
|
||||
code: rpcError.USER_REJECTED,
|
||||
@ -612,7 +683,8 @@ const mainListner = (message: RequestArguments, sender:any, sendResponse: (a: an
|
||||
}
|
||||
case 'wallet_send_data': {
|
||||
if(String(sender.tab?.windowId) in rIdData){
|
||||
rIdData[String(sender?.tab?.windowId ?? '')] = (message as any)?.data ?? {}
|
||||
const intData = rIdData[String(sender?.tab?.windowId ?? '')] ?? {}
|
||||
rIdData[String(sender?.tab?.windowId ?? '')] = {...intData, ...(message?.data ?? {})}
|
||||
sendResponse(true)
|
||||
}
|
||||
break
|
||||
|
@ -8,9 +8,12 @@ export interface Network {
|
||||
explorer?: string
|
||||
}
|
||||
|
||||
export interface Account {
|
||||
export interface Contact {
|
||||
name: string
|
||||
address: string
|
||||
}
|
||||
|
||||
export interface Account extends Contact {
|
||||
pk: string
|
||||
encPk: string
|
||||
}
|
||||
@ -65,3 +68,15 @@ export interface HistoryItem {
|
||||
webiste?: string
|
||||
txHash: string
|
||||
}
|
||||
|
||||
export interface ContractAction {
|
||||
name: string
|
||||
contract: string
|
||||
abi: string
|
||||
functionName: string
|
||||
params: any[]
|
||||
}
|
||||
|
||||
export interface ContractActions {
|
||||
[key: string] : ContractAction
|
||||
}
|
||||
|
@ -4,12 +4,20 @@ export const rIdWin = {} as Record<string, string | undefined>
|
||||
export const rIdData = {} as Record<string, any | undefined>
|
||||
|
||||
export const approve = (rId: string) => {
|
||||
chrome.runtime.sendMessage({ method: 'wallet_approve', resId: rId, type: 'CLWALLET_CONTENT_MSG' })
|
||||
chrome.runtime.sendMessage({ method: 'wallet_approve', resId: rId, type: 'CLWALLET_CONTENT_MSG' }, (r) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.warn("LOC4: Error sending message:", chrome.runtime.lastError);
|
||||
}
|
||||
return r
|
||||
})
|
||||
}
|
||||
|
||||
export const walletSendData = (rId: string, data: any) => {
|
||||
return new Promise((resolve) => {
|
||||
chrome.runtime.sendMessage({ method: 'wallet_send_data', resId: rId, data, type: 'CLWALLET_CONTENT_MSG' }, (r) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.warn("LOC5: Error sending message:", chrome.runtime.lastError);
|
||||
}
|
||||
resolve(r)
|
||||
})
|
||||
})
|
||||
@ -18,6 +26,25 @@ export const walletSendData = (rId: string, data: any) => {
|
||||
export const walletGetData = (rId: string) => {
|
||||
return new Promise((resolve) => {
|
||||
chrome.runtime.sendMessage({ method: 'wallet_get_data', resId: rId, type: 'CLWALLET_CONTENT_MSG' }, (r) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.warn("LOC6: Error sending message:", chrome.runtime.lastError);
|
||||
}
|
||||
resolve(r)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const walletPromptSendTx = (tx: any) => {
|
||||
const rId = [...`${Math.random().toString(16) + Date.now().toString(16)}`].slice(2).join('')
|
||||
return new Promise((resolve) => {
|
||||
chrome.runtime.sendMessage({ method: 'eth_sendTransaction', resId: rId,
|
||||
params: [
|
||||
tx
|
||||
]
|
||||
, type: 'CLWALLET_CONTENT_MSG' }, (r) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.warn("LOC7: Error sending message:", chrome.runtime.lastError);
|
||||
}
|
||||
resolve(r)
|
||||
})
|
||||
})
|
||||
@ -26,6 +53,9 @@ export const walletGetData = (rId: string) => {
|
||||
export const walletPing = () => {
|
||||
return new Promise((resolve) => {
|
||||
chrome.runtime.sendMessage({ method: 'wallet_ping', type: 'CLWALLET_CONTENT_MSG' }, (r) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.warn("LOC8: Error sending message:", chrome.runtime.lastError);
|
||||
}
|
||||
resolve(r)
|
||||
})
|
||||
})
|
||||
|
@ -79,6 +79,19 @@ const routes: Array<RouteRecordRaw> = [
|
||||
path: 'add-network/edit/:chainId',
|
||||
component: () => import('@/views/AddNetwork.vue'),
|
||||
},
|
||||
|
||||
{
|
||||
path: 'send-token',
|
||||
component: () => import('@/views/SendToken.vue'),
|
||||
},
|
||||
{
|
||||
path: 'read-contract',
|
||||
component: () => import('@/views/ReadContract.vue'),
|
||||
},
|
||||
{
|
||||
path: 'write-contract',
|
||||
component: () => import('@/views/WriteContract.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
@ -22,7 +22,7 @@ export const mainNets: {[key: number]: Network} = {
|
||||
},
|
||||
100: {
|
||||
name: 'Gnosis',
|
||||
rpc: 'https://rpc.gnosischain.com/',
|
||||
rpc: 'https://rpc.gnosischain.com',
|
||||
chainId: 100,
|
||||
explorer: 'https://gnosisscan.io',
|
||||
icon:'xdai.webp',
|
||||
@ -56,6 +56,15 @@ export const mainNets: {[key: number]: Network} = {
|
||||
symbol: 'ETH',
|
||||
priceId: 'ethereum'
|
||||
},
|
||||
8453: {
|
||||
name: 'Base Mainnet',
|
||||
rpc: 'https://base.publicnode.com',
|
||||
chainId: 8453,
|
||||
explorer: 'https://basescan.org',
|
||||
icon: 'base.webp',
|
||||
symbol: 'ETH',
|
||||
priceId: 'ethereum'
|
||||
}
|
||||
}
|
||||
|
||||
export const testNets = {
|
||||
@ -77,7 +86,7 @@ export const testNets = {
|
||||
name: 'TESTNET Polygon',
|
||||
rpc: 'https://rpc.ankr.com/polygon_mumbai',
|
||||
chainId: 80001,
|
||||
explorer: 'https://mumbai.polygonscan.com/',
|
||||
explorer: 'https://mumbai.polygonscan.com',
|
||||
icon:'polygon.webp'
|
||||
},
|
||||
100100: {
|
||||
@ -91,21 +100,21 @@ export const testNets = {
|
||||
name: 'TESTNET Optimism Goreli',
|
||||
rpc: 'https://goerli.optimism.io/',
|
||||
chainId: 420,
|
||||
explorer: 'https://goerli.etherscan.io/',
|
||||
explorer: 'https://goerli.etherscan.io',
|
||||
icon: 'optimism.webp'
|
||||
},
|
||||
97: {
|
||||
name: 'TESTNET BSC',
|
||||
rpc: 'https://bsctestapi.terminet.io/rpc',
|
||||
chainId: 97,
|
||||
explorer: 'https://testnet.bscscan.com/',
|
||||
explorer: 'https://testnet.bscscan.com',
|
||||
icon: 'binance.webp'
|
||||
},
|
||||
421613: {
|
||||
name: 'TESTNET Arbitrum One',
|
||||
rpc: 'https://goerli-rollup.arbitrum.io/rpc/',
|
||||
chainId: 421613,
|
||||
explorer: 'https://testnet.arbiscan.io/',
|
||||
explorer: 'https://testnet.arbiscan.io',
|
||||
icon: 'arbitrum.webp'
|
||||
},
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { Network, Account, Prices, Settings, Networks, HistoryItem } from '@/extension/types'
|
||||
import type { Network, Account, Prices, Settings, Networks, HistoryItem, ContractActions, ContractAction, Contact } from '@/extension/types'
|
||||
import type { Ref } from 'vue'
|
||||
|
||||
const defaultSettings = {
|
||||
@ -11,6 +11,12 @@ const defaultSettings = {
|
||||
lastLock: Date.now()
|
||||
}
|
||||
|
||||
const defaultAbis = {} as {
|
||||
[key: string]: string
|
||||
}
|
||||
|
||||
export const CLW_CONTEXT_MENU_ID = 'clw-paste-address'
|
||||
|
||||
export const storageSave = async (key: string, value: any): Promise<void> =>{
|
||||
await chrome.storage.local.set({ [key]: value })
|
||||
}
|
||||
@ -48,11 +54,23 @@ export const saveSelectedNetwork = async (selectedNetwork: Network ): Promise<v
|
||||
}
|
||||
|
||||
|
||||
export const getContacts = async (): Promise<Contact[]> => {
|
||||
return (await storageGet('contacts')).contacts ?? [] as Contact[]
|
||||
}
|
||||
|
||||
export const saveContact = async (contact: Contact): Promise<void> => {
|
||||
const savedContacts = await getContacts()
|
||||
await storageSave('contacts', [contact, ...savedContacts])
|
||||
}
|
||||
|
||||
export const replaceContacts = async (contacts: Contact[]): Promise<void> => {
|
||||
await storageSave('contacts', contacts)
|
||||
}
|
||||
|
||||
export const getAccounts = async (): Promise<Account[]> => {
|
||||
return (await storageGet('accounts')).accounts ?? [] as Account[]
|
||||
}
|
||||
|
||||
|
||||
export const saveAccount = async (account: Account): Promise<void> => {
|
||||
const savedAccounts = await getAccounts()
|
||||
await storageSave('accounts', [account, ...savedAccounts])
|
||||
@ -62,6 +80,7 @@ export const replaceAccounts = async (accounts: Account[]): Promise<void> => {
|
||||
await storageSave('accounts', accounts)
|
||||
}
|
||||
|
||||
|
||||
export const getSelectedAccount = async (): Promise<Account> => {
|
||||
return (await storageGet('selectedAccount'))?.selectedAccount ?? null as unknown as Account
|
||||
}
|
||||
@ -106,6 +125,80 @@ export const setSettings = async (settings: Settings): Promise<void> => {
|
||||
await storageSave('settings', settings )
|
||||
}
|
||||
|
||||
export const getAllAbis = async (): Promise<{ [key: string]: string }> => {
|
||||
return ((await storageGet('abis'))?.abis) ?? defaultAbis
|
||||
}
|
||||
|
||||
export const getAbis = async (name: string): Promise<string> => {
|
||||
return (await getAllAbis())?.[name] ?? ''
|
||||
}
|
||||
|
||||
export const setAbi = async ({
|
||||
name ,
|
||||
content
|
||||
}: {
|
||||
name: string
|
||||
content: string
|
||||
}): Promise<void> => {
|
||||
const abis = await getAllAbis() || defaultAbis
|
||||
await storageSave('abis', { ...abis, [name]: content })
|
||||
}
|
||||
|
||||
export const setAbis = async (abis: { [key: string]: string }): Promise<void> => {
|
||||
await storageSave('abis', abis)
|
||||
}
|
||||
|
||||
export const removeAllAbis = async (): Promise<void> => {
|
||||
await storageSave('abis', defaultAbis)
|
||||
}
|
||||
|
||||
|
||||
export const readCAGetAll = async (): Promise<ContractActions> => {
|
||||
return ((await storageGet('read-actions'))?.['read-actions'] ?? {}) as ContractActions
|
||||
}
|
||||
|
||||
export const readCAGet = async (action: string): Promise<ContractAction | undefined> => {
|
||||
return ((await readCAGetAll())?.[action]) as ContractAction
|
||||
}
|
||||
|
||||
export const readCASet = async (action: ContractAction): Promise<void> => {
|
||||
const actions = await readCAGetAll()
|
||||
await storageSave('read-actions', { ...actions, [action.name]: action })
|
||||
}
|
||||
|
||||
export const readCARemove = async (action: string): Promise<void> => {
|
||||
const actions = await readCAGetAll()
|
||||
delete actions[action]
|
||||
await storageSave('read-actions', actions)
|
||||
}
|
||||
|
||||
export const readCAWipe = async (): Promise<void> => {
|
||||
await storageSave('read-actions', {})
|
||||
}
|
||||
|
||||
export const writeCAGetAll = async (): Promise<ContractActions> => {
|
||||
return ((await storageGet('write-actions'))?.['write-actions'] ?? {}) as ContractActions
|
||||
}
|
||||
|
||||
export const writeCAGet = async (action: string): Promise<ContractAction | undefined> => {
|
||||
return ((await writeCAGetAll())?.[action]) as ContractAction
|
||||
}
|
||||
|
||||
export const writeCASet = async (action: ContractAction): Promise<void> => {
|
||||
const actions = await writeCAGetAll()
|
||||
await storageSave('write-actions', { ...actions, [action.name]: action })
|
||||
}
|
||||
|
||||
export const writeCARemove = async (action: string): Promise<void> => {
|
||||
const actions = await writeCAGetAll()
|
||||
delete actions[action]
|
||||
await storageSave('write-actions', actions)
|
||||
}
|
||||
|
||||
export const writeCAWipe = async (): Promise<void> => {
|
||||
await storageSave('write-actions', {})
|
||||
}
|
||||
|
||||
export const blockLockout = async (): Promise<Settings> => {
|
||||
const settings = await getSettings()
|
||||
settings.lockOutBlocked = true
|
||||
@ -128,15 +221,6 @@ export const setBalanceCache = async (balance: string): Promise<void> => {
|
||||
await storageSave('balance', balance )
|
||||
}
|
||||
|
||||
export const getRandomPk = () => {
|
||||
const array = new Uint32Array(10);
|
||||
crypto.getRandomValues(array)
|
||||
return array.reduce(
|
||||
(pv, cv) => `${pv}${cv.toString(16)}`,
|
||||
'0x'
|
||||
).substring(0, 66)
|
||||
}
|
||||
|
||||
export const smallRandomString = (size = 7) => {
|
||||
if(size <= 7) {
|
||||
return (Math.random() + 1).toString(36).substring(0,7);
|
||||
@ -178,7 +262,7 @@ export const hexTostr = (hexStr: string) =>
|
||||
|
||||
export const strToHex = (str: string) => `0x${str.split('').map( s => s.charCodeAt(0).toString(16)).join('')}`
|
||||
|
||||
export const numToHexStr = (num: number) => `0x${num.toString(16)}`
|
||||
export const numToHexStr = (num: number | bigint) => `0x${num.toString(16)}`
|
||||
|
||||
export const copyAddress = async (address: string, toastRef: Ref<boolean>) => {
|
||||
await navigator.clipboard.writeText(address)
|
||||
@ -195,6 +279,27 @@ export const paste = (id: string) => {
|
||||
}
|
||||
}
|
||||
|
||||
export const enableRightClickVote = async () => {
|
||||
try {
|
||||
await chrome.contextMenus.removeAll();
|
||||
await chrome.contextMenus.create({
|
||||
id: CLW_CONTEXT_MENU_ID,
|
||||
title: "Paste Current Address",
|
||||
contexts: ["editable"],
|
||||
});
|
||||
} catch (error) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
export const pasteToFocused = () => {
|
||||
const el = document.activeElement as HTMLInputElement
|
||||
if(el){
|
||||
el?.focus();
|
||||
(document as any)?.execCommand('paste')
|
||||
}
|
||||
}
|
||||
|
||||
export const openTab = (url: string) => {
|
||||
chrome.tabs.create({
|
||||
url
|
||||
|
@ -1,7 +1,5 @@
|
||||
import { getSelectedAccount, getSelectedNetwork } from '@/utils/platform';
|
||||
import { ethers } from "ethers"
|
||||
import { strToHex } from '@/utils/platform';
|
||||
|
||||
import { ethers} from "ethers"
|
||||
|
||||
export const signMsg = async (msg: string) => {
|
||||
const account = await getSelectedAccount()
|
||||
@ -35,8 +33,8 @@ export const getGasPrice = async () => {
|
||||
const network = await getSelectedNetwork()
|
||||
const provider = new ethers.JsonRpcProvider(network.rpc)
|
||||
const feed = await provider.getFeeData()
|
||||
const gasPrice = feed.gasPrice ?? feed.maxFeePerGas
|
||||
return gasPrice
|
||||
const gasPrice = feed.maxFeePerGas ?? feed.gasPrice ?? 0n
|
||||
return Number(gasPrice) / 1e9
|
||||
}
|
||||
|
||||
export const getBlockNumber = async () => {
|
||||
@ -98,35 +96,35 @@ export const getTxCount = async (addr: string, block: null | string = null) => {
|
||||
}
|
||||
}
|
||||
|
||||
export const sendTransaction = async ({ data= '', gas='0x0', to='', from='', value='0x0', gasPrice='0x0'}:
|
||||
{to: string, from: string, data: string, value: string, gas: string, gasPrice: string},
|
||||
gasEstimate: Promise<bigint> | null = null, pGasPrice : Promise<bigint | null> | null) => {
|
||||
export const getRandomPk = () => {
|
||||
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'}:
|
||||
{to: string, from: string, data: string, value: string, gas: string, gasPrice: string}) => {
|
||||
const account = await getSelectedAccount()
|
||||
const network = await getSelectedNetwork()
|
||||
const wallet = new ethers.Wallet(account.pk, new ethers.JsonRpcProvider(network.rpc))
|
||||
if(gas === '0x0') {
|
||||
if(!gasEstimate){
|
||||
throw new Error('No gas estimate available')
|
||||
}else {
|
||||
gas = (await gasEstimate).toString()
|
||||
}
|
||||
}
|
||||
const gasPriceInt = BigInt(gasPrice)
|
||||
const gasInt = BigInt(gas)
|
||||
|
||||
if(gasPrice === '0x0') {
|
||||
if(!pGasPrice){
|
||||
throw new Error('No gas estimate available')
|
||||
}else {
|
||||
gasPrice = (await pGasPrice ?? 0).toString()
|
||||
}
|
||||
}
|
||||
|
||||
console.log('gasPrice', gasPrice)
|
||||
console.log('gas', gas)
|
||||
|
||||
if(gas === '0x0' || gasPrice === '0x0' || 1 === 1) {
|
||||
if(gas === '0x0' || gasPrice === '0x0') {
|
||||
throw new Error('No gas estimate available')
|
||||
}
|
||||
return await wallet.sendTransaction({to, from, data, value, gasLimit: gas, gasPrice})
|
||||
return await wallet.sendTransaction({
|
||||
to,
|
||||
from,
|
||||
data: data ? data : null,
|
||||
value: value ? value : null,
|
||||
gasLimit: gasInt,
|
||||
gasPrice: null,
|
||||
maxFeePerGas: gasPriceInt,
|
||||
})
|
||||
}
|
||||
|
||||
export const formatBalance = (balance: string) => {
|
||||
@ -135,3 +133,10 @@ export const formatBalance = (balance: string) => {
|
||||
maximumFractionDigits: 6
|
||||
}).format(Number(ethers.parseEther(balance)))
|
||||
}
|
||||
|
||||
export const getSelectedAddress = async () => {
|
||||
// give only the selected address for better privacy
|
||||
const account = await getSelectedAccount()
|
||||
const address = account?.address ? [account?.address] : []
|
||||
return address
|
||||
}
|
212
src/views/AbiAdd.vue
Normal file
212
src/views/AbiAdd.vue
Normal file
@ -0,0 +1,212 @@
|
||||
<template>
|
||||
<ion-page>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-button @click="onCancel">Close</ion-button>
|
||||
</ion-buttons>
|
||||
<ion-title v-if="!isEdit">Add Abi</ion-title>
|
||||
<ion-title v-else>Edit Abi</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding">
|
||||
<ion-item>
|
||||
<ion-input
|
||||