-
Notifications
You must be signed in to change notification settings - Fork 119
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
322 additions
and
15 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
export enum FlowNetwork { | ||
MAINNET = "mainnet", | ||
TESTNET = "testnet", | ||
} | ||
|
||
export const FLOW_CHAINS = { | ||
[FlowNetwork.MAINNET]: { | ||
eip155ChainId: 747, | ||
publicRpcUrl: "https://access.mainnet.nodes.onflow.org", | ||
}, | ||
[FlowNetwork.TESTNET]: { | ||
eip155ChainId: 646, | ||
publicRpcUrl: "https://access.testnet.nodes.onflow.org", | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
201 changes: 201 additions & 0 deletions
201
packages/fcl-ethereum-provider/src/gateway/gateway.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,201 @@ | ||
import HttpConnection from "@walletconnect/jsonrpc-http-connection" | ||
import {Gateway} from "./gateway" | ||
import * as fcl from "@onflow/fcl" | ||
import {JsonRpcProvider} from "@walletconnect/jsonrpc-provider" | ||
|
||
jest.mock("@walletconnect/jsonrpc-http-connection") | ||
jest.mock("@walletconnect/jsonrpc-provider") | ||
jest.mock("@onflow/fcl", () => ({ | ||
getChainId: jest.fn(), | ||
})) | ||
|
||
describe("gateway", () => { | ||
beforeEach(() => { | ||
jest.clearAllMocks() | ||
}) | ||
|
||
test("request should work for mainnet", async () => { | ||
const gateway = new Gateway({ | ||
747: "https://example.com", | ||
646: "https://example.com/testnet", | ||
}) | ||
|
||
jest.mocked(fcl.getChainId).mockResolvedValue("mainnet") | ||
jest.mocked(JsonRpcProvider).mockImplementation( | ||
jest.fn( | ||
() => | ||
({ | ||
request: jest.fn().mockResolvedValue(["0x123"]), | ||
}) as any as JsonRpcProvider | ||
) | ||
) | ||
|
||
const returnValue = await gateway.request({ | ||
method: "eth_accounts", | ||
params: [], | ||
}) | ||
|
||
// Check that the arguments are correct | ||
expect( | ||
jest.mocked(JsonRpcProvider).mock.results[0].value.request | ||
).toHaveBeenCalledWith({method: "eth_accounts", params: []}) | ||
|
||
// Check that the return value propogates correctly | ||
expect(returnValue).toEqual(["0x123"]) | ||
|
||
// Verify that the mainnet provider was used | ||
expect(JsonRpcProvider).toHaveBeenCalled() | ||
expect(JsonRpcProvider).toHaveBeenCalledTimes(1) | ||
expect(JsonRpcProvider).toHaveBeenCalledWith( | ||
jest.mocked(HttpConnection).mock.instances[0] | ||
) | ||
expect(HttpConnection).toHaveBeenCalledWith("https://example.com") | ||
}) | ||
|
||
test("request should work for testnet", async () => { | ||
const gateway = new Gateway({ | ||
747: "https://example.com", | ||
646: "https://example.com/testnet", | ||
}) | ||
|
||
jest.mocked(fcl.getChainId).mockResolvedValue("testnet") | ||
jest.mocked(JsonRpcProvider).mockImplementation( | ||
jest.fn( | ||
() => | ||
({ | ||
request: jest.fn().mockResolvedValue(["0x123"]), | ||
}) as any as JsonRpcProvider | ||
) | ||
) | ||
|
||
const returnValue = await gateway.request({ | ||
method: "eth_accounts", | ||
params: [], | ||
}) | ||
|
||
// Check that the arguments are correct | ||
expect( | ||
jest.mocked(JsonRpcProvider).mock.results[0].value.request | ||
).toHaveBeenCalledWith({method: "eth_accounts", params: []}) | ||
|
||
// Check that the return value propogates correctly | ||
expect(returnValue).toEqual(["0x123"]) | ||
|
||
// Verify that the testnet provider was used | ||
expect(JsonRpcProvider).toHaveBeenCalled() | ||
expect(JsonRpcProvider).toHaveBeenCalledTimes(1) | ||
expect(JsonRpcProvider).toHaveBeenCalledWith( | ||
jest.mocked(HttpConnection).mock.instances[0] | ||
) | ||
expect(HttpConnection).toHaveBeenCalledWith("https://example.com/testnet") | ||
}) | ||
|
||
test("subsequent requests should use the same provider", async () => { | ||
const gateway = new Gateway({ | ||
747: "https://example.com", | ||
646: "https://example.com/testnet", | ||
}) | ||
|
||
jest.mocked(fcl.getChainId).mockResolvedValue("testnet") | ||
jest.mocked(JsonRpcProvider).mockImplementation( | ||
jest.fn( | ||
() => | ||
({ | ||
request: jest.fn().mockResolvedValue(["0x123"]), | ||
}) as any as JsonRpcProvider | ||
) | ||
) | ||
|
||
await gateway.request({ | ||
method: "eth_accounts", | ||
params: [], | ||
}) | ||
|
||
await gateway.request({ | ||
method: "eth_accounts", | ||
params: [], | ||
}) | ||
|
||
// Verify that the testnet provider was used | ||
expect(JsonRpcProvider).toHaveBeenCalled() | ||
expect(JsonRpcProvider).toHaveBeenCalledTimes(1) | ||
expect(JsonRpcProvider).toHaveBeenCalledWith( | ||
jest.mocked(HttpConnection).mock.instances[0] | ||
) | ||
expect(HttpConnection).toHaveBeenCalledWith("https://example.com/testnet") | ||
}) | ||
|
||
test("request should throw if chainId is not found", async () => { | ||
const gateway = new Gateway({ | ||
747: "https://example.com", | ||
646: "https://example.com/testnet", | ||
}) | ||
|
||
jest.mocked(fcl.getChainId).mockResolvedValue("unknown") | ||
|
||
await expect( | ||
gateway.request({ | ||
method: "eth_accounts", | ||
params: [], | ||
}) | ||
).rejects.toThrow("Unsupported chainId unknown") | ||
}) | ||
|
||
test("should default to public gateway mainnet", async () => { | ||
const gateway = new Gateway({}) | ||
|
||
jest.mocked(fcl.getChainId).mockResolvedValue("mainnet") | ||
jest.mocked(JsonRpcProvider).mockImplementation( | ||
jest.fn( | ||
() => | ||
({ | ||
request: jest.fn().mockResolvedValue(["0x123"]), | ||
}) as any as JsonRpcProvider | ||
) | ||
) | ||
|
||
await gateway.request({ | ||
method: "eth_accounts", | ||
params: [], | ||
}) | ||
|
||
// Verify that the mainnet provider was used | ||
expect(JsonRpcProvider).toHaveBeenCalled() | ||
expect(JsonRpcProvider).toHaveBeenCalledTimes(1) | ||
expect(JsonRpcProvider).toHaveBeenCalledWith( | ||
jest.mocked(HttpConnection).mock.instances[0] | ||
) | ||
expect(HttpConnection).toHaveBeenCalledWith( | ||
"https://access.mainnet.nodes.onflow.org" | ||
) | ||
}) | ||
|
||
test("should default to public gateway testnet", async () => { | ||
const gateway = new Gateway({}) | ||
|
||
jest.mocked(fcl.getChainId).mockResolvedValue("testnet") | ||
jest.mocked(JsonRpcProvider).mockImplementation( | ||
jest.fn( | ||
() => | ||
({ | ||
request: jest.fn().mockResolvedValue(["0x123"]), | ||
}) as any as JsonRpcProvider | ||
) | ||
) | ||
|
||
await gateway.request({ | ||
method: "eth_accounts", | ||
params: [], | ||
}) | ||
|
||
// Verify that the testnet provider was used | ||
expect(JsonRpcProvider).toHaveBeenCalled() | ||
expect(JsonRpcProvider).toHaveBeenCalledTimes(1) | ||
expect(JsonRpcProvider).toHaveBeenCalledWith( | ||
jest.mocked(HttpConnection).mock.instances[0] | ||
) | ||
expect(HttpConnection).toHaveBeenCalledWith( | ||
"https://access.testnet.nodes.onflow.org" | ||
) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import HTTPConnection from "@walletconnect/jsonrpc-http-connection" | ||
import * as fcl from "@onflow/fcl" | ||
import {JsonRpcProvider} from "@walletconnect/jsonrpc-provider" | ||
import {FLOW_CHAINS, FlowNetwork} from "../constants" | ||
|
||
export class Gateway { | ||
private providers: {[chainId: number]: JsonRpcProvider} = {} | ||
|
||
constructor(private rpcUrls: {[chainId: number]: string}) {} | ||
|
||
async request({method, params}: {method: string; params: any}) { | ||
return this.getProvider().then(provider => | ||
provider.request({method, params}) | ||
) | ||
} | ||
|
||
private async getProvider(): Promise<JsonRpcProvider> { | ||
const flowChainId = await fcl.getChainId() | ||
if (!(flowChainId in FLOW_CHAINS)) { | ||
throw new Error(`Unsupported chainId ${flowChainId}`) | ||
} | ||
|
||
const {eip155ChainId} = FLOW_CHAINS[flowChainId as FlowNetwork] | ||
if (this.providers[eip155ChainId]) { | ||
return this.providers[eip155ChainId] | ||
} | ||
|
||
const rpcUrl = | ||
this.rpcUrls[eip155ChainId] || | ||
FLOW_CHAINS[flowChainId as FlowNetwork].publicRpcUrl | ||
const provider = new JsonRpcProvider(new HTTPConnection(rpcUrl)) | ||
this.providers[eip155ChainId] = provider | ||
return provider | ||
} | ||
} |
31 changes: 28 additions & 3 deletions
31
packages/fcl-ethereum-provider/src/rpc/rpc-processor.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,30 @@ | ||
describe("rpc", () => { | ||
test("should be tested", () => { | ||
expect(true).toBe(true) | ||
import {AccountManager} from "../accounts/account-manager" | ||
import {Gateway} from "../gateway/gateway" | ||
import {RpcProcessor} from "./rpc-processor" | ||
|
||
jest.mock("../gateway/gateway") | ||
jest.mock("../accounts/account-manager") | ||
|
||
describe("rpc processor", () => { | ||
test("fallback to gateway", async () => { | ||
const gateway: jest.Mocked<Gateway> = new (Gateway as any)() | ||
const accountManager: jest.Mocked<AccountManager> = | ||
new (AccountManager as any)() | ||
const rpcProcessor = new RpcProcessor(gateway, accountManager) | ||
|
||
jest.mocked(gateway).request.mockResolvedValue("0x0") | ||
|
||
const response = await rpcProcessor.handleRequest({ | ||
method: "eth_blockNumber", | ||
params: [], | ||
}) | ||
|
||
expect(response).toEqual("0x0") | ||
expect(gateway.request).toHaveBeenCalled() | ||
expect(gateway.request).toHaveBeenCalledTimes(1) | ||
expect(gateway.request).toHaveBeenCalledWith({ | ||
method: "eth_blockNumber", | ||
params: [], | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.