290 lines
11 KiB
TypeScript
290 lines
11 KiB
TypeScript
|
import { getAccounts, getSelectedAccount, getSelectedNetwork, smallRandomString, storageSave} from '@/utils/platform';
|
||
|
import { userApprove, userReject, rIdWin, rIdData } from '@/extension/userRequest'
|
||
|
import { signMsg, getBalance, getBlockNumber, estimateGas, sendTransaction, getGasPrice } from '@/utils/wallet'
|
||
|
import type { RequestArguments } from '@/extension/types'
|
||
|
import type { Account } from '@/extension/types'
|
||
|
import { rpcError } from '@/extension/rpcConstants'
|
||
|
import { updatePrices } from '@/utils/gecko'
|
||
|
|
||
|
chrome.runtime.onInstalled.addListener(() => {
|
||
|
console.log('Service worker installed');
|
||
|
chrome.runtime.connect(null as unknown as string, {
|
||
|
name:'sw-connection'
|
||
|
})
|
||
|
})
|
||
|
|
||
|
chrome.runtime.onConnect.addListener(port => port.onDisconnect.addListener((a) =>
|
||
|
{
|
||
|
console.log('Service worker connected', storageSave('test-d', a));
|
||
|
}))
|
||
|
|
||
|
|
||
|
chrome.runtime.onStartup.addListener(() => {
|
||
|
console.log('Service worker startup');
|
||
|
})
|
||
|
|
||
|
chrome.runtime.onSuspend.addListener(() => {
|
||
|
console.log('Service worker suspend');
|
||
|
})
|
||
|
|
||
|
|
||
|
chrome.alarms.create('updatePrices', {
|
||
|
periodInMinutes: 1
|
||
|
})
|
||
|
|
||
|
chrome.alarms.onAlarm.addListener((alarm) => {
|
||
|
if(alarm.name === 'updatePrices') {
|
||
|
updatePrices().then(() => {
|
||
|
console.log('Prices updated')
|
||
|
})
|
||
|
}
|
||
|
})
|
||
|
|
||
|
chrome.windows.onRemoved.addListener((winId) => {
|
||
|
if (winId in (userReject ?? {})){
|
||
|
userReject[winId]?.()
|
||
|
}
|
||
|
userReject[winId] = undefined
|
||
|
userApprove[winId] = undefined
|
||
|
rIdWin[winId] = undefined
|
||
|
rIdData[winId] = undefined
|
||
|
chrome.windows.getAll().then((wins) => {
|
||
|
if(wins.length === 0) {
|
||
|
storageSave('test-p', 'browser-closed')
|
||
|
}
|
||
|
})
|
||
|
})
|
||
|
|
||
|
chrome.runtime.onMessage.addListener((message: RequestArguments, sender, sendResponse) => {
|
||
|
console.log(message);
|
||
|
(async () => {
|
||
|
if (!('method' in message)) {
|
||
|
sendResponse({
|
||
|
code: 500,
|
||
|
message: 'Invalid request method'
|
||
|
})
|
||
|
} else {
|
||
|
// ETH API
|
||
|
switch (message.method) {
|
||
|
case 'eth_call': {
|
||
|
break
|
||
|
}
|
||
|
case 'eth_getBalance': {
|
||
|
sendResponse(await getBalance())
|
||
|
break
|
||
|
}
|
||
|
case 'eth_blockNumber': {
|
||
|
sendResponse(await getBlockNumber())
|
||
|
break
|
||
|
}
|
||
|
case 'eth_estimateGas': {
|
||
|
const params = message?.params?.[0] as any
|
||
|
if(!params) {
|
||
|
sendResponse({
|
||
|
error: true,
|
||
|
code: rpcError.INVALID_PARAM,
|
||
|
message: 'Invalid param for gas estimate'
|
||
|
})
|
||
|
break
|
||
|
}
|
||
|
sendResponse(await estimateGas({
|
||
|
to: params?.to ?? '',
|
||
|
from: params?.from ?? '',
|
||
|
data: params?.data ?? '',
|
||
|
value: params?.value ?? '0x0'
|
||
|
}))
|
||
|
break
|
||
|
}
|
||
|
case 'eth_accounts': {
|
||
|
const accounts = await getAccounts()
|
||
|
const addresses = accounts.map((a: Account) => a.address) ?? []
|
||
|
sendResponse(addresses)
|
||
|
break
|
||
|
}
|
||
|
case 'eth_requestAccounts': {
|
||
|
const account = await getSelectedAccount()
|
||
|
const address = account?.address ? [account?.address] : []
|
||
|
sendResponse(address)
|
||
|
break
|
||
|
}
|
||
|
case 'eth_chainId': {
|
||
|
const network = await getSelectedNetwork()
|
||
|
console.log(network, 'network')
|
||
|
const chainId = network?.chainId ?? 0
|
||
|
sendResponse(`0x${chainId.toString(16)}`)
|
||
|
break
|
||
|
}
|
||
|
case 'eth_sendTransaction': {
|
||
|
try {
|
||
|
const params = message?.params?.[0] as any
|
||
|
if(!params) {
|
||
|
sendResponse({
|
||
|
error: true,
|
||
|
code: rpcError.INVALID_PARAM,
|
||
|
message: 'Invalid param for send transaction'
|
||
|
})
|
||
|
break
|
||
|
}
|
||
|
const [account, network] = await Promise.all([getSelectedAccount(), getSelectedNetwork()])
|
||
|
if(!account || !network) {
|
||
|
return
|
||
|
}
|
||
|
const serializeParams = encodeURIComponent(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({
|
||
|
height: 450,
|
||
|
width: 400,
|
||
|
url: chrome.runtime.getURL(`index.html?route=sign-tx¶m=${serializeParams}&rid=${String(message?.resId ?? '')}`),
|
||
|
type: 'popup'
|
||
|
}).then((win) => {
|
||
|
gWin = win
|
||
|
userReject[String(win.id)] = reject
|
||
|
userApprove[String(win.id)] = resolve
|
||
|
rIdWin[String(win.id)] = String(message.resId)
|
||
|
rIdData[String(win.id)] = {}
|
||
|
})
|
||
|
|
||
|
})
|
||
|
sendResponse(
|
||
|
await sendTransaction({...params, ...(rIdData?.[String(gWin?.id ?? 0)] ?? {}) }, pEstimateGas, pGasPrice)
|
||
|
)
|
||
|
} catch(err) {
|
||
|
console.error(err)
|
||
|
sendResponse({
|
||
|
error: true,
|
||
|
code: rpcError.USER_REJECTED,
|
||
|
message: 'User Rejected Signature'
|
||
|
})
|
||
|
}
|
||
|
break
|
||
|
}
|
||
|
case ('personal_sign' || 'eth_sign'): {
|
||
|
try {
|
||
|
|
||
|
await new Promise((resolve, reject) => {
|
||
|
chrome.windows.create({
|
||
|
height: 450,
|
||
|
width: 400,
|
||
|
url: chrome.runtime.getURL(`index.html?route=sign-msg¶m=${String(message?.params?.[0] ?? '' )}&rid=${String(message?.resId ?? '')}`),
|
||
|
type: 'popup'
|
||
|
}).then((win) => {
|
||
|
userReject[String(win.id)] = reject
|
||
|
userApprove[String(win.id)] = resolve
|
||
|
rIdWin[String(win.id)] = String(message.resId)
|
||
|
})
|
||
|
|
||
|
})
|
||
|
sendResponse(
|
||
|
await signMsg(String(message?.params?.[0]) ?? '' )
|
||
|
)
|
||
|
} catch {
|
||
|
sendResponse({
|
||
|
error: true,
|
||
|
code: rpcError.USER_REJECTED,
|
||
|
message: 'User Rejected Signature'
|
||
|
})
|
||
|
}
|
||
|
|
||
|
break
|
||
|
}
|
||
|
// NON Standard metamask API
|
||
|
case 'wallet_requestPermissions': {
|
||
|
const account = await getSelectedAccount()
|
||
|
const address = account?.address ? [account?.address] : []
|
||
|
sendResponse([{
|
||
|
caveats: {
|
||
|
type:'',
|
||
|
value: address
|
||
|
},
|
||
|
invoker: '',
|
||
|
date: Date.now(),
|
||
|
id: smallRandomString(),
|
||
|
parentCapability: Object.keys(message?.params?.[0] ?? {})?.[0] ?? 'unknown'
|
||
|
}])
|
||
|
break
|
||
|
}
|
||
|
case 'net_version': {
|
||
|
const network = await getSelectedNetwork()
|
||
|
const chainId = network?.chainId ?? 0
|
||
|
sendResponse(chainId)
|
||
|
break
|
||
|
}
|
||
|
case 'wallet_switchEthereumChain': {
|
||
|
try {
|
||
|
await new Promise((resolve, reject) => {
|
||
|
chrome.windows.create({
|
||
|
height: 450,
|
||
|
width: 400,
|
||
|
url: chrome.runtime.getURL(`index.html?route=switch-network¶m=${String(message?.params?.[0] ?? '' )}&rid=${String(message?.resId ?? '')}`),
|
||
|
type: 'popup'
|
||
|
}).then((win) => {
|
||
|
userReject[String(win.id)] = reject
|
||
|
userApprove[String(win.id)] = resolve
|
||
|
rIdWin[String(win.id)] = String(message.resId)
|
||
|
})
|
||
|
|
||
|
})
|
||
|
sendResponse(
|
||
|
await signMsg(String(message?.params?.[0]) ?? '' )
|
||
|
)
|
||
|
} catch {
|
||
|
sendResponse({
|
||
|
error: true,
|
||
|
code: rpcError.USER_REJECTED,
|
||
|
message: 'User Rejected Signature'
|
||
|
})
|
||
|
}
|
||
|
break
|
||
|
}
|
||
|
// internal messeges
|
||
|
case 'wallet_approve': {
|
||
|
if(String(sender.tab?.windowId) in rIdWin){
|
||
|
userApprove[String(sender.tab?.windowId)]?.(true)
|
||
|
}
|
||
|
try {
|
||
|
chrome.windows.remove(sender.tab?.windowId ?? 0)
|
||
|
}catch{
|
||
|
// ignore
|
||
|
}
|
||
|
break
|
||
|
}
|
||
|
case 'wallet_send_data': {
|
||
|
if(String(sender.tab?.windowId) in rIdData){
|
||
|
rIdData[String(sender?.tab?.windowId ?? '')] = (message as any)?.data ?? {}
|
||
|
sendResponse(true)
|
||
|
}
|
||
|
break
|
||
|
}
|
||
|
case 'wallet_get_data': {
|
||
|
if(String(sender.tab?.windowId) in rIdData){
|
||
|
sendResponse( rIdData[String(sender?.tab?.windowId ?? '')] ?? {})
|
||
|
}
|
||
|
break
|
||
|
}
|
||
|
case 'wallet_ping': {
|
||
|
sendResponse(true)
|
||
|
break
|
||
|
}
|
||
|
default: {
|
||
|
sendResponse({
|
||
|
error: true,
|
||
|
code: rpcError.INVALID_PARAM,
|
||
|
message: 'Invalid request method'
|
||
|
})
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
)();
|
||
|
return true;
|
||
|
});
|