Skip to content

Commit

Permalink
Merge pull request #188 from palladians/feat/implement-web-connector-…
Browse files Browse the repository at this point in the history
…events

feat(web connector): add events emitting
mrcnk authored Aug 5, 2024
2 parents 1246e61 + 0bf5e98 commit 0ce65dc
Showing 43 changed files with 657 additions and 713 deletions.
11 changes: 11 additions & 0 deletions .deepsource.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
version = 1

[[analyzers]]
name = "javascript"

[analyzers.meta]
plugins = ["react"]
environment = [
"browser",
"vitest"
]
2 changes: 2 additions & 0 deletions apps/extension/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/public/rpc.js

# Logs
logs
*.log
2 changes: 1 addition & 1 deletion apps/extension/manifest.ts
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ export const manifest: chrome.runtime.ManifestV3 = {
],
web_accessible_resources: [
{
resources: ["pallad_rpc.js"],
resources: ["rpc.js"],
matches: ["https://*/*"],
},
],
11 changes: 7 additions & 4 deletions apps/extension/package.json
Original file line number Diff line number Diff line change
@@ -4,7 +4,8 @@
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"build": "tsc && pnpm build:rpc && vite build",
"build:rpc": "tsup",
"build:firefox": "web-ext build --source-dir=dist",
"build:safari": "xcrun safari-web-extension-converter dist --app-name Pallad --bundle-identifier co.pallad.app --swift --no-prompt --force --macos-only --no-open",
"preview": "vite preview",
@@ -18,9 +19,11 @@
"@palladxyz/features": "workspace:*",
"@palladxyz/key-management": "workspace:*",
"@palladxyz/web-provider": "workspace:*",
"@palladxyz/vault": "workspace:*",
"@plasmohq/messaging": "0.6.2",
"buffer": "6.0.3",
"debounce": "^2.1.0",
"p-debounce": "4.0.0",
"mitt": "3.0.1",
"next-themes": "0.3.0",
"react": "18.3.1",
"react-dom": "18.3.1",
@@ -58,8 +61,8 @@
"vite-plugin-svgr": "4.2.0",
"vite-plugin-top-level-await": "1.4.2",
"vite-plugin-wasm": "3.3.0",
"vite-plugin-web-extension": "^4.1.6",
"vite-plugin-web-extension": "4.1.6",
"web-ext": "8.2.0",
"write-json-file": "^6.0.0"
"write-json-file": "6.0.0"
}
}
107 changes: 0 additions & 107 deletions apps/extension/public/pallad_rpc.js

This file was deleted.

10 changes: 10 additions & 0 deletions apps/extension/src/background/handlers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { OnMessageCallback } from "webext-bridge"

export type Handler = OnMessageCallback<any, any>
export * from "./web-provider"
export * from "./wallet"

export const opts = {
projectId: "test",
chains: ["Mainnet"],
}
48 changes: 48 additions & 0 deletions apps/extension/src/background/handlers/wallet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { useVault } from "@palladxyz/vault"
import type { NetworkName } from "@palladxyz/vault"
import { MinaProvider } from "@palladxyz/web-provider"
import { serializeError } from "serialize-error"
import type { Handler } from "./"

export const palladSidePanel: Handler = async ({ sender }) => {
await chrome.sidePanel.open({
tabId: sender.tabId,
})
}

export const palladSwitchNetwork: Handler = async ({ data }) => {
try {
const provider = await MinaProvider.getInstance()
await useVault.persist.rehydrate()
const { switchNetwork, getChainId } = useVault.getState()
const network = data.network as NetworkName
await switchNetwork(network)
await useVault.persist.rehydrate()
const chainId = await getChainId()
provider.emit("pallad_event", {
data: {
chainId: chainId,
},
type: "chainChanged",
})
} catch (error) {
return { error: serializeError(error) }
}
}

export const palladConnected: Handler = async () => {
try {
const provider = await MinaProvider.getInstance()
await useVault.persist.rehydrate()
const { getChainId } = useVault.getState()
const chainId = await getChainId()
provider.emit("pallad_event", {
data: {
chainId: chainId,
},
type: "connect",
})
} catch (error) {
return { error: serializeError(error) }
}
}
180 changes: 180 additions & 0 deletions apps/extension/src/background/handlers/web-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import { serializeError } from "serialize-error"
import type { Handler } from "."
import {
MinaProvider,
Validation,
} from "../../../../../packages/web-provider/src"

