Skip to content

Commit

Permalink
backports wagmi's viem implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
douglance committed Jul 6, 2023
1 parent ba4dae0 commit 9deb273
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 48 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"name": "Test File",
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
"args": [
"${workspaceFolder}/tests/integration/universalSigner.test.ts"
"${workspaceFolder}/tests/integration/universalProvider.test.ts"
],
"internalConsoleOptions": "openOnSessionStart",
"runtimeVersion": "16.16.0",
Expand Down
144 changes: 102 additions & 42 deletions src/lib/utils/providerTransforms.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
import { EthBridger } from '../assetBridger/ethBridger'
import { getL2Network } from '../dataEntities/networks'
import { JsonRpcProvider, WebSocketProvider } from '@ethersproject/providers'

export type Providerish = {
_getConnection?: () => { url?: unknown }
currentProvider?: { clientUrl?: unknown }
transport?: { url?: unknown }
connection?: { url?: unknown }
clientUrl?: unknown
_socketPath?: unknown
}
import EthersV5, {
JsonRpcProvider,
WebSocketProvider,
FallbackProvider,
} from '@ethersproject/providers'
import { HttpTransport, PublicClient } from 'viem'
import EthersV6 from 'ethers-v6'
import Web3, { Web3BaseProvider } from 'web3'

export type Providerish =
| PublicClient
| EthersV5.JsonRpcProvider
| EthersV6.JsonRpcProvider
| Web3BaseProvider
| Web3

