Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.

Example Plugin Implementation #5393

Merged
merged 47 commits into from
Oct 25, 2022
Merged

Conversation

spacesailor24
Copy link
Contributor

@spacesailor24 spacesailor24 commented Aug 30, 2022

Example implementation for #5091

Unresolved Issues

  1. Plugin re-architecture to allow for plugin depending on other plugins #5490
  2. Debug type error for registerPlugin #5491
  3. Contract instantiated with Web3Context should update when .link is used on plugin #5492

Points of Discussion

Argument of type 'this' is not assignable to parameter of type 'Web3Context<EthExecutionAPI, { logs: typeof LogsSubscription; newHeads: typeof NewHeadsSubscription; newBlockHeaders: typeof NewHeadsSubscription; }>'.
  Type 'ChainlinkPlugin' is not assignable to type 'Web3Context<EthExecutionAPI, { logs: typeof LogsSubscription; newHeads: typeof NewHeadsSubscription; newBlockHeaders: typeof NewHeadsSubscription; }>'.
    Types of property '_requestManager' are incompatible.
      Type 'Web3RequestManager<ChainlinkPluginAPI>' is not assignable to type 'Web3RequestManager<EthExecutionAPI>'.
        Type 'ChainlinkPluginAPI' is missing the following properties from type 'EthExecutionAPI': eth_getBlockByHash, eth_getBlockByNumber, eth_getBlockTransactionCountByHash, eth_getBlockTransactionCountByNumber, and 44 more.ts(2345)
  • In order to get the declare module to work, I needed to update the Web3 package from using the default export to a named one - I'm not sure if/how this affects anything This commit updates Web3 to be exported using default and named export
    • Related to this change, importing Web3 like this is the only way I could get the module augmentation to work The above mentioned commit also updates this to use web3 to augment module instead of web3/dist/web3
  • The return type for getPrice is inferred from the contract ABI instead of ChainlinkPluginAPI
    • This doesn't matter so much because the type the end user will see when calling web3.chainlink.getPrice is defined by ChainlinkPluginAPI (i.e. user will see getPrice returns Promise<Price>)

@render
Copy link

render bot commented Aug 30, 2022

@lgtm-com
Copy link

lgtm-com bot commented Aug 30, 2022

This pull request introduces 1 alert when merging d0d388b into aeceed2 - view on LGTM.com

new alerts:

  • 1 for Unused variable, import, function or class

@lgtm-com
Copy link

lgtm-com bot commented Aug 30, 2022

This pull request introduces 1 alert when merging db296ff into aeceed2 - view on LGTM.com

new alerts:

  • 1 for Unused variable, import, function or class

"ts-jest": "^28.0.7",
"typescript": "^4.7.4"
},
"dependencies": {
Copy link
Contributor

Choose a reason for hiding this comment

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

should those be peerDependencies?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure they can be since the plugin is actually importing the packages?

import { ContractAbi } from 'web3-eth-abi';
import Contract from 'web3-eth-contract';
import { Web3PluginBase } from 'web3-core';
import { Address, Web3APISpec } from 'web3-types';
// @ts-expect-error 'Web3' is declared but its value is never read.
import { Web3 } from 'web3/dist/web3';

Copy link
Contributor

Choose a reason for hiding this comment

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

That doesn't really matter. The only difference here is if you put peer dependencies and set a broad range like ">=4.0.0 < 5" it will warn the user if he is supplying an invalid version, otherwise it would use his version. On the other hand, if you leave it as regular dep, it will install the plugin version of web3 along with a user-supplied version of web3.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This commit adds the dependencies as both peerDependencies and devDependencies as per this

@@ -321,6 +321,6 @@ along with web3.js. If not, see <http://www.gnu.org/licenses/>.
/**
* This comment _supports3_ [Markdown](https://marked.js.org/)
*/
import Web3 from './web3';
import { Web3 } from './web3';
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not do both module export and named export instead of just module export?
Named export generally works better with IDE (auto-import and type hinting)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In this commit I've updated Web3 to be exported via default and named

@@ -276,3 +285,7 @@ export type TransactionBuilder<
web3Context: Web3Context<API>;
privateKey?: HexString | Buffer;
}) => Promise<ReturnType>;

