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

Fetch gas price using low-level RPC method #321

Merged
merged 5 commits into from
May 28, 2024
Merged

Fetch gas price using low-level RPC method #321

merged 5 commits into from
May 28, 2024

Conversation

bdrhn9
Copy link
Contributor

@bdrhn9 bdrhn9 commented May 27, 2024

Closes #305

@bdrhn9 bdrhn9 requested a review from Siegrift May 27, 2024 13:41
@bdrhn9
Copy link
Contributor Author

bdrhn9 commented May 27, 2024

Alternatively, it can be implemented by extending the JsonRpcProvider class like following:

// eslint-disable-next-line functional/no-classes
export class LegacyGasPriceRpcProvider extends ethers.JsonRpcProvider {
  public async getGasPrice(): Promise<bigint> {
    const value = await this.send('eth_gasPrice', []);

    return getBigInt(value);
  }
}

I didn't prefer this approach because it would necessitate modifying nearly every file that references ethers.JsonRpcProvider, both as a class and as an interface.

Copy link
Collaborator

@Siegrift Siegrift left a comment

Choose a reason for hiding this comment

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

👍 LGTM

I agree with your implementation choice. This is simple enough.

@@ -443,6 +444,7 @@ describe(updateFeedsLoopsModule.processBatch.name, () => {
jest.spyOn(logger, 'info');

// Skip actions other than generating signed api urls.
jest.spyOn(gasPriceModule, 'fetchAndStoreGasPrice').mockImplementation();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Mhh, why do these need to be mocked now?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes it looks redundant but I wanted to add them because processBatch includes fetchAndStoreGasPrice. Should I remove them?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Nah, leave them. I was just surprised why the test was passing, but I guess either Ethers made a noop call or silently did nothing 🤷

Copy link
Contributor Author

@bdrhn9 bdrhn9 May 27, 2024

Choose a reason for hiding this comment

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

Test was passing probably because fetchAndStoreGasPrice handles error by returning null when it fails. However, this spy on fetchAndStoreGasPrice is good to have because I encountered this error when I am playing with tests even though I couldn't produce it now.

it('fetches and stores the gas price from RPC provider', async () => {
jest.spyOn(Date, 'now').mockReturnValue(dateNowMock);
jest.spyOn(provider, 'getFeeData').mockResolvedValueOnce({ gasPrice: ethers.parseUnits('10', 'gwei') } as any);
jest.spyOn(gasPriceModule, 'getGasPrice').mockResolvedValueOnce(ethers.parseUnits('10', 'gwei'));
Copy link
Collaborator

Choose a reason for hiding this comment

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

I believe you can spy on the provider instead and this way you avoid the need to import the entirety of gas price module. (Similarly in the test below).

Copy link
Contributor Author

@bdrhn9 bdrhn9 May 27, 2024

Choose a reason for hiding this comment

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

Yep, that is what I did first. However, with the current approach, it is abstracted from provider and depends on getGasPrice which we already tested. I'm not good at tests 😄 I'll do what you suggest at the end of the conversation.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I see the point, but I think the ugliness it brings is not worth it. We can have a similarly readable test with:

jest.spyOn(provider, 'send').mockResolvedValueOnce(ethers.toBeHex(ethers.parseUnits('10', 'gwei')));

@@ -373,12 +365,22 @@ describe(getRecommendedGasPrice.name, () => {
});
});

describe(fetchAndStoreGasPrice.name, () => {
describe(gasPriceModule.getGasPrice.name, () => {
it('returns gas price as bigint when internal rpc call returns a valid hex string', async () => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you add one more test when the provider fails? I checked Ethereum RPC spec (and some other sources) and I think we can rely that when the API returns something it will be a hex string...

Copy link
Collaborator

@Siegrift Siegrift left a comment

Choose a reason for hiding this comment

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

👍 LGTM

* Use block number from the RPC call

* Add test for failed block number fetch
@bdrhn9 bdrhn9 merged commit 5f281f9 into main May 28, 2024
4 checks passed
@bdrhn9 bdrhn9 deleted the bdrhn9/issue305 branch May 28, 2024 12:09
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.

Fetch gas price natively
2 participants