From 56cfa253fac22ce84bd4507ed2cafbd7eeaff3a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Bruno?= Date: Mon, 17 Mar 2025 17:28:09 -0300 Subject: [PATCH 1/7] Fix invariant error --- contracts/lib/AclAmmMath.sol | 57 ++++++++-------- test/foundry/AclAmmPoolVirtualBalances.t.sol | 68 ++++++++++++++------ test/foundry/utils/BaseAclAmmTest.sol | 9 +-- 3 files changed, 81 insertions(+), 53 deletions(-) diff --git a/contracts/lib/AclAmmMath.sol b/contracts/lib/AclAmmMath.sol index d5e3aa6..ae13c6c 100644 --- a/contracts/lib/AclAmmMath.sol +++ b/contracts/lib/AclAmmMath.sol @@ -64,9 +64,9 @@ library AclAmmMath { finalBalances[0] = balancesScaled18[0] + virtualBalances[0]; finalBalances[1] = balancesScaled18[1] + virtualBalances[1]; - uint256 invariant = finalBalances[0].mulDown(finalBalances[1]); + uint256 invariant = finalBalances[0].mulUp(finalBalances[1]); - return finalBalances[tokenOutIndex] - invariant.divDown(finalBalances[tokenInIndex] + amountGivenScaled18); + return finalBalances[tokenOutIndex] - invariant.divUp(finalBalances[tokenInIndex] + amountGivenScaled18); } function calculateInGivenOut( @@ -109,6 +109,11 @@ library AclAmmMath { virtualBalances = lastVirtualBalances; + // If the last timestamp is the same as the current timestamp, virtual balances were already reviewed in the current block. + if (lastTimestamp == block.timestamp) { + return (virtualBalances, false); + } + // Calculate currentSqrtQ0 uint256 currentSqrtQ0 = calculateSqrtQ0( currentTimestamp, @@ -118,30 +123,6 @@ library AclAmmMath { sqrtQ0State.endTime ); - if (isPoolInRange(balancesScaled18, lastVirtualBalances, centerednessMargin) == false) { - uint256 q0 = currentSqrtQ0.mulDown(currentSqrtQ0); - - if (isAboveCenter(balancesScaled18, lastVirtualBalances)) { - virtualBalances[1] = lastVirtualBalances[1].mulDown( - LogExpMath.pow(FixedPoint.ONE - c, (block.timestamp - lastTimestamp) * FixedPoint.ONE) - ); - // Va = (Ra * (Vb + Rb)) / (((Q0 - 1) * Vb) - Rb) - virtualBalances[0] = (balancesScaled18[0].mulDown(virtualBalances[1] + balancesScaled18[1])).divDown( - (q0 - FixedPoint.ONE).mulDown(virtualBalances[1]) - balancesScaled18[1] - ); - } else { - virtualBalances[0] = lastVirtualBalances[0].mulDown( - LogExpMath.pow(FixedPoint.ONE - c, (block.timestamp - lastTimestamp) * FixedPoint.ONE) - ); - // Vb = (Rb * (Va + Ra)) / (((Q0 - 1) * Va) - Ra) - virtualBalances[1] = (balancesScaled18[1].mulDown(virtualBalances[0] + balancesScaled18[0])).divDown( - (q0 - FixedPoint.ONE).mulDown(virtualBalances[0]) - balancesScaled18[0] - ); - } - - changed = true; - } - if ( sqrtQ0State.startTime != 0 && currentTimestamp > sqrtQ0State.startTime && @@ -170,6 +151,30 @@ library AclAmmMath { changed = true; } + + if (isPoolInRange(balancesScaled18, lastVirtualBalances, centerednessMargin) == false) { + uint256 q0 = currentSqrtQ0.mulDown(currentSqrtQ0); + + if (isAboveCenter(balancesScaled18, lastVirtualBalances)) { + virtualBalances[1] = lastVirtualBalances[1].mulDown( + LogExpMath.pow(FixedPoint.ONE - c, (block.timestamp - lastTimestamp) * FixedPoint.ONE) + ); + // Va = (Ra * (Vb + Rb)) / (((Q0 - 1) * Vb) - Rb) + virtualBalances[0] = (balancesScaled18[0].mulDown(virtualBalances[1] + balancesScaled18[1])).divDown( + (q0 - FixedPoint.ONE).mulDown(virtualBalances[1]) - balancesScaled18[1] + ); + } else { + virtualBalances[0] = lastVirtualBalances[0].mulDown( + LogExpMath.pow(FixedPoint.ONE - c, (block.timestamp - lastTimestamp) * FixedPoint.ONE) + ); + // Vb = (Rb * (Va + Ra)) / (((Q0 - 1) * Va) - Ra) + virtualBalances[1] = (balancesScaled18[1].mulDown(virtualBalances[0] + balancesScaled18[0])).divDown( + (q0 - FixedPoint.ONE).mulDown(virtualBalances[0]) - balancesScaled18[0] + ); + } + + changed = true; + } } function isPoolInRange( diff --git a/test/foundry/AclAmmPoolVirtualBalances.t.sol b/test/foundry/AclAmmPoolVirtualBalances.t.sol index 7e4317f..ab8178a 100644 --- a/test/foundry/AclAmmPoolVirtualBalances.t.sol +++ b/test/foundry/AclAmmPoolVirtualBalances.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.24; -import { console } from "forge-std/Test.sol"; +import { console, console2 } from "forge-std/Test.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; @@ -20,14 +20,13 @@ contract AclAmmPoolVirtualBalancesTest is BaseAclAmmTest { using FixedPoint for uint256; using ArrayHelpers for *; - uint256 internal constant maxPrice = 4000; - uint256 internal constant minPrice = 2000; - uint256 internal constant initialABalance = 1_000_000e18; - uint256 internal constant initialBBalance = 100_000e18; + uint256 private constant _PRICE_RANGE = 2e18; // Max price is 2x min price. + uint256 private constant _INITIAL_BALANCE_A = 1_000_000e18; + uint256 private constant _INITIAL_BALANCE_B = 100_000e18; function setUp() public virtual override { - setSqrtQ0(minPrice, maxPrice); - setInitialBalances(initialABalance, initialBBalance); + setSqrtQ0(_PRICE_RANGE); + setInitialBalances(_INITIAL_BALANCE_A, _INITIAL_BALANCE_B); setIncreaseDayRate(0); super.setUp(); } @@ -53,11 +52,11 @@ contract AclAmmPoolVirtualBalancesTest is BaseAclAmmTest { uint256[] memory newInitialBalances = new uint256[](2); if (diffCoefficient > 0) { - newInitialBalances[0] = initialABalance * uint256(diffCoefficient); - newInitialBalances[1] = initialBBalance * uint256(diffCoefficient); + newInitialBalances[0] = _INITIAL_BALANCE_A * uint256(diffCoefficient); + newInitialBalances[1] = _INITIAL_BALANCE_B * uint256(diffCoefficient); } else { - newInitialBalances[0] = initialABalance / uint256(-diffCoefficient); - newInitialBalances[1] = initialBBalance / uint256(-diffCoefficient); + newInitialBalances[0] = _INITIAL_BALANCE_A / uint256(-diffCoefficient); + newInitialBalances[1] = _INITIAL_BALANCE_B / uint256(-diffCoefficient); } setInitialBalances(newInitialBalances[0], newInitialBalances[1]); @@ -171,21 +170,49 @@ contract AclAmmPoolVirtualBalancesTest is BaseAclAmmTest { } } - function testSwap_Fuzz(uint256 exactAmountIn) public { - exactAmountIn = bound(exactAmountIn, 1e18, 10_000e18); + function testSwapExactIn_Fuzz(uint256 exactAmountIn) public { + exactAmountIn = bound(exactAmountIn, 1e6, _INITIAL_BALANCE_A); + + uint256[] memory oldVirtualBalances = AclAmmPool(pool).getLastVirtualBalances(); + uint256 invariantBefore = _getCurrentInvariant(); + + vm.prank(alice); + uint256 tokenBOut = router.swapSingleTokenExactIn( + pool, + dai, + usdc, + exactAmountIn, + 1, + UINT256_MAX, + false, + new bytes(0) + ); + + console2.log("tokenBOut ", tokenBOut); + + uint256 invariantAfter = _getCurrentInvariant(); + assertLe(invariantBefore, invariantAfter, "Invariant should not decrease"); + + uint256[] memory newVirtualBalances = AclAmmPool(pool).getLastVirtualBalances(); + assertEq(newVirtualBalances[0], oldVirtualBalances[0], "Virtual A balances do not match"); + assertEq(newVirtualBalances[1], oldVirtualBalances[1], "Virtual B balances do not match"); + } + + function testSwapExactOut_Fuzz(uint256 exactAmountOut) public { + exactAmountOut = bound(exactAmountOut, 1e6, _INITIAL_BALANCE_B); uint256[] memory virtualBalances = _calculateVirtualBalances(); uint256 invariantBefore = _getCurrentInvariant(); vm.prank(alice); - router.swapSingleTokenExactIn(pool, dai, usdc, exactAmountIn, 1, UINT256_MAX, false, new bytes(0)); + router.swapSingleTokenExactOut(pool, dai, usdc, exactAmountOut, UINT256_MAX, UINT256_MAX, false, new bytes(0)); uint256 invariantAfter = _getCurrentInvariant(); - assertEq(invariantBefore, invariantAfter, "Invariant should not change"); + assertLe(invariantBefore, invariantAfter, "Invariant should not decrease"); - uint256[] memory curentVirtualBalances = AclAmmPool(pool).getLastVirtualBalances(); - assertEq(curentVirtualBalances[0], virtualBalances[0], "Virtual A balances don't equal"); - assertEq(curentVirtualBalances[1], virtualBalances[1], "Virtual B balances don't equal"); + uint256[] memory currentVirtualBalances = AclAmmPool(pool).getLastVirtualBalances(); + assertEq(currentVirtualBalances[0], virtualBalances[0], "Virtual A balances don't equal"); + assertEq(currentVirtualBalances[1], virtualBalances[1], "Virtual B balances don't equal"); } function testAddLiquidity_Fuzz(uint256 exactBptAmountOut) public { @@ -231,6 +258,7 @@ contract AclAmmPoolVirtualBalancesTest is BaseAclAmmTest { function _getCurrentInvariant() internal view returns (uint256) { (, , uint256[] memory balances, ) = vault.getPoolTokenInfo(pool); + console2.log("balances", balances[0], balances[1]); return AclAmmPool(pool).computeInvariant(balances, Rounding.ROUND_DOWN); } @@ -238,8 +266,8 @@ contract AclAmmPoolVirtualBalancesTest is BaseAclAmmTest { virtualBalances = new uint256[](2); uint256 sqrtQMinusOne = sqrtQ0() - FixedPoint.ONE; - virtualBalances[0] = initialABalance.divDown(sqrtQMinusOne); - virtualBalances[1] = initialBBalance.divDown(sqrtQMinusOne); + virtualBalances[0] = _INITIAL_BALANCE_A.divDown(sqrtQMinusOne); + virtualBalances[1] = _INITIAL_BALANCE_B.divDown(sqrtQMinusOne); } function _createNewPool() internal returns (address initalPool, address newPool) { diff --git a/test/foundry/utils/BaseAclAmmTest.sol b/test/foundry/utils/BaseAclAmmTest.sol index fb5e4d1..59f6042 100644 --- a/test/foundry/utils/BaseAclAmmTest.sol +++ b/test/foundry/utils/BaseAclAmmTest.sol @@ -57,16 +57,11 @@ contract BaseAclAmmTest is AclAmmPoolContractsDeployer, BaseVaultTest { (daiIdx, usdcIdx) = getSortedIndexes(address(dai), address(usdc)); } - function setSqrtQ0(uint256 minPrice, uint256 maxPrice) internal { - uint256 doubleQ0 = maxPrice.divDown(minPrice); - uint256 Q0 = GyroPoolMath.sqrt(doubleQ0, 5); + function setSqrtQ0(uint256 priceRange) internal { + uint256 Q0 = GyroPoolMath.sqrt(priceRange, 5); _sqrtQ0 = GyroPoolMath.sqrt(Q0, 5); } - function setSqrtQ0(uint256 sqrtQ0_) internal { - _sqrtQ0 = sqrtQ0_; - } - function sqrtQ0() internal view returns (uint256) { return _sqrtQ0; } From 401f0ddd472e5c09c552be96269e6ab308a409da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Bruno?= Date: Mon, 17 Mar 2025 17:30:00 -0300 Subject: [PATCH 2/7] Remove console.log --- test/foundry/AclAmmPoolVirtualBalances.t.sol | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/test/foundry/AclAmmPoolVirtualBalances.t.sol b/test/foundry/AclAmmPoolVirtualBalances.t.sol index ab8178a..7c73137 100644 --- a/test/foundry/AclAmmPoolVirtualBalances.t.sol +++ b/test/foundry/AclAmmPoolVirtualBalances.t.sol @@ -2,8 +2,6 @@ pragma solidity ^0.8.24; -import { console, console2 } from "forge-std/Test.sol"; - import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { GyroPoolMath } from "@balancer-labs/v3-pool-gyro/contracts/lib/GyroPoolMath.sol"; @@ -177,18 +175,7 @@ contract AclAmmPoolVirtualBalancesTest is BaseAclAmmTest { uint256 invariantBefore = _getCurrentInvariant(); vm.prank(alice); - uint256 tokenBOut = router.swapSingleTokenExactIn( - pool, - dai, - usdc, - exactAmountIn, - 1, - UINT256_MAX, - false, - new bytes(0) - ); - - console2.log("tokenBOut ", tokenBOut); + router.swapSingleTokenExactIn(pool, dai, usdc, exactAmountIn, 1, UINT256_MAX, false, new bytes(0)); uint256 invariantAfter = _getCurrentInvariant(); assertLe(invariantBefore, invariantAfter, "Invariant should not decrease"); @@ -258,7 +245,6 @@ contract AclAmmPoolVirtualBalancesTest is BaseAclAmmTest { function _getCurrentInvariant() internal view returns (uint256) { (, , uint256[] memory balances, ) = vault.getPoolTokenInfo(pool); - console2.log("balances", balances[0], balances[1]); return AclAmmPool(pool).computeInvariant(balances, Rounding.ROUND_DOWN); } From 8213f34562f48011385a741b05103567e187197f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Bruno?= Date: Mon, 17 Mar 2025 17:33:06 -0300 Subject: [PATCH 3/7] Fix lint --- contracts/lib/AclAmmMath.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/lib/AclAmmMath.sol b/contracts/lib/AclAmmMath.sol index ae13c6c..fbc10d6 100644 --- a/contracts/lib/AclAmmMath.sol +++ b/contracts/lib/AclAmmMath.sol @@ -109,7 +109,8 @@ library AclAmmMath { virtualBalances = lastVirtualBalances; - // If the last timestamp is the same as the current timestamp, virtual balances were already reviewed in the current block. + // If the last timestamp is the same as the current timestamp, virtual balances were already reviewed in the + // current block. if (lastTimestamp == block.timestamp) { return (virtualBalances, false); } From 05bc74277e12f8802e0cec4c2762192f31dce1cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Bruno?= Date: Mon, 17 Mar 2025 17:33:31 -0300 Subject: [PATCH 4/7] Remove unused import --- contracts/interfaces/IAclAmmPool.sol | 2 -- 1 file changed, 2 deletions(-) diff --git a/contracts/interfaces/IAclAmmPool.sol b/contracts/interfaces/IAclAmmPool.sol index 9b51dab..40d4ba3 100644 --- a/contracts/interfaces/IAclAmmPool.sol +++ b/contracts/interfaces/IAclAmmPool.sol @@ -2,8 +2,6 @@ pragma solidity ^0.8.24; -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - import { IBasePool } from "@balancer-labs/v3-interfaces/contracts/vault/IBasePool.sol"; /// @dev Struct with data for deploying a new AclAmmPool. From 795b44efef3aa24cd1e014647d2f1e9229806ad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Bruno?= Date: Mon, 17 Mar 2025 17:39:49 -0300 Subject: [PATCH 5/7] Fix Price Range test --- package.json | 2 +- test/foundry/AclAmmPoolVirtualBalances.t.sol | 12 ++++++------ test/foundry/utils/BaseAclAmmTest.sol | 6 +++++- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 86bd440..3f0ad70 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "prettier": "npx prettier --write --plugin=prettier-plugin-solidity 'contracts/**/*.sol' 'test/**/*.sol'", "test": "yarn test:hardhat && yarn test:forge", "test:hardhat": "hardhat test", - "test:forge": "forge test --ffi -vvv" + "test:forge": "yarn build && REUSING_HARDHAT_ARTIFACTS=true forge test --ffi -vvv" }, "packageManager": "yarn@4.0.0-rc.42", "dependencies": { diff --git a/test/foundry/AclAmmPoolVirtualBalances.t.sol b/test/foundry/AclAmmPoolVirtualBalances.t.sol index 7c73137..1fe4cc8 100644 --- a/test/foundry/AclAmmPoolVirtualBalances.t.sol +++ b/test/foundry/AclAmmPoolVirtualBalances.t.sol @@ -23,7 +23,7 @@ contract AclAmmPoolVirtualBalancesTest is BaseAclAmmTest { uint256 private constant _INITIAL_BALANCE_B = 100_000e18; function setUp() public virtual override { - setSqrtQ0(_PRICE_RANGE); + setPriceRange(_PRICE_RANGE); setInitialBalances(_INITIAL_BALANCE_A, _INITIAL_BALANCE_B); setIncreaseDayRate(0); super.setUp(); @@ -91,17 +91,17 @@ contract AclAmmPoolVirtualBalancesTest is BaseAclAmmTest { } } - function testWithDifferentPriceRange_Fuzz(uint256 newSqrtQ) public { - newSqrtQ = bound(newSqrtQ, 1.4e18, 1_000_000e18); + function testWithDifferentPriceRange_Fuzz(uint256 newSqrtQ0) public { + newSqrtQ0 = bound(newSqrtQ0, 1.001e18, 1_000_000e18); // Price range cannot be lower than 1. - uint256 initialSqrtQ = sqrtQ0(); - setSqrtQ0(newSqrtQ); + uint256 initialSqrtQ0 = sqrtQ0(); + setSqrtQ0(newSqrtQ0); (address firstPool, address secondPool) = _createNewPool(); uint256[] memory curentFirstPoolVirtualBalances = AclAmmPool(firstPool).getLastVirtualBalances(); uint256[] memory curentNewPoolVirtualBalances = AclAmmPool(secondPool).getLastVirtualBalances(); - if (newSqrtQ > initialSqrtQ) { + if (newSqrtQ0 > initialSqrtQ0) { assertLt( curentNewPoolVirtualBalances[0], curentFirstPoolVirtualBalances[0], diff --git a/test/foundry/utils/BaseAclAmmTest.sol b/test/foundry/utils/BaseAclAmmTest.sol index 59f6042..1fc30d5 100644 --- a/test/foundry/utils/BaseAclAmmTest.sol +++ b/test/foundry/utils/BaseAclAmmTest.sol @@ -57,11 +57,15 @@ contract BaseAclAmmTest is AclAmmPoolContractsDeployer, BaseVaultTest { (daiIdx, usdcIdx) = getSortedIndexes(address(dai), address(usdc)); } - function setSqrtQ0(uint256 priceRange) internal { + function setPriceRange(uint256 priceRange) internal { uint256 Q0 = GyroPoolMath.sqrt(priceRange, 5); _sqrtQ0 = GyroPoolMath.sqrt(Q0, 5); } + function setSqrtQ0(uint256 newSqrtQ0) internal { + _sqrtQ0 = newSqrtQ0; + } + function sqrtQ0() internal view returns (uint256) { return _sqrtQ0; } From 556267ddb6032dbffd4e32cd17787478361deab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Bruno?= Date: Mon, 17 Mar 2025 17:52:26 -0300 Subject: [PATCH 6/7] Fix forge CI --- .github/workflows/ci.yml | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a286bb7..a30b486 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,36 +24,12 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} FORGE_SNAPSHOT_CHECK: true - - uses: actions/upload-artifact@v4 - with: - name: built-artifacts - path: artifacts/ - - uses: actions/upload-artifact@v4 - with: - name: built-lib - path: lib/balancer-v3-monorepo/pkg/ - - uses: actions/upload-artifact@v4 - with: - name: built-lib-pvt - path: lib/balancer-v3-monorepo/pvt/ test-forge: runs-on: ubuntu-latest needs: lint-and-build steps: - uses: actions/checkout@v4 - - uses: actions/download-artifact@v4 - with: - name: built-artifacts - path: artifacts/ - - uses: actions/download-artifact@v4 - with: - name: built-lib - path: lib/balancer-v3-monorepo/pkg/ - - uses: actions/download-artifact@v4 - with: - name: built-lib-pvt - path: lib/balancer-v3-monorepo/pvt/ - name: Set up environment uses: ./.github/actions/setup - name: Test @@ -66,17 +42,5 @@ jobs: - uses: actions/checkout@v4 - name: Set up environment uses: ./.github/actions/setup - - uses: actions/download-artifact@v4 - with: - name: built-artifacts - path: artifacts/ - - uses: actions/download-artifact@v4 - with: - name: built-lib - path: lib/balancer-v3-monorepo/pkg/ - - uses: actions/download-artifact@v4 - with: - name: built-lib-pvt - path: lib/balancer-v3-monorepo/pvt/ - name: Test run: yarn test:hardhat From b9b27fd81b91e2b9d2b534e5d282c7095cac7d00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Bruno?= Date: Mon, 17 Mar 2025 18:01:15 -0300 Subject: [PATCH 7/7] Fix CI --- .github/actions/setup/action.yml | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 0bb6659..f7b2f3a 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -22,28 +22,19 @@ runs: with: path: './node_modules/*' key: yarn-pool-${{ hashFiles('./yarn.lock') }} - - name: Cache library node modules + restore-keys: | + yarn-pool- + - name: Cache library pkg uses: actions/cache@v4 - id: cache-lib-modules + id: cache-lib-pkg with: - path: './lib/balancer-v3-monorepo/**/node_modules/*' - key: lib-modules-${{ hashFiles('./submodule-hash.txt') }} - - name: Cache library artifacts - uses: actions/cache@v4 - id: cache-lib-artifacts - with: - path: './lib/balancer-v3-monorepo/pkg/**/artifacts/*' + path: './lib/balancer-v3-monorepo/pkg' key: lib-pkg-${{ hashFiles('./submodule-hash.txt') }} - - name: Cache library typechain - uses: actions/cache@v4 - id: cache-lib-typechain - with: - path: './lib/balancer-v3-monorepo/pkg/**/typechain-types/*' - key: lib-typechain-${{ hashFiles('./submodule-hash.txt') }} + restore-keys: | + lib-pkg- - name: Install lcov shell: bash run: sudo apt-get install lcov - name: Install fresh shell: bash run: sh ./scripts/install-fresh.sh - if: steps.cache-lib-artifacts.outputs.cache-hit != 'true' || steps.cache-lib-modules.outputs.cache-hit != 'true' || steps.cache-lib-typechain.outputs.cache-hit != 'true'