export const getEthersV5Url = (provider: Providerish) => {
if (typeof provider.connection === 'object') {
const connection = provider.connection
const url = connection.url
if (isEthersV5JsonRpcProvider(provider)) {
const url = provider.connection.url
if (typeof url === 'string') {
return url
}
Expand All @@ -23,7 +25,7 @@ export const getEthersV5Url = (provider: Providerish) => {
}

export const getEthersV6Url = (provider: Providerish) => {
if (typeof provider._getConnection === 'function') {
if (isEthers6Provider(provider)) {
const connection = provider._getConnection()
const url = connection.url
if (typeof url === 'string') {
Expand All @@ -34,40 +36,95 @@ export const getEthersV6Url = (provider: Providerish) => {
}

export const getWeb3Url = (provider: Providerish) => {
if ('clientUrl' in provider && typeof provider.clientUrl === 'string') {
const url = provider.clientUrl
return url
}
if (
'currentProvider' in provider &&
typeof provider.currentProvider === 'object' &&
'clientUrl' in provider?.currentProvider &&
typeof provider.currentProvider.clientUrl === 'string'
) {
const url = provider.currentProvider.clientUrl
if (typeof url === 'string') {
return url
if (isHttpProvider(provider)) {
// @ts-expect-error - private member
if (provider.clientUrl) {
// @ts-expect-error - private member
return provider.clientUrl
// @ts-expect-error - private member
} else if (provider.currentProvider && provider.currentProvider.clientUrl) {
// @ts-expect-error - private member
return provider.currentProvider.clientUrl
// @ts-expect-error - private member
} else if (provider._socketPath) {
// @ts-expect-error - private member
return provider._socketPath
}
}
if ('_socketPath' in provider && typeof provider._socketPath === 'string') {
const url = provider._socketPath
return url
}

return undefined
}

export const getViemUrl = (publicClient: Providerish) => {
if (publicClient?.transport && 'url' in publicClient.transport) {
const url = publicClient.transport.url
if (typeof url === 'string') {
return url
}
export function isEthersV5JsonRpcProvider(
object: any
): object is EthersV5.JsonRpcProvider {
return (
object !== undefined &&
object !== null &&
typeof object === 'object' &&
'connection' in object &&
typeof object.connection === 'object' &&
'url' in object.connection &&
typeof object.connection.url === 'string'
)
}

export function isEthers6Provider(
object: any
): object is EthersV6.JsonRpcProvider {
return (
object !== undefined &&
object !== null &&
typeof object === 'object' &&
'_getConnection' in object &&
typeof object._getConnection === 'function'
)
}

export function isHttpProvider(object: any): object is Web3BaseProvider {
return (
object !== undefined &&
object !== null &&
typeof object === 'object' &&
(('clientUrl' in object && typeof object.clientUrl === 'string') ||
('currentProvider' in object &&
typeof object.currentProvider === 'object' &&
'clientUrl' in object.currentProvider &&
typeof object.currentProvider.clientUrl === 'string') ||
('_socketPath' in object && typeof object._socketPath === 'string'))
)
}

export function publicClientToProvider(publicClient: PublicClient) {
const { chain, transport } = publicClient
if (!chain) throw new Error('Missing chain')
const network = {
chainId: chain.id,
name: chain.name,
ensAddress: chain?.contracts?.ensRegistry?.address,
}
return undefined
if (transport.type === 'fallback' && network)
return new FallbackProvider(
(transport.transports as ReturnType<HttpTransport>[]).map(
({ value }) => new JsonRpcProvider(value?.url, network)
)
)
return new JsonRpcProvider(transport.url, network)
}

const providerGetters = [getEthersV5Url, getEthersV6Url, getWeb3Url, getViemUrl]
export function isPublicClient(object: any): object is PublicClient {
return (
object !== undefined &&
object !== null &&
typeof object === 'object' &&
'transport' in object &&
object.transport !== null &&
typeof object.transport === 'object' &&
'url' in object.transport &&
typeof object.transport.url === 'string'
)
}

const providerGetters = [getEthersV5Url, getEthersV6Url, getWeb3Url]

export const getProviderUrl = (provider: Providerish) => {
for (const getter of providerGetters) {
Expand All @@ -80,6 +137,9 @@ export const getProviderUrl = (provider: Providerish) => {
export const transformUniversalProviderToEthersV5Provider = async (
provider: Providerish
) => {
if (isPublicClient(provider)) {
return publicClientToProvider(provider)
}
const url = getProviderUrl(provider)

if (!url) {
Expand Down
18 changes: 13 additions & 5 deletions tests/integration/universalProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,34 @@ import Web3 from 'web3'
import { config } from '../../scripts/testSetup'
import { EthBridger, addDefaultLocalNetwork } from '../../src'
import 'dotenv/config'
import { arbitrumGoerli } from 'viem/chains'

addDefaultLocalNetwork()
const defaultUrl = config.arbUrl

describe('provider', () => {
it('should convert viem public client to ethers-v5 provider', async () => {
const publicClient = createPublicClient({ transport: http(defaultUrl) })
// TODO: Fix arb goerli url to use local rpc
const url = arbitrumGoerli.rpcUrls.default.http[0]
const publicClient = createPublicClient({
// chain: {
// ...arbitrumGoerli,
// rpcUrls: { default: { http: [defaultUrl] } },
// },
chain: arbitrumGoerli,
transport: http(url),
}) as any // as any is required here for strange type reasons
const viemEthBridger = await EthBridger.fromProvider(publicClient)

const provider = new providers.StaticJsonRpcProvider(defaultUrl)
const provider = new providers.StaticJsonRpcProvider(url)
const ethersEthBridger = await EthBridger.fromProvider(provider)

expect(viemEthBridger).to.be.deep.equal(ethersEthBridger)
})

it('should convert generic web3 provider to ethers-v5 provider', async () => {
const l2Provider = new Web3(defaultUrl)
//@ts-expect-error - TODO: update Providerish type

const web3EthBridger = await EthBridger.fromProvider(l2Provider)

const provider = new providers.StaticJsonRpcProvider(defaultUrl)
Expand All @@ -34,7 +44,6 @@ describe('provider', () => {

it('should convert web3 HttpProvider to ethers-v5 provider', async () => {
const l2Provider = new Web3.providers.HttpProvider(defaultUrl)
//@ts-expect-error - TODO: update Providerish type
const web3EthBridger = await EthBridger.fromProvider(l2Provider)

const provider = new providers.StaticJsonRpcProvider(defaultUrl)
Expand All @@ -47,7 +56,6 @@ describe('provider', () => {
const url = 'ws://localhost:8548'

const l2Provider = new Web3.providers.WebsocketProvider(url)
//@ts-expect-error - TODO: update Providerish type
const web3EthBridger = await EthBridger.fromProvider(l2Provider)
const provider = new providers.WebSocketProvider(url)
const ethersEthBridger = await EthBridger.fromProvider(provider)
Expand Down

0 comments on commit 9deb273

Please sign in to comment.