Skip to content

Commit 86e76c5

Browse files
committed
fix: slippage check in wrong order
1 parent 0d7ea69 commit 86e76c5

File tree

3 files changed

+92
-18
lines changed

3 files changed

+92
-18
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ build-sizes: ## Builds the project and shows sizes
121121

122122
.PHONY: test-vvv
123123
test-vvv: ## Runs tests with verbose output
124-
forge test --match-test test_rebalanceSinglePosition_singleXChainMultiVaultDeposit --evm-version cancun -vvv
124+
forge test --match-contract SuperformRouterPlusTest --evm-version cancun
125125

126126

127127
.PHONY: ftest

src/router-plus/SuperformRouterPlus.sol

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -469,18 +469,18 @@ contract SuperformRouterPlus is ISuperformRouterPlus, BaseSuperformRouterPlus {
469469
/// @dev send SPs to router
470470
_callSuperformRouter(router_, callData, args.rebalanceFromMsgValue);
471471

472-
uint256 amountToDeposit = interimAsset.balanceOf(address(this)) - args.balanceBefore;
472+
uint256 availableBalanceToDeposit = interimAsset.balanceOf(address(this)) - args.balanceBefore;
473473

474-
if (amountToDeposit == 0) revert Error.ZERO_AMOUNT();
474+
if (availableBalanceToDeposit == 0) revert Error.ZERO_AMOUNT();
475475

476476
if (
477-
ENTIRE_SLIPPAGE * amountToDeposit
477+
ENTIRE_SLIPPAGE * availableBalanceToDeposit
478478
< ((args.expectedAmountToReceivePostRebalanceFrom * (ENTIRE_SLIPPAGE - args.slippage)))
479479
) {
480480
revert Error.VAULT_IMPLEMENTATION_FAILED();
481481
}
482482

483-
uint256 amountIn = _validateAndGetAmountIn(rebalanceToCallData, amountToDeposit);
483+
uint256 amountIn = _validateAndGetAmountIn(rebalanceToCallData, availableBalanceToDeposit);
484484

485485
_deposit(router_, interimAsset, amountIn, args.rebalanceToMsgValue, rebalanceToCallData);
486486
}
@@ -651,7 +651,7 @@ contract SuperformRouterPlus is ISuperformRouterPlus, BaseSuperformRouterPlus {
651651

652652
function _validateAndGetAmountIn(
653653
bytes calldata rebalanceToCallData,
654-
uint256 amountToDeposit
654+
uint256 availableBalanceToDeposit
655655
)
656656
internal
657657
view
@@ -711,12 +711,13 @@ contract SuperformRouterPlus is ISuperformRouterPlus, BaseSuperformRouterPlus {
711711
}
712712
}
713713

714-
/// @dev amountIn must be artificially off-chain reduced to be less than amountToDeposit otherwise the approval
715-
/// @dev to transfer tokens to SuperformRouter won't work
716-
if (amountIn > amountToDeposit) revert AMOUNT_IN_NOT_EQUAL_OR_LOWER_THAN_BALANCE();
714+
/// @dev amountIn must be artificially off-chain reduced to be less than availableBalanceToDeposit otherwise the
715+
/// @dev approval to transfer tokens to SuperformRouter won't work
716+
if (amountIn > availableBalanceToDeposit) revert AMOUNT_IN_NOT_EQUAL_OR_LOWER_THAN_BALANCE();
717717

718-
/// @dev check against a GLOBAL_SLIPPAGE to prevent a malicious keeper from sending a low amountIn
719-
if (ENTIRE_SLIPPAGE * amountToDeposit < ((amountIn * (ENTIRE_SLIPPAGE - GLOBAL_SLIPPAGE)))) {
718+
/// @dev check amountIn against availableBalanceToDeposit (available balance) via a GLOBAL_SLIPPAGE to prevent a
719+
/// @dev malicious keeper from sending a low amountIn
720+
if (ENTIRE_SLIPPAGE * amountIn < ((availableBalanceToDeposit * (ENTIRE_SLIPPAGE - GLOBAL_SLIPPAGE)))) {
720721
revert ASSETS_RECEIVED_OUT_OF_SLIPPAGE();
721722
}
722723
}

test/unit/router-plus/SuperformRouterPlus.t.sol

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,78 @@ contract SuperformRouterPlusTest is ProtocolActions {
734734
assertEq(SuperPositions(SUPER_POSITIONS_SOURCE).balanceOf(deployer, superformId1), 0);
735735
}
736736

