diff --git a/chains/SonicLib.sol b/chains/SonicLib.sol index 0b231171..318fe739 100644 --- a/chains/SonicLib.sol +++ b/chains/SonicLib.sol @@ -14,6 +14,7 @@ import {BeetsStableFarm} from "../src/strategies/BeetsStableFarm.sol"; import {StrategyDeveloperLib} from "../src/strategies/libs/StrategyDeveloperLib.sol"; import {IGaugeEquivalent} from "../src/integrations/equalizer/IGaugeEquivalent.sol"; import {EqualizerFarmStrategy} from "../src/strategies/EqualizerFarmStrategy.sol"; +import {BeetsWeightedFarm} from "../src/strategies/BeetsWeightedFarm.sol"; /// @dev Sonic network [chainId: 146] data library // _____ _ @@ -44,6 +45,7 @@ library SonicLib { address public constant POOL_BEETS_BEETS_stS = 0x10ac2F9DaE6539E77e372aDB14B1BF8fBD16b3e8; address public constant POOL_BEETS_wS_USDC = 0xE93a5fc4Ba77179F6843b30cff33a97d89FF441C; address public constant POOL_BEETS_USDC_scUSD = 0xCd4D2b142235D5650fFA6A38787eD0b7d7A51c0C; + address public constant POOL_BEETS_scUSD_stS = 0x25ca5451CD5a50AB1d324B5E64F32C0799661891; address public constant POOL_SUSHI_wS_USDC = 0xE72b6DD415cDACeAC76616Df2C9278B33079E0D3; address public constant POOL_EQUALIZER_USDC_WETH = 0xbCbC5777537c0D0462fb82BA48Eeb6cb361E853f; address public constant POOL_EQUALIZER_wS_stS = 0xB75C9073ea00AbDa9ff420b5Ae46fEe248993380; @@ -55,6 +57,7 @@ library SonicLib { address public constant BEETS_BALANCER_HELPERS = 0x8E9aa87E45e92bad84D5F8DD1bff34Fb92637dE9; address public constant BEETS_GAUGE_wS_stS = 0x8476F3A8DA52092e7835167AFe27835dC171C133; address public constant BEETS_GAUGE_USDC_scUSD = 0x33B29bcf17e866A35941e07CbAd54f1807B337f5; + address public constant BEETS_GAUGE_scUSD_stS = 0xa472438718Fe7785107fCbE584d39183a6420D36; // Equalizer address public constant EQUALIZER_ROUTER_03 = 0xcC6169aA1E879d3a4227536671F85afdb2d23fAD; @@ -142,7 +145,7 @@ library SonicLib { tokenIn[4] = TOKEN_USDC; uint[] memory thresholdAmount = new uint[](5); thresholdAmount[0] = 1e12; - thresholdAmount[1] = 1e10; + thresholdAmount[1] = 1e16; thresholdAmount[2] = 1e10; thresholdAmount[3] = 1e12; thresholdAmount[4] = 1e4; @@ -158,6 +161,7 @@ library SonicLib { //region ----- Deploy strategy logics ----- _addStrategyLogic(factory, StrategyIdLib.BEETS_STABLE_FARM, address(new BeetsStableFarm()), true); + _addStrategyLogic(factory, StrategyIdLib.BEETS_WEIGHTED_FARM, address(new BeetsWeightedFarm()), true); _addStrategyLogic(factory, StrategyIdLib.EQUALIZER_FARM, address(new EqualizerFarmStrategy()), true); LogDeployLib.logDeployStrategies(platform, showLog); //endregion ----- Deploy strategy logics ----- @@ -199,7 +203,7 @@ library SonicLib { } function farms() public view returns (IFactory.Farm[] memory _farms) { - _farms = new IFactory.Farm[](6); + _farms = new IFactory.Farm[](7); uint i; _farms[i++] = _makeBeetsStableFarm(BEETS_GAUGE_wS_stS); @@ -208,6 +212,7 @@ library SonicLib { _farms[i++] = _makeEqualizerFarm(EQUALIZER_GAUGE_wS_stS); _farms[i++] = _makeEqualizerFarm(EQUALIZER_GAUGE_wS_USDC); _farms[i++] = _makeEqualizerFarm(EQUALIZER_GAUGE_USDC_scUSD); + _farms[i++] = _makeBeetsWeightedFarm(BEETS_GAUGE_scUSD_stS); } function _makeBeetsStableFarm(address gauge) internal view returns (IFactory.Farm memory) { @@ -227,6 +232,23 @@ library SonicLib { return farm; } + function _makeBeetsWeightedFarm(address gauge) internal view returns (IFactory.Farm memory) { + IFactory.Farm memory farm; + farm.status = 0; + farm.pool = IBalancerGauge(gauge).lp_token(); + farm.strategyLogicId = StrategyIdLib.BEETS_WEIGHTED_FARM; + uint len = IBalancerGauge(gauge).reward_count(); + farm.rewardAssets = new address[](len); + for (uint i; i < len; ++i) { + farm.rewardAssets[i] = IBalancerGauge(gauge).reward_tokens(i); + } + farm.addresses = new address[](1); + farm.addresses[0] = gauge; + farm.nums = new uint[](0); + farm.ticks = new int24[](0); + return farm; + } + function _makeEqualizerFarm(address gauge) internal view returns (IFactory.Farm memory) { IFactory.Farm memory farm; farm.status = 0; diff --git a/src/strategies/BeetsWeightedFarm.sol b/src/strategies/BeetsWeightedFarm.sol new file mode 100644 index 00000000..903ec6c0 --- /dev/null +++ b/src/strategies/BeetsWeightedFarm.sol @@ -0,0 +1,435 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import {StrategyBase} from "./base/StrategyBase.sol"; +import {LPStrategyBase} from "./base/LPStrategyBase.sol"; +import {FarmingStrategyBase} from "./base/FarmingStrategyBase.sol"; +import {StrategyLib} from "./libs/StrategyLib.sol"; +import {StrategyIdLib} from "./libs/StrategyIdLib.sol"; +import {FarmMechanicsLib} from "./libs/FarmMechanicsLib.sol"; +import {IFactory} from "../interfaces/IFactory.sol"; +import {IAmmAdapter} from "../interfaces/IAmmAdapter.sol"; +import {IStrategy} from "../interfaces/IStrategy.sol"; +import {IFarmingStrategy} from "../interfaces/IFarmingStrategy.sol"; +import {ILPStrategy} from "../interfaces/ILPStrategy.sol"; +import {IControllable} from "../interfaces/IControllable.sol"; +import {IPlatform} from "../interfaces/IPlatform.sol"; +import {VaultTypeLib} from "../core/libs/VaultTypeLib.sol"; +import {CommonLib} from "../core/libs/CommonLib.sol"; +import {AmmAdapterIdLib} from "../adapters/libs/AmmAdapterIdLib.sol"; +import {IBalancerAdapter} from "../interfaces/IBalancerAdapter.sol"; +import {IBVault} from "../integrations/balancer/IBVault.sol"; +import {IBalancerGauge} from "../integrations/balancer/IBalancerGauge.sol"; +import {IBWeightedPoolMinimal} from "../integrations/balancer/IBWeightedPoolMinimal.sol"; + +/// @title Earn Beets weighted pool LP fees and gauge rewards +/// @author Alien Deployer (https://github.com/a17) +contract BeetsWeightedFarm is LPStrategyBase, FarmingStrategyBase { + using SafeERC20 for IERC20; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @inheritdoc IControllable + string public constant VERSION = "1.0.0"; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* DATA TYPES */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + struct BalancerMethodVars { + bytes32 poolId; + address[] poolTokens; + uint bptIndex; + uint len; + uint[] allAmounts; + uint[] amounts; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INITIALIZATION */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @inheritdoc IStrategy + function initialize(address[] memory addresses, uint[] memory nums, int24[] memory ticks) public initializer { + if (addresses.length != 2 || nums.length != 1 || ticks.length != 0) { + revert IControllable.IncorrectInitParams(); + } + + IFactory.Farm memory farm = _getFarm(addresses[0], nums[0]); + if (farm.addresses.length != 1 || farm.nums.length != 0 || farm.ticks.length != 0) { + revert IFarmingStrategy.BadFarm(); + } + + __LPStrategyBase_init( + LPStrategyBaseInitParams({ + id: StrategyIdLib.BEETS_WEIGHTED_FARM, + platform: addresses[0], + vault: addresses[1], + pool: farm.pool, + underlying: farm.pool + }) + ); + + __FarmingStrategyBase_init(addresses[0], nums[0]); + + address[] memory _assets = assets(); + uint len = _assets.length; + address balancerVault = IBWeightedPoolMinimal(farm.pool).getVault(); + for (uint i; i < len; ++i) { + IERC20(_assets[i]).forceApprove(balancerVault, type(uint).max); + } + + IERC20(farm.pool).forceApprove(farm.addresses[0], type(uint).max); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* VIEW FUNCTIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @inheritdoc IERC165 + function supportsInterface(bytes4 interfaceId) + public + view + override(LPStrategyBase, FarmingStrategyBase) + returns (bool) + { + return super.supportsInterface(interfaceId); + } + + /// @inheritdoc IFarmingStrategy + function canFarm() external view override returns (bool) { + IFactory.Farm memory farm = _getFarm(); + return farm.status == 0; + } + + /// @inheritdoc FarmingStrategyBase + function stakingPool() external view override returns (address) { + IFactory.Farm memory farm = _getFarm(); + return farm.addresses[0]; + } + + /// @inheritdoc ILPStrategy + function ammAdapterId() public pure override returns (string memory) { + return AmmAdapterIdLib.BALANCER_WEIGHTED; + } + + /// @inheritdoc IStrategy + function getRevenue() external pure returns (address[] memory __assets, uint[] memory amounts) { + __assets = new address[](0); + amounts = new uint[](0); + } + + /// @inheritdoc IStrategy + function initVariants(address platform_) + public + view + returns (string[] memory variants, address[] memory addresses, uint[] memory nums, int24[] memory ticks) + { + IAmmAdapter _ammAdapter = IAmmAdapter(IPlatform(platform_).ammAdapter(keccak256(bytes(ammAdapterId()))).proxy); + addresses = new address[](0); + ticks = new int24[](0); + + IFactory.Farm[] memory farms = IFactory(IPlatform(platform_).factory()).farms(); + uint len = farms.length; + //slither-disable-next-line uninitialized-local + uint localTtotal; + //nosemgrep + for (uint i; i < len; ++i) { + //nosemgrep + IFactory.Farm memory farm = farms[i]; + //nosemgrep + if (farm.status == 0 && CommonLib.eq(farm.strategyLogicId, strategyLogicId())) { + ++localTtotal; + } + } + + variants = new string[](localTtotal); + nums = new uint[](localTtotal); + localTtotal = 0; + //nosemgrep + for (uint i; i < len; ++i) { + //nosemgrep + IFactory.Farm memory farm = farms[i]; + //nosemgrep + if (farm.status == 0 && CommonLib.eq(farm.strategyLogicId, strategyLogicId())) { + nums[localTtotal] = i; + //slither-disable-next-line calls-loop + variants[localTtotal] = _generateDescription(farm, _ammAdapter); + ++localTtotal; + } + } + } + + /// @inheritdoc IStrategy + function isHardWorkOnDepositAllowed() external pure returns (bool allowed) { + allowed = true; + } + + /// @inheritdoc IStrategy + function isReadyForHardWork() external view returns (bool) { + return total() != 0; + } + + /// @inheritdoc IFarmingStrategy + function farmMechanics() external pure returns (string memory) { + return FarmMechanicsLib.CLASSIC; + } + + /// @inheritdoc IStrategy + function supportedVaultTypes() + external + pure + override(LPStrategyBase, StrategyBase) + returns (string[] memory types) + { + types = new string[](1); + types[0] = VaultTypeLib.COMPOUNDING; + } + + /// @inheritdoc IStrategy + function strategyLogicId() public pure override returns (string memory) { + return StrategyIdLib.BEETS_WEIGHTED_FARM; + } + + /// @inheritdoc IStrategy + function getAssetsProportions() public view returns (uint[] memory proportions) { + ILPStrategy.LPStrategyBaseStorage storage $lp = _getLPStrategyBaseStorage(); + proportions = $lp.ammAdapter.getProportions($lp.pool); + } + + /// @inheritdoc IStrategy + function extra() external pure returns (bytes32) { + //slither-disable-next-line too-many-digits + return CommonLib.bytesToBytes32(abi.encodePacked(bytes3(0xeeeeee), bytes3(0x000000))); + } + + /// @inheritdoc IStrategy + function getSpecificName() external pure override returns (string memory, bool) { + return ("", false); + } + + /// @inheritdoc IStrategy + function description() external view returns (string memory) { + IFarmingStrategy.FarmingStrategyBaseStorage storage $f = _getFarmingStrategyBaseStorage(); + ILPStrategy.LPStrategyBaseStorage storage $lp = _getLPStrategyBaseStorage(); + IFactory.Farm memory farm = IFactory(IPlatform(platform()).factory()).farm($f.farmId); + return _generateDescription(farm, $lp.ammAdapter); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STRATEGY BASE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @inheritdoc StrategyBase + function _depositAssets(uint[] memory amounts, bool) internal override returns (uint value) { + ILPStrategy.LPStrategyBaseStorage storage $lp = _getLPStrategyBaseStorage(); + StrategyBaseStorage storage $base = _getStrategyBaseStorage(); + IBWeightedPoolMinimal _pool = IBWeightedPoolMinimal($lp.pool); + BalancerMethodVars memory v; + + v.poolId = _pool.getPoolId(); + (v.poolTokens,,) = IBVault(_pool.getVault()).getPoolTokens(v.poolId); + + value = IERC20(address(_pool)).balanceOf(address(this)); + + IBVault(_pool.getVault()).joinPool( + v.poolId, + address(this), + address(this), + IBVault.JoinPoolRequest({ + assets: v.poolTokens, + maxAmountsIn: amounts, + userData: abi.encode(IBVault.JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT, amounts, 0), + fromInternalBalance: false + }) + ); + value = IERC20(address(_pool)).balanceOf(address(this)) - value; + $base.total += value; + + IFactory.Farm memory farm = _getFarm(); + IBalancerGauge(farm.addresses[0]).deposit(value); + } + + /// @inheritdoc StrategyBase + function _depositUnderlying(uint amount) internal override returns (uint[] memory amountsConsumed) { + StrategyBaseStorage storage $base = _getStrategyBaseStorage(); + $base.total += amount; + IFactory.Farm memory farm = _getFarm(); + IBalancerGauge(farm.addresses[0]).deposit(amount); + amountsConsumed = _calcAssetsAmounts(amount); + } + + /// @inheritdoc StrategyBase + function _withdrawAssets(uint value, address receiver) internal override returns (uint[] memory amountsOut) { + IFactory.Farm memory farm = _getFarm(); + IBWeightedPoolMinimal _pool = IBWeightedPoolMinimal(pool()); + BalancerMethodVars memory v; + + (v.poolTokens,,) = IBVault(_pool.getVault()).getPoolTokens(_pool.getPoolId()); + + IBalancerGauge(farm.addresses[0]).withdraw(value); + + address[] memory __assets = assets(); + v.len = __assets.length; + amountsOut = new uint[](v.len); + for (uint i; i < v.len; ++i) { + amountsOut[i] = IERC20(__assets[i]).balanceOf(receiver); + } + + IBVault(_pool.getVault()).exitPool( + _pool.getPoolId(), + address(this), + payable(receiver), + IBVault.ExitPoolRequest({ + assets: v.poolTokens, + minAmountsOut: new uint[](v.poolTokens.length), + userData: abi.encode(1, value), + toInternalBalance: false + }) + ); + + for (uint i; i < v.len; ++i) { + amountsOut[i] = IERC20(__assets[i]).balanceOf(receiver) - amountsOut[i]; + } + + StrategyBaseStorage storage $base = _getStrategyBaseStorage(); + $base.total -= value; + } + + /// @inheritdoc StrategyBase + function _withdrawUnderlying(uint amount, address receiver) internal override { + StrategyBaseStorage storage $base = _getStrategyBaseStorage(); + $base.total -= amount; + IFactory.Farm memory farm = _getFarm(); + IBalancerGauge(farm.addresses[0]).withdraw(amount); + IERC20($base._underlying).safeTransfer(receiver, amount); + } + + /// @inheritdoc StrategyBase + function _claimRevenue() + internal + override + returns ( + address[] memory __assets, + uint[] memory __amounts, + address[] memory __rewardAssets, + uint[] memory __rewardAmounts + ) + { + __assets = assets(); + __amounts = new uint[](__assets.length); + FarmingStrategyBaseStorage storage $f = _getFarmingStrategyBaseStorage(); + __rewardAssets = $f._rewardAssets; + uint rwLen = __rewardAssets.length; + uint[] memory balanceBefore = new uint[](rwLen); + __rewardAmounts = new uint[](rwLen); + for (uint i; i < rwLen; ++i) { + balanceBefore[i] = StrategyLib.balance(__rewardAssets[i]); + } + IFactory.Farm memory farm = _getFarm(); + IBalancerGauge(farm.addresses[0]).claim_rewards(); + for (uint i; i < rwLen; ++i) { + __rewardAmounts[i] = StrategyLib.balance(__rewardAssets[i]) - balanceBefore[i]; + } + } + + /// @inheritdoc StrategyBase + function _compound() internal override { + // this is working way too, but better to swap in current pool than in long swapper pool route + /*uint[] memory amountsToDeposit = _swapForDepositProportion(getAssetsProportions()[0]); + if (amountsToDeposit[0] != 0 && amountsToDeposit[1] != 0) { + _depositAssets(amountsToDeposit, false); + }*/ + address[] memory _assets = assets(); + uint len = _assets.length; + uint[] memory amounts = new uint[](len); + //slither-disable-next-line uninitialized-local + bool notZero; + for (uint i; i < len; ++i) { + amounts[i] = StrategyLib.balance(_assets[i]); + if (amounts[i] != 0) { + notZero = true; + } + } + if (notZero) { + _depositAssets(amounts, false); + } + } + + /// @inheritdoc StrategyBase + function _previewDepositAssets(uint[] memory) + internal + pure + override(StrategyBase, LPStrategyBase) + returns (uint[] memory, uint) + { + revert("Not supported"); + } + + /// @inheritdoc StrategyBase + function _previewDepositAssetsWrite(uint[] memory amountsMax) + internal + override(StrategyBase) + returns (uint[] memory amountsConsumed, uint value) + { + IBalancerAdapter _ammAdapter = + IBalancerAdapter(IPlatform(platform()).ammAdapter(keccak256(bytes(ammAdapterId()))).proxy); + ILPStrategy.LPStrategyBaseStorage storage $lp = _getLPStrategyBaseStorage(); + (value, amountsConsumed) = _ammAdapter.getLiquidityForAmountsWrite($lp.pool, amountsMax); + } + + /// @inheritdoc StrategyBase + function _previewDepositAssetsWrite( + address[] memory, + uint[] memory amountsMax + ) internal override(StrategyBase) returns (uint[] memory amountsConsumed, uint value) { + return _previewDepositAssetsWrite(amountsMax); + } + + /// @inheritdoc StrategyBase + function _previewDepositUnderlying(uint amount) internal view override returns (uint[] memory amountsConsumed) { + // todo + } + + /// @inheritdoc StrategyBase + function _assetsAmounts() internal view override returns (address[] memory assets_, uint[] memory amounts_) { + amounts_ = _calcAssetsAmounts(total()); + assets_ = assets(); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INTERNAL LOGIC */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + function _calcAssetsAmounts(uint shares) internal view returns (uint[] memory amounts_) { + IBWeightedPoolMinimal _pool = IBWeightedPoolMinimal(pool()); + (, uint[] memory balances,) = IBVault(_pool.getVault()).getPoolTokens(_pool.getPoolId()); + uint supply = IERC20(address(_pool)).totalSupply(); + uint len = balances.length; + amounts_ = new uint[](len); + for (uint i; i < len; ++i) { + amounts_[i] = shares * balances[i] / supply; + } + } + + function _generateDescription( + IFactory.Farm memory farm, + IAmmAdapter _ammAdapter + ) internal view returns (string memory) { + //slither-disable-next-line calls-loop + return string.concat( + "Earn ", + //slither-disable-next-line calls-loop + CommonLib.implode(CommonLib.getSymbols(farm.rewardAssets), ", "), + " and fees on Beets weighted pool by ", + //slither-disable-next-line calls-loop + CommonLib.implode(CommonLib.getSymbols(_ammAdapter.poolTokens(farm.pool)), "-"), + " LP" + ); + } +} diff --git a/src/strategies/libs/StrategyDeveloperLib.sol b/src/strategies/libs/StrategyDeveloperLib.sol index 2b00012a..7a5f04d4 100644 --- a/src/strategies/libs/StrategyDeveloperLib.sol +++ b/src/strategies/libs/StrategyDeveloperLib.sol @@ -47,6 +47,9 @@ library StrategyDeveloperLib { if (CommonLib.eq(strategyId, StrategyIdLib.BEETS_STABLE_FARM)) { return 0x88888887C3ebD4a33E34a15Db4254C74C75E5D4A; } + if (CommonLib.eq(strategyId, StrategyIdLib.BEETS_WEIGHTED_FARM)) { + return 0x88888887C3ebD4a33E34a15Db4254C74C75E5D4A; + } if (CommonLib.eq(strategyId, StrategyIdLib.EQUALIZER_FARM)) { return 0x88888887C3ebD4a33E34a15Db4254C74C75E5D4A; } diff --git a/src/strategies/libs/StrategyIdLib.sol b/src/strategies/libs/StrategyIdLib.sol index 36703e92..ef883672 100644 --- a/src/strategies/libs/StrategyIdLib.sol +++ b/src/strategies/libs/StrategyIdLib.sol @@ -17,5 +17,6 @@ library StrategyIdLib { string internal constant YEARN = "Yearn"; string internal constant TRIDENT_PEARL_FARM = "Trident Pearl Farm"; string internal constant BEETS_STABLE_FARM = "Beets Stable Farm"; + string internal constant BEETS_WEIGHTED_FARM = "Beets Weighted Farm"; string internal constant EQUALIZER_FARM = "Equalizer Farm"; } diff --git a/test/core/Swapper.Sonic.t.sol b/test/core/Swapper.Sonic.t.sol index b0072bd6..efee1dc2 100644 --- a/test/core/Swapper.Sonic.t.sol +++ b/test/core/Swapper.Sonic.t.sol @@ -20,7 +20,7 @@ contract SwapperSonicTest is Test, SonicSetup { function testSwaps() public { uint got; - swapper.swap(SonicLib.TOKEN_wS, SonicLib.TOKEN_stS, 1e13, 1_000); // 1% + swapper.swap(SonicLib.TOKEN_wS, SonicLib.TOKEN_stS, 1e17, 1_000); // 1% got = IERC20(SonicLib.TOKEN_stS).balanceOf(address(this)); swapper.swap(SonicLib.TOKEN_stS, SonicLib.TOKEN_BEETS, got, 1_000); // 1% got = IERC20(SonicLib.TOKEN_BEETS).balanceOf(address(this)); diff --git a/test/strategies/BWF.Sonic.t.sol b/test/strategies/BWF.Sonic.t.sol new file mode 100644 index 00000000..d829fe0a --- /dev/null +++ b/test/strategies/BWF.Sonic.t.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import {console} from "forge-std/Test.sol"; +import {SonicSetup} from "../base/chains/SonicSetup.sol"; +import "../base/UniversalTest.sol"; + +contract BeetsWeightedFarmStrategyTest is SonicSetup, UniversalTest { + function testBWF() public universalTest { + _addStrategy(6); + } + + function _addStrategy(uint farmId) internal { + strategies.push( + Strategy({id: StrategyIdLib.BEETS_WEIGHTED_FARM, pool: address(0), farmId: farmId, underlying: address(0)}) + ); + } +}