From b402267dbb70495e86549b4520381a464e532ec3 Mon Sep 17 00:00:00 2001 From: ChefMist <133624774+ChefMist@users.noreply.github.com> Date: Mon, 25 Mar 2024 12:29:55 +0800 Subject: [PATCH] feat: fix `settleAndRefund` vulnerability (#4) * feat: update from currency.transfer to mint * refactor: update logic to be more similar to settle * gas: minor gas tweak - reduce repetitive casting --- ...oolManagerTest#testBurnNativeCurrency.snap | 2 +- ...BinPoolManagerTest#testGasBurnHalfBin.snap | 2 +- ...inPoolManagerTest#testGasBurnNineBins.snap | 2 +- .../BinPoolManagerTest#testGasBurnOneBin.snap | 2 +- .../BinPoolManagerTest#testGasDonate.snap | 2 +- ...nPoolManagerTest#testGasMintNneBins-1.snap | 2 +- ...nPoolManagerTest#testGasMintNneBins-2.snap | 2 +- ...inPoolManagerTest#testGasMintOneBin-1.snap | 2 +- ...inPoolManagerTest#testGasMintOneBin-2.snap | 2 +- ...olManagerTest#testGasSwapMultipleBins.snap | 2 +- ...nagerTest#testGasSwapOverBigBinIdGate.snap | 2 +- ...nPoolManagerTest#testGasSwapSingleBin.snap | 2 +- ...oolManagerTest#testMintNativeCurrency.snap | 2 +- .../BinPoolManagerTest#testNoOpGas_Burn.snap | 2 +- ...BinPoolManagerTest#testNoOpGas_Donate.snap | 2 +- .../BinPoolManagerTest#testNoOpGas_Mint.snap | 2 +- .../BinPoolManagerTest#testNoOpGas_Swap.snap | 2 +- ...oolManagerTest#addLiquidity_fromEmpty.snap | 2 +- ...ManagerTest#addLiquidity_fromNonEmpty.snap | 2 +- ...lManagerTest#addLiquidity_nativeToken.snap | 2 +- .../CLPoolManagerTest#donateBothTokens.snap | 2 +- .../CLPoolManagerTest#gasDonateOneToken.snap | 2 +- ...anagerTest#removeLiquidity_toNonEmpty.snap | 2 +- ...PoolManagerTest#swap_againstLiquidity.snap | 2 +- ...gerTest#swap_leaveSurplusTokenInVault.snap | 2 +- ...oolManagerTest#swap_runOutOfLiquidity.snap | 2 +- .../CLPoolManagerTest#swap_simple.snap | 2 +- ...nagerTest#swap_useSurplusTokenAsInput.snap | 2 +- .../CLPoolManagerTest#swap_withHooks.snap | 2 +- .../CLPoolManagerTest#swap_withNative.snap | 2 +- ...CLPoolManagerTest#testNoOp_gas_Donate.snap | 2 +- ...nagerTest#testNoOp_gas_ModifyPosition.snap | 2 +- .../CLPoolManagerTest#testNoOp_gas_Swap.snap | 2 +- .forge-snapshots/VaultTest#Vault.snap | 2 +- ...VaultTest#lockSettledWhenAddLiquidity.snap | 2 +- .../VaultTest#lockSettledWhenFlashloan.snap | 2 +- ...VaultTest#lockSettledWhenMultiHopSwap.snap | 2 +- .../VaultTest#lockSettledWhenSwap.snap | 2 +- .forge-snapshots/VaultTest#testLock_NoOp.snap | 2 +- ...Test#testSettleAndMintRefund_WithMint.snap | 1 + ...t#testSettleAndMintRefund_WithoutMint.snap | 1 + ...testSettleAndRefund_WithErc20Transfer.snap | 1 - ...tSettleAndRefund_WithoutErc20Transfer.snap | 1 - src/Vault.sol | 23 +++++++++------- src/interfaces/IVault.sol | 10 ++++--- test/vault/FakePoolManagerRouter.sol | 8 +++--- test/vault/Vault.t.sol | 26 ++++++++----------- test/vault/VaultInvariant.t.sol | 17 +++++++----- 48 files changed, 86 insertions(+), 80 deletions(-) create mode 100644 .forge-snapshots/VaultTest#testSettleAndMintRefund_WithMint.snap create mode 100644 .forge-snapshots/VaultTest#testSettleAndMintRefund_WithoutMint.snap delete mode 100644 .forge-snapshots/VaultTest#testSettleAndRefund_WithErc20Transfer.snap delete mode 100644 .forge-snapshots/VaultTest#testSettleAndRefund_WithoutErc20Transfer.snap diff --git a/.forge-snapshots/BinPoolManagerTest#testBurnNativeCurrency.snap b/.forge-snapshots/BinPoolManagerTest#testBurnNativeCurrency.snap index ea4b1578..b6a0d9ab 100644 --- a/.forge-snapshots/BinPoolManagerTest#testBurnNativeCurrency.snap +++ b/.forge-snapshots/BinPoolManagerTest#testBurnNativeCurrency.snap @@ -1 +1 @@ -92310 \ No newline at end of file +92245 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasBurnHalfBin.snap b/.forge-snapshots/BinPoolManagerTest#testGasBurnHalfBin.snap index 6f7475df..e0a09995 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasBurnHalfBin.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasBurnHalfBin.snap @@ -1 +1 @@ -67502 \ No newline at end of file +67437 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasBurnNineBins.snap b/.forge-snapshots/BinPoolManagerTest#testGasBurnNineBins.snap index b98ae40d..d570894d 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasBurnNineBins.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasBurnNineBins.snap @@ -1 +1 @@ -151057 \ No newline at end of file +150992 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasBurnOneBin.snap b/.forge-snapshots/BinPoolManagerTest#testGasBurnOneBin.snap index 5c0a7311..33434dff 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasBurnOneBin.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasBurnOneBin.snap @@ -1 +1 @@ -68681 \ No newline at end of file +68616 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasDonate.snap b/.forge-snapshots/BinPoolManagerTest#testGasDonate.snap index 43d2d930..760655c0 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasDonate.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasDonate.snap @@ -1 +1 @@ -53973 \ No newline at end of file +53952 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-1.snap b/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-1.snap index 61b20b76..fcedea97 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-1.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-1.snap @@ -1 +1 @@ -968068 \ No newline at end of file +968047 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-2.snap b/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-2.snap index 49498dc8..606a4052 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-2.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-2.snap @@ -1 +1 @@ -121582 \ No newline at end of file +121561 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-1.snap b/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-1.snap index 265f873c..08f6d723 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-1.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-1.snap @@ -1 +1 @@ -337258 \ No newline at end of file +337237 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-2.snap b/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-2.snap index 8fe11fbd..46204462 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-2.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-2.snap @@ -1 +1 @@ -56319 \ No newline at end of file +56298 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap b/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap index 1a47e6c0..2013546b 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap @@ -1 +1 @@ -93083 \ No newline at end of file +93040 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap b/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap index 4a80de55..0ac0f030 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap @@ -1 +1 @@ -95068 \ No newline at end of file +95025 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap b/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap index cb9b82af..5752d2a0 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap @@ -1 +1 @@ -74512 \ No newline at end of file +74469 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testMintNativeCurrency.snap b/.forge-snapshots/BinPoolManagerTest#testMintNativeCurrency.snap index 54bdfcb1..4a71833f 100644 --- a/.forge-snapshots/BinPoolManagerTest#testMintNativeCurrency.snap +++ b/.forge-snapshots/BinPoolManagerTest#testMintNativeCurrency.snap @@ -1 +1 @@ -318966 \ No newline at end of file +318945 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Burn.snap b/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Burn.snap index cde60315..644edbae 100644 --- a/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Burn.snap +++ b/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Burn.snap @@ -1 +1 @@ -41941 \ No newline at end of file +41876 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Donate.snap b/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Donate.snap index 7e2d8e03..f17589cd 100644 --- a/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Donate.snap +++ b/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Donate.snap @@ -1 +1 @@ -19558 \ No newline at end of file +19493 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Mint.snap b/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Mint.snap index edf5a379..78d7f8e8 100644 --- a/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Mint.snap +++ b/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Mint.snap @@ -1 +1 @@ -37410 \ No newline at end of file +37345 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Swap.snap b/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Swap.snap index bed35a26..bbdca60d 100644 --- a/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Swap.snap +++ b/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Swap.snap @@ -1 +1 @@ -22764 \ No newline at end of file +22699 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromEmpty.snap b/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromEmpty.snap index 49f1036e..a3b6d98b 100644 --- a/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromEmpty.snap +++ b/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromEmpty.snap @@ -1 +1 @@ -348473 \ No newline at end of file +348452 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromNonEmpty.snap b/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromNonEmpty.snap index ab1b307f..4bbcfa2c 100644 --- a/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromNonEmpty.snap +++ b/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromNonEmpty.snap @@ -1 +1 @@ -61021 \ No newline at end of file +61000 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#addLiquidity_nativeToken.snap b/.forge-snapshots/CLPoolManagerTest#addLiquidity_nativeToken.snap index c84788c7..9d0018b5 100644 --- a/.forge-snapshots/CLPoolManagerTest#addLiquidity_nativeToken.snap +++ b/.forge-snapshots/CLPoolManagerTest#addLiquidity_nativeToken.snap @@ -1 +1 @@ -241433 \ No newline at end of file +241390 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#donateBothTokens.snap b/.forge-snapshots/CLPoolManagerTest#donateBothTokens.snap index ac8527f0..ff632f9d 100644 --- a/.forge-snapshots/CLPoolManagerTest#donateBothTokens.snap +++ b/.forge-snapshots/CLPoolManagerTest#donateBothTokens.snap @@ -1 +1 @@ -84159 \ No newline at end of file +84138 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#gasDonateOneToken.snap b/.forge-snapshots/CLPoolManagerTest#gasDonateOneToken.snap index a0f8fb32..ad879fda 100644 --- a/.forge-snapshots/CLPoolManagerTest#gasDonateOneToken.snap +++ b/.forge-snapshots/CLPoolManagerTest#gasDonateOneToken.snap @@ -1 +1 @@ -53488 \ No newline at end of file +53445 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#removeLiquidity_toNonEmpty.snap b/.forge-snapshots/CLPoolManagerTest#removeLiquidity_toNonEmpty.snap index d31d5b07..beda75cb 100644 --- a/.forge-snapshots/CLPoolManagerTest#removeLiquidity_toNonEmpty.snap +++ b/.forge-snapshots/CLPoolManagerTest#removeLiquidity_toNonEmpty.snap @@ -1 +1 @@ -43387 \ No newline at end of file +43322 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_againstLiquidity.snap b/.forge-snapshots/CLPoolManagerTest#swap_againstLiquidity.snap index ad044164..81cd8b6b 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_againstLiquidity.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_againstLiquidity.snap @@ -1 +1 @@ -56488 \ No newline at end of file +56445 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_leaveSurplusTokenInVault.snap b/.forge-snapshots/CLPoolManagerTest#swap_leaveSurplusTokenInVault.snap index cff0aa8a..cecfca2a 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_leaveSurplusTokenInVault.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_leaveSurplusTokenInVault.snap @@ -1 +1 @@ -104597 \ No newline at end of file +104543 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_runOutOfLiquidity.snap b/.forge-snapshots/CLPoolManagerTest#swap_runOutOfLiquidity.snap index 1168907c..4475c1ca 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_runOutOfLiquidity.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_runOutOfLiquidity.snap @@ -1 +1 @@ -25044312 \ No newline at end of file +25044269 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_simple.snap b/.forge-snapshots/CLPoolManagerTest#swap_simple.snap index 4dedc7ce..67c6dee8 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_simple.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_simple.snap @@ -1 +1 @@ -36401 \ No newline at end of file +36336 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_useSurplusTokenAsInput.snap b/.forge-snapshots/CLPoolManagerTest#swap_useSurplusTokenAsInput.snap index e580758f..ac44f3fb 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_useSurplusTokenAsInput.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_useSurplusTokenAsInput.snap @@ -1 +1 @@ -103140 \ No newline at end of file +103041 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_withHooks.snap b/.forge-snapshots/CLPoolManagerTest#swap_withHooks.snap index 610ccdf8..0fd73b02 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_withHooks.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_withHooks.snap @@ -1 +1 @@ -42051 \ No newline at end of file +41986 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_withNative.snap b/.forge-snapshots/CLPoolManagerTest#swap_withNative.snap index 9cc8594e..0aecb1ad 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_withNative.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_withNative.snap @@ -1 +1 @@ -36404 \ No newline at end of file +36339 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_Donate.snap b/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_Donate.snap index 366744e2..7b7d760c 100644 --- a/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_Donate.snap +++ b/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_Donate.snap @@ -1 +1 @@ -19513 \ No newline at end of file +19448 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_ModifyPosition.snap b/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_ModifyPosition.snap index 3fdaecea..228723ef 100644 --- a/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_ModifyPosition.snap +++ b/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_ModifyPosition.snap @@ -1 +1 @@ -27680 \ No newline at end of file +27615 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_Swap.snap b/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_Swap.snap index 4eb79bea..9e1e60bf 100644 --- a/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_Swap.snap +++ b/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_Swap.snap @@ -1 +1 @@ -21962 \ No newline at end of file +21897 \ No newline at end of file diff --git a/.forge-snapshots/VaultTest#Vault.snap b/.forge-snapshots/VaultTest#Vault.snap index c5472716..6a3a44ed 100644 --- a/.forge-snapshots/VaultTest#Vault.snap +++ b/.forge-snapshots/VaultTest#Vault.snap @@ -1 +1 @@ -7075 \ No newline at end of file +7033 \ No newline at end of file diff --git a/.forge-snapshots/VaultTest#lockSettledWhenAddLiquidity.snap b/.forge-snapshots/VaultTest#lockSettledWhenAddLiquidity.snap index 466150e8..cbf29f3c 100644 --- a/.forge-snapshots/VaultTest#lockSettledWhenAddLiquidity.snap +++ b/.forge-snapshots/VaultTest#lockSettledWhenAddLiquidity.snap @@ -1 +1 @@ -122540 \ No newline at end of file +122519 \ No newline at end of file diff --git a/.forge-snapshots/VaultTest#lockSettledWhenFlashloan.snap b/.forge-snapshots/VaultTest#lockSettledWhenFlashloan.snap index f583bc35..932d963e 100644 --- a/.forge-snapshots/VaultTest#lockSettledWhenFlashloan.snap +++ b/.forge-snapshots/VaultTest#lockSettledWhenFlashloan.snap @@ -1 +1 @@ -158832 \ No newline at end of file +158811 \ No newline at end of file diff --git a/.forge-snapshots/VaultTest#lockSettledWhenMultiHopSwap.snap b/.forge-snapshots/VaultTest#lockSettledWhenMultiHopSwap.snap index 9638b220..37e2ed50 100644 --- a/.forge-snapshots/VaultTest#lockSettledWhenMultiHopSwap.snap +++ b/.forge-snapshots/VaultTest#lockSettledWhenMultiHopSwap.snap @@ -1 +1 @@ -47017 \ No newline at end of file +46974 \ No newline at end of file diff --git a/.forge-snapshots/VaultTest#lockSettledWhenSwap.snap b/.forge-snapshots/VaultTest#lockSettledWhenSwap.snap index ccf5975c..e6f87cf8 100644 --- a/.forge-snapshots/VaultTest#lockSettledWhenSwap.snap +++ b/.forge-snapshots/VaultTest#lockSettledWhenSwap.snap @@ -1 +1 @@ -47016 \ No newline at end of file +46973 \ No newline at end of file diff --git a/.forge-snapshots/VaultTest#testLock_NoOp.snap b/.forge-snapshots/VaultTest#testLock_NoOp.snap index ec8b9590..8f91eb99 100644 --- a/.forge-snapshots/VaultTest#testLock_NoOp.snap +++ b/.forge-snapshots/VaultTest#testLock_NoOp.snap @@ -1 +1 @@ -11692 \ No newline at end of file +11627 \ No newline at end of file diff --git a/.forge-snapshots/VaultTest#testSettleAndMintRefund_WithMint.snap b/.forge-snapshots/VaultTest#testSettleAndMintRefund_WithMint.snap new file mode 100644 index 00000000..540ef842 --- /dev/null +++ b/.forge-snapshots/VaultTest#testSettleAndMintRefund_WithMint.snap @@ -0,0 +1 @@ +72506 \ No newline at end of file diff --git a/.forge-snapshots/VaultTest#testSettleAndMintRefund_WithoutMint.snap b/.forge-snapshots/VaultTest#testSettleAndMintRefund_WithoutMint.snap new file mode 100644 index 00000000..6a51203d --- /dev/null +++ b/.forge-snapshots/VaultTest#testSettleAndMintRefund_WithoutMint.snap @@ -0,0 +1 @@ +34113 \ No newline at end of file diff --git a/.forge-snapshots/VaultTest#testSettleAndRefund_WithErc20Transfer.snap b/.forge-snapshots/VaultTest#testSettleAndRefund_WithErc20Transfer.snap deleted file mode 100644 index b0d10039..00000000 --- a/.forge-snapshots/VaultTest#testSettleAndRefund_WithErc20Transfer.snap +++ /dev/null @@ -1 +0,0 @@ -56176 \ No newline at end of file diff --git a/.forge-snapshots/VaultTest#testSettleAndRefund_WithoutErc20Transfer.snap b/.forge-snapshots/VaultTest#testSettleAndRefund_WithoutErc20Transfer.snap deleted file mode 100644 index 806af93a..00000000 --- a/.forge-snapshots/VaultTest#testSettleAndRefund_WithoutErc20Transfer.snap +++ /dev/null @@ -1 +0,0 @@ -36514 \ No newline at end of file diff --git a/src/Vault.sol b/src/Vault.sol index 4acc2aa4..64d8c6a2 100644 --- a/src/Vault.sol +++ b/src/Vault.sol @@ -126,26 +126,29 @@ contract Vault is IVault, VaultToken, Ownable { SettlementGuard.accountDelta(msg.sender, currency, -(paid.toInt128())); } - function settleAndRefund(Currency currency, address to) + function settleAndMintRefund(Currency currency, address to) external payable override isLocked returns (uint256 paid, uint256 refund) { - paid = currency.balanceOfSelf() - reservesOfVault[currency]; - int256 currentDelta = SettlementGuard.getCurrencyDelta(msg.sender, currency); + uint256 reservesBefore = reservesOfVault[currency]; + reservesOfVault[currency] = currency.balanceOfSelf(); + paid = reservesOfVault[currency] - reservesBefore; - if (currentDelta >= 0 && paid > currentDelta.toUint256()) { - // msg.sender owes vault but paid more than than whats owed - refund = paid - currentDelta.toUint256(); - paid = currentDelta.toUint256(); + int256 currentDelta = SettlementGuard.getCurrencyDelta(msg.sender, currency); + if (currentDelta >= 0) { + uint256 currentDeltaUint256 = currentDelta.toUint256(); + if (paid > currentDeltaUint256) { + // msg.sender owes vault but paid more than than whats owed + refund = paid - currentDeltaUint256; + paid = currentDeltaUint256; + } } - reservesOfVault[currency] += paid; SettlementGuard.accountDelta(msg.sender, currency, -(paid.toInt128())); - - if (refund > 0) currency.transfer(to, refund); + if (refund > 0) _mint(to, currency, refund); } /// @inheritdoc IVault diff --git a/src/interfaces/IVault.sol b/src/interfaces/IVault.sol index b3f0bd9e..ea8d905b 100644 --- a/src/interfaces/IVault.sol +++ b/src/interfaces/IVault.sol @@ -67,12 +67,16 @@ interface IVault is IVaultToken { /// @notice Called by the user to pay what is owed function settle(Currency token) external payable returns (uint256 paid); - /// @notice Called by the user to pay what is owed. If the payment is more than the debt, the surplus is refunded + /// @notice Called by the user to pay what is owed. If the payment is more than the debt, the surplus is refunded by minting + /// @dev To claim the refund, caller must eventually call vault.burn() -> vault.take() to take the ERC20 token from vault /// @param currency The currency to settle - /// @param to The address to refund the surplus to + /// @param to The address to mint the refund /// @return paid The amount paid /// @return refund The amount refunded - function settleAndRefund(Currency currency, address to) external payable returns (uint256 paid, uint256 refund); + function settleAndMintRefund(Currency currency, address to) + external + payable + returns (uint256 paid, uint256 refund); /// @notice move the delta from target to the msg.sender, only payment delta can be moved /// @param currency The currency to settle diff --git a/test/vault/FakePoolManagerRouter.sol b/test/vault/FakePoolManagerRouter.sol index 6c9f4090..ccda2b48 100644 --- a/test/vault/FakePoolManagerRouter.sol +++ b/test/vault/FakePoolManagerRouter.sol @@ -131,14 +131,14 @@ contract FakePoolManagerRouter { } else if (data[0] == 0x18) { // call this method via vault.lock(abi.encodePacked(hex"18", alice)); address to = address(uint160(uint256(bytes32(data[1:0x15]) >> 96))); - vault.settleAndRefund(poolKey.currency0, to); - vault.settleAndRefund(poolKey.currency1, to); + vault.settleAndMintRefund(poolKey.currency0, to); + vault.settleAndMintRefund(poolKey.currency1, to); } else if (data[0] == 0x19) { poolManager.mockAccounting(poolKey, 3 ether, -3 ether); vault.settle(poolKey.currency0); - /// try to call settleAndRefund should not revert - vault.settleAndRefund(poolKey.currency1, address(this)); + /// try to call settleAndMintRefund should not revert + vault.settleAndMintRefund(poolKey.currency1, address(this)); vault.take(poolKey.currency1, address(this), 3 ether); } diff --git a/test/vault/Vault.t.sol b/test/vault/Vault.t.sol index dd436db6..df103441 100644 --- a/test/vault/Vault.t.sol +++ b/test/vault/Vault.t.sol @@ -173,43 +173,39 @@ contract VaultTest is Test, GasSnapshot { vault.lock(hex"02"); } - function testSettleAndRefund_WithErc20Transfer() public { + function testSettleAndMintRefund_WithMint() public { address alice = makeAddr("alice"); // simulate someone transferred token to vault currency0.transfer(address(vault), 10 ether); - assertEq(IERC20(Currency.unwrap(currency0)).balanceOf(address(fakePoolManagerRouter)), 0 ether); - assertEq(IERC20(Currency.unwrap(currency0)).balanceOf(address(alice)), 0 ether); + assertEq(vault.balanceOf(alice, currency0), 0 ether); // settle and refund vm.prank(address(fakePoolManagerRouter)); - snapStart("VaultTest#testSettleAndRefund_WithErc20Transfer"); + snapStart("VaultTest#testSettleAndMintRefund_WithMint"); vault.lock(abi.encodePacked(hex"18", alice)); snapEnd(); - // verify - assertEq(IERC20(Currency.unwrap(currency0)).balanceOf(address(fakePoolManagerRouter)), 0 ether); - assertEq(IERC20(Currency.unwrap(currency0)).balanceOf(address(alice)), 10 ether); + // verify excess currency minted to alice + assertEq(vault.balanceOf(alice, currency0), 10 ether); } - function testSettleAndRefund_WithoutErc20Transfer() public { + function testSettleAndMintRefund_WithoutMint() public { address alice = makeAddr("alice"); - assertEq(IERC20(Currency.unwrap(currency0)).balanceOf(address(fakePoolManagerRouter)), 0 ether); - assertEq(IERC20(Currency.unwrap(currency0)).balanceOf(address(alice)), 0 ether); + assertEq(vault.balanceOf(alice, currency0), 0 ether); // settleAndRefund works even if there's no excess currency vm.prank(address(fakePoolManagerRouter)); - snapStart("VaultTest#testSettleAndRefund_WithoutErc20Transfer"); + snapStart("VaultTest#testSettleAndMintRefund_WithoutMint"); vault.lock(abi.encodePacked(hex"18", alice)); snapEnd(); - // verify - assertEq(IERC20(Currency.unwrap(currency0)).balanceOf(address(fakePoolManagerRouter)), 0 ether); - assertEq(IERC20(Currency.unwrap(currency0)).balanceOf(address(alice)), 0 ether); + // verify no extra token minted + assertEq(vault.balanceOf(alice, currency0), 0 ether); } - function testSettleAndRefund_NegativeBalanceDelta() public { + function testSettleAndMintRefund_NegativeBalanceDelta() public { // pre-req: ensure vault has some value in reserveOfVault[] before currency0.transfer(address(vault), 10 ether); currency1.transfer(address(vault), 10 ether); diff --git a/test/vault/VaultInvariant.t.sol b/test/vault/VaultInvariant.t.sol index 79b9f385..fe05de01 100644 --- a/test/vault/VaultInvariant.t.sol +++ b/test/vault/VaultInvariant.t.sol @@ -31,7 +31,7 @@ contract VaultPoolManager is Test { enum ActionType { Take, Settle, - SettleAndRefund, + SettleAndMintRefund, SettleFor, Mint, Burn @@ -87,7 +87,7 @@ contract VaultPoolManager is Test { /// @dev In settleAndRefund case, assume user add liquidity and paying to the vault /// but theres another folk who minted extra token to the vault - function settleAndRefund(uint256 amt0, uint256 amt1, bool sendToVault) public { + function settleAndMintRefund(uint256 amt0, uint256 amt1, bool sendToVault) public { amt0 = bound(amt0, 0, MAX_TOKEN_BALANCE - 1 ether); amt1 = bound(amt1, 0, MAX_TOKEN_BALANCE - 1 ether); @@ -97,7 +97,7 @@ contract VaultPoolManager is Test { // mint token to VaultPoolManager, so VaultPoolManager can pay to the vault token0.mint(address(this), amt0); token1.mint(address(this), amt1); - vault.lock(abi.encode(Action(ActionType.SettleAndRefund, uint128(amt0), uint128(amt1)))); + vault.lock(abi.encode(Action(ActionType.SettleAndMintRefund, uint128(amt0), uint128(amt1)))); } /// @dev In settleFor case, assume user is paying for hook @@ -181,15 +181,18 @@ contract VaultPoolManager is Test { vault.settle(currency0); vault.settle(currency1); - } else if (action.actionType == ActionType.SettleAndRefund) { + } else if (action.actionType == ActionType.SettleAndMintRefund) { BalanceDelta delta = toBalanceDelta(int128(action.amt0), int128(action.amt1)); vault.accountPoolBalanceDelta(poolKey, delta, address(this)); token0.transfer(address(vault), action.amt0); token1.transfer(address(vault), action.amt1); - vault.settleAndRefund(currency0, address(this)); - vault.settleAndRefund(currency1, address(this)); + (, uint256 refund0) = vault.settleAndMintRefund(currency0, address(this)); + (, uint256 refund1) = vault.settleAndMintRefund(currency1, address(this)); + + totalMintedCurrency0 += refund0; + totalMintedCurrency1 += refund1; } else if (action.actionType == ActionType.SettleFor) { // hook cash out the fee ahead BalanceDelta delta = toBalanceDelta(int128(action.amt0), int128(action.amt1)); @@ -244,7 +247,7 @@ contract VaultInvariant is Test, GasSnapshot { selectors[3] = VaultPoolManager.burn.selector; selectors[4] = VaultPoolManager.settleFor.selector; selectors[5] = VaultPoolManager.collectFee.selector; - selectors[6] = VaultPoolManager.settleAndRefund.selector; + selectors[6] = VaultPoolManager.settleAndMintRefund.selector; targetSelector(FuzzSelector({addr: address(vaultPoolManager), selectors: selectors})); }