export abstract class Web3PluginBase<API extends Web3APISpec> extends Web3Context<API> {
Copy link
Contributor

Choose a reason for hiding this comment

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

I assume this is how the rest of the modules in web3 are built. The only issue I see with this is once we have plugins that depend on other plugins, types won't work because we are augmenting Web3 class and plugins are using Web3Context.

Alternative of top of my head would be:

export const plugin1 = {
   namespace,
   init: (web3: Web3) => Plugin1Api
}

declare module web3{
  	interface Web3 {
		plugin1: Plugin1Api;
	}
}


and if you require plugin1 in plugin2:


import plugin2 from "plugin2"

export const plugin1 = {
   namespace,
   needs: [plugin1.namespace]
   // because we imported plugin2, Web3 class here will be augmented with plugin1 api
   init: (web3: Web3) => Plugin1Api
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

#5490 tracks this

getPrice: () => Promise<Price>;
}

declare module 'web3/dist/web3' {
Copy link
Contributor

Choose a reason for hiding this comment

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

Have you tested if end user imports Web3 from 'web3' (instead of 'web3/dist/web3') will they see augmented API?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

After this commit, Web3 is now exported as a named export which means this is now:

import { Web3 } from 'web3';

declare module 'web3'

@@ -31,7 +31,7 @@ import { initAccountsForContext } from './accounts';
import { Web3EthInterface } from './types';
import { Web3PkgInfo } from './version';

export default class Web3 extends Web3Context<EthExecutionAPI> {
Copy link
Contributor

Choose a reason for hiding this comment

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

This will break minified web3.js build #5345

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This commit updates Web3 to be exported via default and named. I've created a test example that uses the web3.min.js and calls various functions to ensure the minified build works

Copy link
Contributor

@jdevcs jdevcs left a comment

Choose a reason for hiding this comment

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

If we want to keep this as example for others to implement plugins, :
web3-plugin-example example package should be placed under tools


public constructor(abi: ContractAbi, address: Address) {
super();
this._contract = new Contract(abi, address);
Copy link
Contributor

Choose a reason for hiding this comment

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

We should leverage context coming via inheritance Web3PluginBase and use that to instantiate contract. Ideally with every usage there should not be need to check :
if (this._contract.currentProvider === undefined) this._contract.link(this); if context is used while instantiation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

#5492 tracks this and there seems to be a bug with updating a context that was passed upon instantiation of Contract

@lgtm-com
Copy link

lgtm-com bot commented Aug 30, 2022

This pull request introduces 1 alert when merging a2f43db into e2afb75 - view on LGTM.com

new alerts:

  • 1 for Unused variable, import, function or class

Copy link
Contributor

@Muhammad-Altabba Muhammad-Altabba left a comment

Choose a reason for hiding this comment

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

Looks great beside tiny stuff in addition to the already mentioned points by other reviewers.

spacesailor24 and others added 2 commits October 24, 2022 06:54
Co-authored-by: Muhammad Altabba <[email protected]>
Co-authored-by: Muhammad Altabba <[email protected]>
'0xc41b9a4f654c44552e135f770945916f57c069b80326f9a5f843e613491ab6b1';

requestManagerSendSpy.mockResolvedValueOnce(expectedGasPrice);
// Not sure what's being mocked here
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we, please, have an issue for investigating the matter and enhancing this piece of code?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed by this commit

@spacesailor24 spacesailor24 merged commit c83a36e into 4.x Oct 25, 2022
@spacesailor24 spacesailor24 deleted the wyatt/4.x/5091-chainlink-plugin branch October 25, 2022 04:55
@jdevcs jdevcs mentioned this pull request Nov 1, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
4.x 4.0 related
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants