Skip to content

chore(wallet)_: fee handling improvements for Status Network Sepolia #6710

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

Merged
merged 4 commits into from
Jul 4, 2025

Conversation

saledjenic
Copy link
Contributor

@saledjenic saledjenic commented Jun 25, 2025

  • Added L1 fee for the Base chain, since it is based on Optimism stack and should follow the same fee calculation.
  • Remove unused functions HasNoBaseFee and HasNoPriorityFee from wallet utilities since that should not be hardcoded, but dynamically evaluated.
  • A temporary patch was added to the getEIP1559SuggestedFees function to handle the specificities of the Status chain.

The last commit bring a dynamic fee evaluation for Status Sepolia chain:

  • Added support for the linea_estimateGas method in the wallet's gas estimation logic.
  • Updated the EstimateGas function to route to linea_estimateGas when the chain ID is for Status Sepolia chain.
  • Enhanced fee management to dynamically evaluate the account that is going to place a tx is a base fee less
    and/or priority fee less for the Status Sepolia chain.

@saledjenic saledjenic requested review from a team, dlipicar, Khushboo-dev-cpp, alaibe and vkjr and removed request for a team June 25, 2025 13:34
@status-im-auto
Copy link
Member

status-im-auto commented Jun 25, 2025

Jenkins Builds