export const minaSetState: Handler = async ({ data }) => {
try {
const provider = await MinaProvider.getInstance()
const params = Validation.setStateRequestSchema.parse(data)
return await provider.request({
method: "mina_setState",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
}

export const minaAddChain = async () => {
return { error: serializeError(new Error("4200 - Unsupported Method")) }
}

export const minaRequestNetwork: Handler = async ({ data }) => {
try {
const provider = await MinaProvider.getInstance()
const params = Validation.requestSchema.parse(data)
return await provider.request({
method: "mina_requestNetwork",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
}

export const minaSwitchChain = async () => {
return { error: serializeError(new Error("4200 - Unsupported Method")) }
}

export const minaGetState: Handler = async ({ data }) => {
try {
const provider = await MinaProvider.getInstance()
const params = Validation.getStateRequestSchema.parse(data)
return await provider.request({
method: "mina_getState",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
}

export const minaChainId: Handler = async ({ data }) => {
try {
const provider = await MinaProvider.getInstance()
const params = Validation.requestSchema.parse(data)
return await provider.request({
method: "mina_chainId",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
}

export const minaAccounts: Handler = async ({ data }) => {
try {
const provider = await MinaProvider.getInstance()
const params = Validation.requestSchema.parse(data)
return await provider.request({
method: "mina_accounts",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
}

export const minaRequestAccounts: Handler = async ({ data }) => {
try {
const provider = await MinaProvider.getInstance()
const params = Validation.requestSchema.parse(data)
return await provider.request({
method: "mina_accounts",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
}

export const minaSign: Handler = async ({ data }) => {
try {
const provider = await MinaProvider.getInstance()
const params = Validation.signMessageRequestSchema.parse(data)
return await provider.request({
method: "mina_sign",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
}

export const minaSignFields: Handler = async ({ data }) => {
try {
const provider = await MinaProvider.getInstance()
const params = Validation.signFieldsRequestSchema.parse(data)
return await provider.request({
method: "mina_signFields",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
}

export const minaSignTransaction: Handler = async ({ data }) => {
try {
const provider = await MinaProvider.getInstance()
const params = Validation.signTransactionRequestSchema.parse(data)
return await provider.request({
method: "mina_signTransaction",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
}

export const minaGetBalance: Handler = async ({ data }) => {
try {
const provider = await MinaProvider.getInstance()
const params = Validation.requestSchema.parse(data)
return await provider.request({
method: "mina_getBalance",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
}

export const minaCreateNullifier: Handler = async ({ data }) => {
try {
const provider = await MinaProvider.getInstance()
const params = Validation.createNullifierRequestSchema.parse(data)
return await provider.request({
method: "mina_createNullifier",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
}

export const minaSendTransaction: Handler = async ({ data }) => {
try {
const provider = await MinaProvider.getInstance()
const params = Validation.sendTransactionRequestSchema.parse(data)
return await provider.request({
method: "mina_sendTransaction",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
}

export const palladIsConnected: Handler = async ({ data }) => {
try {
const provider = await MinaProvider.getInstance()
const { origin } = Validation.requestSchema.parse(data)
return await provider.isConnected({ origin })
} catch (error: unknown) {
return { error: serializeError(error) }
}
}
263 changes: 63 additions & 200 deletions apps/extension/src/background/index.ts
Original file line number Diff line number Diff line change
@@ -1,207 +1,60 @@
import { MinaProvider, Validation } from "@palladxyz/web-provider"
import { serializeError } from "serialize-error"
import { onMessage } from "webext-bridge/background"
import { MinaProvider } from "@palladxyz/web-provider"
import { onMessage, sendMessage } from "webext-bridge/background"
import { runtime, tabs } from "webextension-polyfill"
import {
minaAccounts,
minaAddChain,
minaChainId,
minaCreateNullifier,
minaGetBalance,
minaGetState,
minaRequestAccounts,
minaRequestNetwork,
minaSendTransaction,
minaSetState,
minaSign,
minaSignFields,
minaSignTransaction,
minaSwitchChain,
palladConnected,
palladIsConnected,
palladSidePanel,
palladSwitchNetwork,
} from "./handlers"

const E2E_TESTING = import.meta.env.VITE_APP_E2E === "true"

const opts = {
projectId: "test",
chains: ["Mina - Mainnet"],
}

onMessage("enable", async ({ data }) => {
try {
const provider = await MinaProvider.init(opts, [])
const { origin } = Validation.requestSchema.parse(data)
return await provider.enable({ origin })
} catch (error: unknown) {
return { error: serializeError(error) }
}
})

onMessage("mina_setState", async ({ data }) => {
try {
const provider = await MinaProvider.init(opts, [])
const params = Validation.setStateRequestSchema.parse(data)
return await provider.request({
method: "mina_setState",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
})

onMessage("mina_addChain", async () => {
return { error: serializeError(new Error("4200 - Unsupported Method")) }
})

onMessage("mina_requestNetwork", async ({ data }) => {
try {
const provider = await MinaProvider.init(opts, [])
const params = Validation.requestSchema.parse(data)
return await provider.request({
method: "mina_requestNetwork",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
})

onMessage("mina_switchChain", async () => {
return { error: serializeError(new Error("4200 - Unsupported Method")) }
})

onMessage("mina_getState", async ({ data }) => {
try {
const provider = await MinaProvider.init(opts, [])
const params = Validation.getStateRequestSchema.parse(data)
return await provider.request({
method: "mina_getState",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
})

onMessage("isConnected", async ({ data }) => {
try {
const provider = await MinaProvider.init(opts, [])
const { origin } = Validation.requestSchema.parse(data)
return await provider.isConnected({ origin })
} catch (error: unknown) {
return { error: serializeError(error) }
}
})

onMessage("mina_chainId", async ({ data }) => {
try {
const provider = await MinaProvider.init(opts, [])
const params = Validation.requestSchema.parse(data)
return await provider.request({
method: "mina_chainId",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
})

onMessage("mina_accounts", async ({ data }) => {
try {
const provider = await MinaProvider.init(opts, [])
const params = Validation.requestSchema.parse(data)
return await provider.request({
method: "mina_accounts",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
})

/**
* Web Connector handlers
*/
onMessage("mina_setState", minaSetState)
onMessage("mina_addChain", minaAddChain)
onMessage("mina_requestNetwork", minaRequestNetwork)
onMessage("mina_switchChain", minaSwitchChain)
onMessage("mina_getState", minaGetState)
onMessage("mina_chainId", minaChainId)
onMessage("mina_accounts", minaAccounts)
// TODO: It should be removed, but let's keep it for now for Auro compatibility.
onMessage("mina_requestAccounts", async ({ data }) => {
try {
const provider = await MinaProvider.init(opts, [])
const params = Validation.requestSchema.parse(data)
return await provider.request({
method: "mina_accounts",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
})

onMessage("mina_sign", async ({ data }) => {
try {
const provider = await MinaProvider.init(opts, [])
const params = Validation.signMessageRequestSchema.parse(data)
return await provider.request({
method: "mina_sign",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
})

onMessage("mina_signFields", async ({ data }) => {
try {
const provider = await MinaProvider.init(opts, [])
const params = Validation.signFieldsRequestSchema.parse(data)
return await provider.request({
method: "mina_signFields",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
})

onMessage("mina_signTransaction", async ({ data }) => {
try {
const provider = await MinaProvider.init(opts, [])
const params = Validation.signTransactionRequestSchema.parse(data)
return await provider.request({
method: "mina_signTransaction",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
})

onMessage("mina_getBalance", async ({ data }) => {
try {
const provider = await MinaProvider.init(opts, [])
const params = Validation.requestSchema.parse(data)
return await provider.request({
method: "mina_getBalance",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
})

onMessage("mina_createNullifier", async ({ data }) => {
try {
const provider = await MinaProvider.init(opts, [])
const params = Validation.createNullifierRequestSchema.parse(data)
return await provider.request({
method: "mina_createNullifier",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
})

onMessage("mina_sendTransaction", async ({ data }) => {
try {
const provider = await MinaProvider.init(opts, [])
const params = Validation.sendTransactionRequestSchema.parse(data)
return await provider.request({
method: "mina_sendTransaction",
params,
})
} catch (error: unknown) {
return { error: serializeError(error) }
}
})

onMessage("pallad_sidePanel", async ({ sender }) => {
await chrome.sidePanel.open({
tabId: sender.tabId,
})
})

runtime.onConnect.addListener((port) => {
onMessage("mina_requestAccounts", minaRequestAccounts)
onMessage("mina_sign", minaSign)
onMessage("mina_signFields", minaSignFields)
onMessage("mina_signTransaction", minaSignTransaction)
onMessage("mina_getBalance", minaGetBalance)
onMessage("mina_createNullifier", minaCreateNullifier)
onMessage("mina_sendTransaction", minaSendTransaction)

/**
* Wallet handlers
*/
onMessage("pallad_isConnected", palladIsConnected)
onMessage("pallad_switchNetwork", palladSwitchNetwork)
onMessage("pallad_connected", palladConnected)
onMessage("pallad_sidePanel", palladSidePanel)

/**
* Runtime
*/
runtime.onConnect.addListener(async (port) => {
if (port.name === "prompt") {
port.onDisconnect.addListener(async () => {
await chrome.sidePanel.setOptions({
@@ -211,11 +64,21 @@ runtime.onConnect.addListener((port) => {
})
}
})

runtime.onInstalled.addListener(async ({ reason }) => {
const provider = await MinaProvider.getInstance()
await chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true })
if (reason === "install") {
if (!E2E_TESTING)
await tabs.create({ url: "https://get.pallad.co/welcome" })
}
provider.on("pallad_event", async (data) => {
const { permissions } = await chrome.storage.local.get("permissions")
const urls = Object.entries(permissions)
.filter(([_, allowed]) => allowed === "ALLOWED")
.map(([url]) => `${url}/*`)
const allowedTabs = await tabs.query({ url: urls })
for (const tab of allowedTabs) {
await sendMessage("pallad_event", data, `content-script@${tab.id}`)
}
})
})
12 changes: 9 additions & 3 deletions apps/extension/src/inject/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { deserializeError } from "serialize-error"
import { sendMessage } from "webext-bridge/content-script"
import { onMessage, sendMessage } from "webext-bridge/content-script"
import { runtime } from "webextension-polyfill"

onMessage("pallad_event", async ({ data }) => {
const palladEvent = new CustomEvent("pallad_event", {
detail: data,
})
window.dispatchEvent(palladEvent)
})

const inject = () => {
if (typeof document === "undefined") return
const script = document.createElement("script")
script.src = runtime.getURL("/pallad_rpc.js")
script.src = runtime.getURL("/rpc.js")
script.type = "module"
document.documentElement.appendChild(script)
console.info("[Pallad] RPC has been initialized.")
const channel = new BroadcastChannel("pallad")
channel.addEventListener("message", async ({ data }) => {
const origin = window.location.origin
19 changes: 19 additions & 0 deletions apps/extension/src/inject/rpc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { info, provider } from "./rpc/provider"

const init = () => {
;(window as any).mina = provider
const announceProvider = () => {
window.dispatchEvent(
new CustomEvent("mina:announceProvider", {
detail: Object.freeze({ info, provider }),
}),
)
}
window.addEventListener("mina:requestProvider", () => {
announceProvider()
})
announceProvider()
console.info("[Pallad] RPC has been initialized.")
}

init()
34 changes: 34 additions & 0 deletions apps/extension/src/inject/rpc/provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import mitt from "mitt"
import { debouncedCall } from "./utils"

type EmitterEvents = {
connect: { chainId: string }
chainChanged: { chainId: string }
}

const _events = mitt<EmitterEvents>()

window.addEventListener("pallad_event", (event) => {
event.stopImmediatePropagation()
const { detail } = event as CustomEvent
_events.emit(detail.type, detail.data)
})

export const info = {
slug: "pallad",
name: "Pallad",
icon: "data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMzAwIDMwMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzE5OF8yNDY5NSkiPgo8cmVjdCB3aWR0aD0iMzAwIiBoZWlnaHQ9IjMwMCIgcng9IjEyIiBmaWxsPSIjRjZDMTc3Ii8+CjxwYXRoIGQ9Ik05MCAyMTRDOTAgMjExLjc5MSA5MS43OTA5IDIxMCA5NCAyMTBIMTM2QzE0My43MzIgMjEwIDE1MCAyMTYuMjY4IDE1MCAyMjRWMjI2QzE1MCAyMzMuNzMyIDE0My43MzIgMjQwIDEzNiAyNDBIMTA0Qzk2LjI2OCAyNDAgOTAgMjMzLjczMiA5MCAyMjZWMjE0WiIgZmlsbD0iIzI1MjMzQSIvPgo8cGF0aCBkPSJNOTAgNjRDOTAgNjEuNzkwOSA5MS43OTA5IDYwIDk0IDYwSDE5NkMyMDMuNzMyIDYwIDIxMCA2Ni4yNjggMjEwIDc0Vjc2QzIxMCA4My43MzIgMjAzLjczMiA5MCAxOTYgOTBIMTA0Qzk2LjI2OCA5MCA5MCA4My43MzIgOTAgNzZWNjRaIiBmaWxsPSIjMjUyMzNBIi8+CjxwYXRoIGQ9Ik0yMTAgOTRDMjEwIDkxLjc5MDkgMjExLjc5MSA5MCAyMTQgOTBIMjI2QzIzMy43MzIgOTAgMjQwIDk2LjI2OCAyNDAgMTA0VjEzNkMyNDAgMTQzLjczMiAyMzMuNzMyIDE1MCAyMjYgMTUwSDIyNEMyMTYuMjY4IDE1MCAyMTAgMTQzLjczMiAyMTAgMTM2Vjk0WiIgZmlsbD0iIzI1MjMzQSIvPgo8cGF0aCBkPSJNNjAgOTRDNjAgOTEuNzkwOSA2MS43OTA5IDkwIDY0IDkwSDc2QzgzLjczMiA5MCA5MCA5Ni4yNjggOTAgMTA0VjE5NkM5MCAyMDMuNzMyIDgzLjczMiAyMTAgNzYgMjEwSDc0QzY2LjI2OCAyMTAgNjAgMjAzLjczMiA2MCAxOTZWOTRaIiBmaWxsPSIjMjUyMzNBIi8+CjxwYXRoIGQ9Ik0xNTAgMTUwSDE5NkMyMDMuNzMyIDE1MCAyMTAgMTU2LjI2OCAyMTAgMTY0VjE2NkMyMTAgMTczLjczMiAyMDMuNzMyIDE4MCAxOTYgMTgwSDE2NEMxNTYuMjY4IDE4MCAxNTAgMTczLjczMiAxNTAgMTY2VjE1MFoiIGZpbGw9IiMyNTIzM0EiLz4KPHBhdGggZD0iTTIxMCAxNTBIMTk1QzE5NSAxNTAgMjAxIDE1MCAyMDUuNSAxNTQuNUMyMTAgMTU5IDIxMCAxNjUgMjEwIDE2NVYxNTBaIiBmaWxsPSIjMjUyMzNBIi8+CjxwYXRoIGQ9Ik0yMTAgMTUwTDIyNSAxNTBDMjI1IDE1MCAyMTkgMTUwIDIxNC41IDE0NS41QzIxMCAxNDEgMjEwIDEzNSAyMTAgMTM1TDIxMCAxNTBaIiBmaWxsPSIjMjUyMzNBIi8+CjxwYXRoIGQ9Ik0yMTAgMTUwTDIxMCAxMzVDMjEwIDEzNSAyMTAgMTQxIDIwNS41IDE0NS41QzIwMSAxNTAgMTk1IDE1MCAxOTUgMTUwTDIxMCAxNTBaIiBmaWxsPSIjMjUyMzNBIi8+CjxwYXRoIGQ9Ik05MCA5MEg3NUM3NSA5MCA4MSA5MCA4NS41IDk0LjVDOTAgOTkgOTAgMTA1IDkwIDEwNVY5MFoiIGZpbGw9IiMyNTIzM0EiLz4KPHBhdGggZD0iTTkwIDkwTDEwNSA5MEMxMDUgOTAgOTkgOTAgOTQuNSA4NS41QzkwIDgxIDkwIDc1IDkwIDc1TDkwIDkwWiIgZmlsbD0iIzI1MjMzQSIvPgo8cGF0aCBkPSJNOTAgOTBMOTAgMTA1QzkwIDEwNSA5MCA5OSA5NC41IDk0LjVDOTkgOTAgMTA1IDkwIDEwNSA5MEw5MCA5MFoiIGZpbGw9IiMyNTIzM0EiLz4KPHBhdGggZD0iTTIxMCA5MEgxOTVDMTk1IDkwIDIwMSA5MCAyMDUuNSA5NC41QzIxMCA5OSAyMTAgMTA1IDIxMCAxMDVWOTBaIiBmaWxsPSIjMjUyMzNBIi8+CjxwYXRoIGQ9Ik0yMTAgOTBMMjEwIDc1QzIxMCA3NSAyMTAgODEgMjA1LjUgODUuNUMyMDEgOTAgMTk1IDkwIDE5NSA5MEwyMTAgOTBaIiBmaWxsPSIjMjUyMzNBIi8+CjxwYXRoIGQ9Ik0yMTAgOTBMMjEwIDEwNUMyMTAgMTA1IDIxMCA5OSAyMTQuNSA5NC41QzIxOSA5MCAyMjUgOTAgMjI1IDkwTDIxMCA5MFoiIGZpbGw9IiMyNTIzM0EiLz4KPHBhdGggZD0iTTkwIDIxMEwxMDUgMjEwQzEwNSAyMTAgOTkgMjEwIDk0LjUgMjA1LjVDOTAgMjAxIDkwIDE5NSA5MCAxOTVMOTAgMjEwWiIgZmlsbD0iIzI1MjMzQSIvPgo8cGF0aCBkPSJNOTAgMjEwTDkwIDE5NUM5MCAxOTUgOTAgMjAxIDg1LjUgMjA1LjVDODEgMjEwIDc1IDIxMCA3NSAyMTBMOTAgMjEwWiIgZmlsbD0iIzI1MjMzQSIvPgo8cGF0aCBkPSJNOTAgMjEwTDkwIDIyNUM5MCAyMjUgOTAgMjE5IDk0LjUgMjE0LjVDOTkgMjEwIDEwNSAyMTAgMTA1IDIxMEw5MCAyMTBaIiBmaWxsPSIjMjUyMzNBIi8+CjwvZz4KPGRlZnM+CjxjbGlwUGF0aCBpZD0iY2xpcDBfMTk4XzI0Njk1Ij4KPHJlY3Qgd2lkdGg9IjMwMCIgaGVpZ2h0PSIzMDAiIHJ4PSI0MCIgZmlsbD0id2hpdGUiLz4KPC9jbGlwUGF0aD4KPC9kZWZzPgo8L3N2Zz4K",
rdns: "co.pallad",
}

export const provider = {
_events,
request: async ({ method, params }: { method: string; params: any }) =>
await debouncedCall({
method,
payload: { ...params, origin: window.location.origin },
}),
isPallad: true,
on: _events.on,
off: _events.off,
}
37 changes: 37 additions & 0 deletions apps/extension/src/inject/rpc/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import debounce from "p-debounce"

const BROADCAST_CHANNEL_ID = "pallad"

const callPalladAsync = ({
method,
payload,
}: { method: string; payload: any }) => {
return new Promise((resolve, reject) => {
const privateChannelId = `private-${Math.random()}`
const channel = new BroadcastChannel(BROADCAST_CHANNEL_ID)
const responseChannel = new BroadcastChannel(privateChannelId)
const messageListener = ({ data }: any) => {
channel.close()
const error = data.response?.error
if (error) {
try {
console.table(JSON.parse(error.message))
} catch {
console.info(error.message)
}
return reject(error)
}
return resolve(data.response)
}
responseChannel.addEventListener("message", messageListener)
channel.postMessage({
method,
payload,
isPallad: true,
respondAt: privateChannelId,
})
return channel.close()
})
}

export const debouncedCall = debounce(callPalladAsync, 300)
10 changes: 10 additions & 0 deletions apps/extension/tsup.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { defineConfig } from "tsup"

export default defineConfig({
entry: ["./src/inject/rpc.ts"],
outDir: "public",
format: "esm",
noExternal: [/(.*)/],
splitting: false,
bundle: true,
})
1 change: 1 addition & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
"ignore": [
"apps/**/playwright-report/**/*",
"apps/**/dist/*.js",
"apps/**/public/rpc.js",
"apps/**/dist/*.ts",
"apps/**/dist/*.json",
"packages/**/build/**/*",
2 changes: 1 addition & 1 deletion packages/features/package.json
Original file line number Diff line number Diff line change
@@ -74,7 +74,7 @@
"tailwindcss-animate": "1.0.7",
"webext-bridge": "6.0.1",
"webextension-polyfill": "0.12.0",
"xss": "^1.0.15",
"xss": "1.0.15",
"yaml": "2.5.0",
"zod": "3.23.8",
"zustand": "4.5.4"
3 changes: 2 additions & 1 deletion packages/features/src/common/hooks/use-account.ts
Original file line number Diff line number Diff line change
@@ -65,10 +65,11 @@ export const useAccount = () => {
}
return {
...swr,
fetchWallet,
minaBalance,
gradientBackground,
copyWalletAddress,
accountInfo: currentWallet.accountInfo,
currentWallet,
publicKey,
lockWallet,
restartCurrentWallet,
11 changes: 10 additions & 1 deletion packages/features/src/common/store/app.ts
Original file line number Diff line number Diff line change
@@ -41,8 +41,16 @@ export const useAppStore = create<AppStore>()(
setVaultState(vaultState) {
return set({ vaultState })
},
setVaultStateInitialized: () => {
setVaultStateInitialized: async () => {
const { setVaultState } = get()
const { id } = chrome.runtime
const { permissions } = await chrome.storage.local.get("permissions")
await chrome.storage.local.set({
permissions: {
...permissions,
[`chrome-extension://${id}`]: "ALLOWED",
},
})
return setVaultState(VaultState.INITIALIZED)
},
setVaultStateUninitialized: () => {
@@ -54,6 +62,7 @@ export const useAppStore = create<AppStore>()(
},
}),
{
// Do not change this, may break Web Connector if not updated in Mina Provider.
name: "PalladApp",
storage: createJSONStorage(() => localPersistence),
},
20 changes: 14 additions & 6 deletions packages/features/src/components/address-dropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { truncateString } from "@/common/lib/string"
import { useVault } from "@palladxyz/vault"
import clsx from "clsx"
import { CopyIcon, ExternalLinkIcon, UserPlusIcon } from "lucide-react"
import { Link } from "react-router-dom"
import { toast } from "sonner"

@@ -52,18 +53,25 @@ export const AddressDropdown = ({
</div>
<ul className="p-2 shadow menu dropdown-content border-2 border-secondary z-[1] bg-neutral rounded-box w-52">
<li onClick={handleClick}>
<button type="button" onClick={copyAddress}>
Copy Address
<button type="button" onClick={copyAddress} className="flex gap-2">
<CopyIcon />
<span>Copy Address</span>
</button>
</li>
<li onClick={handleClick}>
<button type="button" onClick={openInExplorer}>
Open in Minascan
<button type="button" onClick={openInExplorer} className="flex gap-2">
<ExternalLinkIcon />
<span>Open in Minascan</span>
</button>
</li>
<li onClick={handleClick}>
<Link to="/contacts/new" state={{ address: publicKey }}>
Create Contact
<Link
to="/contacts/new"
state={{ address: publicKey }}
className="flex gap-2"
>
<UserPlusIcon />
<span>Create Contact</span>
</Link>
</li>
</ul>
6 changes: 3 additions & 3 deletions packages/features/src/components/fee-picker.tsx
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ export const FeePicker = ({ feeValue, setValue }: FeePickerProps) => {
<button
type="button"
className={clsx(
"btn flex-col join-item flex-nowrap",
"btn flex-1 flex-col join-item flex-nowrap",
feeValue === "slow" ? "btn-primary" : "btn-secondary",
)}
onClick={() => setValue("fee", "slow")}
@@ -44,7 +44,7 @@ export const FeePicker = ({ feeValue, setValue }: FeePickerProps) => {
<button
type="button"
className={clsx(
"btn flex-col join-item flex-1 flex-nowrap",
"btn flex-1 flex-col join-item flex-nowrap",
feeValue === "default" ? "btn-primary" : "btn-secondary",
)}
onClick={() => setValue("fee", "default")}
@@ -55,7 +55,7 @@ export const FeePicker = ({ feeValue, setValue }: FeePickerProps) => {
<button
type="button"
className={clsx(
"btn flex-col join-item flex-nowrap",
"btn flex-1 flex-col join-item flex-nowrap",
feeValue === "fast" ? "btn-primary" : "btn-secondary",
)}
onClick={() => setValue("fee", "fast")}
11 changes: 7 additions & 4 deletions packages/features/src/components/hash-dropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useVault } from "@palladxyz/vault"
import clsx from "clsx"
import { CopyIcon, ExternalLinkIcon } from "lucide-react"
import { toast } from "sonner"

type HashDropdownProps = {
@@ -37,13 +38,15 @@ export const HashDropdown = ({ hash, className }: HashDropdownProps) => {
</div>
<ul className="p-2 shadow menu dropdown-content border-2 border-secondary z-[1] bg-neutral rounded-box w-52">
<li onClick={handleClick}>
<button type="button" onClick={copyHash}>
Copy Hash
<button type="button" onClick={copyHash} className="flex gap-2">
<CopyIcon />
<span>Copy Hash</span>
</button>
</li>
<li onClick={handleClick}>
<button type="button" onClick={openInExplorer}>
Open in Minascan
<button type="button" onClick={openInExplorer} className="flex gap-2">
<ExternalLinkIcon />
<span>Open in Minascan</span>
</button>
</li>
</ul>
Original file line number Diff line number Diff line change
@@ -69,7 +69,7 @@ export const SeedBackupConfirmationRoute = () => {
"Test", // TODO: make this a configurable credential name or random if not provided
)
mixpanel.track("WalletCreated")
setVaultStateInitialized()
await setVaultStateInitialized()
return navigate("/onboarding/finish")
} finally {
setRestoring(false)
2 changes: 1 addition & 1 deletion packages/features/src/onboarding/routes/seed-import.tsx
Original file line number Diff line number Diff line change
@@ -61,7 +61,7 @@ export const SeedImportRoute = () => {
"Test", // TODO: make this a configurable credential name or random if not provided
)
mixpanel.track("WalletRestored")
setVaultStateInitialized()
await setVaultStateInitialized()
return navigate("/onboarding/finish")
} finally {
setRestoring(false)
3 changes: 2 additions & 1 deletion packages/features/src/receive/routes/receive.tsx
Original file line number Diff line number Diff line change
@@ -6,10 +6,11 @@ import { ReceiveView } from "../views/receive"

export const ReceiveRoute = () => {
const navigate = useNavigate()
const { copyWalletAddress, publicKey } = useAccount()
const { copyWalletAddress, publicKey, currentWallet } = useAccount()
return (
<ReceiveView
publicKey={publicKey}
walletName={currentWallet.credential.keyAgentName}
onCopyWalletAddress={copyWalletAddress}
onGoBack={() => navigate(-1)}
/>
4 changes: 3 additions & 1 deletion packages/features/src/receive/views/receive.tsx
Original file line number Diff line number Diff line change
@@ -5,12 +5,14 @@ import { MenuBar } from "@/components/menu-bar"

type ReceiveViewProps = {
publicKey: string
walletName: string
onGoBack: () => void
onCopyWalletAddress: () => void
}

export const ReceiveView = ({
publicKey,
walletName,
onGoBack,
onCopyWalletAddress,
}: ReceiveViewProps) => (
@@ -27,7 +29,7 @@ export const ReceiveView = ({
className="relative w-[140px] h-[140px]"
/>
<div className="space-y-3">
<h2 className="text-2xl text-secondary">Personal</h2>
<h2 className="text-2xl text-secondary">{walletName}</h2>
<p className="text-secondary break-all">{publicKey}</p>
<button
type="button"
2 changes: 1 addition & 1 deletion packages/features/src/router.tsx
Original file line number Diff line number Diff line change
@@ -56,7 +56,7 @@ export const Router = () => {
>
<ErrorBoundary FallbackComponent={ErrorView}>
<div className="flex flex-1 pointer">
<Toaster />
<Toaster theme="dark" />
<MemoryRouter>
<Routes>
<Route path="/" element={<StartRoute />} />
2 changes: 1 addition & 1 deletion packages/features/src/settings/routes/settings.tsx
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ export const SettingsRoute = () => {
const onDonateClicked = () => {
navigate("/send", {
state: {
address: "B62qkYa1o6Mj6uTTjDQCob7FYZspuhkm4RRQhgJg9j4koEBWiSrTQrS",
address: "B62qnVUL6A53E4ZaGd3qbTr6RCtEZYTu3kTijVrrquNpPo4d3MuJ3nb",
},
})
}
13 changes: 8 additions & 5 deletions packages/features/src/staking/routes/staking-overview.tsx
Original file line number Diff line number Diff line change
@@ -6,12 +6,15 @@ import { StakingOverviewView } from "../views/staking-overview"

export const StakingOverviewRoute = () => {
const account = useAccount()
const { accountInfo } = account.currentWallet
const { data: transactions } = useTransactions()
const rewardsTransactions = transactions?.filter(
(tx) =>
tx.from === account.accountInfo.MINA.delegate &&
tx.to === account.accountInfo.MINA.publicKey,
)
const rewardsTransactions = transactions
?.filter(
(tx) =>
tx.from === accountInfo.MINA.delegate &&
tx.to === accountInfo.MINA.publicKey,
)
.filter((tx) => tx.from !== accountInfo.MINA.publicKey)
const rewards = Array(6)
.fill({ amount: 0 })
.map((_, i) => ({ amount: rewardsTransactions?.[i]?.amount ?? 0 }))
6 changes: 4 additions & 2 deletions packages/features/src/staking/views/staking-overview.tsx
Original file line number Diff line number Diff line change
@@ -44,15 +44,17 @@ export const StakingOverviewView = ({
stats,
}: StakingOverviewViewProps) => (
<AppLayout>
<div className="card flex-1 flex-col bg-secondary rounded-t-none pb-6">
<div className="card flex-col bg-secondary rounded-t-none pb-6">
<MenuBar variant="dashboard" />
<div className="flex flex-col gap-6 px-8">
<h1 className="text-3xl">Staking</h1>
{stakeDelegated ? (
<div className="flex flex-row justify-between items-center card bg-neutral p-6">
<div className="flex flex-col">
<AddressDropdown
publicKey={account?.accountInfo?.MINA?.delegate ?? ""}
publicKey={
account?.currentWallet.accountInfo?.MINA?.delegate ?? ""
}
className="before:ml-16"
/>
</div>
11 changes: 10 additions & 1 deletion packages/features/src/transactions/routes/transactions.tsx
Original file line number Diff line number Diff line change
@@ -2,21 +2,29 @@ import { useEffect } from "react"

import { useAccount } from "@/common/hooks/use-account"
import { useTransactions } from "@/common/hooks/use-transactions"
import { usePendingTransactionStore } from "@palladxyz/vault"
import { usePendingTransactionStore, useVault } from "@palladxyz/vault"

import { useFiatPrice } from "@palladxyz/offchain-data"
import { TransactionsView } from "../views/transactions"

export const TransactionsRoute = () => {
const { publicKey } = useAccount()
const { current: rawFiatPrice } = useFiatPrice()
const currentNetworkInfo = useVault((state) => state.getCurrentNetworkInfo())
const clearExpired = usePendingTransactionStore((state) => state.clearExpired)
const { data: transactions, error: transactionsError } = useTransactions()
const pendingHashes = usePendingTransactionStore((state) =>
state.pendingTransactions
.map((tx) => tx.hash)
.filter((hash) => !transactions?.map((tx) => tx.hash).includes(hash)),
)
const openPendingTransactions = () => {
const url = currentNetworkInfo.explorer.accountUrl.replace(
"{publicKey}",
publicKey,
)
window.open(`${url}/txs`, "_blank")?.focus()
}
// biome-ignore lint: only run on first render
useEffect(() => {
clearExpired()
@@ -28,6 +36,7 @@ export const TransactionsRoute = () => {
publicKey={publicKey}
transactions={transactions ?? []}
transactionsError={transactionsError}
openPendingTransactions={openPendingTransactions}
/>
)
}
7 changes: 6 additions & 1 deletion packages/features/src/transactions/views/transactions.tsx
Original file line number Diff line number Diff line change
@@ -48,6 +48,7 @@ type TransactionsViewProps = {
publicKey: string
transactions: Mina.TransactionBody[]
transactionsError: boolean
openPendingTransactions: () => void
}

export const TransactionsView = ({
@@ -56,6 +57,7 @@ export const TransactionsView = ({
publicKey,
transactions,
transactionsError,
openPendingTransactions,
}: TransactionsViewProps) => {
const [filtersOpen, setFiltersOpen] = useState(false)
const [currentFilter, setCurrentFilter] = useState(Filters.all)
@@ -118,7 +120,10 @@ export const TransactionsView = ({
<div className="px-8 pb-8 mt-6 space-y-4">
{pendingHashes.length > 0 && (
<p data-testid="transactions/pendingTransactions">
There are pending transactions.
There are pending transactions.{" "}
<button type="button" onClick={openPendingTransactions}>
Preview
</button>
</p>
)}
{Object.values(txsGrouped).map((txs) => (
8 changes: 6 additions & 2 deletions packages/features/src/wallet/routes/networks.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { useAccount } from "@/common/hooks/use-account"
import { useVault } from "@palladxyz/vault"
import { useNavigate } from "react-router-dom"
import { sendMessage } from "webext-bridge/popup"
import { NetworksView } from "../views/networks"

export const NetworksRoute = () => {
const navigate = useNavigate()
const switchNetwork = useVault((state) => state.switchNetwork)
const currentNetworkName = useVault((state) => state.currentNetworkName)
const { fetchWallet } = useAccount()
const onNetworkSwitch = async (network: string) => {
await switchNetwork(network)
await sendMessage("pallad_switchNetwork", { network })
await useVault.persist.rehydrate()
await fetchWallet()
navigate("/dashboard")
}
return (
7 changes: 7 additions & 0 deletions packages/features/src/web-connector/routes/web-connector.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useEffect, useState } from "react"
import type { SubmitHandler } from "react-hook-form"
import { MemoryRouter } from "react-router-dom"
import { sendMessage } from "webext-bridge/popup"
import { runtime, windows } from "webextension-polyfill"
import xss from "xss"
import yaml from "yaml"
@@ -18,6 +19,7 @@ type ActionRequest = {
payload: string
inputType: "text" | "password" | "confirmation"
loading: boolean
emitConnected: boolean
}

export const WebConnectorRoute = () => {
@@ -26,6 +28,7 @@ export const WebConnectorRoute = () => {
payload: "",
inputType: "confirmation",
loading: true,
emitConnected: false,
})
const onSubmit: SubmitHandler<UserInputForm> = async ({ userInput }) => {
const { id } = await windows.getCurrent()
@@ -41,6 +44,9 @@ export const WebConnectorRoute = () => {
userConfirmed: true,
windowId: id,
})
if (request.emitConnected) {
await sendMessage("pallad_connected", {}, "background")
}
window.close()
}
const decline = async () => {
@@ -67,6 +73,7 @@ export const WebConnectorRoute = () => {
payload: await sanitizePayload(message.params.payload),
inputType: message.params.inputType,
loading: false,
emitConnected: message.params.emitConnected,
})
}
})
2 changes: 1 addition & 1 deletion packages/vault/package.json
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@
"@palladxyz/pallad-core": "workspace:*",
"@palladxyz/providers": "workspace:*",
"@palladxyz/util": "workspace:*",
"@plasmohq/storage": "^1.11.0",
"@plasmohq/storage": "1.11.0",
"bs58check": "4.0.0",
"buffer": "6.0.3",
"dayjs": "1.11.12",
9 changes: 6 additions & 3 deletions packages/vault/src/vault/utils/get-current-wallet.ts
Original file line number Diff line number Diff line change
@@ -33,12 +33,15 @@ export function getCurrentWalletHelper(get: any) {
const credential = getCredential(credentialName)
const publicKey = getPublicKey(credential)
const providerConfig = getCurrentNetworkInfo()
const accountsInfo = getAccountsInfo(providerConfig.networkName, publicKey)
const { accountInfo, transactions } = getAccountsInfo(
providerConfig.networkName,
publicKey,
)

return {
singleKeyAgentState,
credential,
accountInfo: accountsInfo.accountInfo,
transactions: accountsInfo.transactions,
accountInfo,
transactions,
}
}
3 changes: 2 additions & 1 deletion packages/web-provider/package.json
Original file line number Diff line number Diff line change
@@ -24,8 +24,9 @@
"@palladxyz/providers": "workspace:*",
"@palladxyz/vault": "workspace:*",
"dayjs": "1.11.12",
"eventemitter3": "5.0.1",
"eventemitter3": "^5.0.1",
"mina-signer": "3.0.7",
"mitt": "3.0.1",
"superjson": "2.2.1",
"webext-bridge": "6.0.1",
"webextension-polyfill": "0.12.0",
328 changes: 89 additions & 239 deletions packages/web-provider/src/mina-network/mina-provider.ts

Large diffs are not rendered by default.

81 changes: 0 additions & 81 deletions packages/web-provider/src/mina-network/types.ts
Original file line number Diff line number Diff line change
@@ -1,96 +1,17 @@
import type { MinaSignablePayload } from "@palladxyz/key-management"
import type { ProviderConfig } from "@palladxyz/providers"

import type {
ProviderAccounts,
ProviderChainId,
ProviderConnectInfo,
ProviderEvent,
ProviderEventArguments,
ProviderMessage,
ProviderRpcError,
RequestArguments,
} from "../web-provider-types"
import type { MinaProvider } from "./mina-provider"

export type RequestSignableData = {
data: MinaSignablePayload
}

export interface OffchainSessionAllowedMethods {
contractAddress: string
method: string
}

export type RequestOffchainSession = {
data: {
sessionKey: string
expirationTime: string
allowedMethods: OffchainSessionAllowedMethods[]
sessionMerkleRoot: MinaSignablePayload
}
}

export type RequestSignableTransaction = {
data: { transaction: MinaSignablePayload }
}

export type RequestDataFields = {
data: {
fields: number[] | bigint[]
}
}

export type RequestDataNullifier = {
data: {
message: number[] | bigint[]
}
}

export type RequestAddChain = {
data: ProviderConfig
}

export type RequestSwitchChain = {
data: { chainId: string }
}

export interface MinaRpcProviderMap {
[chainId: string]: IMinaProviderBase
}

export interface EIP1102Request extends RequestArguments {
method: "mina_requestAccounts"
}

// IMinaProviderEvents interface
export interface IMinaProviderEvents {
on: <E extends ProviderEvent>(
event: E,
listener: (args: ProviderEventArguments[E]) => void,
) => MinaProvider

once: <E extends ProviderEvent>(
event: E,
listener: (args: ProviderEventArguments[E]) => void,
) => MinaProvider

off: <E extends ProviderEvent>(
event: E,
listener: (args: ProviderEventArguments[E]) => void,
) => MinaProvider

removeListener: <E extends ProviderEvent>(
event: E,
listener: (args: ProviderEventArguments[E]) => void,
) => MinaProvider

//emit: <E extends ProviderEvent>(
// event: E,
// payload: ProviderEventArguments[E]
//) => boolean
}

// originally the EIP1193Provider interface
export interface IMinaProviderBase {
// connection event
@@ -120,6 +41,4 @@ export interface IMinaProviderBase {
): MinaProvider
// make an Ethereum RPC method call.
request(args: RequestArguments): Promise<unknown>
// legacy alias for EIP-1102
enable({ origin }: { origin: string }): Promise<ProviderAccounts>
}
4 changes: 2 additions & 2 deletions packages/web-provider/src/universal-provider/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { EventEmitter } from "eventemitter3"
import type { Emitter } from "mitt"

import type { RequestArguments } from "../web-provider-types"

@@ -23,7 +23,7 @@ export interface IProvider {
}

export abstract class IEvents {
public abstract events: EventEmitter
public abstract events: Emitter

// events
public abstract on(event: string, listener: any): void
17 changes: 13 additions & 4 deletions packages/web-provider/src/utils/prompts.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
export const showUserPrompt = async (
inputType: "text" | "password" | "confirmation",
metadata: { title: string; payload?: string },
) => {
type InputType = "text" | "password" | "confirmation"
type Metadata = { title: string; payload?: string }

export const showUserPrompt = async ({
inputType,
metadata,
emitConnected = false,
}: {
inputType: InputType
metadata: Metadata
emitConnected?: boolean
}) => {
return new Promise((resolve, reject) => {
chrome.windows
.create({
@@ -38,6 +46,7 @@ export const showUserPrompt = async (
title: metadata.title,
payload: metadata.payload ?? "{}",
inputType,
emitConnected,
},
})
}, 1000)
1 change: 0 additions & 1 deletion packages/web-provider/src/web-provider-types/data-model.ts
Original file line number Diff line number Diff line change
@@ -41,7 +41,6 @@ export interface ChainRpcConfig {
optionalChains: string[]
methods: string[]
optionalMethods?: string[]
unauthorizedMethods?: string[]
/**
* @description Events that the wallet MUST support or the connection will be rejected
*/
21 changes: 2 additions & 19 deletions packages/web-provider/test/mina/mina-provider.test.ts
Original file line number Diff line number Diff line change
@@ -138,7 +138,7 @@ describe.skip("Wallet Provider Test", () => {
it("should emit connect event on successful connection when using `enable` method", async () => {
// Listen to the connect event
const connectListener = vi.fn()
provider.on("connect", connectListener)
provider.emitter.on("connect", connectListener)

// Trigger connection
const result = await provider.enable({ origin: TEST_ORIGIN })
@@ -308,7 +308,7 @@ describe.skip("Wallet Provider Test", () => {
it.skip("should switch the network successfully when requesting the balance of another chain id", async () => {
// Listen to the chains changed event
const connectListener = vi.fn()
provider.on("chainChanged", connectListener)
provider.emitter.on("chainChanged", connectListener)

const switchNetworkRequestArgs: RequestArguments = {
method: "mina_getBalance",
@@ -363,22 +363,5 @@ describe.skip("Wallet Provider Test", () => {
}),
)
})

it("should emit disconnect event with ProviderRpcError code 4900 when not connected", () => {
// Listen to the disconnect event
const disconnectListener = vi.fn()
provider.on("disconnect", disconnectListener)

// Call the disconnect method
provider.disconnect({ origin: TEST_ORIGIN })

// Assert that the disconnect event was emitted with the correct error
expect(disconnectListener).toHaveBeenCalledWith(
expect.objectContaining({
code: 4900,
message: "Disconnected",
}),
)
})
})
})
37 changes: 23 additions & 14 deletions pnpm-lock.yaml

0 comments on commit 0ce65dc

Please sign in to comment.