737+
function test_revert_AMOUNT_IN_NOT_EQUAL_OR_LOWER_THAN_BALANCE() public {
738+
vm.startPrank(deployer);
739+
740+
_directDeposit(superformId1, 1e18);
741+
742+
ISuperformRouterPlus.RebalanceSinglePositionSyncArgs memory args =
743+
_buildRebalanceSinglePositionToOneVaultArgs(deployer);
744+
745+
SingleVaultSFData memory sfDataRebalanceTo =
746+
abi.decode(_parseCallData(args.rebalanceToCallData), (SingleDirectSingleVaultStateReq)).superformData;
747+
sfDataRebalanceTo.amount = 1e30;
748+
749+
args.rebalanceToCallData = abi.encodeCall(
750+
IBaseRouter.singleDirectSingleVaultDeposit, SingleDirectSingleVaultStateReq(sfDataRebalanceTo)
751+
);
752+
SuperPositions(SUPER_POSITIONS_SOURCE).increaseAllowance(ROUTER_PLUS_SOURCE, superformId1, args.sharesToRedeem);
753+
754+
vm.expectRevert(ISuperformRouterPlus.AMOUNT_IN_NOT_EQUAL_OR_LOWER_THAN_BALANCE.selector);
755+
SuperformRouterPlus(ROUTER_PLUS_SOURCE).rebalanceSinglePosition{ value: 2 ether }(args);
756+
}
757+
758+
function test_revert_ASSETS_RECEIVED_OUT_OF_SLIPPAGE() public {
759+
vm.startPrank(deployer);
760+
761+
_directDeposit(superformId1, 1e18);
762+
_directDeposit(superformId2, 1e6);
763+
764+
(ISuperformRouterPlus.RebalanceMultiPositionsSyncArgs memory args, uint256 totalAmountToDeposit) =
765+
_buildRebalanceTwoPositionsToOneVaultXChainArgs();
766+
767+
SingleVaultSFData memory sfDataRebalanceTo =
768+
abi.decode(_parseCallData(args.rebalanceToCallData), (SingleXChainSingleVaultStateReq)).superformData;
769+
770+
/// @dev keeper attempting to rug the user by reducing amount in
771+
sfDataRebalanceTo.liqRequest.txData = _buildLiqBridgeTxData(
772+
LiqBridgeTxDataArgs(
773+
1,
774+
args.interimAsset,
775+
getContract(OP, "DAI"),
776+
getContract(OP, "DAI"),
777+
getContract(SOURCE_CHAIN, "SuperformRouter"),
778+
SOURCE_CHAIN,
779+
OP,
780+
OP,
781+
false,
782+
getContract(OP, "CoreStateRegistry"),
783+
uint256(OP),
784+
totalAmountToDeposit - 5e5,
785+
false,
786+
0,
787+
1,
788+
1,
789+
1,
790+
address(0)
791+
),
792+
false
793+
);
794+
795+
args.rebalanceToCallData = abi.encodeCall(
796+
IBaseRouter.singleXChainSingleVaultDeposit, SingleXChainSingleVaultStateReq(AMBs, OP, sfDataRebalanceTo)
797+
);
798+
799+
SuperPositions(SUPER_POSITIONS_SOURCE).increaseAllowance(
800+
ROUTER_PLUS_SOURCE, superformId1, args.sharesToRedeem[0]
801+
);
802+
SuperPositions(SUPER_POSITIONS_SOURCE).increaseAllowance(
803+
ROUTER_PLUS_SOURCE, superformId2, args.sharesToRedeem[1]
804+
);
805+
vm.expectRevert(ISuperformRouterPlus.ASSETS_RECEIVED_OUT_OF_SLIPPAGE.selector);
806+
SuperformRouterPlus(ROUTER_PLUS_SOURCE).rebalanceMultiPositions{ value: 2 ether }(args);
807+
}
808+
737809
function test_rebalanceSinglePosition_singleXChainSingleVaultDepositSelector() public {
738810
vm.startPrank(deployer);
739811

@@ -3189,23 +3261,24 @@ contract SuperformRouterPlusTest is ProtocolActions {
31893261
args.callData = _callDataRebalanceFromTwoVaults(args.interimAsset);
31903262

31913263
uint256 decimal1 = MockERC20(getContract(SOURCE_CHAIN, "DAI")).decimals();
3192-
uint256 decimal2 = MockERC20(args.interimAsset).decimals();
3264+
uint256 decimal2 = MockERC20(getContract(SOURCE_CHAIN, "USDC")).decimals();
3265+
uint256 decimalInterim = MockERC20(args.interimAsset).decimals();
31933266
uint256 previewRedeemAmount1 = IBaseForm(superform1).previewRedeemFrom(args.sharesToRedeem[0]);
31943267

31953268
uint256 expectedAmountToReceivePostRebalanceFrom1;
3196-
if (decimal1 > decimal2) {
3197-
expectedAmountToReceivePostRebalanceFrom1 = previewRedeemAmount1 / (10 ** (decimal1 - decimal2));
3269+
if (decimal1 > decimalInterim) {
3270+
expectedAmountToReceivePostRebalanceFrom1 = previewRedeemAmount1 / (10 ** (decimal1 - decimalInterim));
31983271
} else {
3199-
expectedAmountToReceivePostRebalanceFrom1 = previewRedeemAmount1 * 10 ** (decimal2 - decimal1);
3272+
expectedAmountToReceivePostRebalanceFrom1 = previewRedeemAmount1 * 10 ** (decimalInterim - decimal1);
32003273
}
32013274

32023275
uint256 previewRedeemAmount2 = IBaseForm(superform2).previewRedeemFrom(args.sharesToRedeem[1]);
32033276

32043277
uint256 expectedAmountToReceivePostRebalanceFrom2;
3205-
if (decimal1 > decimal2) {
3206-
expectedAmountToReceivePostRebalanceFrom2 = previewRedeemAmount2 / (10 ** (decimal1 - decimal2));
3278+
if (decimal2 > decimalInterim) {
3279+
expectedAmountToReceivePostRebalanceFrom2 = previewRedeemAmount2 / (10 ** (decimal2 - decimalInterim));
32073280
} else {
3208-
expectedAmountToReceivePostRebalanceFrom2 = previewRedeemAmount2 * 10 ** (decimal2 - decimal1);
3281+
expectedAmountToReceivePostRebalanceFrom2 = previewRedeemAmount2 * 10 ** (decimalInterim - decimal2);
32093282
}
32103283

32113284
totalAmountToDeposit = expectedAmountToReceivePostRebalanceFrom1 + expectedAmountToReceivePostRebalanceFrom2;

0 commit comments

Comments
 (0)