Click to see older builds (80)
Commit #️⃣ Finished (UTC) Duration Platform Result
✔️ 7d9d25c #1 2025-06-25 13:38:08 ~3 min macos 📦zip
✔️ 7d9d25c #1 2025-06-25 13:38:19 ~3 min android 📦aar
✔️ 7d9d25c #1 2025-06-25 13:39:49 ~4 min windows 📦zip
✔️ 7d9d25c #1 2025-06-25 13:39:58 ~5 min ios 📦zip
✔️ 7d9d25c #1 2025-06-25 13:41:13 ~6 min macos 📦zip
✔️ 7d9d25c #1 2025-06-25 13:41:46 ~6 min linux 📦zip
✔️ 7d9d25c #1 2025-06-25 13:44:49 ~9 min tests-rpc 📄log
✔️ 7d9d25c #1 2025-06-25 13:46:12 ~11 min linux 📦zip
✔️ 7d9d25c #1 2025-06-25 14:05:26 ~30 min tests 📄log
✔️ 305cdb5 #2 2025-06-26 14:26:32 ~3 min android 📦aar
✔️ 305cdb5 #2 2025-06-26 14:26:57 ~3 min macos 📦zip
✔️ 305cdb5 #2 2025-06-26 14:27:16 ~4 min linux 📦zip
✔️ 305cdb5 #2 2025-06-26 14:28:43 ~5 min macos 📦zip
✔️ 305cdb5 #2 2025-06-26 14:29:16 ~5 min windows 📦zip
✔️ 305cdb5 #2 2025-06-26 14:29:27 ~6 min tests-rpc 📄log
✔️ 305cdb5 #2 2025-06-26 14:29:59 ~6 min ios 📦zip
✔️ 305cdb5 #2 2025-06-26 14:33:55 ~10 min linux 📦zip
✔️ 305cdb5 #2 2025-06-26 14:48:24 ~25 min tests 📄log
✔️ fecfc8d #3 2025-07-01 16:09:38 ~3 min macos 📦zip
✔️ fecfc8d #3 2025-07-01 16:10:24 ~4 min ios 📦zip
✔️ fecfc8d #3 2025-07-01 16:10:52 ~4 min android 📦aar
✔️ fecfc8d #3 2025-07-01 16:10:58 ~4 min linux 📦zip
✔️ fecfc8d #3 2025-07-01 16:11:13 ~4 min macos 📦zip
✔️ fecfc8d #3 2025-07-01 16:13:11 ~6 min windows 📦zip
✔️ fecfc8d #3 2025-07-01 16:13:49 ~7 min tests-rpc 📄log
✔️ fecfc8d #3 2025-07-01 16:19:03 ~12 min linux 📦zip
✔️ fecfc8d #3 2025-07-01 16:35:02 ~28 min tests 📄log
✔️ fecfc8d #4 2025-07-03 07:56:54 ~2 min android 📦aar
✔️ fecfc8d #4 2025-07-03 07:57:55 ~3 min linux 📦zip
✔️ fecfc8d #4 2025-07-03 07:58:06 ~3 min macos 📦zip
✔️ fecfc8d #4 2025-07-03 07:58:21 ~3 min macos 📦zip
✔️ fecfc8d #4 2025-07-03 07:58:53 ~4 min ios 📦zip
✔️ fecfc8d #4 2025-07-03 08:00:20 ~5 min windows 📦zip
✔️ fecfc8d #4 2025-07-03 08:00:53 ~6 min tests-rpc 📄log
✔️ fecfc8d #4 2025-07-03 08:06:14 ~11 min linux 📦zip
✔️ fecfc8d #4 2025-07-03 08:20:58 ~26 min tests 📄log
✔️ 5670e91 #5 2025-07-03 08:00:42 ~2 min android 📦aar
✔️ 5670e91 #5 2025-07-03 08:01:08 ~2 min linux 📦zip
✔️ 5670e91 #5 2025-07-03 08:01:50 ~3 min macos 📦zip
✔️ 5670e91 #5 2025-07-03 08:03:15 ~4 min ios 📦zip
✔️ 5670e91 #5 2025-07-03 08:03:36 ~4 min macos 📦zip
✔️ 5670e91 #5 2025-07-03 08:05:36 ~5 min windows 📦zip
✔️ 5670e91 #5 2025-07-03 08:07:07 ~6 min tests-rpc 📄log
✔️ 5670e91 #5 2025-07-03 08:15:54 ~9 min linux 📦zip
✔️ 5670e91 #5 2025-07-03 08:46:29 ~25 min tests 📄log
✔️ cb63720 #6 2025-07-04 11:35:57 ~2 min android 📦aar
✔️ cb63720 #6 2025-07-04 11:36:58 ~3 min macos 📦zip
✔️ cb63720 #6 2025-07-04 11:37:04 ~3 min linux 📦zip
✔️ cb63720 #6 2025-07-04 11:37:59 ~4 min ios 📦zip
✔️ cb63720 #6 2025-07-04 11:38:47 ~4 min macos 📦zip
✖️ cb63720 #6 2025-07-04 11:39:18 ~5 min tests-rpc 📄log
✔️ cb63720 #6 2025-07-04 11:39:33 ~5 min windows 📦zip
✔️ cb63720 #6 2025-07-04 11:43:18 ~9 min linux 📦zip
✔️ cb63720 #6 2025-07-04 12:00:57 ~27 min tests 📄log
d87ba4b #7 2025-07-04 11:50:44 ~51 sec linux 📄log
d87ba4b #7 2025-07-04 11:50:49 ~51 sec linux 📄log
d87ba4b #7 2025-07-04 11:50:54 ~56 sec macos 📄log
d87ba4b #7 2025-07-04 11:51:14 ~1 min android 📄log
d87ba4b #7 2025-07-04 11:51:26 ~1 min macos 📄log
d87ba4b #7 2025-07-04 11:52:31 ~2 min windows 📄log
d87ba4b #7 2025-07-04 11:53:11 ~3 min ios 📄log
✖️ d87ba4b #7 2025-07-04 11:54:58 ~4 min tests-rpc 📄log
83ceb96 #8 2025-07-04 11:52:34 ~48 sec linux 📄log
83ceb96 #8 2025-07-04 11:52:39 ~49 sec linux 📄log
83ceb96 #8 2025-07-04 11:52:45 ~55 sec macos 📄log
83ceb96 #8 2025-07-04 11:52:57 ~1 min android 📄log
83ceb96 #8 2025-07-04 11:53:15 ~1 min macos 📄log
83ceb96 #8 2025-07-04 11:55:09 ~2 min windows 📄log
83ceb96 #8 2025-07-04 11:56:23 ~3 min ios 📄log
✖️ 83ceb96 #8 2025-07-04 11:57:09 ~2 min tests-rpc 📄log
✖️ 83ceb96 #7 2025-07-04 12:01:59 ~55 sec tests 📄log
9e7c21c #9 2025-07-04 12:37:17 ~48 sec linux 📄log
9e7c21c #9 2025-07-04 12:37:22 ~50 sec linux 📄log
9e7c21c #9 2025-07-04 12:37:28 ~55 sec macos 📄log
✖️ 9e7c21c #8 2025-07-04 12:37:31 ~53 sec tests 📄log
9e7c21c #9 2025-07-04 12:37:49 ~1 min android 📄log
9e7c21c #9 2025-07-04 12:38:00 ~1 min macos 📄log
✖️ 9e7c21c #9 2025-07-04 12:38:32 ~1 min tests-rpc 📄log
9e7c21c #9 2025-07-04 12:39:07 ~2 min windows 📄log
9e7c21c #9 2025-07-04 12:39:29 ~3 min ios 📄log
Commit #️⃣ Finished (UTC) Duration Platform Result
ed44455 #10 2025-07-04 12:58:55 ~51 sec linux 📄log
ed44455 #10 2025-07-04 12:59:03 ~56 sec linux 📄log
✖️ ed44455 #9 2025-07-04 12:59:09 ~55 sec tests 📄log
ed44455 #10 2025-07-04 12:59:18 ~1 min macos 📄log
ed44455 #10 2025-07-04 12:59:39 ~1 min macos 📄log
ed44455 #10 2025-07-04 12:59:48 ~1 min android 📄log
ed44455 #10 2025-07-04 13:00:49 ~2 min windows 📄log
ed44455 #10 2025-07-04 13:01:17 ~3 min ios 📄log
✖️ ed44455 #10 2025-07-04 13:02:44 ~4 min tests-rpc 📄log
✔️ 34394dd #11 2025-07-04 13:21:39 ~2 min android 📦aar
✔️ 34394dd #11 2025-07-04 13:21:53 ~2 min linux 📦zip
✔️ 34394dd #11 2025-07-04 13:22:10 ~3 min macos 📦zip
✔️ 34394dd #11 2025-07-04 13:23:11 ~4 min ios 📦zip
✔️ 34394dd #11 2025-07-04 13:24:01 ~4 min macos 📦zip
✔️ 34394dd #11 2025-07-04 13:24:25 ~5 min tests-rpc 📄log
✔️ 34394dd #11 2025-07-04 13:24:38 ~5 min windows 📦zip
✔️ 34394dd #11 2025-07-04 13:29:04 ~10 min linux 📦zip
✔️ 34394dd #10 2025-07-04 13:45:27 ~26 min tests 📄log

