Skip to content

Commit

Permalink
Fix chainId bug (#1712)
Browse files Browse the repository at this point in the history
  • Loading branch information
jribbink authored Jul 15, 2023
1 parent 6193bd4 commit 6fa3bdc
Show file tree
Hide file tree
Showing 22 changed files with 357 additions and 171 deletions.
5 changes: 5 additions & 0 deletions .changeset/good-monkeys-swim.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@onflow/fcl": patch
---

Fix getChainId bug with nextjs & no longer set flow.network.default in configuration internally
5 changes: 5 additions & 0 deletions .changeset/soft-frogs-reflect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@onflow/transport-http": minor
---

Add opts.enableRequestLogging flag
26 changes: 11 additions & 15 deletions packages/fcl-wc/src/fcl-wc.test.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,23 @@
import {config} from "@onflow/config"
import {init} from './fcl-wc'
import * as fcl from '@onflow/fcl'

jest.mock('@walletconnect/modal', () => {})
jest.mock('@walletconnect/sign-client', () => {})
jest.mock('@walletconnect/utils', () => {})

describe("Init Client", () => {
it("should throw without projectId", async () => {
async function testFn() {
let chainIdSpy
beforeEach(() => {
chainIdSpy = jest.spyOn(fcl, 'getChainId')
chainIdSpy.mockImplementation(async () => "testnet")
})

// Mock transport then import fcl-wc because startup of fcl will call getChainId util which hits the chain
await config.overload(
{
"flow.network.default": "testnet",
"sdk.transport": async ix => ix
},
async () => {
await init()
}
)
}
afterEach(() => {
chainIdSpy.mockRestore()
})

it("should throw without projectId", async () => {
expect.assertions(1)
await expect(testFn).rejects.toThrow(Error)
await expect(init).rejects.toThrow(Error)
})
})
4 changes: 2 additions & 2 deletions packages/fcl/src/app-utils/verify-signatures.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ const getVerifySignaturesScript = async (sig, opts) => {
? "verifyAccountProofSignatures"
: "verifyUserSignatures"

let network = await getChainId()
let network = await getChainId(opts)

let fclCryptoContract

invariant(
opts.fclCryptoContract || network === "testnet" || network === "mainnet",
"${verifyFunction}({ fclCryptoContract }) -- config.flow.network must be specified (testnet || mainnet) or contract address provided via opts.fclCryptoContract"
"${verifyFunction}({ fclCryptoContract }) -- fclCrypto contract address must be set for non-mainnet/testnet networks"
)

if (opts.fclCryptoContract) {
Expand Down
2 changes: 1 addition & 1 deletion packages/fcl/src/current-user/exec-service/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export async function execService({service, msg = {}, config = {}, opts = {}}) {
fclVersion: VERSION,
fclLibrary: "https://github.com/onflow/fcl-js",
hostname: window?.location?.hostname ?? null,
network: await getChainId(),
network: await getChainId(opts),
},
}

Expand Down
18 changes: 12 additions & 6 deletions packages/fcl/src/discovery/services.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {getServices} from "./services"
import {config} from "@onflow/config"
import * as chainIdModule from "../utils/chain-id/get-chain-id"

const serviceOne = {
f_type: "Service",
Expand Down Expand Up @@ -58,20 +59,25 @@ const endpoint = "https://fcl-discovery.onflow.org/api/testnet/authn"

describe("getServices", () => {
let windowSpy
let chainIdSpy
let configRef

beforeEach(() => {
windowSpy = jest.spyOn(window, "window", "get")
chainIdSpy = jest.spyOn(chainIdModule, "getChainId")
chainIdSpy.mockImplementation(async () => "testnet")
configRef = config()
configRef.put(
"discovery.authn.endpoint",
"https://fcl-discovery.onflow.org/api/testnet/authn"
)
.put("accessNode.api", "https://rest-testnet.onflow.org")
configRef
.put(
"discovery.authn.endpoint",
"https://fcl-discovery.onflow.org/api/testnet/authn"
)
.put("accessNode.api", "https://rest-testnet.onflow.org")
})

afterEach(() => {
windowSpy.mockRestore()
chainIdSpy.mockRestore()
global.fetch.mockClear()
})

Expand All @@ -88,7 +94,7 @@ describe("getServices", () => {
})
)

const response = await getServices({ type: ["authn"] })
const response = await getServices({type: ["authn"]})
expect(global.fetch).toHaveBeenCalledTimes(1)
})
})
10 changes: 3 additions & 7 deletions packages/fcl/src/exec/utils/derive-dependencies.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@ import {invariant} from "@onflow/util-invariant"
import {withPrefix} from "@onflow/util-address"
import {getChainId} from "../../utils"

export async function deriveDependencies({template}) {
const network = await getChainId()

invariant(
network,
"FCL configureDependencies Error: Missing configuration value for 'flow.network'"
)
export async function deriveDependencies(opts = {}) {
const template = opts.template
const network = await getChainId(opts)

const derivedDependencies = {}

Expand Down
5 changes: 0 additions & 5 deletions packages/fcl/src/exec/utils/pre.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,6 @@ async function pre(type, opts) {
`${type}({ cadence }) -- cadence must be a string`
)
// prettier-ignore
invariant(
opts.cadence || (await sdk.config().get("flow.network")),
`${type}(opts) -- Required value for "flow.network" not defined in config. See: ${"https://github.com/onflow/flow-js-sdk/blob/master/packages/fcl/src/exec/query.md#configuration"}`
)
// prettier-ignore
invariant(
await sdk.config().get("accessNode.api"),
`${type}(opts) -- Required value for "accessNode.api" not defined in config. See: ${"https://github.com/onflow/flow-js-sdk/blob/master/packages/fcl/src/exec/query.md#configuration"}`
Expand Down
2 changes: 1 addition & 1 deletion packages/fcl/src/exec/utils/prep-template-opts.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export async function prepTemplateOpts(opts) {
opts.cadence ||
deriveCadenceByNetwork({
template: opts.template,
network: await getChainId(),
network: await getChainId(opts),
})

opts.cadence = cadence
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {getChainId} from "../utils"

/**
* @description Returns whether a set of auditors have audited a given Interaction Template
*
*
* @param {object} params
* @param {object} params.template - Interaction Template
* @param {Array<string>} params.auditors - Array of auditors
Expand Down Expand Up @@ -63,7 +63,7 @@ export async function getInteractionTemplateAudits(

let FlowInteractionAuditContract = opts.flowInteractionAuditContract
if (!FlowInteractionAuditContract) {
const fclNetwork = await getChainId()
const fclNetwork = await getChainId(opts)
invariant(
fclNetwork === "mainnet" || fclNetwork === "testnet",
"getInteractionTemplateAudits Error: Unable to determine address for FlowInteractionTemplateAudit contract. Set configuration for 'fcl.network' to 'mainnet' or 'testnet'"
Expand Down
21 changes: 0 additions & 21 deletions packages/fcl/src/utils/chain-id-watcher.js

This file was deleted.

18 changes: 18 additions & 0 deletions packages/fcl/src/utils/chain-id/chain-id-watcher.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {config} from "@onflow/config"
import {getChainId} from "./get-chain-id"

/**
* @description
* Watches the config for changes to access node and updates the chain id accordingly
*
* @returns {Function} A function that unsubscribes the listener
*
*/
export function watchForChainIdChanges() {
return config.subscribe(() => {
// Call getChainId to update the chainId cache if access node has changed
getChainId({
enableRequestLogging: false,
}).catch(() => {})
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ describe("chain-id-watcher", () => {
{"accessNode.api": "https://example.com"},
async () => {
// Mock the setChainIdDefault function
const spy = jest.spyOn(chainIdUtils, "setChainIdDefault")
spy.mockImplementation(() => {})
const spy = jest.spyOn(chainIdUtils, "getChainId")
spy.mockImplementation(async () => {})

// Start watching for changes
unsubscribe = watchForChainIdChanges()
Expand All @@ -25,16 +25,16 @@ describe("chain-id-watcher", () => {
await new Promise(resolve => setTimeout(resolve, 0))

// Expect only one call at initial setup
expect(chainIdUtils.setChainIdDefault).toHaveBeenCalledTimes(1)
expect(chainIdUtils.getChainId).toHaveBeenCalledTimes(1)
}
)
})

test("flow.network.default is correctly set when changed later", async () => {
await config.overload({}, async () => {
// Mock the setChainIdDefault function
const spy = jest.spyOn(chainIdUtils, "setChainIdDefault")
spy.mockImplementation(() => {})
const spy = jest.spyOn(chainIdUtils, "getChainId")
spy.mockImplementation(async () => {})

// Start watching for changes
unsubscribe = watchForChainIdChanges()
Expand All @@ -48,7 +48,23 @@ describe("chain-id-watcher", () => {
await new Promise(resolve => setTimeout(resolve, 0))

// Expect two calls since we changed the access node and there is an initial call
expect(chainIdUtils.setChainIdDefault).toHaveBeenCalledTimes(1)
expect(chainIdUtils.getChainId).toHaveBeenCalledTimes(2)
})
})

test("watcher does not throw error if getChainId throws", async () => {
await config.overload({}, async () => {
// Mock the setChainIdDefault function
const spy = jest.spyOn(chainIdUtils, "getChainId")
spy.mockImplementation(async () => {
throw new Error("dummy error")
})

// Start watching for changes
unsubscribe = watchForChainIdChanges()

// Wait for microtask queue to flush
await new Promise(resolve => setTimeout(resolve, 0))
})
})
})
8 changes: 8 additions & 0 deletions packages/fcl/src/utils/chain-id/fetch-chain-id.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import * as sdk from "@onflow/sdk"

export async function fetchChainId(opts = {}) {
const response = await sdk
.send([sdk.getNetworkParameters()], opts)
.then(sdk.decode)
return response.chainId
}
Loading

0 comments on commit 6fa3bdc

Please sign in to comment.