Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 0 additions & 48 deletions packages/injected-script/main/EthBridge/methods.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const { defineProperty, deleteProperty } = Reflect
const setTimeoutCaptured = setTimeout.bind(window)
const clearTimeoutCaptured = clearTimeout.bind(window)
export function hookInputUploadOnce(...[format, fileName, fileArray]: InternalEvents['hookInputUploadOnce']) {
let timer: number | null = null
let timer: NodeJS.Timeout | null = null
const e = new no_xray_Event('change', {
bubbles: true,
cancelable: true,
Expand Down
54 changes: 54 additions & 0 deletions packages/injected-script/main/GlobalVariableBridge/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { apply } from '../intrinsic'
import { clone_into, handlePromise, sendEvent } from '../utils'
import type { InternalEvents } from '../../shared'

const hasListened: Record<string, boolean> = { __proto__: null! }
Comment thread
Jack-Works marked this conversation as resolved.
const { has } = Reflect
const { Promise, setTimeout } = window
const { resolve } = Promise
const { split } = String.prototype
const { shift } = Array.prototype

function read(path: string) {
const fragments = apply(split, path, ['.' as any])
let result: any = window
while (true) {
if (fragments.length === 0) return result
const key = apply(shift, fragments, [])
result = key ? result[key] : result
}
}

export function access(path: string, id: number, property: string) {
handlePromise(id, () => read(path)[property])
}

export function callRequest(path: string, id: number, request: unknown) {
handlePromise(id, () => read(path).request(request))
}

export function bindEvent(path: string, bridgeEvent: keyof InternalEvents, event: string) {
if (hasListened[event]) return
hasListened[event] = true
read(path).on(
event,
clone_into((...args: any[]) => {
sendEvent(bridgeEvent, event, args)
}),
)
}

function untilInner(name: string) {
if (has(window, name)) return apply<(result: true) => Promise<true>>(resolve, Promise, [true])
return new Promise<true>((r) => {
function check() {
if (has(window, name)) return r(true)
apply(setTimeout, window, [check, 200])
}
check()
})
}

export function until(path: string, id: number) {
handlePromise(id, () => untilInner(path))
}
1 change: 0 additions & 1 deletion packages/injected-script/main/SolanaBridge/index.ts

This file was deleted.

43 changes: 0 additions & 43 deletions packages/injected-script/main/SolanaBridge/methods.ts

This file was deleted.

53 changes: 24 additions & 29 deletions packages/injected-script/main/communicate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,8 @@ import { getCustomEventDetail, apply, warn } from './intrinsic'
import { dispatchInput } from './EventListenerPatch/dispatchInput'
import { dispatchPaste } from './EventListenerPatch/dispatchPaste'
import { dispatchPasteImage } from './EventListenerPatch/dispatchPasteImage'
import {
ethBridgeSendRequest,
ethBridgeIsConnected,
ethBridgeMetaMaskIsUnlocked,
ethBridgePrimitiveAccess,
ethBridgeWatchEvent,
untilEthereumOnline,
} from './EthBridge/methods'
import { callRequest, access, bindEvent, until } from './GlobalVariableBridge'
import { hookInputUploadOnce } from './EventListenerPatch/hookInputUploadOnce'
import {
solanaBridgeIsConnected,
solanaBridgePrimitiveAccess,
solanaBridgeSendRequest,
solanaBridgeWatchEvent,
untilSolanaOnline,
} from './SolanaBridge'

document.addEventListener(CustomEventId, (e) => {
const r = decodeEvent(getCustomEventDetail(e as CustomEvent))
Expand All @@ -41,33 +27,42 @@ document.addEventListener(CustomEventId, (e) => {
case 'resolvePromise':
return

// solana
case 'solanaBridgeRequestListen':
return apply(solanaBridgeWatchEvent, null, r[1])
return apply(bindEvent, null, ['solana', 'solanaBridgeOnEvent', ...r[1]])
case 'solanaBridgeSendRequest':
return apply(solanaBridgeSendRequest, null, r[1])
case 'solanaBridgeIsConnected':
return apply(solanaBridgeIsConnected, null, r[1])
return apply(callRequest, null, ['solana', ...r[1]])
case 'solanaBridgePrimitiveAccess':
return apply(solanaBridgePrimitiveAccess, null, r[1])
return apply(access, null, ['solana', ...r[1]])
case 'untilSolanaBridgeOnline':
return apply(untilSolanaOnline, null, r[1])
return apply(until, null, ['solana', ...r[1]])
case 'solanaBridgeOnEvent':
return

// ethereum
case 'ethBridgeRequestListen':
return apply(ethBridgeWatchEvent, null, r[1])
return apply(bindEvent, null, ['ethereum', 'ethBridgeOnEvent', ...r[1]])
case 'ethBridgeSendRequest':
return apply(ethBridgeSendRequest, null, r[1])
case 'ethBridgeIsConnected':
return apply(ethBridgeIsConnected, null, r[1])
case 'ethBridgeMetaMaskIsUnlocked':
return apply(ethBridgeMetaMaskIsUnlocked, null, r[1])
return apply(callRequest, null, ['ethereum', ...r[1]])
case 'ethBridgePrimitiveAccess':
return apply(ethBridgePrimitiveAccess, null, r[1])
return apply(access, null, ['ethereum', ...r[1]])
case 'untilEthBridgeOnline':
return apply(untilEthereumOnline, null, r[1])
return apply(until, null, ['ethereum', ...r[1]])
case 'ethBridgeOnEvent':
return

// coin98
case 'coin98BridgeRequestListen':
return apply(bindEvent, null, ['coin98.provider', 'coin98BridgeOnEvent', ...r[1]])
case 'coin98BridgeSendRequest':
return apply(callRequest, null, ['coin98.provider', ...r[1]])
case 'coin98BridgePrimitiveAccess':
return apply(access, null, ['coin98.provider', ...r[1]])
case 'untilCoin98BridgeOnline':
return apply(until, null, ['coin98', ...r[1]])
case 'coin98BridgeOnEvent':
return

default:
const neverEvent: never = r[0]
warn('[@masknet/injected-script]', neverEvent, 'not handled')
Expand Down
61 changes: 61 additions & 0 deletions packages/injected-script/sdk/bridgedCoin98.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import type { RequestArguments } from 'web3-core'
import type { JsonRpcPayload, JsonRpcResponse } from 'web3-core-helpers'
import type { EthereumProvider } from '../shared'
import { createPromise, sendEvent } from './utils'

function request(data: RequestArguments) {
return createPromise((id) => sendEvent('coin98BridgeSendRequest', id, data))
}

function send(payload: JsonRpcPayload, callback: (error: Error | null, result?: JsonRpcResponse) => void) {
createPromise((id) =>
sendEvent('coin98BridgeSendRequest', id, {
method: payload.method,
params: payload.params,
}),
).then(
(value) => {
callback(null, {
jsonrpc: '2.0',
id: payload.id as number,
result: value,
})
},
(error) => {
if (error instanceof Error) callback(error)
},
)
}

/** Interact with the current ethereum provider */
export const bridgedCoin98Provider: EthereumProvider = {
request,
send,
sendAsync: send,
on(event, callback) {
if (!bridgedCoin98.has(event)) {
bridgedCoin98.set(event, new Set())
sendEvent('coin98BridgeRequestListen', event)
}
const map = bridgedCoin98.get(event)!
map.add(callback)
return () => void map.delete(callback)
},
getProperty(key) {
return createPromise((id) => sendEvent('coin98BridgePrimitiveAccess', id, key))
},
untilAvailable() {
return createPromise((id) => sendEvent('untilCoin98BridgeOnline', id))
},
}

const bridgedCoin98 = new Map<string, Set<Function>>()
/** @internal */
export function onCoin98Event(event: string, data: unknown[]) {
for (const f of bridgedCoin98.get(event) || []) {
try {
Reflect.apply(f, null, data)
} catch {}
}
return
}
30 changes: 3 additions & 27 deletions packages/injected-script/sdk/bridgedEthereum.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { RequestArguments } from 'web3-core'
import type { JsonRpcPayload, JsonRpcResponse } from 'web3-core-helpers'
import type { EthereumProvider } from '../shared'
import { createPromise, sendEvent } from './utils'

function request(data: RequestArguments) {
Expand Down Expand Up @@ -27,7 +28,7 @@ function send(payload: JsonRpcPayload, callback: (error: Error | null, result?:
}

/** Interact with the current ethereum provider */
export const bridgedEthereumProvider: BridgedEthereumProvider = {
export const bridgedEthereumProvider: EthereumProvider = {
request,
send,
sendAsync: send,
Expand All @@ -43,36 +44,11 @@ export const bridgedEthereumProvider: BridgedEthereumProvider = {
getProperty(key) {
return createPromise((id) => sendEvent('ethBridgePrimitiveAccess', id, key))
},
_metamaskIsUnlocked() {
return createPromise((id) => sendEvent('ethBridgeMetaMaskIsUnlocked', id))
},
isConnected() {
return createPromise((id) => sendEvent('ethBridgeIsConnected', id))
},
untilAvailable() {
return createPromise((id) => sendEvent('untilEthBridgeOnline', id))
},
}
export interface BridgedEthereumProvider {
/** Wait for window.ethereum object appears. */
untilAvailable(): Promise<true>
/** Send JSON RPC to the eth provider. */
request(data: RequestArguments): Promise<unknown>
/** Send JSON RPC */
send(payload: JsonRpcPayload, callback: (error: Error | null, result?: JsonRpcResponse) => void): void
/** Async send JSON RPC */
sendAsync(payload: JsonRpcPayload, callback: (error: Error | null, result?: JsonRpcResponse) => void): void
/** Add event listener */
on(event: string, callback: (...args: any) => void): () => void
/** Access primitive property on the window.ethereum object. */
getProperty(
key: 'isMaskWallet' | 'isMetaMask' | 'isCoin98' | 'isMathWallet' | 'isWalletLink',
): Promise<boolean | undefined>
/** MetaMask only, experimental API. */
_metamaskIsUnlocked(): Promise<boolean>
/** Call window.ethereum.isConnected() */
isConnected(): Promise<boolean>
}

const bridgedEthereum = new Map<string, Set<Function>>()
/** @internal */
export function onEthEvent(event: string, data: unknown[]) {
Expand Down
Loading