Copy link

codecov bot commented Jun 25, 2025

Codecov Report

Attention: Patch coverage is 51.68539% with 86 lines in your changes missing coverage. Please review.

Project coverage is 59.18%. Comparing base (3f9d2fa) to head (34394dd).
Report is 4 commits behind head on develop.

Files with missing lines Patch % Lines
services/wallet/router/fees/fees_history.go 10.71% 23 Missing and 2 partials ⚠️
rpc/chain/client.go 0.00% 19 Missing ⚠️
services/wallet/router/fees/fees.go 50.00% 13 Missing and 1 partial ⚠️
services/wallet/router/router.go 59.37% 12 Missing and 1 partial ⚠️
transactions/rpc_wrapper.go 20.00% 7 Missing and 1 partial ⚠️
services/wallet/common/utils.go 72.22% 3 Missing and 2 partials ⚠️
services/wallet/router/router_updates.go 33.33% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #6710      +/-   ##
===========================================
- Coverage    59.18%   59.18%   -0.01%     
===========================================
  Files          828      828              
  Lines       101465   101546      +81     
===========================================
+ Hits         60052    60097      +45     
- Misses       33836    33865      +29     
- Partials      7577     7584       +7     
Flag Coverage Δ
functional 28.66% <41.57%> (+0.20%) ⬆️
unit 56.39% <50.56%> (-0.05%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
api/default_networks.go 99.41% <100.00%> (ø)
api/defaults.go 77.27% <100.00%> (ø)
rpc/network/testutil/testutil.go 100.00% <100.00%> (ø)
rpc/route.go 100.00% <ø> (ø)
services/connector/commands/send_transaction.go 54.83% <100.00%> (ø)
services/wallet/router/router_helper.go 40.42% <100.00%> (+0.36%) ⬆️
services/wallet/router/router_updates.go 38.26% <33.33%> (ø)
services/wallet/common/utils.go 49.18% <72.22%> (+3.34%) ⬆️
transactions/rpc_wrapper.go 57.57% <20.00%> (-15.40%) ⬇️
services/wallet/router/router.go 55.43% <59.37%> (-0.21%) ⬇️
... and 3 more

... and 43 files with indirect coverage changes

if common.IsGaslessChainAndEIP1559Compatible(chainID) {
return true, nil
// Since the Status Network is gasless chain, but EIP-1559 compatible, we should not rely on checking the BaseFeePerGas, that's why we have this special case.
eip1559Enabled, err := common.IsPartiallyOrFullyGaslessChainEIP1559Compatible(chainID)
Copy link
Contributor

Choose a reason for hiding this comment

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

IsPartiallyOrFullyGaslessChainEIP1559Compatible function looks like overcomplication for me. If all we want to check is that chain is EIP1559-compatible, we don't have to bring the concept of "gasless" into play. We can have function common. IsKnownEIP1559CompatibleChain and use it instead and put the check for status chain there.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@vkjr not really. I prefer naming things what they truly are and what they truly do.

If all we want to check is that chain is EIP1559-compatible

Yes, the function IsEIP1559Enabled really checks if a chain X is EIP1559 compatible or not, and it doesn't bring "gasless" into play, and works for any chain. But the logic for checking that for gasless chains and partially gasless chains differs from checking that for other chains.

We can have function common. IsKnownEIP1559CompatibleChain

Why do we need that one if we already have IsEIP1559Enabled that does that?

Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need that one if we already have IsEIP1559Enabled that does that?

Well, right now IsEIP1559Enabled calls IsPartiallyOrFullyGaslessChainEIP1559Compatible which calls !IsPartiallyOrFullyGaslessChain and all these nested calls do is check if chainId is Status Sepolia. Just putting this check inside isEIP1559Compatible would make things more readable.

Copy link
Contributor

Choose a reason for hiding this comment

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

Buy saying "bring the concept of "gasless" into play" I mean that the word "gasless" appears inside the IsEIP1559Enabled function when we call IsPartiallyOrFullyGaslessChainEIP1559Compatible.

So for someone like me who is less aware of a codebase and reads the code of IsEIP1559Enabled that poses a question "what gasless have to do with EIP 1559", so I'm talking more about cognitive load of reading the code here :)

Copy link
Contributor Author

@saledjenic saledjenic Jun 30, 2025

Choose a reason for hiding this comment

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

Even it's a simple function:

func IsPartiallyOrFullyGaslessChain(chainID uint64) bool {
	return chainID == StatusNetworkSepolia
}

it says a lot. Has a meaningful name, is used in more than a single place in the code, and having in mind that tomorrow when we need to add StatusMainnetChain (or maybe some other gasless chain) that will be just a single line change in that function, it deserves to be a separate function.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just because of the discussion that you ran here, which I wanted to avoid, and don't waste time, I added this comment

// This is something we can do just now (cause Lenea call has some issues), but should not be used later (after September 2025),
// instead `linea_estimateGas` call should be used for the Status Network.

at the moment when I added that condition there.

Copy link
Contributor

Choose a reason for hiding this comment

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

@saledjenic, I've heard that this condition will go away "soon". And I don't see how this as a reason for not improving code "now". Because we all know how delayed can be expected changes.

Also, even if initialization to zeros will go away, where exactly will reside the receiving of actual values with linea_estimateGas? Right now I see 2 functions within SuggestedFees: getEIP1559SuggestedFees and getNonEIP1559SuggestedFees. Receiving fees won't be in any of them?

Speaking of hearing each other. Could you please comment on the whole point of having if chainID == common.StatusNetworkSepolia check within SuggestedFees. As I noted few times, all it does is initializing nil values to zeros. And we do not treat those values any different. What is the point?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

And I don't see how this as a reason for not improving code "now".

Cause that's a temporary code, it doesn't hurt, but even if we don't change it in 3 months, but in 6 months for example, it will boil down to 3 lines (condition) removal and that's it, the rest of the code is untouched and clean. Also that's the point of the comment there.

Right now I see 2 functions within SuggestedFees: getEIP1559SuggestedFees and getNonEIP1559SuggestedFees. Receiving fees won't be in any of them?

Ofc not, they receive feeHistory as an input param and do the calculation.

Could you please comment on the whole point of having if chainID == common.StatusNetworkSepolia check within SuggestedFees.

There are only 2 places where we have if chainID == common.StatusNetworkSepolia, and those are:

  1. in SuggestedFees
  2. in getEIP1559SuggestedFees

We ignore the second one cause it's temporary here and will go away soon. That's just a patch for the Status chain. As soon as the fix lands in the Status chain, we can remove it.

In the first one remains to differentiate Status chain from other chains cause it fetches details from linea_estimateGas, to be clear, the condition could go to getEIP1559SuggestedFees, but then the function would need to be a member of FeeManager.

Copy link
Contributor

Choose a reason for hiding this comment

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

There are only 2 places where we have if chainID == common.StatusNetworkSepolia, and those are:

  1. in SuggestedFees
  2. in getEIP1559SuggestedFees

We ignore the second one cause it's temporary here and will go away soon. That's just a patch for the Status chain. As soon as the fix lands in the Status chain, we can remove it.

I'm fully okay with this one, I think it fully covers initialization needs for now.

In the first one remains to differentiate Status chain from other chains cause it fetches details from linea_estimateGas, to be clear, the condition could go to getEIP1559SuggestedFees, but then the function would need to be a member of FeeManager.

This one I think should be removed because at the moment we don't have linea_estimateGas and the whole if condition doesn't make anything functional. Receiving noBaseFee and noPriorityFee within it also has no practical sense, it only pollutes SuggestedFees returned values and can be done outside of SuggestedFees.

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 one I think should be removed because at the moment we don't have linea_estimateGas

How do you mean that? It must stay and we have to use linea_estimateGas. The only question is, will we keep the call in SuggestedFees or move it to getEIP1559SuggestedFees and make that function a member of FeeManager. Those are only 2 possible options and no other way.

@@ -47,9 +50,36 @@ func (f *FeeManager) getFeeHistory(ctx context.Context, chainID uint64, newestBl
return feeHistory, err
}

func (f *FeeManager) getGaslessParamsForAccount(ctx context.Context, chainID uint64, address ethCommon.Address) (noBaseFee bool, noPriorityFee bool, err error) {
if !walletCommon.IsPartiallyOrFullyGaslessChain(chainID) {
return false, false, nil
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 an error condition?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, it doesn't. Why do you think so?

Copy link
Contributor

Choose a reason for hiding this comment

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

I noticed that we call this function on the top level under condition chainID == common.StatusNetworkSepolia, so it looked like it is intended to be called for gasless chains.

Copy link
Contributor Author

@saledjenic saledjenic Jun 30, 2025

Choose a reason for hiding this comment

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

Yes we call it under that condition, but that's our need in SuggestedFees function, but this function works for any chain supported in the app, not only for StatusNetworkSepolia chain.

Copy link
Contributor

Choose a reason for hiding this comment

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

Okay, in this function we do check IsPartiallyOrFullyGaslessChain but it should work for any network, got it 👍

At the same time in SuggestedFees we firstly check if chainId is status sepolia to initialize fees to zeros. I have a feeling that the same logic should work for any gasless chain, not only for status sepolia.

So it probably would be more logical to cal the getGaslessParamsForAccount first and then depending on returned values of noBaseFee and noPriorityFee initialize fee values with zeros or with the result of getEIP1559SuggestedFees. In this way we will avoid manual check for sepolia status chain id and will rely on more generic IsPartiallyOrFullyGaslessChain used within getGaslessParamsForAccount.
Wdyt?

Copy link
Contributor Author

@saledjenic saledjenic Jun 30, 2025

Choose a reason for hiding this comment

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

Yes, I agree, but isn't this more optimised :) like in that case call to getGaslessParamsForAccount and the code between 145 and 159 lines would be done for every chain, instead of as it's now, that we call that function only if it's StatusSepoliaChain. In all cases we need feeHistory, but getGaslessParamsForAccount are needed only in case of StautsSepoliaChain.

Copy link
Contributor

@vkjr vkjr Jun 30, 2025

Choose a reason for hiding this comment

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

I lean toward the opinion that preliminary optimization is evil and personally always prefer code simplicity unless cpu or memory profiler said I'm wrong)

But I see your point, that also doesn't look beautiful and I think now I may understand why.. because we actually already have a function that should compute all fees - getEIP1559SuggestedFees. This function inside already has a check for status sepolia (line 79)! And on top of it we do this check again and set some fees to zero in `SuggestedFees.

I think we may merge getEIP1559SuggestedFees and f.getGaslessParamsForAccount which will make the SuggestedFees much cleaner.
Also getEIP1559SuggestedFees can return the whole populated suggestedFees structure, it has all data to do this.

wdyt?

Copy link
Contributor Author

@saledjenic saledjenic Jun 30, 2025

Choose a reason for hiding this comment

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

Yes, that's cleaner.

@vkjr actually not, that's not good, cause everything done in this PR has its own reason why it's like that and I would keep it as it is. We cannot merge it cause moving getGaslessParamsForAccount into getEIP1559SuggestedFees will cause other not that nice changes, getGaslessParamsForAccount is a member of FeeManager, then we would need to pass context and address to getEIP1559SuggestedFees which is needless and also acting on the error returned by is is not the same. Those are different cases. So no changes on this topic.

Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like I initially posted this in a wrong theread. Comment should be in this one.

@saledjenic, could you please help me understand the difference in these few cases, I'm not sure I correctly grasp them, maybe because of lack of Go knowledge.

Let's say we are in SuggestedFees.
We have baseFee *big.Int (which will be inialized to nil at first)

Case 1: Network is Status Sepolia and noBaseFee returned from f.getGaslessParamsForAccount equals true.
In this case we will get following sequence:

  • we are entering if chainID == common.StatusNetworkSepolia
  • noBaseFee equals true
  • baseFee = big.NewInt(0) //doing conditional initialization
  • we are exiting if block
  • BaseFee: baseFee //suggestedFees.BaseFee initialized with 0

Case 2: Network is Status Sepolia and noBaseFee returned from f.getGaslessParamsForAccount equals false.

  • we are entering if chainID == common.StatusNetworkSepolia
  • noBaseFee equals false
  • we are exiting if block
  • BaseFee: baseFee //suggestedFees.BaseFee will remain nil

Case 3, Hypothetical: Let's say network is Status Sepolia but we don't have a call to f.getGaslessParamsForAccount in code and only call f.getEIP1559SuggestedFees. In this case:

  • we enter getEIP1559SuggestedFees
  • if chainID == common.StatusNetworkSepolia { //condition meets
  • return big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil // we return 0 values
  • exit getEIP1559SuggestedFees
  • BaseFee: baseFee //suggestedFees.BaseFee initialized with 0

As we can see all these 3 cases leave us with the same result as for fees. Base fee will be 0 or nil which is indifferent in this case (correct me if I'm wrong) because we are never check for nil later.

So that means that call to f.getGaslessParamsForAccount has no practical value for calculating fees.
As you have said earlier,noBaseFee and noPriorityFee are the parameters of chain.

So instead of calling f.getGaslessParamsForAccount inside SuggestedFees (which doesn't affect fees at all) and dragging two fee-unrelated params out of SuggestedFees to r.evaluateAndUpdatePathDetails, we can get rid of that call inside SuggestedFees at all and rely only on what f.getEIP1559SuggestedFees returns, while the call to f.getGaslessParamsForAccount can be moved to evaluateAndUpdatePathDetails. Or maybe it is not needed inside evaluateAndUpdatePathDetails but can be placed before it, on the same level as SuggestedFees.

What we will get:

  • no double check for sepolia status in SuggestedFees and in f.getEIP1559SuggestedFees
  • no need to initialize &SuggestedFees structure in SuggestedFees func, it can be done inside f.getEIP1559SuggestedFees
  • no dragging parameters

I think that would be much cleaner, wdyt?

@@ -125,18 +128,44 @@ func (f *FeeManager) IsEIP1559Enabled(ctx context.Context, chainID uint64) (bool
return block.BaseFee() != nil && block.BaseFee().Cmp(big.NewInt(0)) > 0, nil
}

func (f *FeeManager) SuggestedFees(ctx context.Context, chainID uint64) (*SuggestedFees, error) {
func (f *FeeManager) SuggestedFees(ctx context.Context, chainID uint64, address ethCommon.Address) (suggestedFees *SuggestedFees, noBaseFee bool, noPriorityFee bool, err error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

noBaseFee and noPriorityFee are never used on their own, they always passed to other functions along with suggestedFees. In r.evaluateAndUpdatePathDetails, in r.buildPath, which makes them logically a part of SuggestedFees structure.
So we can move these 2 fields inside SuggestedFees and avoid 2 extra params

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@vkjr yes, I was thinking about that initially, butSuggestedFees type carries the info about fees, how much is each fee, base fee, priority fee... but if there is a base fee or not and if there is a priority fee or not are more fields that are describing the chain behaviour. So the chain can be base-feeless and/or priority-feeless and if the chan has no base fee baseFee field in the SuggestedFees type will be 0, the same logic for priority fee. So that's the reason why they are not there.

Copy link
Contributor

@vkjr vkjr Jun 30, 2025

Choose a reason for hiding this comment

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

That makes sense.
If noBaseFee and noPriorityFee are used to update chain fields, can we just carry this information using SuggestedFess structure?
For example right now inside SuggestedFees function we are getting noBaseFee and noPriorityFee:
noBaseFee, noPriorityFee, err = f.getGaslessParamsForAccount(ctx, chainID, address)

And use them:

if noBaseFee {
	baseFee = big.NewInt(0)
}

But we can also use nil value assigned to baseFee that can indicate that the chain doesn't have baseFee at all. That would result in:

if noBaseFee {
	baseFee = nil
}

And we won't have to pass 2 extra params everywhere. Wdyt?

Copy link
Contributor Author

@saledjenic saledjenic Jun 30, 2025

Choose a reason for hiding this comment

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

Yes, technically we could do that, but I wanted to follow safer solution, cause that one we would most likely require clients updates, cause I am not sure if clients are handling properly null values for those fields and most likely we would need many more lines in functional and unit tests to update.

@saledjenic saledjenic force-pushed the chore/router-simplification branch from 2fab779 to 824b15a Compare July 1, 2025 15:54
@saledjenic saledjenic force-pushed the chore/status-chain-gasless-related-improvements branch from 305cdb5 to fecfc8d Compare July 1, 2025 16:05
@saledjenic saledjenic force-pushed the chore/router-simplification branch from 824b15a to 6971560 Compare July 3, 2025 07:21
Base automatically changed from chore/router-simplification to develop July 3, 2025 07:54
@saledjenic saledjenic force-pushed the chore/status-chain-gasless-related-improvements branch from fecfc8d to 5670e91 Compare July 3, 2025 07:58
@@ -655,6 +657,30 @@ func (c *ClientWithFallback) FeeHistory(ctx context.Context, blockCount uint64,
}

func (c *ClientWithFallback) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error) {
if c.ChainID == walletCommon.StatusNetworkSepolia {
Copy link
Contributor

@friofry friofry Jul 4, 2025

Choose a reason for hiding this comment

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

  1. Can you move this part (if chainID == StatusNetworkSepolia) to a separate method.
    I think this violates the Open/Closed Principle from SOLID (open for extension but closed for modification). It adds complexity without any benefits. Harder to read, maintain.

  2. StatusNetworkSepoliaChainID is also defined in const.go

Copy link
Contributor Author

Choose a reason for hiding this comment

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

StatusNetworkSepoliaChainID is also defined in const.go

One from wallet constants should be used, I can add a commit on top of with that change

Can you move this part (if chainID == StatusNetworkSepolia) to a separate method.

@friofry I can, but in that case this EstimateGas doesn't work for Status Chain, I mean, doesn't give the correct value.

Copy link
Contributor

Choose a reason for hiding this comment

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

doesn't give the correct value.

I guess it's fine. I think this business logic is not the matter of RPC connection wrapper

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@friofry new commit added for constants.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@friofry it's not a quick thing to split that here, cause our processors are estimating gas via GasEstimator interface of go-ethereum, and I would need to update our fork to make it different, which I don't want, since we want to make changes on our side that will let us update easily to the latest go-ethereum implementation.

Need to think and check the code on how to handle that on our side, but that will definitely be a new PR.

The Base chain is based on Optimism stack, so should follow the same fee calculation.
- Remove unused functions `HasNoBaseFee` and `HasNoPriorityFee` from wallet utilities since that should not be hardcoded, but dynamically evaluated.
- A temporary patch was added to the `getEIP1559SuggestedFees` function to handle the specificities of the Status chain.
@saledjenic saledjenic force-pushed the chore/status-chain-gasless-related-improvements branch 2 times, most recently from d87ba4b to 83ceb96 Compare July 4, 2025 11:51
- Added support for the `linea_estimateGas` method in the wallet's gas estimation logic.
- Updated the `EstimateGas` function to route to `linea_estimateGas` when the chain ID is for Status Sepolia chain.
- Enhanced fee management to dynamically evaluate the account that is going to place a tx is base fee less
and/or priority fee less for the Status Sepolia chain.
@saledjenic saledjenic force-pushed the chore/status-chain-gasless-related-improvements branch from 83ceb96 to 9e7c21c Compare July 4, 2025 12:36
@saledjenic saledjenic force-pushed the chore/status-chain-gasless-related-improvements branch from 9e7c21c to ed44455 Compare July 4, 2025 12:57
…tants from wallet common are used instead

- Removed api `common` package since except in a few places the app is using chain constants from the wallet `common` package
- All references to chain IDs from removed package are updated
@saledjenic saledjenic force-pushed the chore/status-chain-gasless-related-improvements branch from ed44455 to 34394dd Compare July 4, 2025 13:18
@friofry friofry self-requested a review July 4, 2025 13:59
Copy link
Contributor

@friofry friofry left a comment

Choose a reason for hiding this comment

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

Looks good!

Hopefully, we can remove the hardcoded complex logic from client.go in the follow-up task

@saledjenic saledjenic merged commit 5fe852d into develop Jul 4, 2025
23 of 24 checks passed
@saledjenic saledjenic deleted the chore/status-chain-gasless-related-improvements branch July 4, 2025 14:02
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.

5 participants