Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple RPC endpoint support #2394

Merged
merged 33 commits into from
Oct 16, 2024
Merged

Multiple RPC endpoint support #2394

merged 33 commits into from
Oct 16, 2024

Conversation

sophialittlejohn
Copy link
Collaborator

@sophialittlejohn sophialittlejohn commented Aug 20, 2024

Description

This pull request...

  • use the provider from getDefaultNetwork for centrifuge-react connectors
  • clean up leftover from goerli
  • fix warnings in console
  • fix start script in main package.json
  • accepts a comma separated list of rpc urls for polkadot and connects to the first healthy one
  • upgrades ethersjs to v6

2164

Approvals

  • Dev

Screenshots

Impact

Copy link

socket-security bot commented Aug 20, 2024

New and removed dependencies detected. Learn more about Socket for GitHub ↗︎

Package New capabilities Transitives Size Publisher

View full report↗︎

Copy link

socket-security bot commented Aug 20, 2024

👍 Dependency issues cleared. Learn more about Socket for GitHub ↗︎

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

View full report↗︎

Copy link

github-actions bot commented Aug 20, 2024

PR deployed in Google Cloud
URL: https://pr2394-app-ff-production.k-f.dev
Commit #: b24b6b3
To access the functions directly check the corresponding deploy Action

Copy link

github-actions bot commented Aug 20, 2024

PR deployed in Google Cloud
URL: https://app-pr2394.k-f.dev
Commit #: b24b6b3
To access the functions directly check the corresponding deploy Action

(cachedProviders[chainId] = new JsonRpcProvider((evmChains as any)[chainId].urls[0], chainId))
)
async function findHealthyProvider(chainId: number, urls: string[]): Promise<JsonRpcProvider> {
for (const url of urls) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would use a Promise.any here

if (!cachedProviders.has(chainId)) {
findHealthyProvider(chainId, urls).catch(console.error)
}
return cachedProviders.get(chainId) || new JsonRpcProvider(urls[0], chainId)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with findHealthyProvider being async, this may return a new JsonRpcProvider multiple times and not garantee that it's healthy

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed the implementation to now use ethers getDefaultProvider() its, much cleaner and doesn't require the manual work from before

const calls: EvmMulticallCall[] = []
const toTokenBalance = (val: BigNumber) => new TokenBalance(val.toString(), 18)
const toCurrencyBalance = (val: BigNumber) => new CurrencyBalance(val.toString(), 18)
const toTokenBalance = (val: BigInt) => new TokenBalance(val.toString(), 18)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BigInt as a type has to be lowercase everywhere

}

private async findHealthyWs(): Promise<string | null> {
for (const url of this.rpcEndpoints) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would use Promise.any here

clearTimeout(timer)
ws.close()
console.log(`Connection to ${url} failed`)
resolve(false)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if using Promise.any above, you can reject here instead

@@ -295,19 +296,69 @@ type Events = ISubmittableResult['events']

const txCompletedEvents: Record<string, Subject<Events>> = {}
const blockEvents: Record<string, Observable<Events>> = {}
let parachainUrlCache: string | null = null
Copy link
Collaborator

@onnovisser onnovisser Sep 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this won't work if there's different instances of the Centrifuge class. It's why the above caches are keyed by parachain url. I think it would be better to keep this as a property on the class. It would need to be copied over when the instance gets cloned though, like in Centrifuge->connect()

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agreed initially that the variable should be stored as a class property, but I noticed in doing so that the url is actually not cached at all and each time the instance is recreated the class property loses it's value. Like this we can store the value across instances which IMO is what we want for this feature instead of constantly opening a ws to check it's health and closing it again. Like this the cached url will only be reset when the page reloads and we can limit the number of ws opening requests to max as many urls as we have

Copy link
Collaborator

@onnovisser onnovisser Sep 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about making this a Set reachableParachainUrls? Then when getting the cached url, it can check which of the config urls is in the set. Then it still works if there's multiple instances of Centrifuge with different configs

@@ -459,7 +510,13 @@ export class CentrifugeBase {
}),
tap((result) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tap callback can be an async function and then this.getTxCompletedEvents() can simply be awaited

Comment on lines 514 to 518
from(this.getTxCompletedEvents())
.pipe(take(1))
.subscribe((subject) => {
subject.next(result.events)
})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
from(this.getTxCompletedEvents())
.pipe(take(1))
.subscribe((subject) => {
subject.next(result.events)
})
(await this.getTxCompletedEvents()).next(result.events)

@@ -373,7 +381,7 @@ export function getLiquidityPoolsModule(inst: Centrifuge) {
...(currencies.flatMap((currency) => ({
target: poolManager,
call: ['function assetToId(address) view returns (uint128)', currency.address],
returns: [[`currencyNeedsAdding[${currency.address}]`, (id: BigNumber) => id.isZero()]],
returns: [[`currencyNeedsAdding[${currency.address}]`, (id: BigInt) => id === BigInt(0)]],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
returns: [[`currencyNeedsAdding[${currency.address}]`, (id: BigInt) => id === BigInt(0)]],
returns: [[`currencyNeedsAdding[${currency.address}]`, (id: bigint) => id === 0n]],

@@ -94,6 +93,7 @@ export function getTinlakeModule(inst: Centrifuge) {
) {
const [tranche] = args
return pending(
// @ts-ignore
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what are all these errors saying?? 😅😅😅

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The types just weren't inferred properly by the connected contract. When using the the ethers Contract directly the methods on the contract are not type checked, but when using a connected contract the are type check even though the method types seem to be non-inferable from the ABI.

@sophialittlejohn sophialittlejohn marked this pull request as draft September 9, 2024 13:05
@sophialittlejohn sophialittlejohn changed the title Use ethers default provider to auto switch to the best rpc network Multiple RPC endpoint support Sep 13, 2024
@sophialittlejohn sophialittlejohn marked this pull request as ready for review September 16, 2024 22:13
Comment on lines 350 to 351
if (parachainUrlCache.values().next().value) {
return parachainUrlCache.values().next().value
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (parachainUrlCache.values().next().value) {
return parachainUrlCache.values().next().value
const match = this.rpcEndpoints.find(url => parachainUrlCache.has(url))
if (match) {
return match

@onnovisser
Copy link
Collaborator

@sophialittlejohn Looking good! One last comment.

@sophialittlejohn sophialittlejohn requested review from onnovisser and removed request for onnovisser October 10, 2024 21:48
@sophialittlejohn sophialittlejohn enabled auto-merge (squash) October 16, 2024 20:11
@sophialittlejohn sophialittlejohn merged commit da791ea into main Oct 16, 2024
13 checks passed
@sophialittlejohn sophialittlejohn deleted the default-provider branch October 16, 2024 20:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants