Skip to content

Add CI job for verifier factory contracts#784

Open
lemunozm wants to merge 31 commits intomainfrom
ci-verifier
Open

Add CI job for verifier factory contracts#784
lemunozm wants to merge 31 commits intomainfrom
ci-verifier

Conversation

@lemunozm
Copy link
Contributor

@lemunozm lemunozm commented Feb 19, 2026

Product requirements

  • We want an easy way to verify contracts for externals in different chains. The current problem is we need to run the verifier script in an specific commit inside the repo

Design notes

  • Runnable github action that fetches the repo in a specific tag, copy the src/ into the current state and then run the script/VerifyFactoryContracts.s.sol script
  • Because the script is idempotent and fast for already verified contracts, it runs automatically in all configured networks from env/*.json files
  • Added extra ward to CI jobs to protect secrets
  • Some fixes in the script to make it work fine in CI

@lemunozm lemunozm self-assigned this Feb 19, 2026
Comment on lines +215 to +220
- name: Mask secrets
run: |
while IFS='=' read -r key value; do
[[ -z "$key" || "$key" == \#* || -z "$value" ]] && continue
echo "::add-mask::$value"
done < .env
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 is a especial addition to the CI jobs that uses secrets that avoid leak those secret in some logs by error

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 Github upload the tarball of an action as an artifact that's publicly available, including the secrets in the .env? Also, we don't need the PRIVATE_KEY for verification.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good question 🤔, then that would be something to fix...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Very good catch @wischli! Now here (61bc4c7), I've moved the loading secret part to each individual job, so the tarball never has an .env file.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Unless you specify a file upload on the job the files are normally lost.
The private key is accessible to any job in this repository that calls the Google cloud login step whether we put it in an environment file or not, it doesn't really matter

@lemunozm lemunozm marked this pull request as ready for review February 19, 2026 11:49
Base automatically changed from global-dump-secrets to main February 23, 2026 10:50
Copy link
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.

How can I test this action before we merge it? Definitely need @gpmayorga eyes on this before merging.

It would be great to have an error reporting, either to slack or by creating a Github issue in this repo in case this action fails. Did you look into that?

submodules: recursive

- name: Checkout src/ from deployed version
run: git checkout ${{ inputs.source_version }} -- src/
Copy link
Contributor

Choose a reason for hiding this comment

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

AFAICT, we also need to include lib/ and foundry.toml. Did you test this manually?

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, I already tested this.

Note the repo that is downloaded is from main, but later we add the src from the tag to be able to do forge verify-contract with that abi. As long as src compiles in its own, we're fine (at least by now)

Comment on lines +215 to +220
- name: Mask secrets
run: |
while IFS='=' read -r key value; do
[[ -z "$key" || "$key" == \#* || -z "$value" ]] && continue
echo "::add-mask::$value"
done < .env
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 Github upload the tarball of an action as an artifact that's publicly available, including the secrets in the .env? Also, we don't need the PRIVATE_KEY for verification.

@lemunozm
Copy link
Contributor Author

How can I test this action before we merge it? Definitely need @gpmayorga eyes on this before merging.

We can not test this until it's merged (GitHub limitations). But what I did is to modify the trigger to push trigger, and I could saw all jobs worked correctly, verifying it.

It would be great to have an error reporting, either to slack or by creating a Github issue in this repo in case this action fails. Did you look into that?

This CI is triggered by a specific action. So the person who trigger this will see all their jobs passing/failing, and they will evaluate consecutively. I don't think we need further error reporting (at least by now)

Copy link
Collaborator

@gpmayorga gpmayorga left a comment

Choose a reason for hiding this comment

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

I read the script and I'm not sure I understand why we need to package the entire repo, upload it and then download it within the same job?
A much easier approach without having to deal with upload/download would be:

  1. Setup -> establish the matrix (nothing else)
  2. Verify -> git checkout $COMMIT -- /src then do what you need to do for each enviornment.

@github-actions
Copy link

Coverage after merging ci-verifier into main will be

97.10%

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
   OpsGuardian.sol100%100%100%100%
   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
   GasService.sol96.55%100%87.50%96.20%106, 135, 145
   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.80%62.50%80%86.46%438, 440–441, 443, 443–444, 446, 448, 448–449, 453, 453–454, 456, 459, 459–460, 462, 465, 465–466, 469, 472, 472, 474, 476, 508–512, 517–518, 520–521, 523–524
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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants