Skip to content

Swappable GasService through OpsAdmin#806

Open
lemunozm wants to merge 14 commits intomainfrom
swappable-gas-service
Open

Swappable GasService through OpsAdmin#806
lemunozm wants to merge 14 commits intomainfrom
swappable-gas-service

Conversation

@lemunozm
Copy link
Copy Markdown
Contributor

Product requirements

Design notes

Solution A (failed).

I initially allow direct modification to GasService values using OpsAdmin making GasService mutable. But this comes with some issues:

  • Extra SLOAD(s).
  • We need to do a lot of calls one per (chain,message) tuple.
    • i.e: if some message change its value I need to update it in each chain for all chains O(n*n).
    • I could use "default" values but I would need another SLOAD.
  • Some messages with internal diferentiations are not easy to represent for dynamic updates
    • i.e: UpdateVault comes in some flavors: DeployAndLink, Link, Unlink, each of them with different values but same MessageType to index.

Solution B

  • Hardcode every change in the GasService bytecode in an immutable way (as it is).
  • Call script/deploy-gas-service.sh to push a safe OpsAdmin propostion to all changes to acept this new GasService.

@lemunozm lemunozm self-assigned this Mar 25, 2026

EnvConfig memory config = Env.load(vm.envString("NETWORK"));

GasService gasService = new GasService(config.network.buildBatchLimits());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Shouldn't the new GasService also be included in the env JSON?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah! Good one, I'll add as part of the script

Copy link
Copy Markdown
Contributor Author

@lemunozm lemunozm Mar 30, 2026

Choose a reason for hiding this comment

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

Added!

@hieronx
Copy link
Copy Markdown
Contributor

hieronx commented Mar 27, 2026

@lemunozm one note: I think we should actually move GasService out of core. Why: every time we update benchmarks / handle some new chain, we will be updating this file in the git repo, and redeploying it. The philosophy of the core is that it's an immutable set of contracts that at some point will never need to be updated; the gas service does not fit that description.

@lemunozm
Copy link
Copy Markdown
Contributor Author

I agree 👍🏻. Also, from the last iteration regarding this, now we have 2 interfaces IMessageProperties (the one that core reads for the things it needs) and IGasService. So now the core doesn't have any knowledge of the GasService contract.

Is it ok if we move this to admin module? I some way, it contains administration stuff regarding the protocol gas for the supported chains.

@hieronx
Copy link
Copy Markdown
Contributor

hieronx commented Mar 30, 2026

Is it ok if we move this to admin module? I some way, it contains administration stuff regarding the protocol gas for the supported chains.

Seems fine yes!

@lemunozm lemunozm force-pushed the swappable-gas-service branch from 028e478 to 1df5d5c Compare April 6, 2026 09:51
@wischli wischli added the version:v3.3.0 Scoped for v3.3.0 label Apr 8, 2026
Copy link
Copy Markdown
Contributor

@wischli wischli left a comment

Choose a reason for hiding this comment

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

Just a few nits and one raised concern that I wanted to discuss but doesn't require any codechange probably.


// Rely opsGuardian
report.multiAdapter.rely(address(report.opsGuardian));
report.gateway.rely(address(report.opsGuardian));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I am not sure if we should give the OpsGuardian a Gateway ward as it allows for updating the message processor or replacing adapters or even calling handle directly to bypass multi-adapter quorum for inbound messages. So I feel like this is in conflict with our trust model. Though, IIUC, this would only be possible in a future version of the OpsGuardian which would support allow it to forward arbitrary calls which it currently cannot?!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is a very good catch! Definitely a security issue imo.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Note that the ward is from the OpsGuardian, not OpsSafe. The OpsGuardian can only do what is coded on it. No one can call handle() or bypass communication actions.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah you are right, I was misreading it, this is okay. We just need to be cautious with what we add to OpsGuardian, but that is anyways important.

Comment thread src/admin/OpsGuardian.sol
emit File(what, data);
}

function setGasService(IGasService gasService) external onlySafe {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nits:

  1. I think we should an event here such in case it matters for the SDK/Apps.
  2. Missing UTs for this setter
  3. Missing @inheritdoc header

Copy link
Copy Markdown
Contributor Author

@lemunozm lemunozm Apr 9, 2026

Choose a reason for hiding this comment

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

The events are already in the file() methods called by this method, not sure if we want to add another event for this 🤔, in the same way we dont add an event for createPool or init adapters.

Good point with the UTs and documentation and the rest of the NITs!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Changes: b411c9c


/// @notice Updates the gas service
/// @param gasService the new gas service to use
function setGasService(IGasService gasService) external;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: We should add a gateway view ABI to this interface

Comment thread src/admin/interfaces/IOpsGuardian.sol Outdated
@@ -39,6 +40,10 @@ interface IOpsGuardian {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: Needs to be updated for the new gateway addition

@github-actions github-actions bot added audit:needed Requires audit review scope:contracts Modifies deployed or deployable contract code scope:invariant Invariant/fuzz test changes (recon, echidna, medusa) scope:scripts Deploy or operational scripts that transact onchain scope:tests Test-only changes (fuzz, invariant, unit, fork) labels Apr 15, 2026
@github-actions
Copy link
Copy Markdown

Auto-labeled: scope:contracts, scope:tests, scope:invariant, scope:scripts, audit:needed. Please verify and add type/version labels manually.

@github-actions
Copy link
Copy Markdown

Coverage after merging swappable-gas-service into main will be

97.11%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
src/adapters
   AxelarAdapter.sol97.67%90%100%100%118
   ChainlinkAdapter.sol98.11%91.67%100%100%95
   LayerZeroAdapter.sol98.41%90%100%100%124
   RecoveryAdapter.sol100%100%100%100%
   WormholeAdapter.sol97.67%90%100%100%108
src/admin
   GasService.sol96.55%100%87.50%96.20%106, 135, 145
   OpsGuardian.sol97.83%92.86%100%100%47
   ProtocolGuardian.sol100%100%100%100%
   Root.sol100%100%100%100%
   TokenRecoverer.sol100%100%100%100%
src/core/hub
   Accounting.sol97.92%96%100%98.31%134, 137
   Holdings.sol97.71%88.89%100%100%118, 243, 82
   Hub.sol93.98%81.13%93.02%97.54%269, 287, 305, 339, 343, 374–375, 413, 498–499, 544, 549, 586, 601, 87
   HubHandler.sol98%90.91%100%100%71
   HubRegistry.sol92.39%76.67%100%100%118, 124, 130, 35, 46, 79, 99
   ShareClassManager.sol98.81%95.45%100%100%42
src/core/libraries
   PricingLib.sol100%100%100%100%
src/core/messaging
   Gateway.sol100%100%100%100%
   MessageDispatcher.sol99.60%98.55%100%100%733
   MessageProcessor.sol82.42%60.26%100%99.01%101, 103, 109, 112, 114, 125, 130, 139, 142, 145, 157, 160, 163, 168, 178, 181, 190, 193, 196, 209, 220, 225, 228, 232, 83–84, 87–88, 91–92, 97, 99
   MultiAdapter.sol100%100%100%100%
src/core/messaging/libraries
   MessageLib.sol100%100%100%100%
src/core/spoke
   BalanceSheet.sol97.47%96.97%92.59%98.55%291, 348, 57
   PoolEscrow.sol100%100%100%100%
   ShareToken.sol92.41%60%94.44%98.04%100, 112, 144, 146, 32
   Spoke.sol97.46%89.71%100%100%132, 132–133, 133, 135, 92–93
   VaultRegistry.sol93.88%85.71%100%98.18%54, 60–62, 98–99
src/core/spoke/factories
   PoolEscrowFactory.sol100%100%100%100%
   TokenFactory.sol100%100%100%100%
src/core/utils
   BatchedMulticall.sol100%100%100%100%
   ContractUpdater.sol100%100%100%100%
src/deployment
   ActionBatchers.sol84.86%62.50%80%86.52%439, 441–442, 444, 444–445, 447, 449, 449–450, 454, 454–455, 457, 460, 460–461, 463, 466, 466–467, 470, 473, 473, 475, 477, 509–513, 518–519, 521–522, 524–525
src/hooks
   BaseTransferHook.sol100%100%100%100%
   FreelyTransferable.sol92.31%80%100%100%37
   FreezeOnly.sol100%100%100%100%
   FullRestrictions.sol95.24%88.89%100%100%47
   RedemptionRestrictions.sol85.71%50%100%100%37
src/hooks/libraries
   UpdateRestrictionMessageLib.sol90%50%100%100%40, 61, 82
src/managers/hub
   NAVManager.sol100%100%100%100%
   SimplePriceManager.sol100%100%100%100%
src/managers/spoke
   MerkleProofManager.sol97.01%87.50%100%100%103, 110
   OnOfframpManager.sol100%100%100%100%
   QueueManager.sol100%100%100%100%
src/managers/spoke/decoders
   BaseDecoder.sol100%100%100%100%
   CircleDecoder.sol83.33%100%100%75%22
   VaultDecoder.sol100%100%100%100%
src/misc
   Auth.sol100%100%100%100%
   ERC20.sol100%100%100%100%
   Escrow.sol56.25%33.33%100%66.67%17, 19, 23–24, 24, 24, 26
   Multicall.sol91.67%66.67%100%100%19
   Recoverable.sol100%100%100%100%
   ReentrancyProtection.sol90%75%100%100%24
src/misc/libraries
   ArrayLib.sol100%100%100%100%
   BitmapLib.sol100%100%100%100%
   BytesLib.sol90.27%56%100%100%109, 120, 131, 14, 142, 153, 16, 164, 175, 186, 87
   CastLib.sol95.24%66.67%100%100%10, 34
   EIP712Lib.sol100%100%100%100%
   ExcessivelySafeCallLib.sol100%100%100%100%
   MathLib.sol93.46%76.19%100%97.33%34–35, 44, 46, 48, 50, 52
   MerkleProofLib.sol100%100%100%100%
   SafeTransferLib.sol96.97%92.86%100%100%75
   SignatureLib.sol95.24%80%100%100%17
   StringLib.sol100%100%100%100%
   TransientArrayLib.sol100%100%100%100%
   TransientBytesLib.sol100%100%100%100%
   TransientStorageLib.sol100%100%100%100%
src/spell
   V2CleaningsSpell.sol0%0%0%0%100–103, 103–106, 111–112, 112–114, 114, 114–116, 116, 116–118, 118, 118–119, 121, 124, 126–127, 129, 133–137, 46–47, 47, 47–48, 50–53, 55, 55–56, 58, 61, 63, 63, 65, 65–66, 66–69, 71, 75, 75–76, 81, 81–82, 82–84, 86–87, 91–94, 96–97
src/utils
   RefundEscrow.sol100%100%100%100%
   RefundEscrowFactory.sol100%100%100%100%
   SubsidyManager.sol100%100%100%100%
src/valuations
   IdentityValuation.sol100%100%100%100%
   OracleValuation.sol100%100%100%100%
src/vaults
   AsyncRequestManager.sol96.85%86.36%100%99.64%195, 198, 201, 204, 215, 227, 295, 328, 455, 460, 505, 573, 580
   AsyncVault.sol96.25%83.33%95%98.15%146, 47
   BaseVaults.sol93.50%80.77%95.24%95.45%124, 137, 239, 309–310, 85–86, 86, 86–88
   BatchRequestManager.sol100%100%100%100%
   SyncDepositVault.sol100%100%100%100%
   SyncManager.sol98.58%92.59%100%100%67, 72
   VaultRouter.sol87.37%58.82%100%91.53%107, 107, 109–110, 110, 112, 149, 70, 73–74, 86–87
src/vaults/factories
   AsyncVaultFactory.sol93.75%50%100%100%32
   SyncDepositVaultFactory.sol95%50%100%100%40
src/vaults/libraries
   RequestCallbackMessageLib.sol89.58%50%100%100%104, 139, 38, 57, 77
   RequestMessageLib.sol89.74%50%100%100%37, 55, 72, 89

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

audit:needed Requires audit review scope:contracts Modifies deployed or deployable contract code scope:invariant Invariant/fuzz test changes (recon, echidna, medusa) scope:scripts Deploy or operational scripts that transact onchain scope:tests Test-only changes (fuzz, invariant, unit, fork) version:v3.3.0 Scoped for v3.3.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants