mirror of
https://github.com/andrei0x309/clear-wallet.git
synced 2024-11-18 23:41:10 +00:00
dev: 1.0.4
This commit is contained in:
parent
6c18b2841d
commit
b376839770
4
.gitignore
vendored
4
.gitignore
vendored
@ -30,4 +30,6 @@ npm-debug.log*
|
|||||||
/plugins
|
/plugins
|
||||||
/www
|
/www
|
||||||
/src/extension/inject.js
|
/src/extension/inject.js
|
||||||
readme.md
|
README.md
|
||||||
|
PRIVACY_POLICY.md
|
||||||
|
LICENSE
|
10
public/_locale/en/messages.json
Normal file
10
public/_locale/en/messages.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"appName": {
|
||||||
|
"message": "Clear EVM Wallet (CLW)",
|
||||||
|
"description": "This is an open-source EVM wallet based on ethers, ionic, vue, that implements the metamask API."
|
||||||
|
},
|
||||||
|
"appDesc": {
|
||||||
|
"message": "Clear EVM Wallet (CLW)",
|
||||||
|
"description": "This is an open-source EVM wallet based on ethers, ionic, vue, that implements the metamask API."
|
||||||
|
}
|
||||||
|
}
|
6
public/assets/randomGrad.svg
Normal file
6
public/assets/randomGrad.svg
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.dev/svgjs" viewBox="0 0 700 700" width="700" height="700" opacity="0.91"><defs><linearGradient gradientTransform="rotate(201, 0.5, 0.5)" x1="50%" y1="0%" x2="50%" y2="100%" id="ffflux-gradient"><stop stop-color="hsl(272, 100%, 27%)" stop-opacity="1" offset="0%"></stop><stop stop-color="hsl(296, 66%, 61%)" stop-opacity="1" offset="100%"></stop></linearGradient><filter id="ffflux-filter" x="-20%" y="-20%" width="140%" height="140%" filterUnits="objectBoundingBox" primitiveUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feTurbulence type="fractalNoise" baseFrequency="0.006 0.004" numOctaves="2" seed="83" stitchTiles="stitch" x="0%" y="0%" width="100%" height="100%" result="turbulence"></feTurbulence>
|
||||||
|
<feGaussianBlur stdDeviation="24 37" x="0%" y="0%" width="100%" height="100%" in="turbulence" edgeMode="duplicate" result="blur"></feGaussianBlur>
|
||||||
|
<feBlend mode="screen" x="0%" y="0%" width="100%" height="100%" in="SourceGraphic" in2="blur" result="blend"></feBlend>
|
||||||
|
|
||||||
|
</filter></defs><rect width="700" height="700" fill="url(#ffflux-gradient)" filter="url(#ffflux-filter)"></rect></svg>
|
After Width: | Height: | Size: 1.2 KiB |
15
src/App.vue
15
src/App.vue
@ -6,8 +6,9 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { IonApp, IonRouterOutlet } from "@ionic/vue";
|
import { IonApp, IonRouterOutlet } from "@ionic/vue";
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent, onBeforeMount } from "vue";
|
||||||
import { useRoute, useRouter} from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
import { getSettings } from '@/utils/platform'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "App",
|
name: "App",
|
||||||
@ -21,6 +22,14 @@ const router = useRouter()
|
|||||||
const { param, rid } = route.query;
|
const { param, rid } = route.query;
|
||||||
console.log(route?.query,'zzzzzzzzzzzzzzz')
|
console.log(route?.query,'zzzzzzzzzzzzzzz')
|
||||||
|
|
||||||
|
onBeforeMount( () => {
|
||||||
|
getSettings().then((settings) => {
|
||||||
|
if(settings.theme !== 'system') {
|
||||||
|
document.body.classList.remove(settings.theme === 'dark' ? 'light': 'dark')
|
||||||
|
document.body.classList.add(settings.theme)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
switch (route?.query?.route ?? "") {
|
switch (route?.query?.route ?? "") {
|
||||||
case "sign-msg": {
|
case "sign-msg": {
|
||||||
@ -43,7 +52,7 @@ switch (route?.query?.route ?? "") {
|
|||||||
}
|
}
|
||||||
case "wallet-error": {
|
case "wallet-error": {
|
||||||
router.push({
|
router.push({
|
||||||
path: `/wallet-error"/${rid}/${param}`
|
path: `/wallet-error/${rid}/${param}`
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { getSelectedNetwork, numToHexStr } from "@/utils/platform";
|
import { getSelectedNetwork, numToHexStr } from "@/utils/platform";
|
||||||
|
import type { RequestArguments } from '@/extension/types'
|
||||||
|
|
||||||
const allowedMethods = {
|
const allowedMethods = {
|
||||||
'eth_accounts': true,
|
'eth_accounts': true,
|
||||||
@ -22,10 +23,11 @@ window.addEventListener("message", (event) => {
|
|||||||
|
|
||||||
if (event.data.type && (event.data.type === "CLWALLET_CONTENT")) {
|
if (event.data.type && (event.data.type === "CLWALLET_CONTENT")) {
|
||||||
event.data.data.resId = event.data.resId
|
event.data.data.resId = event.data.resId
|
||||||
|
event.data.data.type = "CLWALLET_CONTENT_MSG"
|
||||||
if((event?.data?.data?.method ?? 'x') in allowedMethods) {
|
if((event?.data?.data?.method ?? 'x') in allowedMethods) {
|
||||||
chrome.runtime.sendMessage(event.data.data, (res) => {
|
chrome.runtime.sendMessage(event.data.data, (res) => {
|
||||||
const data = { type: "CLWALLET_PAGE", data: res, resId: event.data.resId, website: window?.location?.href ?? '' };
|
const data = { type: "CLWALLET_PAGE", data: res, resId: event.data.resId, website: window?.location?.href ?? '' };
|
||||||
console.log('data back', data)
|
// console.log('data back', data)
|
||||||
window.postMessage(data, "*");
|
window.postMessage(data, "*");
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -36,18 +38,24 @@ window.addEventListener("message", (event) => {
|
|||||||
} else if (event.data.type && (event.data.type === "CLWALLET_PING")) {
|
} else if (event.data.type && (event.data.type === "CLWALLET_PING")) {
|
||||||
getSelectedNetwork().then(network => {
|
getSelectedNetwork().then(network => {
|
||||||
const data = { type: "CLWALLET_PAGE_LISTENER", data: {
|
const data = { type: "CLWALLET_PAGE_LISTENER", data: {
|
||||||
listener: 'connected',
|
listner: 'connect',
|
||||||
data: {
|
data: {
|
||||||
chainId: numToHexStr(network.chainId ?? 0)
|
chainId: numToHexStr(network.chainId ?? 0)
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
window.postMessage(data, "*");
|
window.postMessage(data, "*");
|
||||||
})
|
})
|
||||||
} else if (event.data.type && (event.data.type === "CLWALLET_EXT_LISTNER")) {
|
}
|
||||||
const data = { type: "CLWALLET_PAGE_LISTENER", data: event.data.data, };
|
});
|
||||||
console.log('data listner', data)
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
chrome.runtime.onMessage.addListener((message: RequestArguments , sender, sendResponse) => {
|
||||||
|
if(message.type === "CLWALLET_EXT_LISTNER") {
|
||||||
|
const data = { type: "CLWALLET_PAGE_LISTENER", data: message.data };
|
||||||
|
// console.log('data listner', data)
|
||||||
window.postMessage(data, "*");
|
window.postMessage(data, "*");
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
});
|
});
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
@ -18,7 +18,7 @@ const listner = function(event: any) {
|
|||||||
if (event.data.type && (event.data.type === "CLWALLET_PAGE")) {
|
if (event.data.type && (event.data.type === "CLWALLET_PAGE")) {
|
||||||
if(event?.data?.data?.error){
|
if(event?.data?.data?.error){
|
||||||
promResolvers[event.data.resId].reject(event.data.data);
|
promResolvers[event.data.resId].reject(event.data.data);
|
||||||
console.log('rejected')
|
// console.log('rejected')
|
||||||
}else {
|
}else {
|
||||||
promResolvers[event.data.resId].resolve(event.data.data);
|
promResolvers[event.data.resId].resolve(event.data.data);
|
||||||
}
|
}
|
||||||
@ -45,7 +45,7 @@ return new Promise((resolve, reject) => {
|
|||||||
if (ping) {
|
if (ping) {
|
||||||
data.type = 'CLWALLET_PING'
|
data.type = 'CLWALLET_PING'
|
||||||
}
|
}
|
||||||
console.log('data in', data)
|
// console.log('data in', data)
|
||||||
window.postMessage(data, "*");
|
window.postMessage(data, "*");
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -149,6 +149,9 @@ const eth = new Proxy({
|
|||||||
break
|
break
|
||||||
case 'connect':
|
case 'connect':
|
||||||
listners.connect.add(callback)
|
listners.connect.add(callback)
|
||||||
|
sendMessage({
|
||||||
|
method: 'wallet_ready'
|
||||||
|
}, true)
|
||||||
break;
|
break;
|
||||||
case 'disconnect':
|
case 'disconnect':
|
||||||
listners.disconnect.add(callback)
|
listners.disconnect.add(callback)
|
||||||
@ -161,6 +164,24 @@ const eth = new Proxy({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
removeListener: (eventName: string, callback: () => void) => {
|
||||||
|
switch (eventName) {
|
||||||
|
case 'accountsChanged':
|
||||||
|
listners.accountsChanged.delete(callback)
|
||||||
|
break
|
||||||
|
case 'connect':
|
||||||
|
listners.connect.delete(callback)
|
||||||
|
break;
|
||||||
|
case 'disconnect':
|
||||||
|
listners.disconnect.delete(callback)
|
||||||
|
break;
|
||||||
|
case 'chainChanged':
|
||||||
|
listners.chainChanged.delete(callback)
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
},
|
||||||
// Simulate Metamask
|
// Simulate Metamask
|
||||||
_warnOfDeprecation: () => null,
|
_warnOfDeprecation: () => null,
|
||||||
_state: {},
|
_state: {},
|
||||||
@ -200,25 +221,21 @@ const injectWallet = (win: any) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
console.log('Clear wallet injected', (window as any).ethereum, win)
|
// console.log('Clear wallet injected', (window as any).ethereum, win)
|
||||||
}
|
}
|
||||||
injectWallet(this)
|
injectWallet(this)
|
||||||
sendMessage({
|
|
||||||
method: 'wallet_ready'
|
|
||||||
}, true)
|
|
||||||
|
|
||||||
|
// setTimeout(() => {
|
||||||
setTimeout(() => {
|
// 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, '111111111')});
|
||||||
// (<any>window).ethereum.request({method: 'eth_requestAccounts', params: Array(0)}).then((res: any) => { console.log(res, '111111111')});
|
// // (<any>window).ethereum.request({method: 'eth_accounts', params: Array(0)}).then((res: any) => { console.log(res, '111111111')});
|
||||||
// (<any>window).ethereum.request({method: 'eth_accounts', params: Array(0)}).then((res: any) => { console.log(res, '111111111')});
|
// // (<any>window).ethereum.request({method: 'eth_chainId', params: Array(0)}).then((res: any) => { console.log(res, '111111111')});
|
||||||
// (<any>window).ethereum.request({method: 'eth_chainId', params: Array(0)}).then((res: any) => { console.log(res, '111111111')});
|
// // (<any>window).ethereum.request({method: 'wallet_requestPermissions', params: [{eth_accounts: {}}]}).then((res: any) => { console.log(res, '111111111')});
|
||||||
// (<any>window).ethereum.request({method: 'wallet_requestPermissions', params: [{eth_accounts: {}}]}).then((res: any) => { console.log(res, '111111111')});
|
// // (<any>window).ethereum.request({method: 'net_version', params: []}).then((res: any) => { console.log(res, '111111111')});
|
||||||
// (<any>window).ethereum.request({method: 'net_version', params: []}).then((res: any) => { console.log(res, '111111111')});
|
// // (<any>window).ethereum.request({method: 'wallet_switchEthereumChain', params: [{chainId: "0x99"}]}).then((res: any) => { console.log(res, '111111111')});
|
||||||
// (<any>window).ethereum.request({method: 'wallet_switchEthereumChain', params: [{chainId: "0x99"}]}).then((res: any) => { console.log(res, '111111111')});
|
// (<any>window).ethereum.on('connect', ((a: any, b: any) => console.log('connect', a, b)));
|
||||||
(<any>window).ethereum.on('connect', ((a: any, b: any) => console.log('connect', a, b)));
|
// (<any>window).ethereum.on('accountsChanged', ((a: any, b: any) => console.log('accountsChanged', a, b)));
|
||||||
(<any>window).ethereum.on('accountsChanged', ((a: any, b: any) => console.log('accountsChanged', a, b)));
|
// (<any>window).ethereum.on('chainChanged', ((a: any) => console.log('chainChanged', a, typeof a)));
|
||||||
(<any>window).ethereum.on('chainChanged', ((a: any, b: any) => console.log('chainChanged', a, typeof a)));
|
// }, 3500)
|
||||||
}, 3500)
|
|
||||||
|
|
||||||
// console.log( (window as any).ethereum.request({method: 'eth_chainId'}))
|
// console.log( (window as any).ethereum.request({method: 'eth_chainId'}))
|
@ -2,6 +2,11 @@ import type { listnerType } from '@/extension/types'
|
|||||||
|
|
||||||
export const triggerListner = ( type: listnerType, listnerData: any ) => {
|
export const triggerListner = ( type: listnerType, listnerData: any ) => {
|
||||||
const data = { type: "CLWALLET_EXT_LISTNER", data: { listner: type, data: listnerData } }
|
const data = { type: "CLWALLET_EXT_LISTNER", data: { listner: type, data: listnerData } }
|
||||||
window.postMessage(data, "*")
|
chrome.tabs.query({}, (tabs) => tabs.forEach( tab =>
|
||||||
console.log('trigger', data)
|
{
|
||||||
|
if (tab?.id) {
|
||||||
|
chrome.tabs.sendMessage(tab.id, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,9 @@ if (!chrome.notifications.onButtonClicked.hasListener(viewTxListner)){
|
|||||||
}
|
}
|
||||||
|
|
||||||
chrome.runtime.onMessage.addListener((message: RequestArguments, sender, sendResponse) => {
|
chrome.runtime.onMessage.addListener((message: RequestArguments, sender, sendResponse) => {
|
||||||
console.log(message);
|
if(message?.type !== "CLWALLET_CONTENT_MSG") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
(async () => {
|
(async () => {
|
||||||
if (!('method' in message)) {
|
if (!('method' in message)) {
|
||||||
sendResponse({
|
sendResponse({
|
||||||
@ -147,7 +149,6 @@ chrome.runtime.onMessage.addListener((message: RequestArguments, sender, sendRes
|
|||||||
}
|
}
|
||||||
case 'eth_chainId': {
|
case 'eth_chainId': {
|
||||||
const network = await getSelectedNetwork()
|
const network = await getSelectedNetwork()
|
||||||
console.log(network, 'network')
|
|
||||||
const chainId = network?.chainId ?? 0
|
const chainId = network?.chainId ?? 0
|
||||||
sendResponse(`0x${chainId.toString(16)}`)
|
sendResponse(`0x${chainId.toString(16)}`)
|
||||||
break
|
break
|
||||||
@ -168,7 +169,7 @@ chrome.runtime.onMessage.addListener((message: RequestArguments, sender, sendRes
|
|||||||
await chrome.windows.create({
|
await chrome.windows.create({
|
||||||
height: 450,
|
height: 450,
|
||||||
width: 400,
|
width: 400,
|
||||||
url: chrome.runtime.getURL(`index.html?route=sign-tx¶m=${encodeURIComponent('No account is selected you need to have an account selected before trying to make a transaction')}&rid=${String(message?.resId ?? '')}`),
|
url: chrome.runtime.getURL(`index.html?route=wallet-error¶m=${encodeURIComponent('No account is selected you need to have an account selected before trying to make a transaction')}&rid=${String(message?.resId ?? '')}`),
|
||||||
type: 'popup'
|
type: 'popup'
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@ -177,7 +178,7 @@ chrome.runtime.onMessage.addListener((message: RequestArguments, sender, sendRes
|
|||||||
await chrome.windows.create({
|
await chrome.windows.create({
|
||||||
height: 450,
|
height: 450,
|
||||||
width: 400,
|
width: 400,
|
||||||
url: chrome.runtime.getURL(`index.html?route=sign-tx¶m=${encodeURIComponent('No network is selected you need to have a network selected before trying to make a transaction')}&rid=${String(message?.resId ?? '')}`),
|
url: chrome.runtime.getURL(`index.html?route=wallet-error¶m=${encodeURIComponent('No network is selected you need to have a network selected before trying to make a transaction')}&rid=${String(message?.resId ?? '')}`),
|
||||||
type: 'popup'
|
type: 'popup'
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@ -242,12 +243,17 @@ chrome.runtime.onMessage.addListener((message: RequestArguments, sender, sendRes
|
|||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
|
||||||
sendResponse({
|
sendResponse({
|
||||||
error: true,
|
error: true,
|
||||||
code: rpcError.USER_REJECTED,
|
code: rpcError.USER_REJECTED,
|
||||||
message: 'TX Failed'
|
message: 'TX Failed'
|
||||||
})
|
})
|
||||||
|
chrome.windows.create({
|
||||||
|
height: 450,
|
||||||
|
width: 400,
|
||||||
|
url: chrome.runtime.getURL(`index.html?route=wallet-error¶m=${encodeURIComponent(String(err))}&rid=${String(message?.resId ?? '')}`),
|
||||||
|
type: 'popup'
|
||||||
|
})
|
||||||
chrome.notifications.create({
|
chrome.notifications.create({
|
||||||
message: 'Transaction Failed',
|
message: 'Transaction Failed',
|
||||||
title: 'Error',
|
title: 'Error',
|
||||||
@ -274,7 +280,7 @@ chrome.runtime.onMessage.addListener((message: RequestArguments, sender, sendRes
|
|||||||
await chrome.windows.create({
|
await chrome.windows.create({
|
||||||
height: 450,
|
height: 450,
|
||||||
width: 400,
|
width: 400,
|
||||||
url: chrome.runtime.getURL(`index.html?route=sign-tx¶m=${encodeURIComponent('No account is selected you need to have an account selected before trying sign a message')}&rid=${String(message?.resId ?? '')}`),
|
url: chrome.runtime.getURL(`index.html?route=wallet-error¶m=${encodeURIComponent('No account is selected you need to have an account selected before trying sign a message')}&rid=${String(message?.resId ?? '')}`),
|
||||||
type: 'popup'
|
type: 'popup'
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@ -360,7 +366,8 @@ chrome.runtime.onMessage.addListener((message: RequestArguments, sender, sendRes
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
chrome.windows.remove(sender.tab?.windowId ?? 0)
|
chrome.windows.remove(sender.tab?.windowId ?? 0)
|
||||||
}catch{
|
}catch (e) {
|
||||||
|
console.log(e)
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
@ -24,16 +24,18 @@ export interface Networks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface RequestArguments {
|
export interface RequestArguments {
|
||||||
method: string;
|
method: string
|
||||||
params?: any[];
|
type: string
|
||||||
|
params?: any[]
|
||||||
resId?: string
|
resId?: string
|
||||||
website?: string
|
website?: string
|
||||||
|
data?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProviderRpcError extends Error {
|
export interface ProviderRpcError extends Error {
|
||||||
message: string;
|
message: string
|
||||||
code: number;
|
code: number
|
||||||
data?: unknown;
|
data?: unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Price {
|
export interface Price {
|
||||||
|
@ -1,32 +1,32 @@
|
|||||||
export const userReject = {} as Record<string, (() => any) | undefined>
|
export const userReject = {} as Record<string, (() => any) | undefined>
|
||||||
export const userApprove = {} as Record<string, ((a: unknown) => any) | undefined>
|
export const userApprove = {} as Record<string, ((a: unknown) => any) | undefined>
|
||||||
export const rIdWin = {} as Record<string, string | undefined>
|
export const rIdWin = {} as Record<string, string | undefined>
|
||||||
export const rIdData = {} as Record<string, any | undefined>
|
export const rIdData = {} as Record<string, any | undefined>
|
||||||
|
|
||||||
export const approve = (rId: string) => {
|
export const approve = (rId: string) => {
|
||||||
chrome.runtime.sendMessage({ method: 'wallet_approve', resId: rId })
|
chrome.runtime.sendMessage({ method: 'wallet_approve', resId: rId, type: 'CLWALLET_CONTENT_MSG' })
|
||||||
}
|
}
|
||||||
|
|
||||||
export const walletSendData = (rId: string, data: any) => {
|
export const walletSendData = (rId: string, data: any) => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
chrome.runtime.sendMessage({ method: 'wallet_send_data', resId: rId, data}, (r) => {
|
chrome.runtime.sendMessage({ method: 'wallet_send_data', resId: rId, data, type: 'CLWALLET_CONTENT_MSG' }, (r) => {
|
||||||
resolve(r)
|
resolve(r)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const walletGetData = (rId: string) => {
|
export const walletGetData = (rId: string) => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
chrome.runtime.sendMessage({ method: 'wallet_get_data', resId: rId }, (r) => {
|
chrome.runtime.sendMessage({ method: 'wallet_get_data', resId: rId, type: 'CLWALLET_CONTENT_MSG' }, (r) => {
|
||||||
resolve(r)
|
resolve(r)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const walletPing = () => {
|
export const walletPing = () => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
chrome.runtime.sendMessage({ method: 'wallet_ping' }, (r) => {
|
chrome.runtime.sendMessage({ method: 'wallet_ping', type: 'CLWALLET_CONTENT_MSG' }, (r) => {
|
||||||
resolve(r)
|
resolve(r)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
component: () => import('@/views/ContractError.vue'),
|
component: () => import('@/views/ContractError.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/wallet-error/:rid/:error',
|
path: '/wallet-error/:rid/:param',
|
||||||
component: () => import('@/views/WalletError.vue'),
|
component: () => import('@/views/WalletError.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2,7 +2,167 @@
|
|||||||
http://ionicframework.com/docs/theming/ */
|
http://ionicframework.com/docs/theming/ */
|
||||||
|
|
||||||
/** Ionic CSS Variables **/
|
/** Ionic CSS Variables **/
|
||||||
:root {
|
|
||||||
|
@media (prefers-color-scheme: dark){
|
||||||
|
/*
|
||||||
|
* Dark Colors
|
||||||
|
* -------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
body:not(.light) {
|
||||||
|
--ion-color-primary: #6a64ff;
|
||||||
|
--ion-color-primary-rgb: 106, 100, 255;
|
||||||
|
--ion-color-primary-contrast: #ffffff;
|
||||||
|
--ion-color-primary-contrast-rgb: 255, 255, 255;
|
||||||
|
--ion-color-primary-shade: #5d58e0;
|
||||||
|
--ion-color-primary-tint: #7974ff;
|
||||||
|
|
||||||
|
--ion-color-secondary: #50c8ff;
|
||||||
|
--ion-color-secondary-rgb: 80,200,255;
|
||||||
|
--ion-color-secondary-contrast: #ffffff;
|
||||||
|
--ion-color-secondary-contrast-rgb: 255,255,255;
|
||||||
|
--ion-color-secondary-shade: #46b0e0;
|
||||||
|
--ion-color-secondary-tint: #62ceff;
|
||||||
|
|
||||||
|
--ion-color-tertiary: #6a64ff;
|
||||||
|
--ion-color-tertiary-rgb: 106,100,255;
|
||||||
|
--ion-color-tertiary-contrast: #ffffff;
|
||||||
|
--ion-color-tertiary-contrast-rgb: 255,255,255;
|
||||||
|
--ion-color-tertiary-shade: #5d58e0;
|
||||||
|
--ion-color-tertiary-tint: #7974ff;
|
||||||
|
|
||||||
|
--ion-color-success: #2fdf75;
|
||||||
|
--ion-color-success-rgb: 47,223,117;
|
||||||
|
--ion-color-success-contrast: #000000;
|
||||||
|
--ion-color-success-contrast-rgb: 0,0,0;
|
||||||
|
--ion-color-success-shade: #29c467;
|
||||||
|
--ion-color-success-tint: #44e283;
|
||||||
|
|
||||||
|
--ion-color-warning: #ffd534;
|
||||||
|
--ion-color-warning-rgb: 255,213,52;
|
||||||
|
--ion-color-warning-contrast: #000000;
|
||||||
|
--ion-color-warning-contrast-rgb: 0,0,0;
|
||||||
|
--ion-color-warning-shade: #e0bb2e;
|
||||||
|
--ion-color-warning-tint: #ffd948;
|
||||||
|
|
||||||
|
--ion-color-danger: #ff4961;
|
||||||
|
--ion-color-danger-rgb: 255,73,97;
|
||||||
|
--ion-color-danger-contrast: #ffffff;
|
||||||
|
--ion-color-danger-contrast-rgb: 255,255,255;
|
||||||
|
--ion-color-danger-shade: #e04055;
|
||||||
|
--ion-color-danger-tint: #ff5b71;
|
||||||
|
|
||||||
|
--ion-color-dark: #f4f5f8;
|
||||||
|
--ion-color-dark-rgb: 244,245,248;
|
||||||
|
--ion-color-dark-contrast: #000000;
|
||||||
|
--ion-color-dark-contrast-rgb: 0,0,0;
|
||||||
|
--ion-color-dark-shade: #d7d8da;
|
||||||
|
--ion-color-dark-tint: #f5f6f9;
|
||||||
|
|
||||||
|
--ion-color-medium: #989aa2;
|
||||||
|
--ion-color-medium-rgb: 152,154,162;
|
||||||
|
--ion-color-medium-contrast: #000000;
|
||||||
|
--ion-color-medium-contrast-rgb: 0,0,0;
|
||||||
|
--ion-color-medium-shade: #86888f;
|
||||||
|
--ion-color-medium-tint: #a2a4ab;
|
||||||
|
|
||||||
|
--ion-color-light: #222428;
|
||||||
|
--ion-color-light-rgb: 34,36,40;
|
||||||
|
--ion-color-light-contrast: #ffffff;
|
||||||
|
--ion-color-light-contrast-rgb: 255,255,255;
|
||||||
|
--ion-color-light-shade: #1e2023;
|
||||||
|
--ion-color-light-tint: #383a3e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* iOS Dark Theme
|
||||||
|
* -------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
.ios body:not(.light) {
|
||||||
|
--ion-background-color: #000000;
|
||||||
|
--ion-background-color-rgb: 0,0,0;
|
||||||
|
|
||||||
|
--ion-text-color: #ffffff;
|
||||||
|
--ion-text-color-rgb: 255,255,255;
|
||||||
|
|
||||||
|
--ion-color-step-50: #0d0d0d;
|
||||||
|
--ion-color-step-100: #1a1a1a;
|
||||||
|
--ion-color-step-150: #262626;
|
||||||
|
--ion-color-step-200: #333333;
|
||||||
|
--ion-color-step-250: #404040;
|
||||||
|
--ion-color-step-300: #4d4d4d;
|
||||||
|
--ion-color-step-350: #595959;
|
||||||
|
--ion-color-step-400: #666666;
|
||||||
|
--ion-color-step-450: #737373;
|
||||||
|
--ion-color-step-500: #808080;
|
||||||
|
--ion-color-step-550: #8c8c8c;
|
||||||
|
--ion-color-step-600: #999999;
|
||||||
|
--ion-color-step-650: #a6a6a6;
|
||||||
|
--ion-color-step-700: #b3b3b3;
|
||||||
|
--ion-color-step-750: #bfbfbf;
|
||||||
|
--ion-color-step-800: #cccccc;
|
||||||
|
--ion-color-step-850: #d9d9d9;
|
||||||
|
--ion-color-step-900: #e6e6e6;
|
||||||
|
--ion-color-step-950: #f2f2f2;
|
||||||
|
|
||||||
|
--ion-item-background: #000000;
|
||||||
|
|
||||||
|
--ion-card-background: #1c1c1d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ios ion-modal {
|
||||||
|
--ion-background-color: var(--ion-color-step-100);
|
||||||
|
--ion-toolbar-background: var(--ion-color-step-150);
|
||||||
|
--ion-toolbar-border-color: var(--ion-color-step-250);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Material Design Dark Theme
|
||||||
|
* -------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
.md body:not(.light) {
|
||||||
|
--ion-background-color: #121212;
|
||||||
|
--ion-background-color-rgb: 18,18,18;
|
||||||
|
|
||||||
|
--ion-text-color: #ffffff;
|
||||||
|
--ion-text-color-rgb: 255,255,255;
|
||||||
|
|
||||||
|
--ion-border-color: #222222;
|
||||||
|
|
||||||
|
--ion-color-step-50: #1e1e1e;
|
||||||
|
--ion-color-step-100: #2a2a2a;
|
||||||
|
--ion-color-step-150: #363636;
|
||||||
|
--ion-color-step-200: #414141;
|
||||||
|
--ion-color-step-250: #4d4d4d;
|
||||||
|
--ion-color-step-300: #595959;
|
||||||
|
--ion-color-step-350: #656565;
|
||||||
|
--ion-color-step-400: #717171;
|
||||||
|
--ion-color-step-450: #7d7d7d;
|
||||||
|
--ion-color-step-500: #898989;
|
||||||
|
--ion-color-step-550: #949494;
|
||||||
|
--ion-color-step-600: #a0a0a0;
|
||||||
|
--ion-color-step-650: #acacac;
|
||||||
|
--ion-color-step-700: #b8b8b8;
|
||||||
|
--ion-color-step-750: #c4c4c4;
|
||||||
|
--ion-color-step-800: #d0d0d0;
|
||||||
|
--ion-color-step-850: #dbdbdb;
|
||||||
|
--ion-color-step-900: #e7e7e7;
|
||||||
|
--ion-color-step-950: #f3f3f3;
|
||||||
|
|
||||||
|
--ion-item-background: #1e1e1e;
|
||||||
|
|
||||||
|
--ion-toolbar-background: #1f1f1f;
|
||||||
|
|
||||||
|
--ion-tab-bar-background: #1f1f1f;
|
||||||
|
|
||||||
|
--ion-card-background: #1e1e1e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:root, body.light {
|
||||||
/** primary **/
|
/** primary **/
|
||||||
--ion-color-primary: #5260ff;
|
--ion-color-primary: #5260ff;
|
||||||
--ion-color-primary-rgb: 82, 96, 255;
|
--ion-color-primary-rgb: 82, 96, 255;
|
||||||
@ -76,161 +236,155 @@ http://ionicframework.com/docs/theming/ */
|
|||||||
--ion-color-light-tint: #f5f6f9;
|
--ion-color-light-tint: #f5f6f9;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
/*
|
|
||||||
* Dark Colors
|
|
||||||
* -------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
body {
|
body.dark {
|
||||||
--ion-color-primary: #6a64ff;
|
--ion-color-primary: #6a64ff;
|
||||||
--ion-color-primary-rgb: 106, 100, 255;
|
--ion-color-primary-rgb: 106, 100, 255;
|
||||||
--ion-color-primary-contrast: #ffffff;
|
--ion-color-primary-contrast: #ffffff;
|
||||||
--ion-color-primary-contrast-rgb: 255, 255, 255;
|
--ion-color-primary-contrast-rgb: 255, 255, 255;
|
||||||
--ion-color-primary-shade: #5d58e0;
|
--ion-color-primary-shade: #5d58e0;
|
||||||
--ion-color-primary-tint: #7974ff;
|
--ion-color-primary-tint: #7974ff;
|
||||||
|
|
||||||
--ion-color-secondary: #50c8ff;
|
--ion-color-secondary: #50c8ff;
|
||||||
--ion-color-secondary-rgb: 80,200,255;
|
--ion-color-secondary-rgb: 80,200,255;
|
||||||
--ion-color-secondary-contrast: #ffffff;
|
--ion-color-secondary-contrast: #ffffff;
|
||||||
--ion-color-secondary-contrast-rgb: 255,255,255;
|
--ion-color-secondary-contrast-rgb: 255,255,255;
|
||||||
--ion-color-secondary-shade: #46b0e0;
|
--ion-color-secondary-shade: #46b0e0;
|
||||||
--ion-color-secondary-tint: #62ceff;
|
--ion-color-secondary-tint: #62ceff;
|
||||||
|
|
||||||
--ion-color-tertiary: #6a64ff;
|
--ion-color-tertiary: #6a64ff;
|
||||||
--ion-color-tertiary-rgb: 106,100,255;
|
--ion-color-tertiary-rgb: 106,100,255;
|
||||||
--ion-color-tertiary-contrast: #ffffff;
|
--ion-color-tertiary-contrast: #ffffff;
|
||||||
--ion-color-tertiary-contrast-rgb: 255,255,255;
|
--ion-color-tertiary-contrast-rgb: 255,255,255;
|
||||||
--ion-color-tertiary-shade: #5d58e0;
|
--ion-color-tertiary-shade: #5d58e0;
|
||||||
--ion-color-tertiary-tint: #7974ff;
|
--ion-color-tertiary-tint: #7974ff;
|
||||||
|
|
||||||
--ion-color-success: #2fdf75;
|
--ion-color-success: #2fdf75;
|
||||||
--ion-color-success-rgb: 47,223,117;
|
--ion-color-success-rgb: 47,223,117;
|
||||||
--ion-color-success-contrast: #000000;
|
--ion-color-success-contrast: #000000;
|
||||||
--ion-color-success-contrast-rgb: 0,0,0;
|
--ion-color-success-contrast-rgb: 0,0,0;
|
||||||
--ion-color-success-shade: #29c467;
|
--ion-color-success-shade: #29c467;
|
||||||
--ion-color-success-tint: #44e283;
|
--ion-color-success-tint: #44e283;
|
||||||
|
|
||||||
--ion-color-warning: #ffd534;
|
--ion-color-warning: #ffd534;
|
||||||
--ion-color-warning-rgb: 255,213,52;
|
--ion-color-warning-rgb: 255,213,52;
|
||||||
--ion-color-warning-contrast: #000000;
|
--ion-color-warning-contrast: #000000;
|
||||||
--ion-color-warning-contrast-rgb: 0,0,0;
|
--ion-color-warning-contrast-rgb: 0,0,0;
|
||||||
--ion-color-warning-shade: #e0bb2e;
|
--ion-color-warning-shade: #e0bb2e;
|
||||||
--ion-color-warning-tint: #ffd948;
|
--ion-color-warning-tint: #ffd948;
|
||||||
|
|
||||||
--ion-color-danger: #ff4961;
|
--ion-color-danger: #ff4961;
|
||||||
--ion-color-danger-rgb: 255,73,97;
|
--ion-color-danger-rgb: 255,73,97;
|
||||||
--ion-color-danger-contrast: #ffffff;
|
--ion-color-danger-contrast: #ffffff;
|
||||||
--ion-color-danger-contrast-rgb: 255,255,255;
|
--ion-color-danger-contrast-rgb: 255,255,255;
|
||||||
--ion-color-danger-shade: #e04055;
|
--ion-color-danger-shade: #e04055;
|
||||||
--ion-color-danger-tint: #ff5b71;
|
--ion-color-danger-tint: #ff5b71;
|
||||||
|
|
||||||
--ion-color-dark: #f4f5f8;
|
--ion-color-dark: #f4f5f8;
|
||||||
--ion-color-dark-rgb: 244,245,248;
|
--ion-color-dark-rgb: 244,245,248;
|
||||||
--ion-color-dark-contrast: #000000;
|
--ion-color-dark-contrast: #000000;
|
||||||
--ion-color-dark-contrast-rgb: 0,0,0;
|
--ion-color-dark-contrast-rgb: 0,0,0;
|
||||||
--ion-color-dark-shade: #d7d8da;
|
--ion-color-dark-shade: #d7d8da;
|
||||||
--ion-color-dark-tint: #f5f6f9;
|
--ion-color-dark-tint: #f5f6f9;
|
||||||
|
|
||||||
--ion-color-medium: #989aa2;
|
--ion-color-medium: #989aa2;
|
||||||
--ion-color-medium-rgb: 152,154,162;
|
--ion-color-medium-rgb: 152,154,162;
|
||||||
--ion-color-medium-contrast: #000000;
|
--ion-color-medium-contrast: #000000;
|
||||||
--ion-color-medium-contrast-rgb: 0,0,0;
|
--ion-color-medium-contrast-rgb: 0,0,0;
|
||||||
--ion-color-medium-shade: #86888f;
|
--ion-color-medium-shade: #86888f;
|
||||||
--ion-color-medium-tint: #a2a4ab;
|
--ion-color-medium-tint: #a2a4ab;
|
||||||
|
|
||||||
--ion-color-light: #222428;
|
--ion-color-light: #222428;
|
||||||
--ion-color-light-rgb: 34,36,40;
|
--ion-color-light-rgb: 34,36,40;
|
||||||
--ion-color-light-contrast: #ffffff;
|
--ion-color-light-contrast: #ffffff;
|
||||||
--ion-color-light-contrast-rgb: 255,255,255;
|
--ion-color-light-contrast-rgb: 255,255,255;
|
||||||
--ion-color-light-shade: #1e2023;
|
--ion-color-light-shade: #1e2023;
|
||||||
--ion-color-light-tint: #383a3e;
|
--ion-color-light-tint: #383a3e;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* iOS Dark Theme
|
* iOS Dark Theme
|
||||||
* -------------------------------------------
|
* -------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.ios body {
|
.ios body.dark {
|
||||||
--ion-background-color: #000000;
|
--ion-background-color: #000000;
|
||||||
--ion-background-color-rgb: 0,0,0;
|
--ion-background-color-rgb: 0,0,0;
|
||||||
|
|
||||||
--ion-text-color: #ffffff;
|
--ion-text-color: #ffffff;
|
||||||
--ion-text-color-rgb: 255,255,255;
|
--ion-text-color-rgb: 255,255,255;
|
||||||
|
|
||||||
--ion-color-step-50: #0d0d0d;
|
--ion-color-step-50: #0d0d0d;
|
||||||
--ion-color-step-100: #1a1a1a;
|
--ion-color-step-100: #1a1a1a;
|
||||||
--ion-color-step-150: #262626;
|
--ion-color-step-150: #262626;
|
||||||
--ion-color-step-200: #333333;
|
--ion-color-step-200: #333333;
|
||||||
--ion-color-step-250: #404040;
|
--ion-color-step-250: #404040;
|
||||||
--ion-color-step-300: #4d4d4d;
|
--ion-color-step-300: #4d4d4d;
|
||||||
--ion-color-step-350: #595959;
|
--ion-color-step-350: #595959;
|
||||||
--ion-color-step-400: #666666;
|
--ion-color-step-400: #666666;
|
||||||
--ion-color-step-450: #737373;
|
--ion-color-step-450: #737373;
|
||||||
--ion-color-step-500: #808080;
|
--ion-color-step-500: #808080;
|
||||||
--ion-color-step-550: #8c8c8c;
|
--ion-color-step-550: #8c8c8c;
|
||||||
--ion-color-step-600: #999999;
|
--ion-color-step-600: #999999;
|
||||||
--ion-color-step-650: #a6a6a6;
|
--ion-color-step-650: #a6a6a6;
|
||||||
--ion-color-step-700: #b3b3b3;
|
--ion-color-step-700: #b3b3b3;
|
||||||
--ion-color-step-750: #bfbfbf;
|
--ion-color-step-750: #bfbfbf;
|
||||||
--ion-color-step-800: #cccccc;
|
--ion-color-step-800: #cccccc;
|
||||||
--ion-color-step-850: #d9d9d9;
|
--ion-color-step-850: #d9d9d9;
|
||||||
--ion-color-step-900: #e6e6e6;
|
--ion-color-step-900: #e6e6e6;
|
||||||
--ion-color-step-950: #f2f2f2;
|
--ion-color-step-950: #f2f2f2;
|
||||||
|
|
||||||
--ion-item-background: #000000;
|
--ion-item-background: #000000;
|
||||||
|
|
||||||
--ion-card-background: #1c1c1d;
|
--ion-card-background: #1c1c1d;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ios ion-modal {
|
.ios ion-modal {
|
||||||
--ion-background-color: var(--ion-color-step-100);
|
--ion-background-color: var(--ion-color-step-100);
|
||||||
--ion-toolbar-background: var(--ion-color-step-150);
|
--ion-toolbar-background: var(--ion-color-step-150);
|
||||||
--ion-toolbar-border-color: var(--ion-color-step-250);
|
--ion-toolbar-border-color: var(--ion-color-step-250);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Material Design Dark Theme
|
* Material Design Dark Theme
|
||||||
* -------------------------------------------
|
* -------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.md body {
|
.md body.dark {
|
||||||
--ion-background-color: #121212;
|
--ion-background-color: #121212;
|
||||||
--ion-background-color-rgb: 18,18,18;
|
--ion-background-color-rgb: 18,18,18;
|
||||||
|
|
||||||
--ion-text-color: #ffffff;
|
--ion-text-color: #ffffff;
|
||||||
--ion-text-color-rgb: 255,255,255;
|
--ion-text-color-rgb: 255,255,255;
|
||||||
|
|
||||||
--ion-border-color: #222222;
|
--ion-border-color: #222222;
|
||||||
|
|
||||||
--ion-color-step-50: #1e1e1e;
|
--ion-color-step-50: #1e1e1e;
|
||||||
--ion-color-step-100: #2a2a2a;
|
--ion-color-step-100: #2a2a2a;
|
||||||
--ion-color-step-150: #363636;
|
--ion-color-step-150: #363636;
|
||||||
--ion-color-step-200: #414141;
|
--ion-color-step-200: #414141;
|
||||||
--ion-color-step-250: #4d4d4d;
|
--ion-color-step-250: #4d4d4d;
|
||||||
--ion-color-step-300: #595959;
|
--ion-color-step-300: #595959;
|
||||||
--ion-color-step-350: #656565;
|
--ion-color-step-350: #656565;
|
||||||
--ion-color-step-400: #717171;
|
--ion-color-step-400: #717171;
|
||||||
--ion-color-step-450: #7d7d7d;
|
--ion-color-step-450: #7d7d7d;
|
||||||
--ion-color-step-500: #898989;
|
--ion-color-step-500: #898989;
|
||||||
--ion-color-step-550: #949494;
|
--ion-color-step-550: #949494;
|
||||||
--ion-color-step-600: #a0a0a0;
|
--ion-color-step-600: #a0a0a0;
|
||||||
--ion-color-step-650: #acacac;
|
--ion-color-step-650: #acacac;
|
||||||
--ion-color-step-700: #b8b8b8;
|
--ion-color-step-700: #b8b8b8;
|
||||||
--ion-color-step-750: #c4c4c4;
|
--ion-color-step-750: #c4c4c4;
|
||||||
--ion-color-step-800: #d0d0d0;
|
--ion-color-step-800: #d0d0d0;
|
||||||
--ion-color-step-850: #dbdbdb;
|
--ion-color-step-850: #dbdbdb;
|
||||||
--ion-color-step-900: #e7e7e7;
|
--ion-color-step-900: #e7e7e7;
|
||||||
--ion-color-step-950: #f3f3f3;
|
--ion-color-step-950: #f3f3f3;
|
||||||
|
|
||||||
--ion-item-background: #1e1e1e;
|
--ion-item-background: #1e1e1e;
|
||||||
|
|
||||||
--ion-toolbar-background: #1f1f1f;
|
--ion-toolbar-background: #1f1f1f;
|
||||||
|
|
||||||
--ion-tab-bar-background: #1f1f1f;
|
--ion-tab-bar-background: #1f1f1f;
|
||||||
|
|
||||||
--ion-card-background: #1e1e1e;
|
--ion-card-background: #1e1e1e;
|
||||||
}
|
|
||||||
}
|
}
|
@ -94,6 +94,10 @@ export const addToHistory = async (historyItem: HistoryItem): Promise<void> => {
|
|||||||
await storageSave('history', history)
|
await storageSave('history', history)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const wipeHistory = async (): Promise<void> => {
|
||||||
|
await storageSave('history', [])
|
||||||
|
}
|
||||||
|
|
||||||
export const getSettings = async (): Promise<Settings> => {
|
export const getSettings = async (): Promise<Settings> => {
|
||||||
return (await storageGet('settings'))?.settings ?? defaultSettings as unknown as Settings
|
return (await storageGet('settings'))?.settings ?? defaultSettings as unknown as Settings
|
||||||
}
|
}
|
||||||
@ -140,6 +144,9 @@ export const smallRandomString = () => {
|
|||||||
export const clearPk = async (): Promise<void> => {
|
export const clearPk = async (): Promise<void> => {
|
||||||
let accounts = await getAccounts()
|
let accounts = await getAccounts()
|
||||||
const accProm = accounts.map(async a => {
|
const accProm = accounts.map(async a => {
|
||||||
|
if(a.encPk) {
|
||||||
|
a.pk = ''
|
||||||
|
}
|
||||||
return a
|
return a
|
||||||
})
|
})
|
||||||
accounts = await Promise.all(accProm)
|
accounts = await Promise.all(accProm)
|
||||||
|
@ -10,8 +10,8 @@ export const signMsg = async (msg: string) => {
|
|||||||
export const getBalance = async () =>{
|
export const getBalance = async () =>{
|
||||||
const account = await getSelectedAccount()
|
const account = await getSelectedAccount()
|
||||||
const network = await getSelectedNetwork()
|
const network = await getSelectedNetwork()
|
||||||
const wallet = new ethers.Wallet(account.pk, new ethers.providers.JsonRpcProvider(network.rpc))
|
const provider = new ethers.providers.JsonRpcProvider(network.rpc)
|
||||||
return await wallet.getBalance()
|
return await provider.getBalance(account.address)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getGasPrice = async () => {
|
export const getGasPrice = async () => {
|
||||||
|
@ -34,18 +34,42 @@
|
|||||||
<p style="font-size:0.7rem">{{ account.address }}</p><ion-icon :icon="copyOutline"></ion-icon>
|
<p style="font-size:0.7rem">{{ account.address }}</p><ion-icon :icon="copyOutline"></ion-icon>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<ion-chip>View Pk</ion-chip>
|
<ion-chip @click="viewPk(account.address)">View Pk</ion-chip>
|
||||||
<ion-chip @click="deleteAccount(account.address)">Delete</ion-chip>
|
<ion-chip @click="deleteAccount(account.address)">Delete</ion-chip>
|
||||||
<ion-chip @click="editAccount(account.address)">Edit Name</ion-chip>
|
<ion-chip @click="editAccount(account.address)">Edit Name</ion-chip>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</ion-list>
|
</ion-list>
|
||||||
|
|
||||||
|
|
||||||
|
<ion-modal
|
||||||
|
:is-open="pkModal"
|
||||||
|
@didDismiss="shownPk=''"
|
||||||
|
>
|
||||||
|
<ion-header>
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-buttons slot="start">
|
||||||
|
<ion-button @click="pkModal=false">Close</ion-button>
|
||||||
|
</ion-buttons>
|
||||||
|
<ion-title>View PK</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
<ion-content class="ion-padding">
|
||||||
|
<ion-item @click="copyAddress(shownPk, getToastRef())" button>
|
||||||
|
<ion-icon style="margin-right: 0.5rem;" :icon="copyOutline" />
|
||||||
|
<ion-label button>PK</ion-label>
|
||||||
|
<ion-input id="pastePk" v-model="shownPk" readonly></ion-input>
|
||||||
|
</ion-item>
|
||||||
|
</ion-content>
|
||||||
|
</ion-modal>
|
||||||
|
|
||||||
|
|
||||||
</ion-content>
|
</ion-content>
|
||||||
</ion-page>
|
</ion-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, ref, Ref } from "vue";
|
import { defineComponent, ref, Ref } from "vue";
|
||||||
import { getAccounts, copyAddress, replaceAccounts } from "@/utils/platform"
|
import { getAccounts, copyAddress, replaceAccounts, getSettings, clearPk } from "@/utils/platform"
|
||||||
import {
|
import {
|
||||||
IonContent,
|
IonContent,
|
||||||
IonHeader,
|
IonHeader,
|
||||||
@ -60,12 +84,17 @@ import {
|
|||||||
IonButtons,
|
IonButtons,
|
||||||
IonButton,
|
IonButton,
|
||||||
onIonViewWillEnter,
|
onIonViewWillEnter,
|
||||||
IonToast
|
IonToast,
|
||||||
|
modalController,
|
||||||
|
IonInput,
|
||||||
|
IonModal
|
||||||
} from "@ionic/vue";
|
} from "@ionic/vue";
|
||||||
|
|
||||||
import { addCircleOutline, copyOutline } from "ionicons/icons";
|
import { addCircleOutline, copyOutline } from "ionicons/icons";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import type { Account } from '@/extension/types'
|
import UnlockModal from '@/views/UnlockModal.vue'
|
||||||
|
|
||||||
|
import type { Account, Settings } from '@/extension/types'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
@ -81,19 +110,26 @@ export default defineComponent({
|
|||||||
IonChip,
|
IonChip,
|
||||||
IonButtons,
|
IonButtons,
|
||||||
IonButton,
|
IonButton,
|
||||||
IonToast
|
IonToast,
|
||||||
|
IonInput,
|
||||||
|
IonModal
|
||||||
},
|
},
|
||||||
setup () {
|
setup () {
|
||||||
const accounts = ref({}) as Ref<Account[]>
|
const accounts = ref([]) as Ref<Account[]>
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const toastState = ref(false)
|
const toastState = ref(false)
|
||||||
|
const shownPk = ref('')
|
||||||
|
const pkModal = ref(false)
|
||||||
|
const settings = ref({}) as Ref<Settings>
|
||||||
|
|
||||||
const getToastRef = () => toastState
|
const getToastRef = () => toastState
|
||||||
|
|
||||||
const loadData = () => {
|
const loadData = () => {
|
||||||
const pAccounts = getAccounts()
|
const pAccounts = getAccounts()
|
||||||
Promise.all([pAccounts]).then(( res ) => {
|
const pGetSettings = getSettings()
|
||||||
|
Promise.all([pAccounts, pGetSettings]).then(( res ) => {
|
||||||
accounts.value = res[0]
|
accounts.value = res[0]
|
||||||
|
settings.value = res[1]
|
||||||
loading.value = false
|
loading.value = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -120,6 +156,45 @@ export default defineComponent({
|
|||||||
loadData()
|
loadData()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const openModal = async () => {
|
||||||
|
const modal = await modalController.create({
|
||||||
|
component: UnlockModal,
|
||||||
|
componentProps: {
|
||||||
|
unlockType: 'viewPk'
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
modal.present();
|
||||||
|
const { role } = await modal.onWillDismiss();
|
||||||
|
if(role === 'confirm') return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const viewPk = async (addr: string) => {
|
||||||
|
let pk = ''
|
||||||
|
const account = accounts.value.find(a => a.address === addr)
|
||||||
|
if(settings.value.enableStorageEnctyption) {
|
||||||
|
if(account?.encPk) {
|
||||||
|
const modalR = await openModal()
|
||||||
|
if(modalR){
|
||||||
|
const account = (await getAccounts()).find(a => a.address === addr)
|
||||||
|
pk = account?.pk ?? ''
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
pk = account?.pk ?? ''
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
pk = account?.pk ?? ''
|
||||||
|
}
|
||||||
|
if(pk) {
|
||||||
|
shownPk.value = pk
|
||||||
|
if(settings.value.encryptAfterEveryTx) {
|
||||||
|
clearPk()
|
||||||
|
}
|
||||||
|
pkModal.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
accounts,
|
accounts,
|
||||||
addCircleOutline,
|
addCircleOutline,
|
||||||
@ -130,7 +205,10 @@ export default defineComponent({
|
|||||||
deleteAccount,
|
deleteAccount,
|
||||||
editAccount,
|
editAccount,
|
||||||
loading,
|
loading,
|
||||||
goToAddAccount
|
goToAddAccount,
|
||||||
|
viewPk,
|
||||||
|
pkModal,
|
||||||
|
shownPk
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<ion-button @click="onCancel">Cancel</ion-button>
|
<ion-button @click="onCancel">Cancel</ion-button>
|
||||||
<ion-button @click="onAddAccount">Add Account</ion-button>
|
<ion-button @click="onAddAccount">{{ isEdit ? 'Edit Account' : 'Add Account' }}</ion-button>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-alert
|
<ion-alert
|
||||||
:is-open="alertOpen"
|
:is-open="alertOpen"
|
||||||
@ -42,12 +42,14 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, ref } from "vue";
|
import { defineComponent, ref } from "vue";
|
||||||
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonItem, IonLabel, IonInput, IonButton, IonAlert, IonIcon, onIonViewWillEnter } from "@ionic/vue";
|
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonItem, IonLabel, IonInput, IonButton, IonAlert, IonIcon, onIonViewWillEnter, modalController } from "@ionic/vue";
|
||||||
import { ethers } from "ethers"
|
import { ethers } from "ethers"
|
||||||
import { saveSelectedAccount, getAccounts, saveAccount, getRandomPk, smallRandomString, paste } from "@/utils/platform";
|
import { saveSelectedAccount, getAccounts, saveAccount, getRandomPk, smallRandomString, paste, getSettings } from "@/utils/platform";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import type { Account } from '@/extension/types'
|
import type { Account, Settings } from '@/extension/types'
|
||||||
|
import UnlockModal from '@/views/UnlockModal.vue'
|
||||||
|
import { encrypt, getCryptoParams } from '@/utils/webCrypto'
|
||||||
|
|
||||||
import { clipboardOutline } from "ionicons/icons";
|
import { clipboardOutline } from "ionicons/icons";
|
||||||
|
|
||||||
@ -62,15 +64,31 @@ export default defineComponent({
|
|||||||
const isEdit = route.path.includes('/edit')
|
const isEdit = route.path.includes('/edit')
|
||||||
const paramAddress = route.params.address ?? ""
|
const paramAddress = route.params.address ?? ""
|
||||||
let accountsProm: Promise<Account[] | undefined>
|
let accountsProm: Promise<Account[] | undefined>
|
||||||
|
let settingsProm: Promise<Settings | undefined>
|
||||||
|
|
||||||
const resetFields = () => {
|
const resetFields = () => {
|
||||||
name.value = ''
|
name.value = ''
|
||||||
pk.value = ''
|
pk.value = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const openModal = async () => {
|
||||||
|
const modal = await modalController.create({
|
||||||
|
component: UnlockModal,
|
||||||
|
componentProps: {
|
||||||
|
unlockType: 'addAccount'
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
modal.present();
|
||||||
|
const { role, data } = await modal.onWillDismiss();
|
||||||
|
if(role === 'confirm') return data
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
onIonViewWillEnter(async () => {
|
onIonViewWillEnter(async () => {
|
||||||
if(isEdit && paramAddress) {
|
if(isEdit && paramAddress) {
|
||||||
accountsProm = getAccounts()
|
accountsProm = getAccounts()
|
||||||
|
settingsProm = getSettings()
|
||||||
const accounts = await accountsProm as Account[]
|
const accounts = await accountsProm as Account[]
|
||||||
const acc = accounts.find(account => account.address === paramAddress)
|
const acc = accounts.find(account => account.address === paramAddress)
|
||||||
if(acc) {
|
if(acc) {
|
||||||
@ -95,7 +113,40 @@ export default defineComponent({
|
|||||||
if(!accountsProm) {
|
if(!accountsProm) {
|
||||||
accountsProm = getAccounts()
|
accountsProm = getAccounts()
|
||||||
}
|
}
|
||||||
|
if(!settingsProm) {
|
||||||
|
settingsProm = getSettings()
|
||||||
|
}
|
||||||
const accounts = await accountsProm as Account[]
|
const accounts = await accountsProm as Account[]
|
||||||
|
const settings = await settingsProm as Settings
|
||||||
|
if( settings.enableStorageEnctyption) {
|
||||||
|
const pass = await openModal()
|
||||||
|
if(!pass){
|
||||||
|
alertMsg.value = "Cannot add account with encryption password."
|
||||||
|
alertOpen.value = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const cryptoParams = await getCryptoParams(pass)
|
||||||
|
if((accounts.length ?? 0) < 1 ){
|
||||||
|
p1 = saveSelectedAccount({
|
||||||
|
address: wallet.address,
|
||||||
|
name: name.value,
|
||||||
|
pk: pk.value,
|
||||||
|
encPk: await encrypt(pk.value, cryptoParams)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if(accounts.find(account => account.address === wallet.address)){
|
||||||
|
alertMsg.value = "Account already exists."
|
||||||
|
return alertOpen.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const p2 = saveAccount({
|
||||||
|
address: wallet.address,
|
||||||
|
name: name.value,
|
||||||
|
pk: pk.value,
|
||||||
|
encPk: await encrypt(pk.value, cryptoParams)
|
||||||
|
})
|
||||||
|
await Promise.all([p1, p2])
|
||||||
|
}else {
|
||||||
if((accounts.length ?? 0) < 1 ){
|
if((accounts.length ?? 0) < 1 ){
|
||||||
p1 = saveSelectedAccount({
|
p1 = saveSelectedAccount({
|
||||||
address: wallet.address,
|
address: wallet.address,
|
||||||
@ -116,10 +167,11 @@ export default defineComponent({
|
|||||||
encPk: ''
|
encPk: ''
|
||||||
})
|
})
|
||||||
await Promise.all([p1, p2])
|
await Promise.all([p1, p2])
|
||||||
|
}
|
||||||
if(isEdit) {
|
if(isEdit) {
|
||||||
router.push('accounts')
|
router.push('/tabs/accounts')
|
||||||
}else {
|
}else {
|
||||||
router.push('/')
|
router.push('/tabs/home')
|
||||||
}
|
}
|
||||||
resetFields()
|
resetFields()
|
||||||
}
|
}
|
||||||
@ -134,9 +186,9 @@ export default defineComponent({
|
|||||||
|
|
||||||
const onCancel = () => {
|
const onCancel = () => {
|
||||||
if(isEdit) {
|
if(isEdit) {
|
||||||
router.push('accounts')
|
router.push('/tabs/accounts')
|
||||||
}else {
|
}else {
|
||||||
router.push('/')
|
router.push('/tabs/home')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content class="ion-padding">
|
<ion-content class="ion-padding">
|
||||||
<ion-button @click="templateModal=true" expand="block">Add from popular chain list</ion-button>
|
<ion-button v-if="!isEdit" @click="templateModal=true" expand="block">Add from popular chain list</ion-button>
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<ion-label>Name(*)</ion-label>
|
<ion-label>Name(*)</ion-label>
|
||||||
<ion-input v-model="name" placeholder="ex: Polygon"></ion-input>
|
<ion-input v-model="name" placeholder="ex: Polygon"></ion-input>
|
||||||
@ -190,9 +190,9 @@ export default defineComponent({
|
|||||||
const p2 = replaceNetworks(networks)
|
const p2 = replaceNetworks(networks)
|
||||||
await Promise.all([p1, p2])
|
await Promise.all([p1, p2])
|
||||||
if(isEdit) {
|
if(isEdit) {
|
||||||
router.push('networks')
|
router.push('/tabs/networks')
|
||||||
}else {
|
}else {
|
||||||
router.push('/')
|
router.push('/tabs/home')
|
||||||
}
|
}
|
||||||
resetFields()
|
resetFields()
|
||||||
}
|
}
|
||||||
@ -203,9 +203,9 @@ export default defineComponent({
|
|||||||
|
|
||||||
const onCancel = () => {
|
const onCancel = () => {
|
||||||
if(isEdit) {
|
if(isEdit) {
|
||||||
router.push('networks')
|
router.push('/tabs/networks')
|
||||||
}else {
|
}else {
|
||||||
router.push('/')
|
router.push('/tabs/home')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,33 +6,226 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content class="ion-padding">
|
<ion-content class="ion-padding">
|
||||||
1
|
|
||||||
</ion-content>
|
<ion-loading
|
||||||
<ion-content class="ion-padding">
|
:is-open="loading"
|
||||||
2
|
cssClass="my-custom-class"
|
||||||
</ion-content>
|
message="Please wait..."
|
||||||
<ion-content class="ion-padding">
|
:duration="4000"
|
||||||
3
|
@didDismiss="loading = false"
|
||||||
</ion-content>
|
>
|
||||||
</ion-page>
|
</ion-loading>
|
||||||
|
<ion-toast
|
||||||
|
:is-open="toastState"
|
||||||
|
@didDismiss="toastState = false"
|
||||||
|
message="Copied to clipboard"
|
||||||
|
:duration="1500"
|
||||||
|
></ion-toast>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>Assests for Account: {{ selectedAccount?.name }}</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item button @click="copyAddress(selectedAccount?.address, getToastRef())">
|
||||||
|
<p style="font-size: 0.7rem">{{ selectedAccount?.address }}</p>
|
||||||
|
<ion-icon style="margin-left: 0.5rem" :icon="copyOutline"></ion-icon>
|
||||||
|
</ion-item>
|
||||||
|
<template v-if="isError">
|
||||||
|
Assets info could not be retrieved because of an http error, API down or conectivity issues.
|
||||||
|
</template>
|
||||||
|
<template v-else-if="noAssets">
|
||||||
|
No assets found for this wallet address.
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<ion-item v-if="assets.yupScore">
|
||||||
|
<span style="font-size: 0.9rem">YUP Score:</span> <span style="font-size: 1.1rem; margin-left: 0.5rem">{{ assets.yupScore.toFixed(2) }}</span>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item>
|
||||||
|
<p style="font-size: 0.7rem">YUP score is a score of your wallet based on assets and transactions. </p>
|
||||||
|
</ion-item>
|
||||||
|
<template v-if="assets.tokens">
|
||||||
|
<template v-if="ethTokens.length">
|
||||||
|
<ion-item>Ethereum Tokens</ion-item>
|
||||||
|
<ion-list>
|
||||||
|
<ion-item v-for="token of ethTokens" :key="token.address">
|
||||||
|
<ion-avatar
|
||||||
|
v-if="token?.image"
|
||||||
|
style="margin-right: 1rem; width: 1.8rem; height: 1.8rem"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:alt="token?.name"
|
||||||
|
:src="token?.image"
|
||||||
|
@error="token.image = getUrl('assets/randomGrad.svg')"
|
||||||
|
/>
|
||||||
|
</ion-avatar>
|
||||||
|
<ion-label><b>{{ token?.symbol }}:</b> {{ token?.balance }}</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item v-if="hasMore.ethTokens">
|
||||||
|
<ion-button @click="loadMore('ethTokens')">Load More</ion-button>
|
||||||
|
</ion-item>
|
||||||
|
</ion-list>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-if="polyTokens.length">
|
||||||
|
<ion-item>Polygon Tokens</ion-item>
|
||||||
|
<ion-list>
|
||||||
|
<ion-item v-for="token of polyTokens" :key="token.address">
|
||||||
|
<ion-avatar
|
||||||
|
v-if="token?.image"
|
||||||
|
style="margin-right: 1rem; width: 1.8rem; height: 1.8rem"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:alt="token?.name"
|
||||||
|
:src="token?.image"
|
||||||
|
@error="token.image = getUrl('assets/randomGrad.svg')"
|
||||||
|
/>
|
||||||
|
</ion-avatar>
|
||||||
|
<ion-label><b>{{ token?.symbol }}:</b> {{ token?.balance }}</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item v-if="hasMore.polyTokens">
|
||||||
|
<ion-button @click="loadMore('polyTokens')">Load More</ion-button>
|
||||||
|
</ion-item>
|
||||||
|
</ion-list>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<template v-if="assets.nfts">
|
||||||
|
|
||||||
|
<template v-if="ethNfts.length">
|
||||||
|
<ion-item>Ethereum NFTs</ion-item>
|
||||||
|
<ion-list>
|
||||||
|
<ion-item v-for="nft of ethNfts" :key="nft.address">
|
||||||
|
<ion-avatar
|
||||||
|
v-if="nft?.imageURI"
|
||||||
|
style="margin-right: 1rem; width: 1.8rem; height: 1.8rem"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:alt="nft?.collectionName"
|
||||||
|
:src="nft?.imageURI"
|
||||||
|
@error="nft.imageURI = getUrl('assets/randomGrad.svg')"
|
||||||
|
/>
|
||||||
|
</ion-avatar>
|
||||||
|
<ion-label><b>{{ nft?.collectionName }}</b></ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item v-if="hasMore.ethNfts">
|
||||||
|
<ion-button @click="loadMore('ethNfts')">Load More</ion-button>
|
||||||
|
</ion-item>
|
||||||
|
</ion-list>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-if="polyNfts.length">
|
||||||
|
<ion-item>Polygon NFTs</ion-item>
|
||||||
|
<ion-list>
|
||||||
|
<ion-item v-for="nft of polyNfts" :key="nft.address">
|
||||||
|
<ion-avatar
|
||||||
|
v-if="nft?.imageURI"
|
||||||
|
style="margin-right: 1rem; width: 1.8rem; height: 1.8rem"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:alt="nft?.collectionName"
|
||||||
|
:src="nft?.imageURI"
|
||||||
|
@error="nft.imageURI = getUrl('assets/randomGrad.svg')"
|
||||||
|
/>
|
||||||
|
</ion-avatar>
|
||||||
|
<ion-label><b>{{ nft?.collectionName }}</b></ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item v-if="hasMore.polyNfts">
|
||||||
|
<ion-button @click="loadMore('polyNfts')">Load More</ion-button>
|
||||||
|
</ion-item>
|
||||||
|
</ion-list>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<template v-if="assets.poaps">
|
||||||
|
<template v-if="poaps.length">
|
||||||
|
<ion-item>POAPs</ion-item>
|
||||||
|
<ion-list>
|
||||||
|
<ion-item v-for="nft of poaps" :key="nft.eventId">
|
||||||
|
<ion-avatar
|
||||||
|
v-if="nft?.image"
|
||||||
|
style="margin-right: 1rem; width: 1.8rem; height: 1.8rem"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:alt="nft?.title"
|
||||||
|
:src="nft?.image"
|
||||||
|
@error="nft.image = getUrl('assets/randomGrad.svg')"
|
||||||
|
/>
|
||||||
|
</ion-avatar>
|
||||||
|
<ion-label><b>{{ nft?.title }}</b></ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item v-if="hasMore.poaps">
|
||||||
|
<ion-button @click="loadMore('poaps')">Load More</ion-button>
|
||||||
|
</ion-item>
|
||||||
|
</ion-list>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</ion-content>
|
||||||
|
</ion-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, Ref, ref } from "vue";
|
import { defineComponent, Ref, ref, reactive } from "vue";
|
||||||
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, onIonViewWillEnter } from "@ionic/vue";
|
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, onIonViewWillEnter, IonItem, IonLabel, IonAvatar, IonList, IonButton, IonToast, IonLoading, IonIcon } from "@ionic/vue";
|
||||||
import { getSelectedAccount } from "@/utils/platform"
|
import { getSelectedAccount, copyAddress, getUrl } from "@/utils/platform"
|
||||||
import type { Account } from "@/extension/types"
|
import type { Account } from "@/extension/types"
|
||||||
|
|
||||||
|
import { copyOutline } from "ionicons/icons";
|
||||||
|
|
||||||
|
|
||||||
const yupAssetsApi = 'https://api.yup.io/profile'
|
const yupAssetsApi = 'https://api.yup.io/profile'
|
||||||
|
|
||||||
|
interface IProfileToken {
|
||||||
|
address: string
|
||||||
|
balance: number
|
||||||
|
image: string
|
||||||
|
name: string
|
||||||
|
symbol: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IProfileNFT {
|
||||||
|
address: string
|
||||||
|
collectionImageURI: string
|
||||||
|
collectionName: string
|
||||||
|
imageURI: string
|
||||||
|
link: string
|
||||||
|
tokenId: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IProfilePOAP {
|
||||||
|
description: string
|
||||||
|
eventId: string
|
||||||
|
image: string
|
||||||
|
link: string
|
||||||
|
title: string
|
||||||
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { IonContent, IonHeader, IonPage, IonTitle, IonToolbar },
|
components: { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonItem, IonLabel, IonAvatar, IonList, IonButton, IonToast, IonLoading, IonIcon },
|
||||||
setup: () => {
|
setup: () => {
|
||||||
const selectedAccount = ref({}) as Ref<Account>
|
const selectedAccount = ref({}) as Ref<Account>
|
||||||
const assets = ref({})
|
const assets = ref({}) as Ref< {
|
||||||
|
yupScore?: number
|
||||||
|
tokens?: any[]
|
||||||
|
nfts?: any[]
|
||||||
|
poaps?: any[]
|
||||||
|
}>
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const isError = ref(false)
|
const isError = ref(false)
|
||||||
const noAssets = ref(false)
|
const noAssets = ref(false)
|
||||||
|
const toastState = ref(false);
|
||||||
|
const ethTokens = ref([]) as Ref< IProfileToken[]>
|
||||||
|
const polyTokens = ref([]) as Ref< IProfileToken[]>
|
||||||
|
const ethNfts = ref([]) as Ref< IProfileNFT[]>
|
||||||
|
const polyNfts = ref([]) as Ref< IProfileNFT[]>
|
||||||
|
const poaps = ref([]) as Ref< IProfilePOAP[]>
|
||||||
|
const hasMore = reactive({
|
||||||
|
poaps: true,
|
||||||
|
ethTokens: true,
|
||||||
|
polyTokens: true,
|
||||||
|
ethNfts: true,
|
||||||
|
polyNfts: true,
|
||||||
|
})
|
||||||
|
const getToastRef = () => toastState;
|
||||||
|
|
||||||
onIonViewWillEnter(async () => {
|
onIonViewWillEnter(async () => {
|
||||||
selectedAccount.value = await getSelectedAccount()
|
selectedAccount.value = await getSelectedAccount()
|
||||||
@ -42,11 +235,100 @@ export default defineComponent({
|
|||||||
if(!('poaps' in assets.value) && !('tokens' in assets.value) && !('nfts' in assets.value)) {
|
if(!('poaps' in assets.value) && !('tokens' in assets.value) && !('nfts' in assets.value)) {
|
||||||
noAssets.value = true
|
noAssets.value = true
|
||||||
}
|
}
|
||||||
|
if ('poaps' in assets.value) {
|
||||||
|
poaps.value = assets.value?.poaps?.slice(0, 10) ?? []
|
||||||
|
if(poaps.value.length >= (assets.value?.poaps?.length ?? 0)) {
|
||||||
|
hasMore.poaps = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ('nfts' in assets.value) {
|
||||||
|
ethNfts.value = assets.value?.nfts?.filter(n => n.chain === 'ethereum').slice(0, 10) ?? []
|
||||||
|
if(ethNfts.value.length >= (assets.value?.nfts?.filter(n => n.chain === 'ethereum').length ?? 0)) {
|
||||||
|
hasMore.ethNfts = false
|
||||||
|
}
|
||||||
|
polyNfts.value = assets.value?.nfts?.filter(n => n.chain === 'polygon').slice(0, 10) ?? []
|
||||||
|
if(polyNfts.value.length >= (assets.value?.nfts?.filter(n => n.chain === 'polygon').length ?? 0)) {
|
||||||
|
hasMore.polyNfts = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ('tokens' in assets.value) {
|
||||||
|
ethTokens.value = assets.value?.tokens?.filter(n => n.chain === 'ethereum').slice(0, 10) ?? []
|
||||||
|
if(ethTokens.value.length >= (assets.value?.tokens?.filter(n => n.chain === 'ethereum').length ?? 0)) {
|
||||||
|
hasMore.ethTokens = false
|
||||||
|
}
|
||||||
|
polyTokens.value = assets.value?.tokens?.filter(n => n.chain === 'polygon').slice(0, 10) ?? []
|
||||||
|
if(polyTokens.value.length >= (assets.value?.tokens?.filter(n => n.chain === 'polygon').length ?? 0)) {
|
||||||
|
hasMore.polyTokens = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}else {
|
}else {
|
||||||
isError.value = true
|
isError.value = true
|
||||||
}
|
}
|
||||||
loading .value = false
|
loading .value = false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const loadMore = (type: string) => {
|
||||||
|
switch(type) {
|
||||||
|
case 'ethTokens': {
|
||||||
|
ethTokens.value = assets.value?.tokens?.filter(n => n.chain === 'ethereum').slice(0, ethTokens.value.length + 10) ?? []
|
||||||
|
if(ethTokens.value.length >= (assets.value?.tokens?.filter(n => n.chain === 'ethereum').length ?? 0)) {
|
||||||
|
hasMore.ethTokens = false
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'polyTokens': {
|
||||||
|
polyTokens.value = assets.value?.tokens?.filter(n => n.chain === 'polygon').slice(0, polyTokens.value.length + 10) ?? []
|
||||||
|
if(polyTokens.value.length >= (assets.value?.tokens?.filter(n => n.chain === 'polygon').length ?? 0)) {
|
||||||
|
hasMore.polyTokens = false
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'ethNfts': {
|
||||||
|
ethNfts.value = assets.value?.nfts?.filter(n => n.chain === 'ethereum').slice(0, ethNfts.value.length + 10) ?? []
|
||||||
|
if(ethNfts.value.length >= (assets.value?.nfts?.filter(n => n.chain === 'ethereum').length ?? 0)) {
|
||||||
|
hasMore.ethNfts = false
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'polyNfts': {
|
||||||
|
polyNfts.value = assets.value?.nfts?.filter(n => n.chain === 'polygon').slice(0, polyNfts.value.length + 10) ?? []
|
||||||
|
if(polyNfts.value.length >= (assets.value?.nfts?.filter(n => n.chain === 'polygon').length ?? 0)) {
|
||||||
|
hasMore.polyNfts = false
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'poaps': {
|
||||||
|
poaps.value = assets.value?.poaps?.slice(0, poaps.value.length + 10) ?? []
|
||||||
|
if(poaps.value.length >= (assets.value?.poaps?.length ?? 0)) {
|
||||||
|
hasMore.poaps = false
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
selectedAccount,
|
||||||
|
loading,
|
||||||
|
isError,
|
||||||
|
noAssets,
|
||||||
|
assets,
|
||||||
|
getToastRef,
|
||||||
|
copyAddress,
|
||||||
|
copyOutline,
|
||||||
|
ethTokens,
|
||||||
|
polyTokens,
|
||||||
|
ethNfts,
|
||||||
|
poaps,
|
||||||
|
hasMore,
|
||||||
|
polyNfts,
|
||||||
|
loadMore,
|
||||||
|
toastState,
|
||||||
|
getUrl
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -5,29 +5,87 @@
|
|||||||
<ion-title>History</ion-title>
|
<ion-title>History</ion-title>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
<ion-content class="ion-padding">
|
||||||
|
<ion-item v-if="history.length === 0">
|
||||||
|
You don't have any transaction history
|
||||||
|
</ion-item>
|
||||||
|
<ion-item v-else>
|
||||||
|
<ion-list>
|
||||||
|
<ion-item style="margin-bottom: 0.3rem;margin-top: 0.3rem" v-for="item of history" :key="item.txHash">
|
||||||
|
<ion-list>
|
||||||
|
<ion-item><b style="margin-right: 0.5rem">Date:</b> {{ new Date(item.date).toDateString() }}</ion-item>
|
||||||
|
<ion-item button @click="copyAddress(item.txHash, getToastRef())">
|
||||||
|
<p style="font-size: 0.7rem"><b style="margin-right: 0.5rem"><ion-icon style="margin-right: 0.3rem; display: inline-block;" :icon="copyOutline"></ion-icon>TxHash:</b>{{ item.txHash }}</p>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item v-if="item.chainId"><b style="margin-right: 0.5rem">ChainId:</b> {{ item.chainId }}</ion-item>
|
||||||
|
<ion-item v-if="item.webiste"><b style="margin-right: 0.5rem">Website:</b> {{ item.webiste }}</ion-item>
|
||||||
|
<ion-item v-if="item.txUrl"><b style="margin-right: 0.5rem">ViewTx:</b> <a :href="item.txUrl">LINK</a></ion-item>
|
||||||
|
</ion-list>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item>
|
||||||
|
<ion-button style="margin-left: 0.5rem" color="warning" @click="onWipeHistory">WIPE HISTORY</ion-button>
|
||||||
|
</ion-item>
|
||||||
|
</ion-list>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
<ion-content class="ion-padding">Not implemented</ion-content>
|
<ion-loading
|
||||||
|
:is-open="loading"
|
||||||
|
cssClass="my-custom-class"
|
||||||
|
message="Please wait..."
|
||||||
|
:duration="4000"
|
||||||
|
@didDismiss="loading = false"
|
||||||
|
>
|
||||||
|
</ion-loading>
|
||||||
|
<ion-toast
|
||||||
|
:is-open="toastState"
|
||||||
|
@didDismiss="toastState = false"
|
||||||
|
message="Copied to clipboard"
|
||||||
|
:duration="1500"
|
||||||
|
></ion-toast>
|
||||||
|
|
||||||
|
</ion-content>
|
||||||
</ion-page>
|
</ion-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, Ref, ref } from "vue";
|
import { defineComponent, Ref, ref } from "vue";
|
||||||
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, onIonViewWillEnter } from "@ionic/vue";
|
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, onIonViewWillEnter, IonItem, IonList, IonToast, IonLoading, IonButton, IonIcon } from "@ionic/vue";
|
||||||
import { getHistory } from '@/utils/platform'
|
import { getHistory, copyAddress, wipeHistory } from '@/utils/platform'
|
||||||
import type { HistoryItem } from '@/extension/types'
|
import type { HistoryItem } from '@/extension/types'
|
||||||
|
|
||||||
|
import { copyOutline } from "ionicons/icons";
|
||||||
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { IonContent, IonHeader, IonPage, IonTitle, IonToolbar },
|
components: { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonItem, IonList, IonToast, IonLoading, IonButton, IonIcon },
|
||||||
setup: () => {
|
setup: () => {
|
||||||
const history = ref([]) as Ref<HistoryItem[]>;
|
const history = ref([]) as Ref<HistoryItem[]>;
|
||||||
const loading = ref(true)
|
const loading = ref(false)
|
||||||
onIonViewWillEnter(async () => {
|
const toastState = ref(false);
|
||||||
|
const getToastRef = () => toastState;
|
||||||
|
|
||||||
|
const loadData = async () => {
|
||||||
|
loading.value = true
|
||||||
history.value = await getHistory()
|
history.value = await getHistory()
|
||||||
loading.value = false
|
loading.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const onWipeHistory = async () => {
|
||||||
|
await wipeHistory()
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
onIonViewWillEnter(async () => {
|
||||||
|
loadData()
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
history,
|
history,
|
||||||
loading
|
loading,
|
||||||
|
copyAddress,
|
||||||
|
getToastRef,
|
||||||
|
toastState,
|
||||||
|
copyOutline,
|
||||||
|
onWipeHistory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content class="ion-padding">
|
<ion-content class="ion-padding">
|
||||||
<ion-accordion-group v-if="!loading">
|
<ion-accordion-group :value="defaultAccordionOpen" v-if="!loading">
|
||||||
<ion-accordion value="1">
|
<ion-accordion value="1">
|
||||||
<ion-item slot="header" color="light">
|
<ion-item slot="header" color="light">
|
||||||
<ion-label>Security</ion-label>
|
<ion-label>Security</ion-label>
|
||||||
@ -28,7 +28,7 @@
|
|||||||
<ion-toggle :key="updateKey" @ion-change="changeAutoLock" slot="end" :checked="settings.s.lockOutEnabled"></ion-toggle>
|
<ion-toggle :key="updateKey" @ion-change="changeAutoLock" slot="end" :checked="settings.s.lockOutEnabled"></ion-toggle>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-list>
|
<ion-list>
|
||||||
<ion-item :disabled="!settings.s.enableStorageEnctyption || !settings.s.lockOutEnabled">
|
<ion-item :disabled="!settings.s.enableStorageEnctyption || !settings.s.lockOutEnabled">
|
||||||
<ion-label>Auto-lock Period: (2-120) minutes</ion-label>
|
<ion-label>Auto-lock Period: (2-120) minutes</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item :disabled="!settings.s.enableStorageEnctyption || !settings.s.lockOutEnabled">
|
<ion-item :disabled="!settings.s.enableStorageEnctyption || !settings.s.lockOutEnabled">
|
||||||
@ -41,7 +41,7 @@
|
|||||||
<ion-list>
|
<ion-list>
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<ion-label>Permanent Lock</ion-label>
|
<ion-label>Permanent Lock</ion-label>
|
||||||
<ion-toggle :key="updateKey" slot="end" :disabled="!settings.s.enableStorageEnctyption" :checked="settings.s.encryptAfterEveryTx"></ion-toggle>
|
<ion-toggle @ion-change="changePermaLock" :key="updateKey" slot="end" :disabled="!settings.s.enableStorageEnctyption" :checked="settings.s.encryptAfterEveryTx"></ion-toggle>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item>Will require decrypt pass before any sign or transaction</ion-item>
|
<ion-item>Will require decrypt pass before any sign or transaction</ion-item>
|
||||||
</ion-list>
|
</ion-list>
|
||||||
@ -54,11 +54,12 @@
|
|||||||
</ion-item>
|
</ion-item>
|
||||||
<div class="ion-padding" slot="content">
|
<div class="ion-padding" slot="content">
|
||||||
<ion-list>
|
<ion-list>
|
||||||
<ion-radio-group :value="settings.s.theme">
|
<ion-radio-group :value="radioTheme">
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<ion-radio
|
<ion-radio
|
||||||
slot="start"
|
slot="start"
|
||||||
value="system"
|
value="system"
|
||||||
|
@click="changeTheme('system')"
|
||||||
/>
|
/>
|
||||||
<ion-label>System Default</ion-label>
|
<ion-label>System Default</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
@ -66,6 +67,7 @@
|
|||||||
<ion-radio
|
<ion-radio
|
||||||
slot="start"
|
slot="start"
|
||||||
value="dark"
|
value="dark"
|
||||||
|
@click="changeTheme('dark')"
|
||||||
/>
|
/>
|
||||||
<ion-label>Dark</ion-label>
|
<ion-label>Dark</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
@ -73,6 +75,7 @@
|
|||||||
<ion-radio
|
<ion-radio
|
||||||
slot="start"
|
slot="start"
|
||||||
value="light"
|
value="light"
|
||||||
|
@click="changeTheme('light')"
|
||||||
/>
|
/>
|
||||||
<ion-label>Light</ion-label>
|
<ion-label>Light</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
@ -85,7 +88,16 @@
|
|||||||
<ion-label>About</ion-label>
|
<ion-label>About</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<div class="ion-padding" slot="content">
|
<div class="ion-padding" slot="content">
|
||||||
About text
|
<p>Clear EVM Wallet (CLW) is a fully open-source wallet built with Vue, Ionic, and Ethers.</p>
|
||||||
|
<p>It emulates Metamask Wallet and can be used as a drop-in replacement, right now if you have both extensions, CLW will overwrite Metamask.</p>
|
||||||
|
<p>Main philosophy of the wallet is: no trackers, full control, export/import JSONs with accounts, fast generate new accounts, and wipe everything with one click.</p>
|
||||||
|
<p>Github Repo: <a href="#" @click="openTab('https://github.com/andrei0x309/clear-wallet')">LINK</a></p>
|
||||||
|
<br/>
|
||||||
|
<p style="margin-bottom: 0.2rem">Some Web3 Projects I personally appreciate:</p>
|
||||||
|
<p>YUP - web3 social platform <a href="#" @click="openTab('https://app.yup.io')">LINK</a></p>
|
||||||
|
<p>Crypto-Leftists: web3 left-wing crypto community <a href="#" @click="openTab('https://discord.gg/gzA4bTCdhb')">LINK</a></p>
|
||||||
|
<p>Idena: web3 fully private identity provider blockchain <a href="#" @click="openTab('https://www.idena.io/')">LINK</a></p>
|
||||||
|
<p>Mirror: web3 publishing platform <a href="#" @click="openTab('https://mirror.xyz')">LINK</a></p>
|
||||||
</div>
|
</div>
|
||||||
</ion-accordion>
|
</ion-accordion>
|
||||||
<ion-accordion value="4">
|
<ion-accordion value="4">
|
||||||
@ -146,7 +158,7 @@
|
|||||||
<ion-content class="ion-padding">
|
<ion-content class="ion-padding">
|
||||||
<ion-list v-if="settings.s.enableStorageEnctyption">
|
<ion-list v-if="settings.s.enableStorageEnctyption">
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<ion-label>Old Passord</ion-label>
|
<ion-label>Old Password</ion-label>
|
||||||
</ion-item> <ion-item>
|
</ion-item> <ion-item>
|
||||||
<ion-input v-model="mpPass" type="password"></ion-input>
|
<ion-input v-model="mpPass" type="password"></ion-input>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
@ -185,7 +197,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, ref, reactive, Ref } from "vue";
|
import { defineComponent, ref, reactive, Ref } from "vue";
|
||||||
import { storageWipe, getSettings, setSettings, getAccounts, saveSelectedAccount, replaceAccounts } from "@/utils/platform";
|
import { storageWipe, getSettings, setSettings, getAccounts, saveSelectedAccount, replaceAccounts, openTab } from "@/utils/platform";
|
||||||
import { decrypt, encrypt, getCryptoParams } from "@/utils/webCrypto"
|
import { decrypt, encrypt, getCryptoParams } from "@/utils/webCrypto"
|
||||||
import { Account } from '@/extension/types'
|
import { Account } from '@/extension/types'
|
||||||
import { exportFile } from '@/utils/misc'
|
import { exportFile } from '@/utils/misc'
|
||||||
@ -252,6 +264,8 @@ export default defineComponent({
|
|||||||
type ModalPromisePassword = null | { resolve: ((p?: unknown) => void), reject: ((p?: unknown) => void)}
|
type ModalPromisePassword = null | { resolve: ((p?: unknown) => void), reject: ((p?: unknown) => void)}
|
||||||
const modalGetPassword = ref(null) as Ref<ModalPromisePassword>
|
const modalGetPassword = ref(null) as Ref<ModalPromisePassword>
|
||||||
const noAccounts = ref(true)
|
const noAccounts = ref(true)
|
||||||
|
const defaultAccordionOpen = ref("0")
|
||||||
|
const radioTheme = ref('system') as Ref<'system' | 'light' | 'dark'>
|
||||||
|
|
||||||
const wipeStorage = async () => {
|
const wipeStorage = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
@ -271,12 +285,30 @@ export default defineComponent({
|
|||||||
const setEncryptToggle = (state: boolean) => {
|
const setEncryptToggle = (state: boolean) => {
|
||||||
settings.s.enableStorageEnctyption = state
|
settings.s.enableStorageEnctyption = state
|
||||||
updateKey.value++
|
updateKey.value++
|
||||||
|
defaultAccordionOpen.value = "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
const changeAutoLock = async () => {
|
const changeAutoLock = async () => {
|
||||||
settings.s.lockOutEnabled = !settings.s.lockOutEnabled
|
settings.s.lockOutEnabled = !settings.s.lockOutEnabled
|
||||||
updateKey.value++
|
updateKey.value++
|
||||||
await saveSettings()
|
await saveSettings()
|
||||||
|
defaultAccordionOpen.value = "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
const changePermaLock = async () => {
|
||||||
|
settings.s.lockOutEnabled = !settings.s.encryptAfterEveryTx
|
||||||
|
updateKey.value++
|
||||||
|
await saveSettings()
|
||||||
|
defaultAccordionOpen.value = "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeTheme = async (theme: 'system' | 'light' | 'dark') => {
|
||||||
|
document.body.classList.remove(radioTheme.value)
|
||||||
|
document.body.classList.add(theme)
|
||||||
|
radioTheme.value = theme
|
||||||
|
settings.s.theme = theme
|
||||||
|
await saveSettings()
|
||||||
|
defaultAccordionOpen.value = "2"
|
||||||
}
|
}
|
||||||
|
|
||||||
const changeEncryption = async () => {
|
const changeEncryption = async () => {
|
||||||
@ -352,7 +384,6 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// settings.s.enableStorageEnctyption = true;
|
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -488,6 +519,7 @@ export default defineComponent({
|
|||||||
await Promise.all([getSettings().then((storeSettings) =>
|
await Promise.all([getSettings().then((storeSettings) =>
|
||||||
{
|
{
|
||||||
settings.s = storeSettings
|
settings.s = storeSettings
|
||||||
|
radioTheme.value = settings.s.theme
|
||||||
}),
|
}),
|
||||||
getAccounts().then((accounts) => {
|
getAccounts().then((accounts) => {
|
||||||
if(accounts.length) {
|
if(accounts.length) {
|
||||||
@ -539,7 +571,12 @@ export default defineComponent({
|
|||||||
modalGetPassword,
|
modalGetPassword,
|
||||||
noAccounts,
|
noAccounts,
|
||||||
alertHeader,
|
alertHeader,
|
||||||
changeAutoLock
|
changeAutoLock,
|
||||||
|
defaultAccordionOpen,
|
||||||
|
changeTheme,
|
||||||
|
openTab,
|
||||||
|
radioTheme,
|
||||||
|
changePermaLock
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -57,7 +57,7 @@ import {
|
|||||||
import { hexTostr } from "@/utils/platform";
|
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, clearPk, getSettings } from "@/utils/platform";
|
||||||
import UnlockModal from "@/views/UnlockModal.vue";
|
import UnlockModal from "@/views/UnlockModal.vue";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@ -83,6 +83,7 @@ export default defineComponent({
|
|||||||
const alertMsg = ref("");
|
const alertMsg = ref("");
|
||||||
const timerReject = ref(140);
|
const timerReject = ref(140);
|
||||||
let interval: any;
|
let interval: any;
|
||||||
|
let pSettings = getSettings()
|
||||||
|
|
||||||
const onCancel = () => {
|
const onCancel = () => {
|
||||||
window.close();
|
window.close();
|
||||||
@ -129,6 +130,13 @@ export default defineComponent({
|
|||||||
const modalResult = await openModal();
|
const modalResult = await openModal();
|
||||||
if (modalResult) {
|
if (modalResult) {
|
||||||
unBlockLockout();
|
unBlockLockout();
|
||||||
|
if(!pSettings) {
|
||||||
|
pSettings = getSettings()
|
||||||
|
}
|
||||||
|
const settings = await pSettings
|
||||||
|
if(settings.encryptAfterEveryTx) {
|
||||||
|
clearPk()
|
||||||
|
}
|
||||||
approve(rid);
|
approve(rid);
|
||||||
} else {
|
} else {
|
||||||
onCancel();
|
onCancel();
|
||||||
|
@ -157,7 +157,7 @@ import {
|
|||||||
import { ethers } from "ethers";
|
import { ethers } from "ethers";
|
||||||
import { approve, walletPing, walletSendData } from "@/extension/userRequest";
|
import { approve, walletPing, walletSendData } from "@/extension/userRequest";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import { getSelectedNetwork, getUrl, getPrices, numToHexStr, blockLockout, unBlockLockout, getSelectedAccount, strToHex} from '@/utils/platform'
|
import { getSelectedNetwork, getUrl, getPrices, numToHexStr, blockLockout, unBlockLockout, getSelectedAccount, strToHex, getSettings, clearPk } from '@/utils/platform'
|
||||||
import { getBalance, getGasPrice, estimateGas } from '@/utils/wallet'
|
import { getBalance, getGasPrice, estimateGas } from '@/utils/wallet'
|
||||||
import type { Network } from '@/extension/types'
|
import type { Network } from '@/extension/types'
|
||||||
import { mainNets } from "@/utils/networks";
|
import { mainNets } from "@/utils/networks";
|
||||||
@ -209,6 +209,7 @@ export default defineComponent({
|
|||||||
const gasPriceModal = ref(false)
|
const gasPriceModal = ref(false)
|
||||||
const inGasPrice = ref(0)
|
const inGasPrice = ref(0)
|
||||||
const inGasLimit = ref(0)
|
const inGasLimit = ref(0)
|
||||||
|
let pSettings = getSettings()
|
||||||
|
|
||||||
let interval = 0
|
let interval = 0
|
||||||
const bars = ref(0)
|
const bars = ref(0)
|
||||||
@ -227,7 +228,7 @@ export default defineComponent({
|
|||||||
const modal = await modalController.create({
|
const modal = await modalController.create({
|
||||||
component: UnlockModal,
|
component: UnlockModal,
|
||||||
componentProps: {
|
componentProps: {
|
||||||
unlockType: 'message'
|
unlockType: 'transaction'
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
@ -240,10 +241,18 @@ export default defineComponent({
|
|||||||
const onSign = async () => {
|
const onSign = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const selectedAccount = await getSelectedAccount()
|
const selectedAccount = await getSelectedAccount()
|
||||||
|
loading.value = false
|
||||||
if ((selectedAccount.pk ?? '').length !== 66) {
|
if ((selectedAccount.pk ?? '').length !== 66) {
|
||||||
const modalResult = await openModal()
|
const modalResult = await openModal()
|
||||||
if(modalResult) {
|
if(modalResult) {
|
||||||
unBlockLockout()
|
unBlockLockout()
|
||||||
|
if(!pSettings) {
|
||||||
|
pSettings = getSettings()
|
||||||
|
}
|
||||||
|
const settings = await pSettings
|
||||||
|
if(settings.encryptAfterEveryTx) {
|
||||||
|
clearPk()
|
||||||
|
}
|
||||||
approve(rid)
|
approve(rid)
|
||||||
}else {
|
}else {
|
||||||
onCancel()
|
onCancel()
|
||||||
@ -287,9 +296,9 @@ export default defineComponent({
|
|||||||
const pBalance = getBalance()
|
const pBalance = getBalance()
|
||||||
const pGetPrices = getPrices()
|
const pGetPrices = getPrices()
|
||||||
selectedNetwork.value = await getSelectedNetwork()
|
selectedNetwork.value = await getSelectedNetwork()
|
||||||
userBalance.value = Number(ethers.utils.formatEther((await pBalance).toString()))
|
userBalance.value = Number(ethers.utils.formatEther((await pBalance).toString() ?? '0x0'))
|
||||||
|
|
||||||
gasPrice.value = parseInt(ethers.utils.formatUnits((await pGasPrice).toString(), "gwei"), 10)
|
gasPrice.value = parseInt(ethers.utils.formatUnits((await pGasPrice).toString() ?? '0x0', "gwei"), 10)
|
||||||
try {
|
try {
|
||||||
gasLimit.value = parseInt((await pEstimateGas).toString(), 10)
|
gasLimit.value = parseInt((await pEstimateGas).toString(), 10)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -194,10 +194,10 @@ export default defineComponent({
|
|||||||
const onSwitchTemplates = async () => {
|
const onSwitchTemplates = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
selectedNetwork.value = templateNetworks[Number(networkId.value)]
|
selectedNetwork.value = templateNetworks[Number(networkId.value)]
|
||||||
saveNetwork(templateNetworks[Number(networkId.value)])
|
await saveNetwork(templateNetworks[Number(networkId.value)])
|
||||||
saveSelectedNetwork(templateNetworks[Number(networkId.value)])
|
await saveSelectedNetwork(templateNetworks[Number(networkId.value)])
|
||||||
approve(rid);
|
approve(rid);
|
||||||
loading.value = true;
|
loading.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSwitchNotExisting = async () => {
|
const onSwitchNotExisting = async () => {
|
||||||
|
@ -8,20 +8,29 @@
|
|||||||
<ion-title>Unlock to Proceed</ion-title>
|
<ion-title>Unlock to Proceed</ion-title>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding">
|
<ion-content class="ion-padding">
|
||||||
<ion-list>
|
<ion-list>
|
||||||
<ion-list v-if="unlockType === 'message'">
|
<ion-list v-if="unlockType === 'message'">
|
||||||
<ion-item>To continue signing the message, unlock wallet.</ion-item>
|
<ion-item>To continue signing the message, unlock wallet.</ion-item>
|
||||||
<ion-item>Closing will reject sigining the message</ion-item>
|
<ion-item>Closing will reject sigining the message.</ion-item>
|
||||||
|
</ion-list>
|
||||||
|
<ion-list v-else-if="unlockType === 'viewPk'">
|
||||||
|
<ion-item>To view the PK, unlock wallet.</ion-item>
|
||||||
|
<ion-item>Closing will not show the PK.</ion-item>
|
||||||
|
</ion-list>
|
||||||
|
<ion-list v-else-if="unlockType === 'addAccount'">
|
||||||
|
<ion-item>Storage Encrypted, Unlock to add account.</ion-item>
|
||||||
|
<ion-item>Closing will not add the account.</ion-item>
|
||||||
</ion-list>
|
</ion-list>
|
||||||
<ion-list v-else>
|
<ion-list v-else>
|
||||||
<ion-item>To continue sending the transaction, unlock wallet.</ion-item>
|
<ion-item>To continue sending the transaction, unlock wallet.</ion-item>
|
||||||
<ion-item>Closing will reject sending the tranzaction.</ion-item>
|
<ion-item>Closing will reject sending the transaction.</ion-item>
|
||||||
</ion-list>
|
</ion-list>
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<ion-label>Unlock Password</ion-label>
|
<ion-label>Unlock Password</ion-label>
|
||||||
</ion-item> <ion-item>
|
</ion-item>
|
||||||
|
<ion-item>
|
||||||
<ion-input v-model="mpPass" type="password"></ion-input>
|
<ion-input v-model="mpPass" type="password"></ion-input>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</ion-list>
|
</ion-list>
|
||||||
@ -100,7 +109,7 @@ export default defineComponent({
|
|||||||
const alertMsg = ref('');
|
const alertMsg = ref('');
|
||||||
|
|
||||||
const close = () => {
|
const close = () => {
|
||||||
return modalController.dismiss(null, 'cancel');
|
return modalController?.dismiss(null, 'cancel');
|
||||||
}
|
}
|
||||||
|
|
||||||
const unlock = async () => {
|
const unlock = async () => {
|
||||||
@ -109,14 +118,16 @@ export default defineComponent({
|
|||||||
let accounts = await getAccounts()
|
let accounts = await getAccounts()
|
||||||
const cryptoParams = await getCryptoParams(mpPass.value)
|
const cryptoParams = await getCryptoParams(mpPass.value)
|
||||||
const accProm = accounts.map(async a => {
|
const accProm = accounts.map(async a => {
|
||||||
a.pk = await decrypt(a.encPk, cryptoParams)
|
if(a.encPk) {
|
||||||
|
a.pk = await decrypt(a.encPk, cryptoParams)
|
||||||
|
}
|
||||||
return a
|
return a
|
||||||
})
|
})
|
||||||
accounts = await Promise.all(accProm)
|
accounts = await Promise.all(accProm)
|
||||||
await replaceAccounts(accounts)
|
await replaceAccounts(accounts)
|
||||||
await saveSelectedAccount(accounts[0])
|
await saveSelectedAccount(accounts[0])
|
||||||
loading.value = false
|
loading.value = false
|
||||||
return modalController.dismiss(null, 'confirm');
|
return modalController?.dismiss(mpPass.value, 'confirm');
|
||||||
} catch {
|
} catch {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
alertMsg.value = 'Decryption failed, password is not correct, try again.';
|
alertMsg.value = 'Decryption failed, password is not correct, try again.';
|
||||||
|
Loading…
Reference in New Issue
Block a user