diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index ea328ecf..0548820c 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -45,6 +45,9 @@ jobs: timeout-minutes: 180 strategy: fail-fast: false + # The suites share one provider key. Running them one at a time keeps the combined + # request rate inside the plan limit; concurrently they trip HTTP 429. + max-parallel: 1 matrix: suite: - name: mainnet forks @@ -59,7 +62,15 @@ jobs: env: FOUNDRY_PROFILE: pr ETH_RPC_URL: ${{ secrets.ETH_RPC_URL }} - MAINNET_FORK_BLOCK: 25422678 + # Must be at or after the Liquid Lane 3 deployment (blocks 25697401-25697403), otherwise + # the mainnet suites assert against contracts that do not yet exist at the fork block. + # Bump this whenever a deployment adds live state that new fork tests depend on. + MAINNET_FORK_BLOCK: 25700000 + # Cap in-job test parallelism as a second brake on the provider request rate. + # Note: --compute-units-per-second and --fork-retries cannot be used here. They are + # gated behind --rpc-url, and --rpc-url is an alias for --fork-url, which would fork + # every test rather than only the ones that call vm.createSelectFork. + FORK_TEST_FLAGS: --threads 2 steps: - uses: bullfrogsec/bullfrog@1831f79cce8ad602eef14d2163873f27081ebfb3 # v0.8.4 - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 @@ -71,13 +82,28 @@ jobs: with: version: v1.7.1 - - name: Cache Foundry RPC responses - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + # Restore and save are split so the cache is written even when the suite fails. + # actions/cache skips its post-run save on job failure, so while the suites were + # failing every run started cold, re-fetched all state, and tripped the provider + # rate limit - which failed the job, which skipped the save. A partial cache from + # a failed run still removes most of the requests the next run would make. + - name: Restore Foundry RPC cache + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ~/.foundry/cache/rpc key: ${{ runner.os }}-foundry-rpc-mainnet-${{ env.MAINNET_FORK_BLOCK }}-${{ matrix.suite.id }} restore-keys: | + ${{ runner.os }}-foundry-rpc-mainnet-${{ env.MAINNET_FORK_BLOCK }}-${{ matrix.suite.id }} ${{ runner.os }}-foundry-rpc-mainnet-${{ env.MAINNET_FORK_BLOCK }}- - name: Run Forge mainnet tests - run: ${{ matrix.suite.command }} + run: ${{ matrix.suite.command }} $FORK_TEST_FLAGS + + - name: Save Foundry RPC cache + if: always() + uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: ~/.foundry/cache/rpc + # Unique per run: cache/save errors on an existing key, and restore-keys above + # matches the prefix so the newest entry is picked up regardless. + key: ${{ runner.os }}-foundry-rpc-mainnet-${{ env.MAINNET_FORK_BLOCK }}-${{ matrix.suite.id }}-${{ github.run_id }}-${{ github.run_attempt }} diff --git a/.github/workflows/trufflehog.yml b/.github/workflows/trufflehog.yml index 1b393afd..ae6c07f3 100644 --- a/.github/workflows/trufflehog.yml +++ b/.github/workflows/trufflehog.yml @@ -33,4 +33,8 @@ jobs: path: . base: ${{ github.event.pull_request.base.sha }} head: ${{ github.event.pull_request.head.sha }} - extra_args: --results=verified,unknown + # Lob is excluded: its key pattern is `test_` + 35 alphanumerics, which collides with + # Foundry test names recorded in snapshots/gas.txt (e.g. test_AddAdapterUsesAdapterWhitelistEntry). + # That produced 56 false positives and, because egress to api.lob.com is blocked, they surfaced + # as unverifiable and failed the scan. A postal-mail API key cannot legitimately live in this repo. + extra_args: --results=verified,unknown --exclude-detectors=lob diff --git a/src/contracts/adapters/ll-adapter/tokens-to-redeem/msyrupUSDp_Account.sol b/src/contracts/adapters/ll-adapter/tokens-to-redeem/msyrupUSDp_Account.sol index 89ec1030..e326d458 100644 --- a/src/contracts/adapters/ll-adapter/tokens-to-redeem/msyrupUSDp_Account.sol +++ b/src/contracts/adapters/ll-adapter/tokens-to-redeem/msyrupUSDp_Account.sol @@ -11,7 +11,11 @@ import {IMidasTokenAccount} from "../../../../interfaces/adapters/ll-adapter/mid contract msyrupUSDp_Account is MidasCompAccount, IMidasTokenAccount { uint48 internal constant TOKEN_COOLDOWN = 1 days; - address internal constant MAINNET_USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + /// @dev Unlike the other Midas USD vaults, this redemption vault lists only USDT as a payment + /// token, so USDC would be rejected. MidasAccount._requestRedeem falls back to + /// REDEMPTION_TOKEN when the vault has no config for the vault asset, and the USDT is + /// settled back to the vault asset through the CoW converter. + address internal constant MAINNET_USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7; address internal constant TOKEN_ADDRESS = 0x2fE058CcF29f123f9dd2aEC0418AA66a877d8E50; address internal constant REDEMPTION_VAULT_ADDRESS = 0x71EFa7AF1686C5c04AA34a120a91cb4262679C44; @@ -27,7 +31,7 @@ contract msyrupUSDp_Account is MidasCompAccount, IMidasTokenAccount { factory, TOKEN_COOLDOWN, TOKEN_ADDRESS, - MAINNET_USDC, + MAINNET_USDT, REDEMPTION_VAULT_ADDRESS, cowSwapSettlement )