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

refactor: chain manager WIP #1352

Draft
wants to merge 17 commits into
base: master
Choose a base branch
from
Draft

refactor: chain manager WIP #1352

wants to merge 17 commits into from

Conversation

alexandre-abrioux
Copy link
Member

@alexandre-abrioux alexandre-abrioux commented Feb 7, 2024

Introducing a new package: @requestnetwork/chain 👋

End Goal

"Dynamic chain injection"
Builders should be able to work with custom chains without modifying the Request Network library.

Constraints

1. Do not lose chain assertion

The different types of chains that we support, later referred to as "ecosystems", are currently strongly typed across our packages since (#1056) refactor: chain configurations. This was introduced to infer, by design, the compatibility of our codebase with specific chains.

The issue with the current solution is that our ecosystem types consist of a static list of chain names: see here. We cannot keep this design while allowing chain names to be dynamic.

I propose representing chains as objects and using different interfaces for chain ecosystems. This is a significant endeavor, as chains are currently described as strings across the codebase. However, we only need it in some places. Inputs and outputs (e.g. Request data) still contain strings and will not change. Only the internal logic should use objects, whenever possible, for strong typing of payment extensions and advanced logic.

The @requestnetwork/smart-contracts and @requestnetwork/ethereum-storage packages target only one ecosystem (EVMs). We don't need to represent chains as objects in these packages; type inference is unnecessary. The migration for this package was straightforward.

2. Keep dependencies as small as possible

Chains are currently part of @requestnetwork/currency, which contains multiple external dependencies. If we want to introduce logic for making chain description dynamic across the protocol, having a separate "light" package for handling chain configurations could be appropriate. To answer this, I've introduced @requestnetwork/chain, a package that should have no external dependency and can be safely included across our libraries.


Copy link
Contributor

@benjlevesque benjlevesque left a comment

Choose a reason for hiding this comment

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

Great work @alexandre-abrioux!!

* Returns the list of supported chains
*/
get chains(): ChainTypes.IChain[] {
return Object.keys(this.ecosystems).reduce((chains, ecosystemName) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

should this be stored in the instance?

@@ -0,0 +1,12 @@
import { EcosystemAbstract } from '../ecosystem-abstract';
import { ChainTypes, RequestLogicTypes } from '@requestnetwork/types';
import { chains } from './index';
Copy link
Contributor

Choose a reason for hiding this comment

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

don't you have a circular dependency here? shouldn't the index for chains be in the chains/ folder?

Comment on lines +68 to +72
if (chains.length < 1) {
throw new Error(
`No chain found with "${propertyName}=${propertyValue}" for ecosystem(s) "${ecosystemsFilter}"`,
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I have mixed feelings about throwing when a chain isn't found. It's convenient for types, but it can lead to unnecessary complexity if you want to check if a chain is supported.

For instance, we could imagine a dApp when we want to check in the ChainManager if the wallet's current chain is supported...

I think this is OK for now, we can review later if it proves problematic

if (!network) {
throw new Error(`Storage network not supported: ${config.getStorageNetworkId()}`);
}
EvmChains.assertChainSupported(network);
return network;
return ChainManager.current().fromName(network, [ChainTypes.ECOSYSTEM.EVM]);
Copy link
Contributor

Choose a reason for hiding this comment

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

for this to work, it means setCurrent was called? (or the ChainManager will be empty) The request-node is an executable, not a library, so we can't set it before running the node

Copy link
Contributor

Choose a reason for hiding this comment

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

I believe this works due to this trick

};

constructor(inputChains?: Record<ChainTypes.ECOSYSTEM, Record<string, ChainDefinition>>) {
if (!inputChains) return;
Copy link
Contributor

Choose a reason for hiding this comment

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

what's the purpose of this? in what case is it useful to have an emtpy ChainManager?

@@ -52,6 +52,8 @@ export class CurrencyManager<TMeta = unknown> implements ICurrencyManager<TMeta>
}
this.legacyTokens = legacyTokens || CurrencyManager.getDefaultLegacyTokens();
this.conversionPairs = conversionPairs || CurrencyManager.getDefaultConversionPairs();
this.chainManager = chainManager || ChainManager.current();
ChainManager.setCurrent(this.chainManager);
Copy link
Contributor

Choose a reason for hiding this comment

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

ha! this is the trick ;) So this is why it works in request-node.

Copy link
Contributor

Choose a reason for hiding this comment

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

@alexandre-abrioux does that mean setCurrent should almost never be called directly?
As calling the constructor to CurrencyManager (or even getDefault would override it)

I feel this could lead to unexpected behaviours :thinking_face:

ExtensionTypes.ID,
readonly ChainTypes.ECOSYSTEM[]
> = {
[ExtensionTypes.ID.CONTENT_DATA]: [ECOSYSTEM.EVM],
Copy link
Contributor

Choose a reason for hiding this comment

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

strange... CONTENT_DATA isn't a payment network...

return extension;
}

public getExtensionsForChain(
Copy link
Contributor

Choose a reason for hiding this comment

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

any reason this was made public?

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