Skip to content

Commit

Permalink
Create mux transport template
Browse files Browse the repository at this point in the history
  • Loading branch information
Agusx1211 committed Jul 20, 2023
1 parent e5ac749 commit ac0ae66
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 82 deletions.
29 changes: 18 additions & 11 deletions packages/provider/src/client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { JsonRpcRequest, NetworkConfig, allNetworks, findNetworkConfig } from "@0xsequence/network"
import { ConnectDetails, ConnectOptions, ItemStore, OpenWalletIntent, ProviderTransport, WalletSession } from "."
import { ConnectDetails, ConnectOptions, ItemStore, MuxMessageProvider, MuxTransportTemplate, OpenWalletIntent, ProviderTransport, WalletSession, isMuxTransportTemplate } from "."
import { commons } from "@0xsequence/core"
import { TypedData } from "@0xsequence/utils"
import { toExtended } from "./extended"
Expand Down Expand Up @@ -110,41 +110,48 @@ export class DefaultChainIDTracker {
*
* It doesn't implement a full ethereum Provider, it doesn't include read-only methods.
*/
export class SequenceClient {
private session: SequenceClientSession
private defaultChainId: DefaultChainIDTracker
export class SequenceClient {
private readonly session: SequenceClientSession
private readonly defaultChainId: DefaultChainIDTracker
private readonly callbacks: { [K in keyof Callbacks]?: Callbacks[K][] } = {}

callbacks: { [K in keyof Callbacks]?: Callbacks[K][] } = {}
public readonly transport: ProviderTransport

constructor (
public transport: ProviderTransport,
transport: ProviderTransport | MuxTransportTemplate,
store: ItemStore,
defaultChainId?: number
) {
if (isMuxTransportTemplate(transport)) {
this.transport = MuxMessageProvider.new(transport)
} else {
this.transport = transport
}

this.session = new SequenceClientSession(store)
this.defaultChainId = new DefaultChainIDTracker(store, defaultChainId)

transport.on('accountsChanged', (accounts: string[]) => {
this.transport.on('accountsChanged', (accounts: string[]) => {
if (accounts.length > 1) {
console.warn('SequenceClient: wallet-webapp returned more than one account')
}

this.callbacks.onAccountsChanged?.forEach(cb => cb(accounts))
})

transport.on('networks', (networks: NetworkConfig[]) => {
this.transport.on('networks', (networks: NetworkConfig[]) => {
this.callbacks.onNetworks?.forEach(cb => cb(networks))
})

transport.on('walletContext', (context: commons.context.VersionedContext) => {
this.transport.on('walletContext', (context: commons.context.VersionedContext) => {
this.callbacks.onWalletContext?.forEach(cb => cb(context))
})

transport.on('open', () => {
this.transport.on('open', () => {
this.callbacks.onOpen?.forEach(cb => cb())
})

transport.on('close', () => {
this.transport.on('close', () => {
this.callbacks.onOpen?.forEach(cb => cb())
})

Expand Down
75 changes: 6 additions & 69 deletions packages/provider/src/init.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { CachedProvider, ChainIdLike, JsonRpcRouter, JsonRpcSender, NetworkConfig, allNetworks, exceptionProviderMiddleware, findNetworkConfig, loggingProviderMiddleware } from "@0xsequence/network"
import { ExtensionMessageProvider, MuxMessageProvider, ProxyMessageChannelPort, ProxyMessageProvider, UnrealMessageProvider, WindowMessageProvider } from "./transports"
import { MuxTransportTemplate } from "./transports"
import { ItemStore, LocalStorage } from "./utils"
import { Runtime } from "webextension-polyfill"
import { ethers } from "ethers"
import { SequenceClient } from "./client"
import { SequenceProvider } from "./provider"
Expand All @@ -12,9 +11,6 @@ export interface ProviderConfig {
// For example, this option should be used when using React Native since window.localStorage is not available.
localStorage?: ItemStore

// Sequence Wallet App URL, default: https://sequence.app
walletAppURL: string

// defaultNetwork is the primary network of a dapp and the default network a
// provider will communicate. Note: this setting is also configurable from the
// Wallet constructor's first argument. If both are specified, then they
Expand All @@ -30,46 +26,19 @@ export interface ProviderConfig {
// defined in sequence.js.
networks?: Partial<NetworkConfig>[]

// networkRpcUrl will set the provider rpcUrl of the default network
networkRpcUrl?: string

// transports for dapp to wallet jron-rpc communication
transports?: {
// WindowMessage transport (optional)
windowTransport?: {
enabled: boolean
}

// ProxyMessage transport (optional)
proxyTransport?: {
enabled: boolean
appPort?: ProxyMessageChannelPort
}

// Extension transport (optional)
extensionTransport?: {
enabled: boolean
runtime: Runtime.Static
}

// Unreal Engine transport (optional)
unrealTransport?: {
enabled: boolean
}
}
transports?: MuxTransportTemplate
}

export const DefaultProviderConfig: ProviderConfig = {
walletAppURL: 'https://sequence.app',

export const DefaultProviderConfig = {
transports: {
walletAppURL: 'https://sequence.app',
windowTransport: { enabled: true },
proxyTransport: { enabled: false }
},

defaultNetwork: 1,
defaultNetworkId: 1
} as any
}

let sequenceWalletProvider: SequenceProvider | undefined

Expand Down Expand Up @@ -124,38 +93,6 @@ export const initWallet = (
return rpcProviders[chainId]
}

// Build transport
// TODO: Move this to transports
const muxMessageProvider = new MuxMessageProvider()

if (config.transports?.windowTransport?.enabled && typeof window === 'object') {
const windowMessageProvider = new WindowMessageProvider(config.walletAppURL)
muxMessageProvider.add(windowMessageProvider)
}

if (config.transports?.proxyTransport?.enabled) {
const proxyMessageProvider = new ProxyMessageProvider(config.transports.proxyTransport.appPort!)
muxMessageProvider.add(proxyMessageProvider)
}

if (config.transports?.extensionTransport?.enabled) {
const extensionMessageProvider = new ExtensionMessageProvider(config.transports.extensionTransport.runtime)
muxMessageProvider.add(extensionMessageProvider)

// NOTE/REVIEW: see note in mux-message-provider
//
// We don't add the extensionMessageProvider here because we don't send requests to it anyways, we seem to
// send all requests to the WindowMessageProvider anyways. By allowing it, if browser restarts, it will break
// the entire extension because messageProvider.provider will be undefined. So this is a hack to fix it.
}

if (config.transports?.unrealTransport?.enabled) {
const unrealMessageProvider = new UnrealMessageProvider(config.walletAppURL)
muxMessageProvider.add(unrealMessageProvider)
}

muxMessageProvider.register()

// This is the starting default network (as defined by the config)
// it can be later be changed using `wallet_switchEthereumChain` or some
// of the other methods on the provider.
Expand All @@ -168,7 +105,7 @@ export const initWallet = (
const itemStore = config.localStorage || LocalStorage.getInstance()

// Create client, provider and return signer
const client = new SequenceClient(muxMessageProvider, itemStore, defaultNetwork)
const client = new SequenceClient(config.transports, itemStore, defaultNetwork)
sequenceWalletProvider = new SequenceProvider(client, providerForChainId)

return sequenceWalletProvider
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,62 @@
import {
ProviderMessage, EventType, ProviderTransport,
ProviderMessage, ProviderTransport,
ProviderEventTypes, ProviderMessageRequest, ProviderMessageResponse, WalletSession, OpenWalletIntent, ConnectDetails
} from '../../types'

import { JsonRpcRequest, JsonRpcResponseCallback } from '@0xsequence/network'
import { ProxyMessageChannelPort, ProxyMessageProvider } from '../proxy-transport'
import { Runtime } from 'webextension-polyfill'
import { UnrealMessageProvider } from '../unreal-transport'
import { ExtensionMessageProvider } from '../extension-transport'
import { WindowMessageProvider } from '../window-transport'

export class MuxMessageProvider implements ProviderTransport {
export type MuxTransportTemplate = {
walletAppURL?: string

// WindowMessage transport (optional)
windowTransport?: {
enabled: boolean
}

// ProxyMessage transport (optional)
proxyTransport?: {
enabled: boolean
appPort?: ProxyMessageChannelPort
}

// Extension transport (optional)
extensionTransport?: {
enabled: boolean
runtime: Runtime.Static
}

// Unreal Engine transport (optional)
unrealTransport?: {
enabled: boolean
}
}

export function isMuxTransportTemplate(obj: any): obj is MuxTransportTemplate {
return (
obj &&
typeof obj === 'object' &&
(
(obj.windowTransport && typeof obj.windowTransport === 'object') ||
(obj.proxyTransport && typeof obj.proxyTransport === 'object') ||
(obj.extensionTransport && typeof obj.extensionTransport === 'object') ||
(obj.unrealTransport && typeof obj.unrealTransport === 'object')
) &&
(
// One of the transports must be enabled
(obj.windowTransport && obj.windowTransport.enabled) ||
(obj.proxyTransport && obj.proxyTransport.enabled) ||
(obj.extensionTransport && obj.extensionTransport.enabled) ||
(obj.unrealTransport && obj.unrealTransport.enabled)
)
)
}

export class MuxMessageProvider implements ProviderTransport {
private messageProviders: ProviderTransport[]
private provider: ProviderTransport | undefined

Expand All @@ -15,6 +65,40 @@ export class MuxMessageProvider implements ProviderTransport {
this.provider = undefined
}

static new(template: MuxTransportTemplate): MuxMessageProvider {
const muxMessageProvider = new MuxMessageProvider()

if (template.windowTransport?.enabled && typeof window === 'object' && template.walletAppURL) {
const windowMessageProvider = new WindowMessageProvider(template.walletAppURL)
muxMessageProvider.add(windowMessageProvider)
}

if (template.proxyTransport?.enabled) {
const proxyMessageProvider = new ProxyMessageProvider(template.proxyTransport.appPort!)
muxMessageProvider.add(proxyMessageProvider)
}

if (template.extensionTransport?.enabled) {
const extensionMessageProvider = new ExtensionMessageProvider(template.extensionTransport.runtime)
muxMessageProvider.add(extensionMessageProvider)

// NOTE/REVIEW: see note in mux-message-provider
//
// We don't add the extensionMessageProvider here because we don't send requests to it anyways, we seem to
// send all requests to the WindowMessageProvider anyways. By allowing it, if browser restarts, it will break
// the entire extension because messageProvider.provider will be undefined. So this is a hack to fix it.
}

if (template.unrealTransport?.enabled && template.windowTransport && template.walletAppURL) {
const unrealMessageProvider = new UnrealMessageProvider(template.walletAppURL)
muxMessageProvider.add(unrealMessageProvider)
}

muxMessageProvider.register()

return muxMessageProvider
}

add(...messageProviders: ProviderTransport[]) {
this.messageProviders.push(...messageProviders)
}
Expand Down

0 comments on commit ac0ae66

Please sign in to comment.