From 1089f49febad7d887f7a39c23c548b4042d092af Mon Sep 17 00:00:00 2001 From: nakul1010 Date: Mon, 6 Jan 2025 16:53:39 +0530 Subject: [PATCH 1/5] feat: add strategy contracts --- src/gateway/CommonStructs.sol | 6 ++ src/gateway/IStrategy.sol | 30 ++++++ src/gateway/strategy/BedrockStrategy.sol | 58 ++++++++++ src/gateway/strategy/IonicStrategy.sol | 99 +++++++++++++++++ src/gateway/strategy/PellStrategy.sol | 125 ++++++++++++++++++++++ src/gateway/strategy/SegmentStrategy.sol | 123 +++++++++++++++++++++ src/gateway/strategy/ShoebillStrategy.sol | 58 ++++++++++ src/gateway/strategy/SolvStrategy.sol | 121 +++++++++++++++++++++ 8 files changed, 620 insertions(+) create mode 100644 src/gateway/CommonStructs.sol create mode 100644 src/gateway/IStrategy.sol create mode 100644 src/gateway/strategy/BedrockStrategy.sol create mode 100644 src/gateway/strategy/IonicStrategy.sol create mode 100644 src/gateway/strategy/PellStrategy.sol create mode 100644 src/gateway/strategy/SegmentStrategy.sol create mode 100644 src/gateway/strategy/ShoebillStrategy.sol create mode 100644 src/gateway/strategy/SolvStrategy.sol diff --git a/src/gateway/CommonStructs.sol b/src/gateway/CommonStructs.sol new file mode 100644 index 00000000..49d6c403 --- /dev/null +++ b/src/gateway/CommonStructs.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +struct StrategySlippageArgs { + uint256 amountOutMin; +} diff --git a/src/gateway/IStrategy.sol b/src/gateway/IStrategy.sol new file mode 100644 index 00000000..a3bc0102 --- /dev/null +++ b/src/gateway/IStrategy.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {StrategySlippageArgs} from "./CommonStructs.sol"; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +interface IStrategy { + event TokenOutput(address tokenReceived, uint256 amountOut); + + function handleGatewayMessage(IERC20 tokenSent, uint256 amountIn, address recipient, bytes memory message) + external; +} + +abstract contract IStrategyWithSlippageArgs is IStrategy { + function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amountIn, + address recipient, + StrategySlippageArgs memory args + ) public virtual; + + function handleGatewayMessage(IERC20 tokenSent, uint256 amountIn, address recipient, bytes memory message) + external + { + StrategySlippageArgs memory args = abi.decode(message, (StrategySlippageArgs)); + + handleGatewayMessageWithSlippageArgs(tokenSent, amountIn, recipient, args); + } +} diff --git a/src/gateway/strategy/BedrockStrategy.sol b/src/gateway/strategy/BedrockStrategy.sol new file mode 100644 index 00000000..a3a74b6d --- /dev/null +++ b/src/gateway/strategy/BedrockStrategy.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {IStrategyWithSlippageArgs} from "../IStrategy.sol"; +import {StrategySlippageArgs} from "../CommonStructs.sol"; + +import {Context} from "@openzeppelin/contracts/utils/Context.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +/** + * @dev Bedrock ABI for their Vault. + */ +interface IBedrockVault { + function mint(address _token, uint256 _amount) external; + function redeem(address _token, uint256 _amount) external; + function uniBTC() external view returns (address); +} + +/** + * @title Strategy contract for Bedrock (uniBTC). + */ +contract BedrockStrategy is IStrategyWithSlippageArgs, Context { + using SafeERC20 for IERC20; + + IBedrockVault public immutable vault; + + constructor(IBedrockVault _vault) { + vault = _vault; + } + + /** + * @notice Deposits tokens into Bedrock to mint uniBTC. + * @dev Requires that the strategy is approved to spend the incoming tokens. + * @param tokenSent The ERC20 token to deposit. + * @param amountIn The amount to be deposited. + * @param recipient The address to receive uniBTC. + * @param args Additional args for slippage protection. + */ + function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amountIn, + address recipient, + StrategySlippageArgs memory args + ) public override { + tokenSent.safeTransferFrom(_msgSender(), address(this), amountIn); + tokenSent.safeIncreaseAllowance(address(vault), amountIn); + + vault.mint(address(tokenSent), amountIn); + IERC20 uniBTC = IERC20(vault.uniBTC()); + uint256 uniBTCAmount = uniBTC.balanceOf(address(this)); + require(uniBTCAmount >= args.amountOutMin, "Insufficient output amount"); + + uniBTC.safeTransfer(recipient, uniBTCAmount); + + emit TokenOutput(address(uniBTC), uniBTCAmount); + } +} diff --git a/src/gateway/strategy/IonicStrategy.sol b/src/gateway/strategy/IonicStrategy.sol new file mode 100644 index 00000000..88c1b6e2 --- /dev/null +++ b/src/gateway/strategy/IonicStrategy.sol @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {IStrategyWithSlippageArgs} from "../IStrategy.sol"; +import {StrategySlippageArgs} from "../CommonStructs.sol"; +import {SolvLSTStrategy} from "./SolvStrategy.sol"; + +import {Context} from "@openzeppelin/contracts/utils/Context.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "forge-std/Test.sol"; + +/** + * @dev Interface for the Ionic Finance token, providing minting, redeeming, + * and balance query functions. + */ +interface IIonicToken { + function mint(uint256 mintAmount) external returns (uint256); + function redeem(uint256 redeemTokens) external returns (uint256); +} + +/** + * @dev Interface for the Ionic Finance Pool, allowing entry and exit from markets. + */ +interface IPool { + function enterMarkets(address[] memory cTokens) external returns (uint256[] memory); + function exitMarket(address cTokenAddress) external returns (uint256); +} + +/** + * @title Strategy contract for interacting with Ionic Finance markets. + * @dev Implements IStrategyWithSlippageArgs and allows the contract to handle tokens with slippage arguments. + */ +contract IonicStrategy is IStrategyWithSlippageArgs, Context { + using SafeERC20 for IERC20; + + // Immutable references to the Ionic token and pool interfaces. + IIonicToken public immutable ioErc20; + IPool public immutable pool; + + /** + * @dev Constructor to initialize the Ionic token and pool interfaces. + * @param _ioErc20 Address of the Ionic token. + * @param _pool Address of the Ionic pool. + */ + constructor(IIonicToken _ioErc20, IPool _pool) { + ioErc20 = _ioErc20; + pool = _pool; + } + + /** + * @dev Handles the transfer and minting of tokens with slippage control. + * @param tokenSent The token to be transferred. + * @param amountIn The amount of tokens to be transferred. + * @param recipient The recipient address. + * @param args Slippage arguments, including minimum acceptable output amount. + */ + function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amountIn, + address recipient, + StrategySlippageArgs memory args + ) public override { + // Transfer tokens from sender to this contract + tokenSent.safeTransferFrom(_msgSender(), address(this), amountIn); + + // Approve the Ionic token contract to spend the transferred tokens + tokenSent.safeIncreaseAllowance(address(ioErc20), amountIn); + + // Get the current balance of the recipient's Ionic token holdings + IERC20 ionicToken = IERC20(address(ioErc20)); + uint256 amountBefore = ionicToken.balanceOf(recipient); + + // Enter the Ionic market with the specified token + address[] memory markets = new address[](1); + markets[0] = address(ioErc20); + uint256[] memory results = pool.enterMarkets(markets); + require(results[0] == 0, "Couldn't enter in Market"); + + // Mint Ionic tokens with the transferred amount + uint256 mintResult = ioErc20.mint(amountIn); + require(mintResult == 0, "Could not mint token in Ionic market"); + + // Calculate the amount of Ionic tokens to transfer to the recipient + uint256 ionicAmountToTransfer = ionicToken.balanceOf(address(this)); + + // Increase allowance for the recipient if necessary and transfer Ionic tokens + ionicToken.safeTransfer(recipient, ionicAmountToTransfer); + + // Confirm the recipient's new balance and validate output amount + uint256 amountAfter = IERC20(address(ioErc20)).balanceOf(recipient); + require(amountAfter > amountBefore, "Insufficient supply provided"); + uint256 amountOut = amountAfter - amountBefore; + require(amountOut >= args.amountOutMin, "Insufficient output amount"); + + // Emit an event to record the token output + emit TokenOutput(address(ionicToken), amountOut); + } +} diff --git a/src/gateway/strategy/PellStrategy.sol b/src/gateway/strategy/PellStrategy.sol new file mode 100644 index 00000000..3e139ab0 --- /dev/null +++ b/src/gateway/strategy/PellStrategy.sol @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {IStrategyWithSlippageArgs} from "../IStrategy.sol"; +import {StrategySlippageArgs} from "../CommonStructs.sol"; +import {BedrockStrategy} from "./BedrockStrategy.sol"; +import {SolvLSTStrategy} from "./SolvStrategy.sol"; + +import {Context} from "@openzeppelin/contracts/utils/Context.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +/** + * @dev Pell ABI for their strategy manager. + */ +interface IPellStrategyManager { + function depositIntoStrategyWithStaker(address staker, IPellStrategy strategy, IERC20 token, uint256 amount) + external + returns (uint256 shares); + function stakerStrategyShares(address staker, IPellStrategy strategy) external view returns (uint256); +} + +interface IPellStrategy {} + +/** + * @title Strategy contract for Pell Network. + */ +contract PellStrategy is IStrategyWithSlippageArgs, Context { + using SafeERC20 for IERC20; + + IPellStrategyManager public immutable pellStrategyManager; + IPellStrategy public immutable pellStrategy; + + constructor(IPellStrategyManager _pellStrategyManager, IPellStrategy _pellStrategy) { + pellStrategyManager = _pellStrategyManager; + pellStrategy = _pellStrategy; + } + + /** + * @notice Deposits tokens into Pell Network. + * @dev Requires that the strategy is approved to spend the incoming tokens. + * @param tokenSent The ERC20 token to deposit. + * @param amountIn The amount to be deposited. + * @param recipient The address to receive the shares. + * @param args Additional args for slippage protection. + */ + function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amountIn, + address recipient, + StrategySlippageArgs memory args + ) public override { + tokenSent.safeTransferFrom(_msgSender(), address(this), amountIn); + tokenSent.safeIncreaseAllowance(address(pellStrategyManager), amountIn); + + uint256 shares = pellStrategyManager.depositIntoStrategyWithStaker(recipient, pellStrategy, tokenSent, amountIn); + require(shares >= args.amountOutMin, "Insufficient output amount"); + + emit TokenOutput(address(0), shares); + } + + function stakerStrategyShares(address recipient) public view returns (uint256) { + return pellStrategyManager.stakerStrategyShares(recipient, pellStrategy); + } +} + +contract PellBedrockStrategy is IStrategyWithSlippageArgs, Context { + using SafeERC20 for IERC20; + + BedrockStrategy public immutable bedrockStrategy; + PellStrategy public immutable pellStrategy; + + constructor(BedrockStrategy _bedrockStrategy, PellStrategy _pellStrategy) { + bedrockStrategy = _bedrockStrategy; + pellStrategy = _pellStrategy; + } + + function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amount, + address recipient, + StrategySlippageArgs memory args + ) public override { + tokenSent.safeTransferFrom(_msgSender(), address(this), amount); + tokenSent.safeIncreaseAllowance(address(bedrockStrategy), amount); + + bedrockStrategy.handleGatewayMessageWithSlippageArgs(tokenSent, amount, address(this), StrategySlippageArgs(0)); + + IERC20 uniBTC = IERC20(bedrockStrategy.vault().uniBTC()); + uint256 uniBTCAmount = uniBTC.balanceOf(address(this)); + uniBTC.safeIncreaseAllowance(address(pellStrategy), uniBTCAmount); + + pellStrategy.handleGatewayMessageWithSlippageArgs(uniBTC, uniBTCAmount, recipient, args); + } +} + +contract PellSolvLSTStrategy is IStrategyWithSlippageArgs, Context { + using SafeERC20 for IERC20; + + SolvLSTStrategy public immutable solvLSTStrategy; + PellStrategy public immutable pellStrategy; + + constructor(SolvLSTStrategy _solvLSTStrategy, PellStrategy _pellStrategy) { + solvLSTStrategy = _solvLSTStrategy; + pellStrategy = _pellStrategy; + } + + function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amount, + address recipient, + StrategySlippageArgs memory args + ) public override { + tokenSent.safeTransferFrom(_msgSender(), address(this), amount); + tokenSent.safeIncreaseAllowance(address(solvLSTStrategy), amount); + + solvLSTStrategy.handleGatewayMessageWithSlippageArgs(tokenSent, amount, address(this), StrategySlippageArgs(0)); + + IERC20 solvLST = solvLSTStrategy.solvLST(); + uint256 solvLSTAmount = solvLST.balanceOf(address(this)); + solvLST.safeIncreaseAllowance(address(pellStrategy), solvLSTAmount); + + pellStrategy.handleGatewayMessageWithSlippageArgs(solvLST, solvLSTAmount, recipient, args); + } +} diff --git a/src/gateway/strategy/SegmentStrategy.sol b/src/gateway/strategy/SegmentStrategy.sol new file mode 100644 index 00000000..034a83b5 --- /dev/null +++ b/src/gateway/strategy/SegmentStrategy.sol @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {IStrategyWithSlippageArgs} from "../IStrategy.sol"; +import {StrategySlippageArgs} from "../CommonStructs.sol"; +import {BedrockStrategy} from "./BedrockStrategy.sol"; +import {SolvLSTStrategy} from "./SolvStrategy.sol"; + +import {Context} from "@openzeppelin/contracts/utils/Context.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +/** + * @dev Segment ABI for their seTokens. + */ +interface ISeBep20 { + function mint(uint256 mintAmount) external returns (uint256); + function mintBehalf(address receiver, uint256 mintAmount) external returns (uint256); + function balanceOfUnderlying(address owner) external returns (uint256); + function redeem(uint256 redeemTokens) external returns (uint256); +} + +/** + * @title Strategy contract for Segment Finance. + */ +contract SegmentStrategy is IStrategyWithSlippageArgs, Context { + using SafeERC20 for IERC20; + + ISeBep20 public immutable seBep20; + + constructor(ISeBep20 _seBep20) { + seBep20 = _seBep20; + } + + /** + * @notice Mints lending tokens to the recipient. + * @dev Requires that the strategy is approved to spend the incoming tokens. + * @param tokenSent The ERC20 token to deposit. + * @param amountIn The amount to be deposited. + * @param recipient The address to receive the lending tokens. + * @param args Additional args for slippage protection. + */ + function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amountIn, + address recipient, + StrategySlippageArgs memory args + ) public override { + tokenSent.safeTransferFrom(_msgSender(), address(this), amountIn); + tokenSent.safeIncreaseAllowance(address(seBep20), amountIn); + + IERC20 token = IERC20(address(seBep20)); + uint256 amountBefore = token.balanceOf(recipient); + uint256 err = seBep20.mintBehalf(recipient, amountIn); + require(err == 0, "Could not mint token"); + uint256 amountAfter = token.balanceOf(recipient); + require(amountAfter > amountBefore, "Insufficient supply provided"); + uint256 amountOut = amountAfter - amountBefore; + require(amountOut >= args.amountOutMin, "Insufficient output amount"); + + emit TokenOutput(address(token), amountOut); + } +} + +contract SegmentBedrockStrategy is IStrategyWithSlippageArgs, Context { + using SafeERC20 for IERC20; + + BedrockStrategy public immutable bedrockStrategy; + SegmentStrategy public immutable segmentStrategy; + + constructor(BedrockStrategy _bedrockStrategy, SegmentStrategy _segmentStrategy) { + bedrockStrategy = _bedrockStrategy; + segmentStrategy = _segmentStrategy; + } + + function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amount, + address recipient, + StrategySlippageArgs memory args + ) public override { + tokenSent.safeTransferFrom(_msgSender(), address(this), amount); + tokenSent.safeIncreaseAllowance(address(bedrockStrategy), amount); + + bedrockStrategy.handleGatewayMessageWithSlippageArgs(tokenSent, amount, address(this), StrategySlippageArgs(0)); + + IERC20 uniBTC = IERC20(bedrockStrategy.vault().uniBTC()); + uint256 uniBTCAmount = uniBTC.balanceOf(address(this)); + uniBTC.safeIncreaseAllowance(address(segmentStrategy), uniBTCAmount); + + segmentStrategy.handleGatewayMessageWithSlippageArgs(uniBTC, uniBTCAmount, recipient, args); + } +} + +contract SegmentSolvLSTStrategy is IStrategyWithSlippageArgs, Context { + using SafeERC20 for IERC20; + + SolvLSTStrategy public immutable solvLSTStrategy; + SegmentStrategy public immutable segmentStrategy; + + constructor(SolvLSTStrategy _solvLSTStrategy, SegmentStrategy _segmentStrategy) { + solvLSTStrategy = _solvLSTStrategy; + segmentStrategy = _segmentStrategy; + } + + function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amount, + address recipient, + StrategySlippageArgs memory args + ) public override { + tokenSent.safeTransferFrom(_msgSender(), address(this), amount); + tokenSent.safeIncreaseAllowance(address(solvLSTStrategy), amount); + + solvLSTStrategy.handleGatewayMessageWithSlippageArgs(tokenSent, amount, address(this), StrategySlippageArgs(0)); + + IERC20 solvLST = solvLSTStrategy.solvLST(); + uint256 solvLSTAmount = solvLST.balanceOf(address(this)); + solvLST.safeIncreaseAllowance(address(segmentStrategy), solvLSTAmount); + + segmentStrategy.handleGatewayMessageWithSlippageArgs(solvLST, solvLSTAmount, recipient, args); + } +} diff --git a/src/gateway/strategy/ShoebillStrategy.sol b/src/gateway/strategy/ShoebillStrategy.sol new file mode 100644 index 00000000..754e34b5 --- /dev/null +++ b/src/gateway/strategy/ShoebillStrategy.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {IStrategyWithSlippageArgs} from "../IStrategy.sol"; +import {StrategySlippageArgs} from "../CommonStructs.sol"; + +import {Context} from "@openzeppelin/contracts/utils/Context.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +/** + * @dev Shoebill ABI for their sbTokens. + */ +interface ICErc20 { + function mint(uint256 mintAmount) external returns (uint256); + function balanceOfUnderlying(address owner) external returns (uint256); +} + +/** + * @title Strategy contract for Shoebill Finance. + */ +contract ShoebillStrategy is IStrategyWithSlippageArgs, Context { + using SafeERC20 for IERC20; + + ICErc20 public immutable cErc20; + + constructor(ICErc20 _cErc20) { + cErc20 = _cErc20; + } + + /** + * @notice Mints lending tokens to the recipient. + * @dev Requires that the strategy is approved to spend the incoming tokens. + * @param tokenSent The ERC20 token to deposit. + * @param amountIn The amount to be deposited. + * @param recipient The address to receive the lending tokens. + * @param args Additional args for slippage protection. + */ + function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amountIn, + address recipient, + StrategySlippageArgs memory args + ) public override { + tokenSent.safeTransferFrom(_msgSender(), address(this), amountIn); + tokenSent.safeIncreaseAllowance(address(cErc20), amountIn); + + IERC20 token = IERC20(address(cErc20)); + uint256 err = cErc20.mint(amountIn); + require(err == 0, "Could not mint token"); + uint256 amountOut = token.balanceOf(address(this)); + require(amountOut >= args.amountOutMin, "Insufficient output amount"); + + token.safeTransfer(recipient, amountOut); + + emit TokenOutput(address(token), amountOut); + } +} diff --git a/src/gateway/strategy/SolvStrategy.sol b/src/gateway/strategy/SolvStrategy.sol new file mode 100644 index 00000000..f17981fe --- /dev/null +++ b/src/gateway/strategy/SolvStrategy.sol @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {IStrategyWithSlippageArgs} from "../IStrategy.sol"; +import {StrategySlippageArgs} from "../CommonStructs.sol"; + +import {Context} from "@openzeppelin/contracts/utils/Context.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +/** + * @dev Solv ABI for their router. + */ +interface ISolvBTCRouter { + /** + * Subscribe with payment currency (i.e. WBTC) and receive SolvBTC. + * @param poolId SolvBTC fund ID. + * @param currencyAmount Amount of currency to be paid. + * @return shareValue Amount of SolvBTC to be received after subscription. + */ + function createSubscription(bytes32 poolId, uint256 currencyAmount) external returns (uint256 shareValue); +} + +/** + * @title Strategy contract for SolvBTC. + */ +contract SolvBTCStrategy is IStrategyWithSlippageArgs, Context { + using SafeERC20 for IERC20; + + ISolvBTCRouter public immutable solvBTCRouter; + bytes32 public immutable poolId; + IERC20 public immutable solvBTC; + + constructor(ISolvBTCRouter _solvBTCRouter, bytes32 _poolId, IERC20 _solvBTC) { + solvBTCRouter = _solvBTCRouter; + poolId = _poolId; + solvBTC = _solvBTC; + } + + /** + * @notice Deposits tokens into Solv. + * @dev Requires that the strategy is approved to spend the incoming tokens. + * @param tokenSent The ERC20 token to deposit. + * @param amountIn The amount to be deposited. + * @param recipient The address to receive SolvBTC. + * @param args Additional args for slippage protection. + */ + function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amountIn, + address recipient, + StrategySlippageArgs memory args + ) public override { + tokenSent.safeTransferFrom(_msgSender(), address(this), amountIn); + tokenSent.safeIncreaseAllowance(address(solvBTCRouter), amountIn); + + uint256 shareValue = solvBTCRouter.createSubscription(poolId, amountIn); + require(shareValue >= args.amountOutMin, "Insufficient output amount"); + + solvBTC.safeTransfer(recipient, shareValue); + + emit TokenOutput(address(solvBTC), shareValue); + } +} + +/** + * @title Strategy contract for e.g. SolvBTC.BBN. + */ +contract SolvLSTStrategy is IStrategyWithSlippageArgs, Context { + using SafeERC20 for IERC20; + + ISolvBTCRouter public immutable solvBTCRouter; + ISolvBTCRouter public immutable solvLSTRouter; + bytes32 public immutable solvBTCPoolId; + bytes32 public immutable solvLSTPoolId; + IERC20 public immutable solvBTC; + IERC20 public immutable solvLST; + + constructor( + ISolvBTCRouter _solvBTCRouter, + ISolvBTCRouter _solvLSTRouter, + bytes32 _solvBTCPoolId, + bytes32 _solvLSTPoolId, + IERC20 _solvBTC, + IERC20 _solvLST + ) { + solvBTCRouter = _solvBTCRouter; + solvLSTRouter = _solvLSTRouter; + solvBTCPoolId = _solvBTCPoolId; + solvLSTPoolId = _solvLSTPoolId; + solvBTC = _solvBTC; + solvLST = _solvLST; + } + + /** + * @notice Deposits tokens into Solv. + * @dev Requires that the strategy is approved to spend the incoming tokens. + * @param tokenSent The ERC20 token to deposit. + * @param amountIn The amount to be deposited. + * @param recipient The address to receive e.g. SolvBTC.BBN. + * @param args Additional args for slippage protection. + */ + function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amountIn, + address recipient, + StrategySlippageArgs memory args + ) public override { + tokenSent.safeTransferFrom(_msgSender(), address(this), amountIn); + tokenSent.safeIncreaseAllowance(address(solvBTCRouter), amountIn); + uint256 shareValueBTC = solvBTCRouter.createSubscription(solvBTCPoolId, amountIn); + + solvBTC.safeIncreaseAllowance(address(solvLSTRouter), shareValueBTC); + uint256 shareValueLST = solvLSTRouter.createSubscription(solvLSTPoolId, shareValueBTC); + require(shareValueLST >= args.amountOutMin, "Insufficient output amount"); + + solvLST.safeTransfer(recipient, shareValueLST); + + emit TokenOutput(address(solvLST), shareValueLST); + } +} From a27804387727d06fbd299e8efa48cf38f63e5a54 Mon Sep 17 00:00:00 2001 From: nakul1010 Date: Fri, 10 Jan 2025 12:13:44 +0530 Subject: [PATCH 2/5] feat: add gateway strategy plus test cases --- .github/workflows/test.yml | 3 +- .../struct.StrategySlippageArgs.md | 10 + .../abstract.IStrategyWithSlippageArgs.md | 27 +++ .../IStrategy.sol/interface.IStrategy.md | 19 ++ .../contract.AvalonLendingStrategy.md | 55 ++++++ .../contract.AvalonLstStrategy.md | 55 ++++++ .../interface.IAvalonIPool.md | 46 +++++ .../contract.BedrockStrategy.md | 48 +++++ .../interface.IBedrockVault.md | 28 +++ .../contract.IonicStrategy.md | 64 +++++++ .../interface.IIonicToken.md | 22 +++ .../IonicStrategy.sol/interface.IPool.md | 21 +++ .../contract.PellBedrockStrategy.md | 42 +++++ .../contract.PellSolvLSTStrategy.md | 42 +++++ .../PellStrategy.sol/contract.PellStrategy.md | 62 ++++++ .../interface.IPellStrategy.md | 4 + .../interface.IPellStrategyManager.md | 23 +++ .../contract.SegmentBedrockStrategy.md | 42 +++++ .../contract.SegmentSolvLSTStrategy.md | 42 +++++ .../contract.SegmentStrategy.md | 48 +++++ .../SegmentStrategy.sol/interface.ISeBep20.md | 35 ++++ .../contract.ShoebillStrategy.md | 48 +++++ .../ShoebillStrategy.sol/interface.ICErc20.md | 21 +++ .../contract.SolvBTCStrategy.md | 62 ++++++ .../contract.SolvLSTStrategy.md | 90 +++++++++ .../interface.ISolvBTCRouter.md | 29 +++ src/gateway/strategy/AvalonStrategy.sol | 116 ++++++++++++ src/gateway/strategy/BedrockStrategy.sol | 2 +- src/gateway/strategy/IonicStrategy.sol | 1 - .../AvalonStrategyForked.sol | 131 +++++++++++++ .../BedrockStrategyForked.sol | 37 ++++ test/gateway/e2e-strategy-tests/Constants.sol | 13 ++ .../e2e-strategy-tests/ForkedTemplate.sol | 39 ++++ .../IonicStrategyForked.sol | 46 +++++ .../e2e-strategy-tests/PellStrategyForked.sol | 125 +++++++++++++ .../SegmentStrategyForked.sol | 128 +++++++++++++ .../ShoebillStrategyForked.sol | 38 ++++ .../e2e-strategy-tests/SolvStrategyForked.sol | 60 ++++++ test/gateway/unit-tests/AvalonStrategy.sol | 130 +++++++++++++ test/gateway/unit-tests/BedrockStrategy.sol | 81 ++++++++ test/gateway/unit-tests/IonicStrategy.sol | 149 +++++++++++++++ test/gateway/unit-tests/PellStrategy.sol | 134 +++++++++++++ test/gateway/unit-tests/SegmentStrategy.sol | 176 ++++++++++++++++++ test/gateway/unit-tests/ShoebillStrategy.sol | 83 +++++++++ test/gateway/unit-tests/SolvStrategy.sol | 100 ++++++++++ test/gateway/unit-tests/Utils.sol | 14 ++ 46 files changed, 2588 insertions(+), 3 deletions(-) create mode 100644 docs/docs/contracts/src/src/gateway/CommonStructs.sol/struct.StrategySlippageArgs.md create mode 100644 docs/docs/contracts/src/src/gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md create mode 100644 docs/docs/contracts/src/src/gateway/IStrategy.sol/interface.IStrategy.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/contract.AvalonLendingStrategy.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/contract.AvalonLstStrategy.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/interface.IAvalonIPool.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/BedrockStrategy.sol/contract.BedrockStrategy.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/BedrockStrategy.sol/interface.IBedrockVault.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/IonicStrategy.sol/contract.IonicStrategy.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/IonicStrategy.sol/interface.IIonicToken.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/IonicStrategy.sol/interface.IPool.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellBedrockStrategy.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellSolvLSTStrategy.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellStrategy.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/interface.IPellStrategy.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/interface.IPellStrategyManager.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentBedrockStrategy.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentSolvLSTStrategy.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentStrategy.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/interface.ISeBep20.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/ShoebillStrategy.sol/contract.ShoebillStrategy.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/ShoebillStrategy.sol/interface.ICErc20.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/SolvStrategy.sol/contract.SolvBTCStrategy.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/SolvStrategy.sol/contract.SolvLSTStrategy.md create mode 100644 docs/docs/contracts/src/src/gateway/strategy/SolvStrategy.sol/interface.ISolvBTCRouter.md create mode 100644 src/gateway/strategy/AvalonStrategy.sol create mode 100644 test/gateway/e2e-strategy-tests/AvalonStrategyForked.sol create mode 100644 test/gateway/e2e-strategy-tests/BedrockStrategyForked.sol create mode 100644 test/gateway/e2e-strategy-tests/Constants.sol create mode 100644 test/gateway/e2e-strategy-tests/ForkedTemplate.sol create mode 100644 test/gateway/e2e-strategy-tests/IonicStrategyForked.sol create mode 100644 test/gateway/e2e-strategy-tests/PellStrategyForked.sol create mode 100644 test/gateway/e2e-strategy-tests/SegmentStrategyForked.sol create mode 100644 test/gateway/e2e-strategy-tests/ShoebillStrategyForked.sol create mode 100644 test/gateway/e2e-strategy-tests/SolvStrategyForked.sol create mode 100644 test/gateway/unit-tests/AvalonStrategy.sol create mode 100644 test/gateway/unit-tests/BedrockStrategy.sol create mode 100644 test/gateway/unit-tests/IonicStrategy.sol create mode 100644 test/gateway/unit-tests/PellStrategy.sol create mode 100644 test/gateway/unit-tests/SegmentStrategy.sol create mode 100644 test/gateway/unit-tests/ShoebillStrategy.sol create mode 100644 test/gateway/unit-tests/SolvStrategy.sol create mode 100644 test/gateway/unit-tests/Utils.sol diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b83f524d..973fb595 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,8 +29,9 @@ jobs: forge build --sizes --deny-warnings id: build - name: Run forge tests + # Currently forked tests are disabled to increase reliability of CI builds run: | - forge test -vvv --deny-warnings + forge test --no-match-contract Forked -vvv --deny-warnings id: test - name: Run forge docs run: | diff --git a/docs/docs/contracts/src/src/gateway/CommonStructs.sol/struct.StrategySlippageArgs.md b/docs/docs/contracts/src/src/gateway/CommonStructs.sol/struct.StrategySlippageArgs.md new file mode 100644 index 00000000..a4830d15 --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/CommonStructs.sol/struct.StrategySlippageArgs.md @@ -0,0 +1,10 @@ +# StrategySlippageArgs +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/CommonStructs.sol) + + +```solidity +struct StrategySlippageArgs { + uint256 amountOutMin; +} +``` + diff --git a/docs/docs/contracts/src/src/gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md b/docs/docs/contracts/src/src/gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md new file mode 100644 index 00000000..217d347c --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md @@ -0,0 +1,27 @@ +# IStrategyWithSlippageArgs +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/IStrategy.sol) + +**Inherits:** +[IStrategy](../../gateway/IStrategy.sol/interface.IStrategy.md) + + +## Functions +### handleGatewayMessageWithSlippageArgs + + +```solidity +function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amountIn, + address recipient, + StrategySlippageArgs memory args +) public virtual; +``` + +### handleGatewayMessage + + +```solidity +function handleGatewayMessage(IERC20 tokenSent, uint256 amountIn, address recipient, bytes memory message) external; +``` + diff --git a/docs/docs/contracts/src/src/gateway/IStrategy.sol/interface.IStrategy.md b/docs/docs/contracts/src/src/gateway/IStrategy.sol/interface.IStrategy.md new file mode 100644 index 00000000..c8f2b342 --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/IStrategy.sol/interface.IStrategy.md @@ -0,0 +1,19 @@ +# IStrategy +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/IStrategy.sol) + + +## Functions +### handleGatewayMessage + + +```solidity +function handleGatewayMessage(IERC20 tokenSent, uint256 amountIn, address recipient, bytes memory message) external; +``` + +## Events +### TokenOutput + +```solidity +event TokenOutput(address tokenReceived, uint256 amountOut); +``` + diff --git a/docs/docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/contract.AvalonLendingStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/contract.AvalonLendingStrategy.md new file mode 100644 index 00000000..53f35094 --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/contract.AvalonLendingStrategy.md @@ -0,0 +1,55 @@ +# AvalonLendingStrategy +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/AvalonStrategy.sol) + +**Inherits:** +[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context + + +## State Variables +### avBep20 + +```solidity +IERC20 public immutable avBep20; +``` + + +### pool + +```solidity +IAvalonIPool public immutable pool; +``` + + +## Functions +### constructor + + +```solidity +constructor(IERC20 _avBep20, IAvalonIPool _pool); +``` + +### handleGatewayMessageWithSlippageArgs + +Mints lending tokens to the recipient. + +*Requires that the strategy is approved to spend the incoming tokens.* + + +```solidity +function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amountIn, + address recipient, + StrategySlippageArgs memory args +) public override; +``` +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`tokenSent`|`IERC20`|The ERC20 token to deposit.| +|`amountIn`|`uint256`|The amount to be deposited.| +|`recipient`|`address`|The address to receive the lending tokens.| +|`args`|`StrategySlippageArgs`|Additional args for slippage protection.| + + diff --git a/docs/docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/contract.AvalonLstStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/contract.AvalonLstStrategy.md new file mode 100644 index 00000000..64e79133 --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/contract.AvalonLstStrategy.md @@ -0,0 +1,55 @@ +# AvalonLstStrategy +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/AvalonStrategy.sol) + +**Inherits:** +[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context + + +## State Variables +### solvLSTStrategy + +```solidity +SolvLSTStrategy public immutable solvLSTStrategy; +``` + + +### avalonLendingStrategy + +```solidity +AvalonLendingStrategy public immutable avalonLendingStrategy; +``` + + +## Functions +### constructor + + +```solidity +constructor(SolvLSTStrategy _solvLSTStrategy, AvalonLendingStrategy _avalonLendingStrategy); +``` + +### handleGatewayMessageWithSlippageArgs + +Mints lending tokens to the recipient. + +*Requires that the strategy is approved to spend the incoming tokens.* + + +```solidity +function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amountIn, + address recipient, + StrategySlippageArgs memory args +) public override; +``` +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`tokenSent`|`IERC20`|The ERC20 token to deposit.| +|`amountIn`|`uint256`|The amount to be deposited.| +|`recipient`|`address`|The address to receive the lending tokens.| +|`args`|`StrategySlippageArgs`|Additional args for slippage protection.| + + diff --git a/docs/docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/interface.IAvalonIPool.md b/docs/docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/interface.IAvalonIPool.md new file mode 100644 index 00000000..14f78769 --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/interface.IAvalonIPool.md @@ -0,0 +1,46 @@ +# IAvalonIPool +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/AvalonStrategy.sol) + + +## Functions +### supply + +Mints pool tokens to the recipient. + + +```solidity +function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external; +``` +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`asset`|`address`|The address of the ERC20 token to supply to the pool.| +|`amount`|`uint256`|The amount of the asset to supply.| +|`onBehalfOf`|`address`|The address that will receive the supplied amount.| +|`referralCode`|`uint16`|Optional referral code to track the origin of the supply.| + + +### withdraw + +Withdraws asset from the pool. + + +```solidity +function withdraw(address asset, uint256 amount, address to) external returns (uint256); +``` +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`asset`|`address`|The address of the ERC20 token to withdraw from the pool.| +|`amount`|`uint256`|The amount of the asset to withdraw.| +|`to`|`address`|The address that will receive the withdrawn amount.| + +**Returns** + +|Name|Type|Description| +|----|----|-----------| +|``|`uint256`|The actual amount withdrawn.| + + diff --git a/docs/docs/contracts/src/src/gateway/strategy/BedrockStrategy.sol/contract.BedrockStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/BedrockStrategy.sol/contract.BedrockStrategy.md new file mode 100644 index 00000000..4b9258fb --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/BedrockStrategy.sol/contract.BedrockStrategy.md @@ -0,0 +1,48 @@ +# BedrockStrategy +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/BedrockStrategy.sol) + +**Inherits:** +[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context + + +## State Variables +### vault + +```solidity +IBedrockVault public immutable vault; +``` + + +## Functions +### constructor + + +```solidity +constructor(IBedrockVault _vault); +``` + +### handleGatewayMessageWithSlippageArgs + +Deposits tokens into Bedrock to mint uniBTC. + +*Requires that the strategy is approved to spend the incoming tokens.* + + +```solidity +function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amountIn, + address recipient, + StrategySlippageArgs memory args +) public override; +``` +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`tokenSent`|`IERC20`|The ERC20 token to deposit.| +|`amountIn`|`uint256`|The amount to be deposited.| +|`recipient`|`address`|The address to receive uniBTC.| +|`args`|`StrategySlippageArgs`|Additional args for slippage protection.| + + diff --git a/docs/docs/contracts/src/src/gateway/strategy/BedrockStrategy.sol/interface.IBedrockVault.md b/docs/docs/contracts/src/src/gateway/strategy/BedrockStrategy.sol/interface.IBedrockVault.md new file mode 100644 index 00000000..898cf470 --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/BedrockStrategy.sol/interface.IBedrockVault.md @@ -0,0 +1,28 @@ +# IBedrockVault +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/BedrockStrategy.sol) + +*Bedrock ABI for their Vault.* + + +## Functions +### mint + + +```solidity +function mint(address _token, uint256 _amount) external; +``` + +### redeem + + +```solidity +function redeem(address _token, uint256 _amount) external; +``` + +### uniBTC + + +```solidity +function uniBTC() external view returns (address); +``` + diff --git a/docs/docs/contracts/src/src/gateway/strategy/IonicStrategy.sol/contract.IonicStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/IonicStrategy.sol/contract.IonicStrategy.md new file mode 100644 index 00000000..1076bf5e --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/IonicStrategy.sol/contract.IonicStrategy.md @@ -0,0 +1,64 @@ +# IonicStrategy +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/IonicStrategy.sol) + +**Inherits:** +[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context + +*Implements IStrategyWithSlippageArgs and allows the contract to handle tokens with slippage arguments.* + + +## State Variables +### ioErc20 + +```solidity +IIonicToken public immutable ioErc20; +``` + + +### pool + +```solidity +IPool public immutable pool; +``` + + +## Functions +### constructor + +*Constructor to initialize the Ionic token and pool interfaces.* + + +```solidity +constructor(IIonicToken _ioErc20, IPool _pool); +``` +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`_ioErc20`|`IIonicToken`|Address of the Ionic token.| +|`_pool`|`IPool`|Address of the Ionic pool.| + + +### handleGatewayMessageWithSlippageArgs + +*Handles the transfer and minting of tokens with slippage control.* + + +```solidity +function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amountIn, + address recipient, + StrategySlippageArgs memory args +) public override; +``` +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`tokenSent`|`IERC20`|The token to be transferred.| +|`amountIn`|`uint256`|The amount of tokens to be transferred.| +|`recipient`|`address`|The recipient address.| +|`args`|`StrategySlippageArgs`|Slippage arguments, including minimum acceptable output amount.| + + diff --git a/docs/docs/contracts/src/src/gateway/strategy/IonicStrategy.sol/interface.IIonicToken.md b/docs/docs/contracts/src/src/gateway/strategy/IonicStrategy.sol/interface.IIonicToken.md new file mode 100644 index 00000000..0ddfc956 --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/IonicStrategy.sol/interface.IIonicToken.md @@ -0,0 +1,22 @@ +# IIonicToken +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/IonicStrategy.sol) + +*Interface for the Ionic Finance token, providing minting, redeeming, +and balance query functions.* + + +## Functions +### mint + + +```solidity +function mint(uint256 mintAmount) external returns (uint256); +``` + +### redeem + + +```solidity +function redeem(uint256 redeemTokens) external returns (uint256); +``` + diff --git a/docs/docs/contracts/src/src/gateway/strategy/IonicStrategy.sol/interface.IPool.md b/docs/docs/contracts/src/src/gateway/strategy/IonicStrategy.sol/interface.IPool.md new file mode 100644 index 00000000..e0086d63 --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/IonicStrategy.sol/interface.IPool.md @@ -0,0 +1,21 @@ +# IPool +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/IonicStrategy.sol) + +*Interface for the Ionic Finance Pool, allowing entry and exit from markets.* + + +## Functions +### enterMarkets + + +```solidity +function enterMarkets(address[] memory cTokens) external returns (uint256[] memory); +``` + +### exitMarket + + +```solidity +function exitMarket(address cTokenAddress) external returns (uint256); +``` + diff --git a/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellBedrockStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellBedrockStrategy.md new file mode 100644 index 00000000..10d83f42 --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellBedrockStrategy.md @@ -0,0 +1,42 @@ +# PellBedrockStrategy +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/PellStrategy.sol) + +**Inherits:** +[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context + + +## State Variables +### bedrockStrategy + +```solidity +BedrockStrategy public immutable bedrockStrategy; +``` + + +### pellStrategy + +```solidity +PellStrategy public immutable pellStrategy; +``` + + +## Functions +### constructor + + +```solidity +constructor(BedrockStrategy _bedrockStrategy, PellStrategy _pellStrategy); +``` + +### handleGatewayMessageWithSlippageArgs + + +```solidity +function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amount, + address recipient, + StrategySlippageArgs memory args +) public override; +``` + diff --git a/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellSolvLSTStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellSolvLSTStrategy.md new file mode 100644 index 00000000..c922bed3 --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellSolvLSTStrategy.md @@ -0,0 +1,42 @@ +# PellSolvLSTStrategy +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/PellStrategy.sol) + +**Inherits:** +[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context + + +## State Variables +### solvLSTStrategy + +```solidity +SolvLSTStrategy public immutable solvLSTStrategy; +``` + + +### pellStrategy + +```solidity +PellStrategy public immutable pellStrategy; +``` + + +## Functions +### constructor + + +```solidity +constructor(SolvLSTStrategy _solvLSTStrategy, PellStrategy _pellStrategy); +``` + +### handleGatewayMessageWithSlippageArgs + + +```solidity +function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amount, + address recipient, + StrategySlippageArgs memory args +) public override; +``` + diff --git a/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellStrategy.md new file mode 100644 index 00000000..2941ec65 --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellStrategy.md @@ -0,0 +1,62 @@ +# PellStrategy +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/PellStrategy.sol) + +**Inherits:** +[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context + + +## State Variables +### pellStrategyManager + +```solidity +IPellStrategyManager public immutable pellStrategyManager; +``` + + +### pellStrategy + +```solidity +IPellStrategy public immutable pellStrategy; +``` + + +## Functions +### constructor + + +```solidity +constructor(IPellStrategyManager _pellStrategyManager, IPellStrategy _pellStrategy); +``` + +### handleGatewayMessageWithSlippageArgs + +Deposits tokens into Pell Network. + +*Requires that the strategy is approved to spend the incoming tokens.* + + +```solidity +function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amountIn, + address recipient, + StrategySlippageArgs memory args +) public override; +``` +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`tokenSent`|`IERC20`|The ERC20 token to deposit.| +|`amountIn`|`uint256`|The amount to be deposited.| +|`recipient`|`address`|The address to receive the shares.| +|`args`|`StrategySlippageArgs`|Additional args for slippage protection.| + + +### stakerStrategyShares + + +```solidity +function stakerStrategyShares(address recipient) public view returns (uint256); +``` + diff --git a/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/interface.IPellStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/interface.IPellStrategy.md new file mode 100644 index 00000000..afcd5681 --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/interface.IPellStrategy.md @@ -0,0 +1,4 @@ +# IPellStrategy +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/PellStrategy.sol) + + diff --git a/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/interface.IPellStrategyManager.md b/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/interface.IPellStrategyManager.md new file mode 100644 index 00000000..b028baed --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/interface.IPellStrategyManager.md @@ -0,0 +1,23 @@ +# IPellStrategyManager +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/PellStrategy.sol) + +*Pell ABI for their strategy manager.* + + +## Functions +### depositIntoStrategyWithStaker + + +```solidity +function depositIntoStrategyWithStaker(address staker, IPellStrategy strategy, IERC20 token, uint256 amount) + external + returns (uint256 shares); +``` + +### stakerStrategyShares + + +```solidity +function stakerStrategyShares(address staker, IPellStrategy strategy) external view returns (uint256); +``` + diff --git a/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentBedrockStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentBedrockStrategy.md new file mode 100644 index 00000000..0d0dd29b --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentBedrockStrategy.md @@ -0,0 +1,42 @@ +# SegmentBedrockStrategy +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/SegmentStrategy.sol) + +**Inherits:** +[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context + + +## State Variables +### bedrockStrategy + +```solidity +BedrockStrategy public immutable bedrockStrategy; +``` + + +### segmentStrategy + +```solidity +SegmentStrategy public immutable segmentStrategy; +``` + + +## Functions +### constructor + + +```solidity +constructor(BedrockStrategy _bedrockStrategy, SegmentStrategy _segmentStrategy); +``` + +### handleGatewayMessageWithSlippageArgs + + +```solidity +function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amount, + address recipient, + StrategySlippageArgs memory args +) public override; +``` + diff --git a/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentSolvLSTStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentSolvLSTStrategy.md new file mode 100644 index 00000000..c66c5c17 --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentSolvLSTStrategy.md @@ -0,0 +1,42 @@ +# SegmentSolvLSTStrategy +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/SegmentStrategy.sol) + +**Inherits:** +[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context + + +## State Variables +### solvLSTStrategy + +```solidity +SolvLSTStrategy public immutable solvLSTStrategy; +``` + + +### segmentStrategy + +```solidity +SegmentStrategy public immutable segmentStrategy; +``` + + +## Functions +### constructor + + +```solidity +constructor(SolvLSTStrategy _solvLSTStrategy, SegmentStrategy _segmentStrategy); +``` + +### handleGatewayMessageWithSlippageArgs + + +```solidity +function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amount, + address recipient, + StrategySlippageArgs memory args +) public override; +``` + diff --git a/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentStrategy.md new file mode 100644 index 00000000..02dc4ce5 --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentStrategy.md @@ -0,0 +1,48 @@ +# SegmentStrategy +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/SegmentStrategy.sol) + +**Inherits:** +[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context + + +## State Variables +### seBep20 + +```solidity +ISeBep20 public immutable seBep20; +``` + + +## Functions +### constructor + + +```solidity +constructor(ISeBep20 _seBep20); +``` + +### handleGatewayMessageWithSlippageArgs + +Mints lending tokens to the recipient. + +*Requires that the strategy is approved to spend the incoming tokens.* + + +```solidity +function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amountIn, + address recipient, + StrategySlippageArgs memory args +) public override; +``` +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`tokenSent`|`IERC20`|The ERC20 token to deposit.| +|`amountIn`|`uint256`|The amount to be deposited.| +|`recipient`|`address`|The address to receive the lending tokens.| +|`args`|`StrategySlippageArgs`|Additional args for slippage protection.| + + diff --git a/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/interface.ISeBep20.md b/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/interface.ISeBep20.md new file mode 100644 index 00000000..ff24a9a9 --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/interface.ISeBep20.md @@ -0,0 +1,35 @@ +# ISeBep20 +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/SegmentStrategy.sol) + +*Segment ABI for their seTokens.* + + +## Functions +### mint + + +```solidity +function mint(uint256 mintAmount) external returns (uint256); +``` + +### mintBehalf + + +```solidity +function mintBehalf(address receiver, uint256 mintAmount) external returns (uint256); +``` + +### balanceOfUnderlying + + +```solidity +function balanceOfUnderlying(address owner) external returns (uint256); +``` + +### redeem + + +```solidity +function redeem(uint256 redeemTokens) external returns (uint256); +``` + diff --git a/docs/docs/contracts/src/src/gateway/strategy/ShoebillStrategy.sol/contract.ShoebillStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/ShoebillStrategy.sol/contract.ShoebillStrategy.md new file mode 100644 index 00000000..55208fd9 --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/ShoebillStrategy.sol/contract.ShoebillStrategy.md @@ -0,0 +1,48 @@ +# ShoebillStrategy +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/ShoebillStrategy.sol) + +**Inherits:** +[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context + + +## State Variables +### cErc20 + +```solidity +ICErc20 public immutable cErc20; +``` + + +## Functions +### constructor + + +```solidity +constructor(ICErc20 _cErc20); +``` + +### handleGatewayMessageWithSlippageArgs + +Mints lending tokens to the recipient. + +*Requires that the strategy is approved to spend the incoming tokens.* + + +```solidity +function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amountIn, + address recipient, + StrategySlippageArgs memory args +) public override; +``` +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`tokenSent`|`IERC20`|The ERC20 token to deposit.| +|`amountIn`|`uint256`|The amount to be deposited.| +|`recipient`|`address`|The address to receive the lending tokens.| +|`args`|`StrategySlippageArgs`|Additional args for slippage protection.| + + diff --git a/docs/docs/contracts/src/src/gateway/strategy/ShoebillStrategy.sol/interface.ICErc20.md b/docs/docs/contracts/src/src/gateway/strategy/ShoebillStrategy.sol/interface.ICErc20.md new file mode 100644 index 00000000..88436131 --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/ShoebillStrategy.sol/interface.ICErc20.md @@ -0,0 +1,21 @@ +# ICErc20 +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/ShoebillStrategy.sol) + +*Shoebill ABI for their sbTokens.* + + +## Functions +### mint + + +```solidity +function mint(uint256 mintAmount) external returns (uint256); +``` + +### balanceOfUnderlying + + +```solidity +function balanceOfUnderlying(address owner) external returns (uint256); +``` + diff --git a/docs/docs/contracts/src/src/gateway/strategy/SolvStrategy.sol/contract.SolvBTCStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/SolvStrategy.sol/contract.SolvBTCStrategy.md new file mode 100644 index 00000000..39745985 --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/SolvStrategy.sol/contract.SolvBTCStrategy.md @@ -0,0 +1,62 @@ +# SolvBTCStrategy +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/SolvStrategy.sol) + +**Inherits:** +[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context + + +## State Variables +### solvBTCRouter + +```solidity +ISolvBTCRouter public immutable solvBTCRouter; +``` + + +### poolId + +```solidity +bytes32 public immutable poolId; +``` + + +### solvBTC + +```solidity +IERC20 public immutable solvBTC; +``` + + +## Functions +### constructor + + +```solidity +constructor(ISolvBTCRouter _solvBTCRouter, bytes32 _poolId, IERC20 _solvBTC); +``` + +### handleGatewayMessageWithSlippageArgs + +Deposits tokens into Solv. + +*Requires that the strategy is approved to spend the incoming tokens.* + + +```solidity +function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amountIn, + address recipient, + StrategySlippageArgs memory args +) public override; +``` +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`tokenSent`|`IERC20`|The ERC20 token to deposit.| +|`amountIn`|`uint256`|The amount to be deposited.| +|`recipient`|`address`|The address to receive SolvBTC.| +|`args`|`StrategySlippageArgs`|Additional args for slippage protection.| + + diff --git a/docs/docs/contracts/src/src/gateway/strategy/SolvStrategy.sol/contract.SolvLSTStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/SolvStrategy.sol/contract.SolvLSTStrategy.md new file mode 100644 index 00000000..a5ffd483 --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/SolvStrategy.sol/contract.SolvLSTStrategy.md @@ -0,0 +1,90 @@ +# SolvLSTStrategy +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/SolvStrategy.sol) + +**Inherits:** +[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context + + +## State Variables +### solvBTCRouter + +```solidity +ISolvBTCRouter public immutable solvBTCRouter; +``` + + +### solvLSTRouter + +```solidity +ISolvBTCRouter public immutable solvLSTRouter; +``` + + +### solvBTCPoolId + +```solidity +bytes32 public immutable solvBTCPoolId; +``` + + +### solvLSTPoolId + +```solidity +bytes32 public immutable solvLSTPoolId; +``` + + +### solvBTC + +```solidity +IERC20 public immutable solvBTC; +``` + + +### solvLST + +```solidity +IERC20 public immutable solvLST; +``` + + +## Functions +### constructor + + +```solidity +constructor( + ISolvBTCRouter _solvBTCRouter, + ISolvBTCRouter _solvLSTRouter, + bytes32 _solvBTCPoolId, + bytes32 _solvLSTPoolId, + IERC20 _solvBTC, + IERC20 _solvLST +); +``` + +### handleGatewayMessageWithSlippageArgs + +Deposits tokens into Solv. + +*Requires that the strategy is approved to spend the incoming tokens.* + + +```solidity +function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amountIn, + address recipient, + StrategySlippageArgs memory args +) public override; +``` +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`tokenSent`|`IERC20`|The ERC20 token to deposit.| +|`amountIn`|`uint256`|The amount to be deposited.| +|`recipient`|`address`|The address to receive e.g. SolvBTC.BBN.| +|`args`|`StrategySlippageArgs`|Additional args for slippage protection.| + + diff --git a/docs/docs/contracts/src/src/gateway/strategy/SolvStrategy.sol/interface.ISolvBTCRouter.md b/docs/docs/contracts/src/src/gateway/strategy/SolvStrategy.sol/interface.ISolvBTCRouter.md new file mode 100644 index 00000000..e953f694 --- /dev/null +++ b/docs/docs/contracts/src/src/gateway/strategy/SolvStrategy.sol/interface.ISolvBTCRouter.md @@ -0,0 +1,29 @@ +# ISolvBTCRouter +[Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/SolvStrategy.sol) + +*Solv ABI for their router.* + + +## Functions +### createSubscription + +Subscribe with payment currency (i.e. WBTC) and receive SolvBTC. + + +```solidity +function createSubscription(bytes32 poolId, uint256 currencyAmount) external returns (uint256 shareValue); +``` +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`poolId`|`bytes32`|SolvBTC fund ID.| +|`currencyAmount`|`uint256`|Amount of currency to be paid.| + +**Returns** + +|Name|Type|Description| +|----|----|-----------| +|`shareValue`|`uint256`|Amount of SolvBTC to be received after subscription.| + + diff --git a/src/gateway/strategy/AvalonStrategy.sol b/src/gateway/strategy/AvalonStrategy.sol new file mode 100644 index 00000000..f8268603 --- /dev/null +++ b/src/gateway/strategy/AvalonStrategy.sol @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {IStrategyWithSlippageArgs} from "../IStrategy.sol"; +import {StrategySlippageArgs} from "../CommonStructs.sol"; +import {BedrockStrategy} from "./BedrockStrategy.sol"; +import {SolvLSTStrategy} from "./SolvStrategy.sol"; + +import {Context} from "@openzeppelin/contracts/utils/Context.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +interface IAvalonIPool { + /** + * @notice Mints pool tokens to the recipient. + * @param asset The address of the ERC20 token to supply to the pool. + * @param amount The amount of the asset to supply. + * @param onBehalfOf The address that will receive the supplied amount. + * @param referralCode Optional referral code to track the origin of the supply. + */ + function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external; + + /** + * @notice Withdraws asset from the pool. + * @param asset The address of the ERC20 token to withdraw from the pool. + * @param amount The amount of the asset to withdraw. + * @param to The address that will receive the withdrawn amount. + * @return The actual amount withdrawn. + */ + function withdraw(address asset, uint256 amount, address to) external returns (uint256); +} + +/** + * @title Strategy contract for Avalon Finance. + */ +contract AvalonLendingStrategy is IStrategyWithSlippageArgs, Context { + using SafeERC20 for IERC20; + + IERC20 public immutable avBep20; + IAvalonIPool public immutable pool; + + constructor(IERC20 _avBep20, IAvalonIPool _pool) { + avBep20 = _avBep20; + pool = _pool; + } + + /** + * @notice Mints lending tokens to the recipient. + * @dev Requires that the strategy is approved to spend the incoming tokens. + * @param tokenSent The ERC20 token to deposit. + * @param amountIn The amount to be deposited. + * @param recipient The address to receive the lending tokens. + * @param args Additional args for slippage protection. + */ + function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amountIn, + address recipient, + StrategySlippageArgs memory args + ) public override { + tokenSent.safeTransferFrom(_msgSender(), address(this), amountIn); + tokenSent.safeIncreaseAllowance(address(pool), amountIn); + uint256 amountBefore = avBep20.balanceOf(recipient); + + // referralCode: 0, as the action is executed directly by the contract without any intermediary. + // This parameter is typically used to register the integrator initiating the operation for potential rewards. + pool.supply(address(tokenSent), amountIn, recipient, 0); + + uint256 amountAfter = avBep20.balanceOf(recipient); + require(amountAfter > amountBefore, "Insufficient supply provided"); + uint256 amountOut = amountAfter - amountBefore; + require(amountOut >= args.amountOutMin, "Insufficient output amount"); + + emit TokenOutput(address(avBep20), amountOut); + } +} + +contract AvalonLstStrategy is IStrategyWithSlippageArgs, Context { + using SafeERC20 for IERC20; + + SolvLSTStrategy public immutable solvLSTStrategy; + AvalonLendingStrategy public immutable avalonLendingStrategy; + + constructor(SolvLSTStrategy _solvLSTStrategy, AvalonLendingStrategy _avalonLendingStrategy) { + solvLSTStrategy = _solvLSTStrategy; + avalonLendingStrategy = _avalonLendingStrategy; + } + + /** + * @notice Mints lending tokens to the recipient. + * @dev Requires that the strategy is approved to spend the incoming tokens. + * @param tokenSent The ERC20 token to deposit. + * @param amountIn The amount to be deposited. + * @param recipient The address to receive the lending tokens. + * @param args Additional args for slippage protection. + */ + function handleGatewayMessageWithSlippageArgs( + IERC20 tokenSent, + uint256 amountIn, + address recipient, + StrategySlippageArgs memory args + ) public override { + tokenSent.safeTransferFrom(_msgSender(), address(this), amountIn); + tokenSent.safeIncreaseAllowance(address(solvLSTStrategy), amountIn); + + solvLSTStrategy.handleGatewayMessageWithSlippageArgs( + tokenSent, amountIn, address(this), StrategySlippageArgs(0) + ); + + IERC20 solvLST = solvLSTStrategy.solvLST(); + uint256 solvLSTAmount = solvLST.balanceOf(address(this)); + solvLST.safeIncreaseAllowance(address(avalonLendingStrategy), solvLSTAmount); + + avalonLendingStrategy.handleGatewayMessageWithSlippageArgs(solvLST, solvLSTAmount, recipient, args); + } +} diff --git a/src/gateway/strategy/BedrockStrategy.sol b/src/gateway/strategy/BedrockStrategy.sol index a3a74b6d..b1b8dd8f 100644 --- a/src/gateway/strategy/BedrockStrategy.sol +++ b/src/gateway/strategy/BedrockStrategy.sol @@ -50,7 +50,7 @@ contract BedrockStrategy is IStrategyWithSlippageArgs, Context { IERC20 uniBTC = IERC20(vault.uniBTC()); uint256 uniBTCAmount = uniBTC.balanceOf(address(this)); require(uniBTCAmount >= args.amountOutMin, "Insufficient output amount"); - + // ToDo: Missing corner case to check Insufficient supply provided. uniBTC.safeTransfer(recipient, uniBTCAmount); emit TokenOutput(address(uniBTC), uniBTCAmount); diff --git a/src/gateway/strategy/IonicStrategy.sol b/src/gateway/strategy/IonicStrategy.sol index 88c1b6e2..05eee671 100644 --- a/src/gateway/strategy/IonicStrategy.sol +++ b/src/gateway/strategy/IonicStrategy.sol @@ -8,7 +8,6 @@ import {SolvLSTStrategy} from "./SolvStrategy.sol"; import {Context} from "@openzeppelin/contracts/utils/Context.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import "forge-std/Test.sol"; /** * @dev Interface for the Ionic Finance token, providing minting, redeeming, diff --git a/test/gateway/e2e-strategy-tests/AvalonStrategyForked.sol b/test/gateway/e2e-strategy-tests/AvalonStrategyForked.sol new file mode 100644 index 00000000..a2686354 --- /dev/null +++ b/test/gateway/e2e-strategy-tests/AvalonStrategyForked.sol @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {stdStorage, StdStorage, Test, console} from "forge-std/Test.sol"; + +using stdStorage for StdStorage; + +import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import { + IAvalonIPool, AvalonLendingStrategy, AvalonLstStrategy +} from "../../../src/gateway/strategy/AvalonStrategy.sol"; +import {StrategySlippageArgs} from "../../../src/gateway/CommonStructs.sol"; +import {Constants} from "./Constants.sol"; +import {ForkedStrategyTemplateTbtc, ForkedStrategyTemplateWbtc} from "./ForkedTemplate.sol"; +import {SolvLSTStrategy, ISolvBTCRouter} from "../../../src/gateway/strategy/SolvStrategy.sol"; + +// Command to run this contract tests with Foundry: +// BOB_PROD_PUBLIC_RPC_URL=https://rpc.gobob.xyz/ forge test --match-contract AvalonTBTCLendingStrategyForked -vv +contract AvalonTBTCLendingStrategyForked is ForkedStrategyTemplateTbtc { + function setUp() public { + super.simulateForkAndTransfer( + 6077077, address(0xa79a356B01ef805B3089b4FE67447b96c7e6DD4C), Constants.DUMMY_SENDER, 1 ether + ); + } + + function testAvalonTBTCStrategy() public { + // Instantiate the Avalon TBTC token and pool contracts + IERC20 avalonTBTCToken = IERC20(0x5E007Ed35c7d89f5889eb6FD0cdCAa38059560ef); + IAvalonIPool pool = IAvalonIPool(0x35B3F1BFe7cbE1e95A3DC2Ad054eB6f0D4c879b6); + + // Deploy a new AvalonLendingStrategy contract + AvalonLendingStrategy strategy = new AvalonLendingStrategy(avalonTBTCToken, pool); + + vm.prank(Constants.DUMMY_SENDER); + token.approve(address(strategy), 1 ether); + vm.stopPrank(); + + vm.prank(Constants.DUMMY_SENDER); + strategy.handleGatewayMessageWithSlippageArgs(token, 1 ether, Constants.DUMMY_RECEIVER, StrategySlippageArgs(0)); + vm.stopPrank(); + + // Assert that receivers token balance is still 0 (funds are in the pool) + assertEq(token.balanceOf(Constants.DUMMY_RECEIVER), 0 ether); + + // receiver withdraws Received tokens from the pool + vm.prank(Constants.DUMMY_RECEIVER); + pool.withdraw(address(token), 1 ether, Constants.DUMMY_RECEIVER); + vm.stopPrank(); + + // Assert that receiver now has 1 token in their balance + assertEq(token.balanceOf(Constants.DUMMY_RECEIVER), 1 ether); + } +} + +// Command to run this contract tests with Foundry: +// BOB_PROD_PUBLIC_RPC_URL=https://rpc.gobob.xyz/ forge test --match-contract AvalonWBTCLendingStrategyForked -vv +contract AvalonWBTCLendingStrategyForked is ForkedStrategyTemplateWbtc { + function setUp() public { + super.simulateForkAndTransfer( + 6216882, address(0x5A8E9774d67fe846C6F4311c073e2AC34b33646F), Constants.DUMMY_SENDER, 1e8 + ); + } + + function testAvalonWBTCStrategy() public { + // Instantiate the Avalon WBTC token and pool contracts + IERC20 avalonWBTCToken = IERC20(0xd6890176e8d912142AC489e8B5D8D93F8dE74D60); + IAvalonIPool pool = IAvalonIPool(0x35B3F1BFe7cbE1e95A3DC2Ad054eB6f0D4c879b6); + + // Deploy a new AvalonLendingStrategy contract + AvalonLendingStrategy strategy = new AvalonLendingStrategy(avalonWBTCToken, pool); + + vm.startPrank(Constants.DUMMY_SENDER); + token.approve(address(strategy), 1 * 1e8); + + strategy.handleGatewayMessageWithSlippageArgs(token, 1e8, Constants.DUMMY_RECEIVER, StrategySlippageArgs(0)); + vm.stopPrank(); + + // Assert that receiver's token balance is still 0 (funds are in the pool) + assertEq(token.balanceOf(Constants.DUMMY_RECEIVER), 0); + + // receiver withdraws Received WBTC from the pool + vm.prank(Constants.DUMMY_RECEIVER); + pool.withdraw(address(token), 1e8, Constants.DUMMY_RECEIVER); + + // Assert that receiver now has 1 WBTC in their balance + assertEq(token.balanceOf(Constants.DUMMY_RECEIVER), 1e8); + } +} + +// Command to run this contract tests with Foundry: +// BOB_PROD_PUBLIC_RPC_URL=https://rpc.gobob.xyz/ forge test --match-contract AvalonWBTCLstStrategyForked -vv +contract AvalonWBTCLstStrategyForked is ForkedStrategyTemplateWbtc { + function setUp() public { + super.simulateForkAndTransfer( + 6216882, address(0x5A8E9774d67fe846C6F4311c073e2AC34b33646F), Constants.DUMMY_SENDER, 1e8 + ); + } + + function testWbtcLstStrategy() public { + IERC20 solvBTC = IERC20(0x541FD749419CA806a8bc7da8ac23D346f2dF8B77); + IERC20 solvBTCBBN = IERC20(0xCC0966D8418d412c599A6421b760a847eB169A8c); + SolvLSTStrategy solvLSTStrategy = new SolvLSTStrategy( + ISolvBTCRouter(0x49b072158564Db36304518FFa37B1cFc13916A90), + ISolvBTCRouter(0xbA46FcC16B464D9787314167bDD9f1Ce28405bA1), + 0x5664520240a46b4b3e9655c20cc3f9e08496a9b746a478e476ae3e04d6c8fc31, + 0x6899a7e13b655fa367208cb27c6eaa2410370d1565dc1f5f11853a1e8cbef033, + solvBTC, + solvBTCBBN + ); + + IERC20 avalonSolvBtcBBNToken = IERC20(0x2E6500A7Add9a788753a897e4e3477f651c612eb); + IAvalonIPool pool = IAvalonIPool(0x35B3F1BFe7cbE1e95A3DC2Ad054eB6f0D4c879b6); + AvalonLendingStrategy avalonLendingStrategy = new AvalonLendingStrategy(avalonSolvBtcBBNToken, pool); + + // Deploy a new AvalonLstStrategy contract + AvalonLstStrategy avalonLstStrategy = new AvalonLstStrategy(solvLSTStrategy, avalonLendingStrategy); + + vm.startPrank(Constants.DUMMY_SENDER); + token.approve(address(avalonLstStrategy), 1e8); + + // check before calling receiver has not avalonSolvBtcBBN tokens + assertEq(avalonSolvBtcBBNToken.balanceOf(address(Constants.DUMMY_RECEIVER)), 0); + + avalonLstStrategy.handleGatewayMessageWithSlippageArgs( + token, 1e8, Constants.DUMMY_RECEIVER, StrategySlippageArgs(0) + ); + vm.stopPrank(); + + assertEq(avalonSolvBtcBBNToken.balanceOf(address(Constants.DUMMY_RECEIVER)), 1 ether); + } +} diff --git a/test/gateway/e2e-strategy-tests/BedrockStrategyForked.sol b/test/gateway/e2e-strategy-tests/BedrockStrategyForked.sol new file mode 100644 index 00000000..deafd412 --- /dev/null +++ b/test/gateway/e2e-strategy-tests/BedrockStrategyForked.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import {Test, console} from "forge-std/Test.sol"; +import {StrategySlippageArgs} from "../../../src/gateway/CommonStructs.sol"; +import {Constants} from "./Constants.sol"; +import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import {IBedrockVault, BedrockStrategy} from "../../../src/gateway/strategy/BedrockStrategy.sol"; +import {ForkedStrategyTemplateWbtc} from "./ForkedTemplate.sol"; + +// Command to run this contract tests with Foundry: +// BOB_PROD_PUBLIC_RPC_URL=https://rpc.gobob.xyz/ forge test --match-contract BedrockStrategyForked -vv +contract BedrockStrategyForked is ForkedStrategyTemplateWbtc { + function setUp() public { + super.simulateForkAndTransfer( + 6077077, address(0x5A8E9774d67fe846C6F4311c073e2AC34b33646F), Constants.DUMMY_SENDER, 1e8 + ); + } + + function testBedrockStrategy() public { + IBedrockVault vault = IBedrockVault(0x2ac98DB41Cbd3172CB7B8FD8A8Ab3b91cFe45dCf); + BedrockStrategy strategy = new BedrockStrategy(vault); + + vm.startPrank(Constants.DUMMY_SENDER); + token.approve(address(strategy), 1e8); + strategy.handleGatewayMessageWithSlippageArgs( + token, + 1e8, // Amount: 1 WBTC + Constants.DUMMY_RECEIVER, + StrategySlippageArgs(0) // No slippage allowed + ); + vm.stopPrank(); + + IERC20 uniBTC = IERC20(vault.uniBTC()); + assertEq(uniBTC.balanceOf(Constants.DUMMY_RECEIVER), 1e8, "User uniBTC balance mismatch"); + } +} diff --git a/test/gateway/e2e-strategy-tests/Constants.sol b/test/gateway/e2e-strategy-tests/Constants.sol new file mode 100644 index 00000000..bd9138af --- /dev/null +++ b/test/gateway/e2e-strategy-tests/Constants.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +/** + * @title Commonly used constants. + */ +library Constants { + // Used for providing a uniform interface for functions that deal with both ERC20 and native tokens. + address constant WBTC_ADDRESS = 0x03C7054BCB39f7b2e5B2c7AcB37583e32D70Cfa3; + address constant TBTC_ADDRESS = 0xBBa2eF945D523C4e2608C9E1214C2Cc64D4fc2e2; + address constant DUMMY_SENDER = 0x999999cf1046e68e36E1aA2E0E07105eDDD1f08E; + address constant DUMMY_RECEIVER = 0xa2adc38f06704Cd2e633e8656DbF8B3224E840b8; +} diff --git a/test/gateway/e2e-strategy-tests/ForkedTemplate.sol b/test/gateway/e2e-strategy-tests/ForkedTemplate.sol new file mode 100644 index 00000000..63eca5f7 --- /dev/null +++ b/test/gateway/e2e-strategy-tests/ForkedTemplate.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {stdStorage, StdStorage, Test, console} from "forge-std/Test.sol"; + +using stdStorage for StdStorage; + +import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import {IAvalonIPool, AvalonLendingStrategy} from "../../../src/gateway/strategy/AvalonStrategy.sol"; +import {StrategySlippageArgs} from "../../../src/gateway/CommonStructs.sol"; +import {Constants} from "./Constants.sol"; + +abstract contract ForkedStrategyTemplateWbtc is Test { + IERC20 public token; + + constructor() { + token = IERC20(Constants.WBTC_ADDRESS); + } + + function simulateForkAndTransfer(uint256 forkAtBlock, address sender, address receiver, uint256 amount) public { + vm.createSelectFork(vm.envString("BOB_PROD_PUBLIC_RPC_URL"), forkAtBlock); + vm.prank(sender); + token.transfer(receiver, amount); + } +} + +abstract contract ForkedStrategyTemplateTbtc is Test { + IERC20 public token; + + constructor() { + token = IERC20(Constants.TBTC_ADDRESS); + } + + function simulateForkAndTransfer(uint256 forkAtBlock, address sender, address receiver, uint256 amount) public { + vm.createSelectFork(vm.envString("BOB_PROD_PUBLIC_RPC_URL"), forkAtBlock); + vm.prank(sender); + token.transfer(receiver, amount); + } +} diff --git a/test/gateway/e2e-strategy-tests/IonicStrategyForked.sol b/test/gateway/e2e-strategy-tests/IonicStrategyForked.sol new file mode 100644 index 00000000..7de0d1ef --- /dev/null +++ b/test/gateway/e2e-strategy-tests/IonicStrategyForked.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {stdStorage, StdStorage, Test, console} from "forge-std/Test.sol"; + +using stdStorage for StdStorage; + +import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import {IIonicToken, IPool, IonicStrategy} from "../../../src/gateway/strategy/IonicStrategy.sol"; +import {StrategySlippageArgs} from "../../../src/gateway/CommonStructs.sol"; +import {Constants} from "./Constants.sol"; +import {ForkedStrategyTemplateTbtc} from "./ForkedTemplate.sol"; + +// Command to run this contract tests with Foundry: +// BOB_PROD_PUBLIC_RPC_URL=https://rpc.gobob.xyz/ forge test --match-contract IonicStrategyForked -vv +contract IonicStrategyForked is ForkedStrategyTemplateTbtc { + function setUp() public { + super.simulateForkAndTransfer( + 6077077, address(0xa79a356B01ef805B3089b4FE67447b96c7e6DD4C), Constants.DUMMY_SENDER, 1 ether + ); + } + + function testIonicStrategy() public { + // Define Ionic tBTC v2 (iontBTC) token and the CErc20Delegate contract instance + IIonicToken iontBtcToken = IIonicToken(0x68e0e4d875FDe34fc4698f40ccca0Db5b67e3693); + + // Define Comptroller contract for market entry + IPool poolContract = IPool(0x9cFEe81970AA10CC593B83fB96eAA9880a6DF715); + + // Instantiate the strategy + IonicStrategy ionicStrategy = new IonicStrategy(iontBtcToken, poolContract); + + vm.startPrank(Constants.DUMMY_SENDER); + token.approve(address(ionicStrategy), 1 ether); + ionicStrategy.handleGatewayMessageWithSlippageArgs( + token, + 1 ether, // Amount: 1 TBTC + Constants.DUMMY_RECEIVER, + StrategySlippageArgs(0) // No slippage allowed + ); + vm.stopPrank(); + + // ToDo: remove magic number + assertEq(IERC20(address(iontBtcToken)).balanceOf(Constants.DUMMY_RECEIVER), 4999999998829624675); + } +} diff --git a/test/gateway/e2e-strategy-tests/PellStrategyForked.sol b/test/gateway/e2e-strategy-tests/PellStrategyForked.sol new file mode 100644 index 00000000..5935a8f1 --- /dev/null +++ b/test/gateway/e2e-strategy-tests/PellStrategyForked.sol @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {stdStorage, StdStorage, Test, console} from "forge-std/Test.sol"; + +using stdStorage for StdStorage; + +import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import { + IPellStrategyManager, + IPellStrategy, + PellStrategy, + PellBedrockStrategy, + PellSolvLSTStrategy +} from "../../../src/gateway/strategy/PellStrategy.sol"; +import {IBedrockVault, BedrockStrategy} from "../../../src/gateway/strategy/BedrockStrategy.sol"; +import {SolvLSTStrategy, ISolvBTCRouter} from "../../../src/gateway/strategy/SolvStrategy.sol"; +import {StrategySlippageArgs} from "../../../src/gateway/CommonStructs.sol"; +import {Constants} from "./Constants.sol"; +import {ForkedStrategyTemplateTbtc, ForkedStrategyTemplateWbtc} from "./ForkedTemplate.sol"; + +// Command to run this contract tests with Foundry: +// BOB_PROD_PUBLIC_RPC_URL=https://rpc.gobob.xyz/ forge test --match-contract PellStrategyForked -vv +contract PellStrategyForked is ForkedStrategyTemplateTbtc { + function setUp() public { + super.simulateForkAndTransfer( + 6077077, address(0xa79a356B01ef805B3089b4FE67447b96c7e6DD4C), Constants.DUMMY_SENDER, 1 ether + ); + } + + function testPellStrategy() public { + PellStrategy pellStrategy = new PellStrategy( + IPellStrategyManager(0x00B67E4805138325ce871D5E27DC15f994681bC1), + IPellStrategy(0x0a5e1Fe85BE84430c6eb482512046A04b25D2484) + ); + + vm.startPrank(Constants.DUMMY_SENDER); + token.approve(address(pellStrategy), 1 ether); + + pellStrategy.handleGatewayMessageWithSlippageArgs( + token, + 1 ether, // Amount: 1 TBTC + Constants.DUMMY_RECEIVER, + StrategySlippageArgs(0) // No slippage allowed + ); + vm.stopPrank(); + + assertEq(pellStrategy.stakerStrategyShares(Constants.DUMMY_RECEIVER), 1 ether); + } +} + +// Command to run this contract tests with Foundry: +// BOB_PROD_PUBLIC_RPC_URL=https://rpc.gobob.xyz/ forge test --match-contract PellBedRockStrategyForked -vv +contract PellBedRockStrategyForked is ForkedStrategyTemplateWbtc { + function setUp() public { + super.simulateForkAndTransfer( + 6642119, address(0x5A8E9774d67fe846C6F4311c073e2AC34b33646F), Constants.DUMMY_SENDER, 1e8 + ); + } + + function testPellBedrockStrategy() public { + IBedrockVault vault = IBedrockVault(0x2ac98DB41Cbd3172CB7B8FD8A8Ab3b91cFe45dCf); + BedrockStrategy bedrockStrategy = new BedrockStrategy(vault); + + PellStrategy pellStrategy = new PellStrategy( + IPellStrategyManager(0x00B67E4805138325ce871D5E27DC15f994681bC1), + IPellStrategy(0x631ae97e24f9F30150d31d958d37915975F12ed8) + ); + + PellBedrockStrategy pellBedrockstrategy = new PellBedrockStrategy(bedrockStrategy, pellStrategy); + + vm.startPrank(Constants.DUMMY_SENDER); + token.approve(address(pellBedrockstrategy), 1e8); + + pellBedrockstrategy.handleGatewayMessageWithSlippageArgs( + token, 1e8, Constants.DUMMY_RECEIVER, StrategySlippageArgs(0) + ); + vm.stopPrank(); + + assertEq(pellStrategy.stakerStrategyShares(Constants.DUMMY_RECEIVER), 1e8); + } +} + +// Command to run this contract tests with Foundry: +// BOB_PROD_PUBLIC_RPC_URL=https://rpc.gobob.xyz/ forge test --match-contract PellBedRockLSTStrategyForked -vv +contract PellBedRockLSTStrategyForked is ForkedStrategyTemplateWbtc { + function setUp() public { + super.simulateForkAndTransfer( + 6642119, address(0x5A8E9774d67fe846C6F4311c073e2AC34b33646F), Constants.DUMMY_SENDER, 1e8 + ); + } + + function testPellBedrockLSTStrategy() public { + IERC20 solvBTC = IERC20(0x541FD749419CA806a8bc7da8ac23D346f2dF8B77); + IERC20 solvBTCBBN = IERC20(0xCC0966D8418d412c599A6421b760a847eB169A8c); + SolvLSTStrategy solvLSTStrategy = new SolvLSTStrategy( + ISolvBTCRouter(0x49b072158564Db36304518FFa37B1cFc13916A90), + ISolvBTCRouter(0xbA46FcC16B464D9787314167bDD9f1Ce28405bA1), + 0x5664520240a46b4b3e9655c20cc3f9e08496a9b746a478e476ae3e04d6c8fc31, + 0x6899a7e13b655fa367208cb27c6eaa2410370d1565dc1f5f11853a1e8cbef033, + solvBTC, + solvBTCBBN + ); + + PellStrategy pellStrategy = new PellStrategy( + IPellStrategyManager(0x00B67E4805138325ce871D5E27DC15f994681bC1), + IPellStrategy(0x6f0AfADE16BFD2E7f5515634f2D0E3cd03C845Ef) + ); + + PellSolvLSTStrategy strategy = new PellSolvLSTStrategy(solvLSTStrategy, pellStrategy); + + vm.startPrank(Constants.DUMMY_SENDER); + token.approve(address(strategy), 1e8); + + strategy.handleGatewayMessageWithSlippageArgs( + token, + 1e8, // Amount: 1 WBTC + Constants.DUMMY_RECEIVER, + StrategySlippageArgs(0) // No slippage allowed + ); + vm.stopPrank(); + + assertEq(pellStrategy.stakerStrategyShares(Constants.DUMMY_RECEIVER), 1e18); + } +} diff --git a/test/gateway/e2e-strategy-tests/SegmentStrategyForked.sol b/test/gateway/e2e-strategy-tests/SegmentStrategyForked.sol new file mode 100644 index 00000000..569e78b8 --- /dev/null +++ b/test/gateway/e2e-strategy-tests/SegmentStrategyForked.sol @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {stdStorage, StdStorage, Test, console} from "forge-std/Test.sol"; + +using stdStorage for StdStorage; + +import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import { + IPellStrategyManager, + IPellStrategy, + PellStrategy, + PellBedrockStrategy, + PellSolvLSTStrategy +} from "../../../src/gateway/strategy/PellStrategy.sol"; +import { + ISeBep20, + SegmentStrategy, + SegmentBedrockStrategy, + SegmentSolvLSTStrategy +} from "../../../src/gateway/strategy/SegmentStrategy.sol"; +import {IBedrockVault, BedrockStrategy} from "../../../src/gateway/strategy/BedrockStrategy.sol"; +import {SolvLSTStrategy, ISolvBTCRouter} from "../../../src/gateway/strategy/SolvStrategy.sol"; +import {StrategySlippageArgs} from "../../../src/gateway/CommonStructs.sol"; +import {Constants} from "./Constants.sol"; +import {ForkedStrategyTemplateTbtc, ForkedStrategyTemplateWbtc} from "./ForkedTemplate.sol"; + +// Command to run this contract tests with Foundry: +// BOB_PROD_PUBLIC_RPC_URL=https://rpc.gobob.xyz/ forge test --match-contract SegmentStrategyForked -vv +contract SegmentStrategyForked is ForkedStrategyTemplateTbtc { + function setUp() public { + super.simulateForkAndTransfer( + 5607192, address(0xa79a356B01ef805B3089b4FE67447b96c7e6DD4C), Constants.DUMMY_SENDER, 1 ether + ); + } + + function testSegmentStrategy() public { + ISeBep20 seBep20 = ISeBep20(0xD30288EA9873f376016A0250433b7eA375676077); + SegmentStrategy strategy = new SegmentStrategy(seBep20); + + vm.startPrank(Constants.DUMMY_SENDER); + token.approve(address(strategy), 1 ether); + + strategy.handleGatewayMessageWithSlippageArgs(token, 1 ether, Constants.DUMMY_RECEIVER, StrategySlippageArgs(0)); + vm.stopPrank(); + + uint256 userSeBalance = IERC20(address(seBep20)).balanceOf(Constants.DUMMY_RECEIVER); + assertGt(userSeBalance, 0, "User has seTokens"); + assertEq(token.balanceOf(Constants.DUMMY_RECEIVER), 0, "User has no TBTC tokens"); + + vm.prank(Constants.DUMMY_RECEIVER); + seBep20.redeem(userSeBalance); + + assertGt(token.balanceOf(Constants.DUMMY_RECEIVER), 0, "User received TBTC tokens after redeem"); + } +} + +// Command to run this contract tests with Foundry: +// BOB_PROD_PUBLIC_RPC_URL=https://rpc.gobob.xyz/ forge test --match-contract SegmentBedrockAndLstStrategyForked -vv +contract SegmentBedrockAndLstStrategyForked is ForkedStrategyTemplateWbtc { + function setUp() public { + super.simulateForkAndTransfer( + 6945930, address(0x5A8E9774d67fe846C6F4311c073e2AC34b33646F), Constants.DUMMY_SENDER, 1e8 + ); + } + + function testSegmentBedrockStrategy() public { + IBedrockVault vault = IBedrockVault(0x2ac98DB41Cbd3172CB7B8FD8A8Ab3b91cFe45dCf); + BedrockStrategy bedrockStrategy = new BedrockStrategy(vault); + ISeBep20 seBep20 = ISeBep20(0x7848F0775EebaBbF55cB74490ce6D3673E68773A); + SegmentStrategy segmentStrategy = new SegmentStrategy(seBep20); + SegmentBedrockStrategy strategy = new SegmentBedrockStrategy(bedrockStrategy, segmentStrategy); + + vm.startPrank(Constants.DUMMY_SENDER); + token.approve(address(strategy), 1e8); + + strategy.handleGatewayMessageWithSlippageArgs(token, 1e8, Constants.DUMMY_RECEIVER, StrategySlippageArgs(0)); + vm.stopPrank(); + + uint256 userSeBalance = IERC20(address(seBep20)).balanceOf(Constants.DUMMY_RECEIVER); + assertGt(userSeBalance, 0, "User has seTokens"); + assertEq(token.balanceOf(Constants.DUMMY_RECEIVER), 0, "User has no WBTC tokens"); + + IERC20 uniBTC = IERC20(vault.uniBTC()); + assertEq(uniBTC.balanceOf(Constants.DUMMY_RECEIVER), 0, "User has no uniBTC tokens"); + + vm.prank(Constants.DUMMY_RECEIVER); + seBep20.redeem(userSeBalance); + + userSeBalance = IERC20(address(seBep20)).balanceOf(Constants.DUMMY_RECEIVER); + assertEq(userSeBalance, 0, "User has redeemed"); + + assertGt(uniBTC.balanceOf(Constants.DUMMY_RECEIVER), 0, "User increase in uniBTC Balance"); + } + + function testSegmentSolvLstStrategy() public { + IERC20 solvBTC = IERC20(0x541FD749419CA806a8bc7da8ac23D346f2dF8B77); + IERC20 solvBTCBBN = IERC20(0xCC0966D8418d412c599A6421b760a847eB169A8c); + SolvLSTStrategy solvLSTStrategy = new SolvLSTStrategy( + ISolvBTCRouter(0x49b072158564Db36304518FFa37B1cFc13916A90), + ISolvBTCRouter(0xbA46FcC16B464D9787314167bDD9f1Ce28405bA1), + 0x5664520240a46b4b3e9655c20cc3f9e08496a9b746a478e476ae3e04d6c8fc31, + 0x6899a7e13b655fa367208cb27c6eaa2410370d1565dc1f5f11853a1e8cbef033, + solvBTC, + solvBTCBBN + ); + ISeBep20 seBep20 = ISeBep20(0x5EF2B8fbCc8aea2A9Dbe2729F0acf33E073Fa43e); + SegmentStrategy segmentStrategy = new SegmentStrategy(seBep20); + SegmentSolvLSTStrategy strategy = new SegmentSolvLSTStrategy(solvLSTStrategy, segmentStrategy); + + vm.startPrank(Constants.DUMMY_SENDER); + token.approve(address(strategy), 1e8); + + strategy.handleGatewayMessageWithSlippageArgs(token, 1e8, Constants.DUMMY_RECEIVER, StrategySlippageArgs(0)); + vm.stopPrank(); + + uint256 userSeBalance = IERC20(address(seBep20)).balanceOf(Constants.DUMMY_RECEIVER); + assertGt(userSeBalance, 0, "User has seTokens"); + assertEq(token.balanceOf(Constants.DUMMY_RECEIVER), 0, "User has no WBTC tokens"); + + vm.prank(Constants.DUMMY_RECEIVER); + seBep20.redeem(userSeBalance); + + userSeBalance = IERC20(address(seBep20)).balanceOf(Constants.DUMMY_RECEIVER); + assertEq(userSeBalance, 0, "User has redeemed"); + assertGt(solvBTCBBN.balanceOf(Constants.DUMMY_RECEIVER), 0, "User has SolvBTC.BBN tokens"); + } +} diff --git a/test/gateway/e2e-strategy-tests/ShoebillStrategyForked.sol b/test/gateway/e2e-strategy-tests/ShoebillStrategyForked.sol new file mode 100644 index 00000000..d1d8c9f9 --- /dev/null +++ b/test/gateway/e2e-strategy-tests/ShoebillStrategyForked.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {stdStorage, StdStorage, Test, console} from "forge-std/Test.sol"; + +using stdStorage for StdStorage; + +import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import {ICErc20, ShoebillStrategy} from "../../../src/gateway/strategy/ShoebillStrategy.sol"; +import {StrategySlippageArgs} from "../../../src/gateway/CommonStructs.sol"; +import {Constants} from "./Constants.sol"; +import {ForkedStrategyTemplateTbtc} from "./ForkedTemplate.sol"; + +// Command to run this contract tests with Foundry: +// BOB_PROD_PUBLIC_RPC_URL=https://rpc.gobob.xyz/ forge test --match-contract ShoebillTBTCStrategyForked -vv +contract ShoebillTBTCStrategyForked is ForkedStrategyTemplateTbtc { + function setUp() public { + super.simulateForkAndTransfer( + 5607192, address(0xa79a356B01ef805B3089b4FE67447b96c7e6DD4C), Constants.DUMMY_SENDER, 1 ether + ); + } + + function testShoebillStrategy() public { + ICErc20 cErc20 = ICErc20(0x2925dF9Eb2092B53B06A06353A7249aF3a8B139e); + ShoebillStrategy shoebillStrategy = new ShoebillStrategy(cErc20); + + vm.startPrank(Constants.DUMMY_SENDER); + token.approve(address(shoebillStrategy), 1 ether); + + shoebillStrategy.handleGatewayMessageWithSlippageArgs( + token, 1 ether, Constants.DUMMY_RECEIVER, StrategySlippageArgs(0) + ); + vm.stopPrank(); + + // ToDo: remove the magic number + assertEq(cErc20.balanceOfUnderlying(address(Constants.DUMMY_RECEIVER)), 999999999973746162); + } +} diff --git a/test/gateway/e2e-strategy-tests/SolvStrategyForked.sol b/test/gateway/e2e-strategy-tests/SolvStrategyForked.sol new file mode 100644 index 00000000..496c8750 --- /dev/null +++ b/test/gateway/e2e-strategy-tests/SolvStrategyForked.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {stdStorage, StdStorage, Test, console} from "forge-std/Test.sol"; + +using stdStorage for StdStorage; + +import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import {ISolvBTCRouter, SolvBTCStrategy, SolvLSTStrategy} from "../../../src/gateway/strategy/SolvStrategy.sol"; +import {StrategySlippageArgs} from "../../../src/gateway/CommonStructs.sol"; +import {Constants} from "./Constants.sol"; +import {ForkedStrategyTemplateWbtc} from "./ForkedTemplate.sol"; + +// Command to run this contract tests with Foundry: +// BOB_PROD_PUBLIC_RPC_URL=https://rpc.gobob.xyz/ forge test --match-contract SolvStrategyForked -vv +contract SolvStrategyForked is ForkedStrategyTemplateWbtc { + function setUp() public { + super.simulateForkAndTransfer( + 6077077, address(0x5A8E9774d67fe846C6F4311c073e2AC34b33646F), Constants.DUMMY_SENDER, 1e8 + ); + } + + function testSolvBTCStrategy() public { + IERC20 solvBTC = IERC20(0x541FD749419CA806a8bc7da8ac23D346f2dF8B77); + SolvBTCStrategy strategy = new SolvBTCStrategy( + ISolvBTCRouter(0x49b072158564Db36304518FFa37B1cFc13916A90), + 0x5664520240a46b4b3e9655c20cc3f9e08496a9b746a478e476ae3e04d6c8fc31, + solvBTC + ); + + vm.startPrank(Constants.DUMMY_SENDER); + token.approve(address(strategy), 1 * 1e8); + + strategy.handleGatewayMessageWithSlippageArgs(token, 1e8, Constants.DUMMY_RECEIVER, StrategySlippageArgs(0)); + vm.stopPrank(); + + assertEq(solvBTC.balanceOf(Constants.DUMMY_RECEIVER), 1 ether); + } + + function testSolvLSTStrategy() public { + IERC20 solvBTC = IERC20(0x541FD749419CA806a8bc7da8ac23D346f2dF8B77); + IERC20 solvBTCBBN = IERC20(0xCC0966D8418d412c599A6421b760a847eB169A8c); + SolvLSTStrategy strategy = new SolvLSTStrategy( + ISolvBTCRouter(0x49b072158564Db36304518FFa37B1cFc13916A90), + ISolvBTCRouter(0xbA46FcC16B464D9787314167bDD9f1Ce28405bA1), + 0x5664520240a46b4b3e9655c20cc3f9e08496a9b746a478e476ae3e04d6c8fc31, + 0x6899a7e13b655fa367208cb27c6eaa2410370d1565dc1f5f11853a1e8cbef033, + solvBTC, + solvBTCBBN + ); + + vm.startPrank(Constants.DUMMY_SENDER); + token.approve(address(strategy), 1 * 1e8); + + strategy.handleGatewayMessageWithSlippageArgs(token, 1e8, Constants.DUMMY_RECEIVER, StrategySlippageArgs(0)); + vm.stopPrank(); + + assertEq(solvBTCBBN.balanceOf(Constants.DUMMY_RECEIVER), 1 ether); + } +} diff --git a/test/gateway/unit-tests/AvalonStrategy.sol b/test/gateway/unit-tests/AvalonStrategy.sol new file mode 100644 index 00000000..44735cb1 --- /dev/null +++ b/test/gateway/unit-tests/AvalonStrategy.sol @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {stdStorage, StdStorage, Test, console} from "forge-std/Test.sol"; + +using stdStorage for StdStorage; + +import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import {ERC20} from "openzeppelin-contracts/token/ERC20/ERC20.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {ArbitaryErc20} from "./Utils.sol"; +import { + IAvalonIPool, AvalonLendingStrategy, AvalonLstStrategy +} from "../../../src/gateway/strategy/AvalonStrategy.sol"; +import {StrategySlippageArgs} from "../../../src/gateway/CommonStructs.sol"; +import {ISolvBTCRouter, SolvLSTStrategy} from "../../../src/gateway/strategy/SolvStrategy.sol"; +import {DummySolvRouter} from "./SolvStrategy.sol"; + +contract DummyAvalonPoolImplementation is IAvalonIPool { + ArbitaryErc20 avalonToken; + bool private doSupply; + + // Constructor with a flag to determine supply behavior + constructor(ArbitaryErc20 _avalonToken, bool _doSupply) { + doSupply = _doSupply; + avalonToken = _avalonToken; + } + + // Supply function behavior changes based on the flag + function supply(address, /* asset */ uint256 amount, address onBehalfOf, uint16 /* referralCode */ ) + external + override + { + if (doSupply) { + // Supply logic for DummyAvalonPoolImplementation: transfers tokens + avalonToken.transfer(onBehalfOf, amount); + } + // If doSupply is false, no supply action is taken (DummyAvalonPoolImplementation behavior) + } + + function withdraw(address, uint256, address /* to */ ) external pure override returns (uint256) { + return 0; + } +} + +contract AvalonStrategyTest is Test { + event TokenOutput(address tokenReceived, uint256 amountOut); + + ArbitaryErc20 wrappedBTC; + ArbitaryErc20 avalonToken; + ArbitaryErc20 solvLST; + + function setUp() public { + wrappedBTC = new ArbitaryErc20("", ""); + avalonToken = new ArbitaryErc20("", ""); + solvLST = new ArbitaryErc20("", ""); + wrappedBTC.sudoMint(address(this), 100 ether); // Mint 100 tokens to this contract + } + + function testLendingStrategyForValidAmount() public { + IAvalonIPool dummyPool = new DummyAvalonPoolImplementation(avalonToken, true); + avalonToken.sudoMint(address(dummyPool), 100 ether); + + AvalonLendingStrategy avalonStrategy = new AvalonLendingStrategy(avalonToken, dummyPool); + + // Approve ionicStrategy to spend a token on behalf of this contract + wrappedBTC.increaseAllowance(address(avalonStrategy), 1 ether); + + vm.expectEmit(); + emit TokenOutput(address(avalonToken), 1 ether); + avalonStrategy.handleGatewayMessageWithSlippageArgs( + wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether) + ); + + assertEq(avalonToken.balanceOf(vm.addr(1)), 1 ether); + assertEq(wrappedBTC.balanceOf(address(this)), 99 ether); + } + + function testWhenInsufficientSupplyProvided() public { + IAvalonIPool dummyPool = new DummyAvalonPoolImplementation(avalonToken, false); + AvalonLendingStrategy avalonStrategy = new AvalonLendingStrategy(avalonToken, dummyPool); + + // Approve ionicStrategy to spend 100 tBTC tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(avalonStrategy), 1 ether); + + vm.expectRevert("Insufficient supply provided"); + avalonStrategy.handleGatewayMessageWithSlippageArgs( + wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether) + ); + } + + function testWhenInsufficientOutputAmount() public { + IAvalonIPool dummyPool = new DummyAvalonPoolImplementation(avalonToken, true); + avalonToken.sudoMint(address(dummyPool), 100 ether); // Mint 100 tokens to this contract + + AvalonLendingStrategy avalonStrategy = new AvalonLendingStrategy(avalonToken, dummyPool); + + wrappedBTC.increaseAllowance(address(avalonStrategy), 1 ether); + + vm.expectRevert("Insufficient output amount"); + avalonStrategy.handleGatewayMessageWithSlippageArgs( + wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether + 1) + ); + } + + function testAvalonLSTStrategyForValidAmount() public { + ISolvBTCRouter btcRouter = new DummySolvRouter(true, wrappedBTC); + ISolvBTCRouter lstRouter = new DummySolvRouter(true, solvLST); + SolvLSTStrategy solvStrategy = + new SolvLSTStrategy(btcRouter, lstRouter, bytes32(0), bytes32(0), wrappedBTC, solvLST); + + wrappedBTC.sudoMint(address(btcRouter), 1 ether); + solvLST.sudoMint(address(lstRouter), 1 ether); + + IAvalonIPool dummyPool = new DummyAvalonPoolImplementation(avalonToken, true); + avalonToken.sudoMint(address(dummyPool), 1 ether); // Mint 100 tokens to this contract + + AvalonLendingStrategy avalonLendingStrategy = new AvalonLendingStrategy(avalonToken, dummyPool); + + AvalonLstStrategy avalonLSTStrategy = new AvalonLstStrategy(solvStrategy, avalonLendingStrategy); + + wrappedBTC.increaseAllowance(address(avalonLSTStrategy), 1 ether); + + vm.expectEmit(); + emit TokenOutput(address(avalonToken), 1 ether); + avalonLSTStrategy.handleGatewayMessageWithSlippageArgs( + wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether) + ); + } +} diff --git a/test/gateway/unit-tests/BedrockStrategy.sol b/test/gateway/unit-tests/BedrockStrategy.sol new file mode 100644 index 00000000..db0c8897 --- /dev/null +++ b/test/gateway/unit-tests/BedrockStrategy.sol @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {stdStorage, StdStorage, Test, console} from "forge-std/Test.sol"; + +using stdStorage for StdStorage; + +import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import {ERC20} from "openzeppelin-contracts/token/ERC20/ERC20.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +import {BedrockStrategy, IBedrockVault} from "../../../src/gateway/strategy/BedrockStrategy.sol"; +import {StrategySlippageArgs} from "../../../src/gateway/CommonStructs.sol"; +import {ArbitaryErc20} from "./Utils.sol"; + +contract DummyBedrockVaultImplementation is IBedrockVault { + ArbitaryErc20 uniBtcToken; + bool private doMint; + + // Constructor with a flag to determine supply behavior + constructor(ArbitaryErc20 _uniBtcToken, bool _doMint) { + doMint = _doMint; + uniBtcToken = _uniBtcToken; + } + + function mint(address, /* token */ uint256 amount) external override { + if (doMint) { + uniBtcToken.transfer(msg.sender, amount); + } + } + + function redeem(address token, uint256 amount) external override {} + + function uniBTC() external view returns (address) { + return address(uniBtcToken); + } +} + +contract BedrockStrategyTest is Test { + event TokenOutput(address tokenReceived, uint256 amountOut); + + ArbitaryErc20 wrappedBTC; + ArbitaryErc20 uniBtcToken; + + function setUp() public { + wrappedBTC = new ArbitaryErc20("", ""); + uniBtcToken = new ArbitaryErc20("", ""); + wrappedBTC.sudoMint(address(this), 1 ether); // Mint 100 tokens to this contract + } + + function testDepositTokenIntoVault() public { + IBedrockVault vault = new DummyBedrockVaultImplementation(uniBtcToken, true); + uniBtcToken.sudoMint(address(vault), 1 ether); + + BedrockStrategy bedrockStrategy = new BedrockStrategy(vault); + + // Approve strategy to spend a token on behalf of this contract + wrappedBTC.increaseAllowance(address(bedrockStrategy), 1 ether); + + vm.expectEmit(); + emit TokenOutput(address(uniBtcToken), 1 ether); + bedrockStrategy.handleGatewayMessageWithSlippageArgs( + wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether) + ); + } + + function testBedrockDepositFailsDueToInsufficientAmount() public { + IBedrockVault vault = new DummyBedrockVaultImplementation(uniBtcToken, false); + uniBtcToken.sudoMint(address(vault), 1 ether); + + BedrockStrategy bedrockStrategy = new BedrockStrategy(vault); + + // Approve strategy to spend 100 tBTC tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(bedrockStrategy), 1 ether); + + vm.expectRevert("Insufficient output amount"); + bedrockStrategy.handleGatewayMessageWithSlippageArgs( + wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether) + ); + } +} diff --git a/test/gateway/unit-tests/IonicStrategy.sol b/test/gateway/unit-tests/IonicStrategy.sol new file mode 100644 index 00000000..b6db7281 --- /dev/null +++ b/test/gateway/unit-tests/IonicStrategy.sol @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {stdStorage, StdStorage, Test, console} from "forge-std/Test.sol"; + +using stdStorage for StdStorage; + +import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import {ERC20} from "openzeppelin-contracts/token/ERC20/ERC20.sol"; +import {IIonicToken, IPool, IonicStrategy} from "../../../src/gateway/strategy/IonicStrategy.sol"; +import {StrategySlippageArgs} from "../../../src/gateway/CommonStructs.sol"; +import {ArbitaryErc20} from "./Utils.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract DummyIonicToken is IIonicToken, ERC20, Ownable { + bool private doMint; + bool private suppressMintError; + + constructor(string memory name_, string memory symbol_, bool _doMint, bool _suppressMintError) + ERC20(name_, symbol_) + { + doMint = _doMint; + suppressMintError = _suppressMintError; + } + + function sudoMint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } + + function mint(uint256 mintAmount) external returns (uint256) { + if (suppressMintError) { + return 0; + } + if (doMint) { + _mint(_msgSender(), mintAmount); + return 0; + } + return 1; + } + + function redeem(uint256 /*redeemTokens*/ ) external pure returns (uint256) { + return 0; + } +} + +contract DummyIonicPool is IPool { + bool private doEnterMarkets; + + constructor(bool _doEnterMarkets) { + doEnterMarkets = _doEnterMarkets; + } + + function enterMarkets(address[] memory cTokens) external view override returns (uint256[] memory) { + if (doEnterMarkets) { + // Return an empty array to simulate entered in the market + return new uint256[](cTokens.length); + } + + uint256[] memory result = new uint256[](1); + result[0] = 1; + return result; // Return the array + } + + function exitMarket(address /* cTokenAddress */ ) external pure override returns (uint256) { + // Return 0 to simulate doing nothing + return 0; + } +} + +contract IonicStrategyTest is Test { + IIonicToken ionicToken; + ArbitaryErc20 wrappedBTC; + + event TokenOutput(address tokenReceived, uint256 amountOut); + + function setUp() public { + ionicToken = new DummyIonicToken("", "", true, false); + wrappedBTC = new ArbitaryErc20("", ""); + wrappedBTC.sudoMint(address(this), 1 ether); // Mint 100 tokens to this contract + } + + function testIonicStrategy() public { + IPool dummyIonicPool = new DummyIonicPool(true); + IonicStrategy ionicStrategy = new IonicStrategy(ionicToken, dummyIonicPool); + + // Approve strategy to spend tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(ionicStrategy), 1 ether); + + vm.expectEmit(); + emit TokenOutput(address(ionicToken), 1 ether); + ionicStrategy.handleGatewayMessageWithSlippageArgs( + wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether) + ); + } + + function testIonicStrategyWhenMarketNotPresent() public { + IPool dummyIonicPool = new DummyIonicPool(false); + IonicStrategy ionicStrategy = new IonicStrategy(ionicToken, dummyIonicPool); + + // Approve strategy to spend 100 tBTC tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(ionicStrategy), 1 ether); + + vm.expectRevert("Couldn't enter in Market"); + ionicStrategy.handleGatewayMessageWithSlippageArgs( + wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether) + ); + } + + function testIonicStrategyWhenCouldNotMint() public { + ionicToken = new DummyIonicToken("Ionic Token", "ion", false, false); + IPool dummyIonicPool = new DummyIonicPool(true); + IonicStrategy ionicStrategy = new IonicStrategy(ionicToken, dummyIonicPool); + + // Approve strategy to spend 100 tBTC tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(ionicStrategy), 1 ether); + + vm.expectRevert("Could not mint token in Ionic market"); + ionicStrategy.handleGatewayMessageWithSlippageArgs( + wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether) + ); + } + + function testIonicStrategyForInsufficientSupply() public { + ionicToken = new DummyIonicToken("Ionic Token", "ion", false, true); + IPool dummyIonicPool = new DummyIonicPool(true); + IonicStrategy ionicStrategy = new IonicStrategy(ionicToken, dummyIonicPool); + + // Approve strategy to spend 100 tBTC tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(ionicStrategy), 1 ether); + + vm.expectRevert("Insufficient supply provided"); + ionicStrategy.handleGatewayMessageWithSlippageArgs( + wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether) + ); + } + + function testIonicStrategyForInsufficientOutput() public { + IPool dummyIonicPool = new DummyIonicPool(true); + IonicStrategy ionicStrategy = new IonicStrategy(ionicToken, dummyIonicPool); + + // Approve strategy to spend 100 tBTC tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(ionicStrategy), 1 ether); + + vm.expectRevert("Insufficient output amount"); + ionicStrategy.handleGatewayMessageWithSlippageArgs( + wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(2 ether) + ); + } +} diff --git a/test/gateway/unit-tests/PellStrategy.sol b/test/gateway/unit-tests/PellStrategy.sol new file mode 100644 index 00000000..92c95a99 --- /dev/null +++ b/test/gateway/unit-tests/PellStrategy.sol @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {stdStorage, StdStorage, Test, console} from "forge-std/Test.sol"; + +using stdStorage for StdStorage; + +import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import {ERC20} from "openzeppelin-contracts/token/ERC20/ERC20.sol"; +import { + IPellStrategyManager, + IPellStrategy, + PellStrategy, + PellBedrockStrategy, + PellSolvLSTStrategy +} from "../../../src/gateway/strategy/PellStrategy.sol"; +import {IBedrockVault, BedrockStrategy} from "../../../src/gateway/strategy/BedrockStrategy.sol"; +import {SolvLSTStrategy, ISolvBTCRouter} from "../../../src/gateway/strategy/SolvStrategy.sol"; +import {StrategySlippageArgs} from "../../../src/gateway/CommonStructs.sol"; +import {ArbitaryErc20} from "./Utils.sol"; +import {DummyBedrockVaultImplementation} from "./BedrockStrategy.sol"; +import {DummySolvRouter} from "./SolvStrategy.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract DummyPellStrategyManager is IPellStrategyManager { + function depositIntoStrategyWithStaker( + address, /*staker*/ + IPellStrategy, /*strategy*/ + IERC20, /*token*/ + uint256 amount + ) external pure returns (uint256 shares) { + return amount; + } + + function stakerStrategyShares(address, /*staker*/ IPellStrategy /*strategy*/ ) external pure returns (uint256) { + return 0; + } +} + +// Dummy implementation of IPellStrategy +contract DummyPellStrategy is IPellStrategy {} + +contract PellStrategyTest is Test { + ArbitaryErc20 shareToken; + ArbitaryErc20 wrappedBTC; + ArbitaryErc20 solvLST; + ArbitaryErc20 uniBtcToken; + + event TokenOutput(address tokenReceived, uint256 amountOut); + + function setUp() public { + shareToken = new ArbitaryErc20("", ""); + solvLST = new ArbitaryErc20("", ""); + wrappedBTC = new ArbitaryErc20("", ""); + uniBtcToken = new ArbitaryErc20("", ""); + wrappedBTC.sudoMint(address(this), 100 ether); // Mint 100 tokens to this contract + } + + function testPellStrategy() public { + IPellStrategyManager pellStrategyManager = new DummyPellStrategyManager(); + IPellStrategy pellStrategy = new DummyPellStrategy(); + PellStrategy strategy = new PellStrategy(pellStrategyManager, pellStrategy); + + // Approve strategy to spend tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(strategy), 1 ether); + + wrappedBTC.sudoMint(address(pellStrategyManager), 1 ether); + + vm.expectEmit(); + emit TokenOutput(address(0), 1 ether); + strategy.handleGatewayMessageWithSlippageArgs(wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether)); + } + + function testPellStrategyInsufficientShareIncrease() public { + IPellStrategyManager pellStrategyManager = new DummyPellStrategyManager(); + IPellStrategy pellStrategy = new DummyPellStrategy(); + PellStrategy strategy = new PellStrategy(pellStrategyManager, pellStrategy); + + // Approve strategy to spend tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(strategy), 1 ether); + + wrappedBTC.sudoMint(address(pellStrategyManager), 1 ether); + + vm.expectRevert("Insufficient output amount"); + strategy.handleGatewayMessageWithSlippageArgs(wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(2 ether)); + } + + function testPellBedrockStrategy() public { + IPellStrategyManager pellStrategyManager = new DummyPellStrategyManager(); + IPellStrategy pellStrategyI = new DummyPellStrategy(); + PellStrategy pellStrategy = new PellStrategy(pellStrategyManager, pellStrategyI); + + IBedrockVault vault = new DummyBedrockVaultImplementation(uniBtcToken, true); + BedrockStrategy bedrockStrategy = new BedrockStrategy(vault); + + PellBedrockStrategy pellBedrockStrategy = new PellBedrockStrategy(bedrockStrategy, pellStrategy); + + // Approve strategy to spend tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(pellBedrockStrategy), 1 ether); + uniBtcToken.sudoMint(address(vault), 1 ether); + wrappedBTC.sudoMint(address(pellStrategyManager), 1 ether); + + vm.expectEmit(); + emit TokenOutput(address(0), 1 ether); + pellBedrockStrategy.handleGatewayMessageWithSlippageArgs( + wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether) + ); + } + + function testPellSolvLstStrategy() public { + ISolvBTCRouter btcRouter = new DummySolvRouter(true, wrappedBTC); + ISolvBTCRouter lstRouter = new DummySolvRouter(true, solvLST); + SolvLSTStrategy solvLSTstrategy = + new SolvLSTStrategy(btcRouter, lstRouter, bytes32(0), bytes32(0), wrappedBTC, solvLST); + + wrappedBTC.sudoMint(address(btcRouter), 1 ether); + solvLST.sudoMint(address(lstRouter), 1 ether); + + IPellStrategyManager pellStrategyManager = new DummyPellStrategyManager(); + IPellStrategy pellStrategyI = new DummyPellStrategy(); + PellStrategy pellStrategy = new PellStrategy(pellStrategyManager, pellStrategyI); + + PellSolvLSTStrategy pellLSTStrategy = new PellSolvLSTStrategy(solvLSTstrategy, pellStrategy); + + // Approve strategy to spend tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(pellLSTStrategy), 1 ether); + + vm.expectEmit(); + emit TokenOutput(address(0), 1 ether); + pellLSTStrategy.handleGatewayMessageWithSlippageArgs( + wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether) + ); + } +} diff --git a/test/gateway/unit-tests/SegmentStrategy.sol b/test/gateway/unit-tests/SegmentStrategy.sol new file mode 100644 index 00000000..59ccd1c8 --- /dev/null +++ b/test/gateway/unit-tests/SegmentStrategy.sol @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {stdStorage, StdStorage, Test, console} from "forge-std/Test.sol"; + +using stdStorage for StdStorage; + +import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import {ERC20} from "openzeppelin-contracts/token/ERC20/ERC20.sol"; +import { + ISeBep20, + SegmentStrategy, + SegmentBedrockStrategy, + SegmentSolvLSTStrategy +} from "../../../src/gateway/strategy/SegmentStrategy.sol"; +import {IBedrockVault, BedrockStrategy} from "../../../src/gateway/strategy/BedrockStrategy.sol"; +import {SolvLSTStrategy, ISolvBTCRouter} from "../../../src/gateway/strategy/SolvStrategy.sol"; +import {StrategySlippageArgs} from "../../../src/gateway/CommonStructs.sol"; +import {ArbitaryErc20} from "./Utils.sol"; +import {DummyBedrockVaultImplementation} from "./BedrockStrategy.sol"; +import {DummySolvRouter} from "./SolvStrategy.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract DummySeBep20 is ISeBep20, ERC20, Ownable { + bool private doMint; + bool private suppressMintError; + + constructor(string memory name_, string memory symbol_, bool _doMint, bool _suppressMintError) + ERC20(name_, symbol_) + { + doMint = _doMint; + suppressMintError = _suppressMintError; + } + + function sudoMint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } + + function mint(uint256 /*mintAmount*/ ) external pure override returns (uint256) { + return 0; + } + + function mintBehalf(address receiver, uint256 mintAmount) external override returns (uint256) { + if (suppressMintError) { + return 0; + } + if (doMint) { + _mint(receiver, mintAmount); + return 0; + } + return 1; + } + + function balanceOfUnderlying(address /*owner*/ ) external pure override returns (uint256) { + return 0; + } + + function redeem(uint256 /*redeemTokens*/ ) external pure override returns (uint256) { + return 0; + } +} + +contract SegmentStrategyTest is Test { + ArbitaryErc20 wrappedBTC; + ArbitaryErc20 uniBtcToken; + ArbitaryErc20 solvBTC; + ArbitaryErc20 solvLST; + + event TokenOutput(address tokenReceived, uint256 amountOut); + + function setUp() public { + wrappedBTC = new ArbitaryErc20("", ""); + uniBtcToken = new ArbitaryErc20("", ""); + solvBTC = new ArbitaryErc20("", ""); + solvLST = new ArbitaryErc20("", ""); + wrappedBTC.sudoMint(address(this), 100 ether); + } + + function testSegmentStrategy() public { + ISeBep20 seBep20 = new DummySeBep20("", "", true, false); + + SegmentStrategy segmentStrategy = new SegmentStrategy(seBep20); + + // Approve strategy to spend tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(segmentStrategy), 1 ether); + + vm.expectEmit(); + emit TokenOutput(address(seBep20), 1 ether); + segmentStrategy.handleGatewayMessageWithSlippageArgs( + wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether) + ); + } + + function testSegmentStrategyCouldNotMint() public { + ISeBep20 seBep20 = new DummySeBep20("", "", false, false); + SegmentStrategy segmentStrategy = new SegmentStrategy(seBep20); + + // Approve strategy to spend tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(segmentStrategy), 1 ether); + + vm.expectRevert("Could not mint token"); + segmentStrategy.handleGatewayMessageWithSlippageArgs( + wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether) + ); + } + + function testSegmentStrategyInsufficientSupply() public { + ISeBep20 seBep20 = new DummySeBep20("", "", false, true); + SegmentStrategy segmentStrategy = new SegmentStrategy(seBep20); + + // Approve strategy to spend tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(segmentStrategy), 1 ether); + + vm.expectRevert("Insufficient supply provided"); + segmentStrategy.handleGatewayMessageWithSlippageArgs( + wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether) + ); + } + + function testSegmentStrategyInsufficientOutput() public { + ISeBep20 seBep20 = new DummySeBep20("", "", true, false); + SegmentStrategy segmentStrategy = new SegmentStrategy(seBep20); + + // Approve strategy to spend tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(segmentStrategy), 1 ether); + + vm.expectRevert("Insufficient output amount"); + segmentStrategy.handleGatewayMessageWithSlippageArgs( + wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(2 ether) + ); + } + + function testSegmentBedrockStrategy() public { + ISeBep20 seBep20 = new DummySeBep20("", "", true, false); + SegmentStrategy segmentStrategy = new SegmentStrategy(seBep20); + IBedrockVault vault = new DummyBedrockVaultImplementation(uniBtcToken, true); + + uniBtcToken.sudoMint(address(vault), 1 ether); + + BedrockStrategy bedrockStrategy = new BedrockStrategy(vault); + + SegmentBedrockStrategy segmentBedrockStrategy = new SegmentBedrockStrategy(bedrockStrategy, segmentStrategy); + + // Approve strategy to spend tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(segmentBedrockStrategy), 1 ether); + + vm.expectEmit(); + emit TokenOutput(address(seBep20), 1 ether); + segmentBedrockStrategy.handleGatewayMessageWithSlippageArgs( + wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether) + ); + } + + function testSegmentSolvLstStrategy() public { + ISeBep20 seBep20 = new DummySeBep20("", "", true, false); + SegmentStrategy segmentStrategy = new SegmentStrategy(seBep20); + + ISolvBTCRouter btcRouter = new DummySolvRouter(true, solvBTC); + ISolvBTCRouter lstRouter = new DummySolvRouter(true, solvLST); + SolvLSTStrategy solvLSTAtrategy = + new SolvLSTStrategy(btcRouter, lstRouter, bytes32(0), bytes32(0), solvBTC, solvLST); + solvBTC.sudoMint(address(btcRouter), 1 ether); + solvLST.sudoMint(address(lstRouter), 1 ether); + + SegmentSolvLSTStrategy segmentSolvLSTStrategy = new SegmentSolvLSTStrategy(solvLSTAtrategy, segmentStrategy); + + // Approve strategy to spend tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(segmentSolvLSTStrategy), 1 ether); + + vm.expectEmit(); + emit TokenOutput(address(seBep20), 1 ether); + segmentSolvLSTStrategy.handleGatewayMessageWithSlippageArgs( + wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether) + ); + } +} diff --git a/test/gateway/unit-tests/ShoebillStrategy.sol b/test/gateway/unit-tests/ShoebillStrategy.sol new file mode 100644 index 00000000..a78890d6 --- /dev/null +++ b/test/gateway/unit-tests/ShoebillStrategy.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {stdStorage, StdStorage, Test, console} from "forge-std/Test.sol"; + +using stdStorage for StdStorage; + +import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import {ERC20} from "openzeppelin-contracts/token/ERC20/ERC20.sol"; +import {ICErc20, ShoebillStrategy} from "../../../src/gateway/strategy/ShoebillStrategy.sol"; +import {StrategySlippageArgs} from "../../../src/gateway/CommonStructs.sol"; +import {ArbitaryErc20} from "./Utils.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract DummyShoeBillToken is ICErc20, ERC20, Ownable { + bool private doMint; + bool private mintInsufficientAmount; + + constructor(string memory name_, string memory symbol_, bool _doMint) ERC20(name_, symbol_) { + doMint = _doMint; + } + + function sudoMint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } + + function mint(uint256 mintAmount) external returns (uint256) { + if (doMint) { + _mint(_msgSender(), mintAmount); + return 0; + } + return 1; + } + + function balanceOfUnderlying(address /*owner*/ ) external pure returns (uint256) { + return 0; + } +} + +contract ShoebillStrategyTest is Test { + ICErc20 shoeBillToken; + ArbitaryErc20 wrappedBTC; + + event TokenOutput(address tokenReceived, uint256 amountOut); + + function setUp() public { + shoeBillToken = new DummyShoeBillToken("", "", true); + wrappedBTC = new ArbitaryErc20("", ""); + wrappedBTC.sudoMint(address(this), 100 ether); // Mint 100 tokens to this contract + } + + function testShoeBillStrategy() public { + ShoebillStrategy strategy = new ShoebillStrategy(shoeBillToken); + + // Approve strategy to spend tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(strategy), 1 ether); + + vm.expectEmit(); + emit TokenOutput(address(shoeBillToken), 1 ether); + strategy.handleGatewayMessageWithSlippageArgs(wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether)); + } + + function testUnableToMintShoeBillToken() public { + shoeBillToken = new DummyShoeBillToken("", "", false); + ShoebillStrategy strategy = new ShoebillStrategy(shoeBillToken); + + // Approve strategy to spend tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(strategy), 1 ether); + + vm.expectRevert("Could not mint token"); + strategy.handleGatewayMessageWithSlippageArgs(wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether)); + } + + function testMintedInsufficientAmountOfShoeBillToken() public { + ShoebillStrategy strategy = new ShoebillStrategy(shoeBillToken); + + // Approve strategy to spend tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(strategy), 1 ether); + + vm.expectRevert("Insufficient output amount"); + strategy.handleGatewayMessageWithSlippageArgs(wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(2 ether)); + } +} diff --git a/test/gateway/unit-tests/SolvStrategy.sol b/test/gateway/unit-tests/SolvStrategy.sol new file mode 100644 index 00000000..9ccadf2d --- /dev/null +++ b/test/gateway/unit-tests/SolvStrategy.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {stdStorage, StdStorage, Test, console} from "forge-std/Test.sol"; + +using stdStorage for StdStorage; + +import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import {ISolvBTCRouter, SolvBTCStrategy, SolvLSTStrategy} from "../../../src/gateway/strategy/SolvStrategy.sol"; +import {StrategySlippageArgs} from "../../../src/gateway/CommonStructs.sol"; +import {ArbitaryErc20} from "./Utils.sol"; + +contract DummySolvRouter is ISolvBTCRouter { + bool private doTransferAmount; + ArbitaryErc20 private solvBTC; + + constructor(bool _doTransferAmount, ArbitaryErc20 _solvBTC) { + doTransferAmount = _doTransferAmount; + solvBTC = _solvBTC; + } + + function createSubscription(bytes32, /* poolId */ uint256 amount) external override returns (uint256 shareValue) { + if (doTransferAmount) { + solvBTC.transfer(msg.sender, amount); + return amount; + } + return 0; + } +} + +contract SolvStrategyTest is Test { + ArbitaryErc20 wrappedBTC; + ArbitaryErc20 solvBTC; + ArbitaryErc20 solvLST; + + event TokenOutput(address tokenReceived, uint256 amountOut); + + function setUp() public { + solvBTC = new ArbitaryErc20("", ""); + solvLST = new ArbitaryErc20("", ""); + wrappedBTC = new ArbitaryErc20("", ""); + wrappedBTC.sudoMint(address(this), 1 ether); // Mint 100 tokens to this contract + } + + function testSolvStrategy() public { + ISolvBTCRouter router = new DummySolvRouter(true, solvBTC); + SolvBTCStrategy strategy = new SolvBTCStrategy(router, bytes32(0), solvBTC); + solvBTC.sudoMint(address(router), 1 ether); + + // Approve strategy to spend tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(strategy), 1 ether); + + vm.expectEmit(); + emit TokenOutput(address(solvBTC), 1 ether); + strategy.handleGatewayMessageWithSlippageArgs(wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether)); + } + + function testSolvStrategyInsufficientOutputAmount() public { + ISolvBTCRouter router = new DummySolvRouter(false, solvBTC); + SolvBTCStrategy strategy = new SolvBTCStrategy(router, bytes32(0), solvBTC); + solvBTC.sudoMint(address(router), 1 ether); + + // Approve strategy to spend tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(strategy), 1 ether); + + vm.expectRevert("Insufficient output amount"); + strategy.handleGatewayMessageWithSlippageArgs(wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether)); + } + + function testSolvLstStrategy() public { + ISolvBTCRouter btcRouter = new DummySolvRouter(true, solvBTC); + ISolvBTCRouter lstRouter = new DummySolvRouter(true, solvLST); + SolvLSTStrategy strategy = new SolvLSTStrategy(btcRouter, lstRouter, bytes32(0), bytes32(0), solvBTC, solvLST); + + solvBTC.sudoMint(address(btcRouter), 1 ether); + solvLST.sudoMint(address(lstRouter), 1 ether); + + // Approve strategy to spend tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(strategy), 1 ether); + + vm.expectEmit(); + emit TokenOutput(address(solvLST), 1 ether); + strategy.handleGatewayMessageWithSlippageArgs(wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether)); + } + + function testSolvLSTStrategyInsufficientOutputAmount() public { + ISolvBTCRouter btcRouter = new DummySolvRouter(true, solvBTC); + ISolvBTCRouter lstRouter = new DummySolvRouter(false, solvLST); + SolvLSTStrategy strategy = new SolvLSTStrategy(btcRouter, lstRouter, bytes32(0), bytes32(0), solvBTC, solvLST); + + solvBTC.sudoMint(address(btcRouter), 1 ether); + solvLST.sudoMint(address(lstRouter), 1 ether); + + // Approve strategy to spend tokens on behalf of this contract + wrappedBTC.increaseAllowance(address(strategy), 1 ether); + + vm.expectRevert("Insufficient output amount"); + strategy.handleGatewayMessageWithSlippageArgs(wrappedBTC, 1 ether, vm.addr(1), StrategySlippageArgs(1 ether)); + } +} diff --git a/test/gateway/unit-tests/Utils.sol b/test/gateway/unit-tests/Utils.sol new file mode 100644 index 00000000..5ec9d344 --- /dev/null +++ b/test/gateway/unit-tests/Utils.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {ERC20} from "openzeppelin-contracts/token/ERC20/ERC20.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract ArbitaryErc20 is ERC20, Ownable { + constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) {} + + // Mint function accessible only to the owner + function sudoMint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } +} From e17424ed821db35fdac8479815417349329da4b5 Mon Sep 17 00:00:00 2001 From: nakul1010 Date: Sun, 12 Jan 2025 16:54:28 +0530 Subject: [PATCH 3/5] fix: fix py script --- docs/docs/contracts/contract_references.md | 7 - .../SystemState.sol/library.SystemState.md | 14 -- .../bridge/BitcoinTx.sol/library.BitcoinTx.md | 164 ------------------ .../BridgeState.sol/library.BridgeState.md | 14 -- .../src/bridge/IRelay.sol/interface.IRelay.md | 27 --- .../bridge/WitnessTx.sol/library.WitnessTx.md | 99 ----------- .../contract.AvalonLendingStrategy.md | 2 +- .../contract.AvalonLstStrategy.md | 2 +- .../contract.BedrockStrategy.md | 2 +- .../contract.IonicStrategy.md | 2 +- .../contract.PellBedrockStrategy.md | 2 +- .../contract.PellSolvLSTStrategy.md | 2 +- .../PellStrategy.sol/contract.PellStrategy.md | 2 +- .../contract.SegmentBedrockStrategy.md | 2 +- .../contract.SegmentSolvLSTStrategy.md | 2 +- .../contract.SegmentStrategy.md | 2 +- .../contract.ShoebillStrategy.md | 2 +- .../contract.SolvBTCStrategy.md | 2 +- .../contract.SolvLSTStrategy.md | 2 +- .../src/swap/Bridge.sol/contract.Bridge.md | 162 ----------------- docs/scripts/forge_doc_reformat.py | 19 +- 21 files changed, 28 insertions(+), 504 deletions(-) delete mode 100644 docs/docs/contracts/contract_references.md delete mode 100644 docs/docs/contracts/src/src/SystemState.sol/library.SystemState.md delete mode 100644 docs/docs/contracts/src/src/bridge/BitcoinTx.sol/library.BitcoinTx.md delete mode 100644 docs/docs/contracts/src/src/bridge/BridgeState.sol/library.BridgeState.md delete mode 100644 docs/docs/contracts/src/src/bridge/IRelay.sol/interface.IRelay.md delete mode 100644 docs/docs/contracts/src/src/bridge/WitnessTx.sol/library.WitnessTx.md delete mode 100644 docs/docs/contracts/src/src/swap/Bridge.sol/contract.Bridge.md diff --git a/docs/docs/contracts/contract_references.md b/docs/docs/contracts/contract_references.md deleted file mode 100644 index f109f392..00000000 --- a/docs/docs/contracts/contract_references.md +++ /dev/null @@ -1,7 +0,0 @@ -# Smart Contracts - -The source code for the smart contracts can be found in the following repository: - -- [Relay Smart Contracts](https://github.com/bob-collective/bob/tree/master/src/relay) -- [Bridge Smart Contracts](https://github.com/bob-collective/bob/tree/master/src/bridge) -- [Swap Smart Contracts](https://github.com/bob-collective/bob/tree/master/src/swap) diff --git a/docs/docs/contracts/src/src/SystemState.sol/library.SystemState.md b/docs/docs/contracts/src/src/SystemState.sol/library.SystemState.md deleted file mode 100644 index f00a0066..00000000 --- a/docs/docs/contracts/src/src/SystemState.sol/library.SystemState.md +++ /dev/null @@ -1,14 +0,0 @@ -# SystemState -[Git Source](https://github.com/bob-collective/bob/blob/master/src/SystemState.sol) - - -## Structs -### Storage - -```solidity -struct Storage { - IRelay relay; - uint256 txProofDifficultyFactor; -} -``` - diff --git a/docs/docs/contracts/src/src/bridge/BitcoinTx.sol/library.BitcoinTx.md b/docs/docs/contracts/src/src/bridge/BitcoinTx.sol/library.BitcoinTx.md deleted file mode 100644 index 031dfbfa..00000000 --- a/docs/docs/contracts/src/src/bridge/BitcoinTx.sol/library.BitcoinTx.md +++ /dev/null @@ -1,164 +0,0 @@ -# BitcoinTx -[Git Source](https://github.com/bob-collective/bob/blob/master/src/bridge/BitcoinTx.sol) - -Allows to reference Bitcoin raw transaction in Solidity. - -*See https://developer.bitcoin.org/reference/transactions.html#raw-transaction-format* - - -## Functions -### validateProof - -Validates the SPV proof of the Bitcoin transaction. -Reverts in case the validation or proof verification fail. - - -```solidity -function validateProof(BridgeState.Storage storage self, Info memory txInfo, Proof memory proof) - internal - view - returns (bytes32 txHash); -``` -**Parameters** - -|Name|Type|Description| -|----|----|-----------| -|`self`|`BridgeState.Storage`|| -|`txInfo`|`Info`|Bitcoin transaction data.| -|`proof`|`Proof`|Bitcoin proof data.| - -**Returns** - -|Name|Type|Description| -|----|----|-----------| -|`txHash`|`bytes32`|Proven 32-byte transaction hash.| - - -### evaluateProofDifficulty - -Evaluates the given Bitcoin proof difficulty against the actual -Bitcoin chain difficulty provided by the relay oracle. -Reverts in case the evaluation fails. - - -```solidity -function evaluateProofDifficulty(BridgeState.Storage storage self, bytes memory bitcoinHeaders) internal view; -``` -**Parameters** - -|Name|Type|Description| -|----|----|-----------| -|`self`|`BridgeState.Storage`|| -|`bitcoinHeaders`|`bytes`|Bitcoin headers chain being part of the SPV proof. Used to extract the observed proof difficulty.| - - -### getTxOutputValue - -Processes the Bitcoin transaction output vector. - - -```solidity -function getTxOutputValue(bytes32 scriptPubKeyHash, bytes memory txOutputVector) internal pure returns (uint64 value); -``` -**Parameters** - -|Name|Type|Description| -|----|----|-----------| -|`scriptPubKeyHash`|`bytes32`|Expected Bitcoin scriptPubKey keccak256 hash.| -|`txOutputVector`|`bytes`|Bitcoin transaction output vector. This function assumes vector's structure is valid so it must be validated using e.g. `BTCUtils.validateVout` function before it is passed here.| - -**Returns** - -|Name|Type|Description| -|----|----|-----------| -|`value`|`uint64`|Outcomes of the processing.| - - -### getTxOutputValue - -Processes all outputs from the transaction. - - -```solidity -function getTxOutputValue( - bytes32 scriptPubKeyHash, - bytes memory txOutputVector, - TxOutputsProcessingInfo memory processInfo -) internal pure returns (uint64 value); -``` -**Parameters** - -|Name|Type|Description| -|----|----|-----------| -|`scriptPubKeyHash`|`bytes32`|Expected Bitcoin scriptPubKey keccak256 hash.| -|`txOutputVector`|`bytes`|Bitcoin transaction output vector. This function assumes vector's structure is valid so it must be validated using e.g. `BTCUtils.validateVout` function before it is passed here.| -|`processInfo`|`TxOutputsProcessingInfo`|TxOutputsProcessingInfo identifying output starting index and the number of outputs.| - - -### reverseEndianness - - -```solidity -function reverseEndianness(bytes32 b) internal pure returns (bytes32 txHash); -``` - -### ensureTxInputSpendsUtxo - - -```solidity -function ensureTxInputSpendsUtxo(bytes memory _vin, BitcoinTx.UTXO memory utxo) internal pure; -``` - -## Structs -### Info -Represents Bitcoin transaction data. - - -```solidity -struct Info { - bytes4 version; - bytes inputVector; - bytes outputVector; - bytes4 locktime; -} -``` - -### Proof -Represents data needed to perform a Bitcoin SPV proof. - - -```solidity -struct Proof { - bytes merkleProof; - uint256 txIndexInBlock; - bytes bitcoinHeaders; -} -``` - -### UTXO -Represents info about an unspent transaction output. - - -```solidity -struct UTXO { - bytes32 txHash; - uint32 txOutputIndex; - uint64 txOutputValue; -} -``` - -### TxOutputsProcessingInfo -Represents temporary information needed during the processing of -the Bitcoin transaction outputs. This structure is an internal one -and should not be exported outside of the transaction processing code. - -*Allows to mitigate "stack too deep" errors on EVM.* - - -```solidity -struct TxOutputsProcessingInfo { - uint256 outputStartingIndex; - uint256 outputsCount; -} -``` - diff --git a/docs/docs/contracts/src/src/bridge/BridgeState.sol/library.BridgeState.md b/docs/docs/contracts/src/src/bridge/BridgeState.sol/library.BridgeState.md deleted file mode 100644 index 9f531b79..00000000 --- a/docs/docs/contracts/src/src/bridge/BridgeState.sol/library.BridgeState.md +++ /dev/null @@ -1,14 +0,0 @@ -# BridgeState -[Git Source](https://github.com/bob-collective/bob/blob/master/src/bridge/BridgeState.sol) - - -## Structs -### Storage - -```solidity -struct Storage { - IRelay relay; - uint96 txProofDifficultyFactor; -} -``` - diff --git a/docs/docs/contracts/src/src/bridge/IRelay.sol/interface.IRelay.md b/docs/docs/contracts/src/src/bridge/IRelay.sol/interface.IRelay.md deleted file mode 100644 index 194cecae..00000000 --- a/docs/docs/contracts/src/src/bridge/IRelay.sol/interface.IRelay.md +++ /dev/null @@ -1,27 +0,0 @@ -# IRelay -[Git Source](https://github.com/bob-collective/bob/blob/master/src/bridge/IRelay.sol) - -Contains only the methods needed by tBTC v2. The Bitcoin relay -provides the difficulty of the previous and current epoch. One -difficulty epoch spans 2016 blocks. - - -## Functions -### getCurrentEpochDifficulty - -Returns the difficulty of the current epoch. - - -```solidity -function getCurrentEpochDifficulty() external view returns (uint256); -``` - -### getPrevEpochDifficulty - -Returns the difficulty of the previous epoch. - - -```solidity -function getPrevEpochDifficulty() external view returns (uint256); -``` - diff --git a/docs/docs/contracts/src/src/bridge/WitnessTx.sol/library.WitnessTx.md b/docs/docs/contracts/src/src/bridge/WitnessTx.sol/library.WitnessTx.md deleted file mode 100644 index 974e2498..00000000 --- a/docs/docs/contracts/src/src/bridge/WitnessTx.sol/library.WitnessTx.md +++ /dev/null @@ -1,99 +0,0 @@ -# WitnessTx -[Git Source](https://github.com/bob-collective/bob/blob/master/src/bridge/WitnessTx.sol) - - -## State Variables -### SEGWIT_MARKER - -```solidity -bytes1 constant SEGWIT_MARKER = hex"00"; -``` - - -### SEGWIT_FLAG - -```solidity -bytes1 constant SEGWIT_FLAG = hex"01"; -``` - - -## Functions -### validateWitnessProof - -Validates the SPV proof of the Bitcoin transaction with witness data. -Reverts in case the validation or proof verification fail. - - -```solidity -function validateWitnessProof(WitnessInfo memory txInfo, WitnessProof memory proof) - internal - view - returns (bytes32 wTxHash); -``` -**Parameters** - -|Name|Type|Description| -|----|----|-----------| -|`txInfo`|`WitnessInfo`|Bitcoin transaction data.| -|`proof`|`WitnessProof`|Bitcoin proof data.| - -**Returns** - -|Name|Type|Description| -|----|----|-----------| -|`wTxHash`|`bytes32`|Proven 32-byte transaction hash.| - - -### validateWitnessProofAndDifficulty - -Validates the witness SPV proof using the relay. - - -```solidity -function validateWitnessProofAndDifficulty( - BridgeState.Storage storage self, - WitnessInfo memory txInfo, - WitnessProof memory proof -) internal view returns (bytes32 wTxHash); -``` -**Parameters** - -|Name|Type|Description| -|----|----|-----------| -|`self`|`BridgeState.Storage`|| -|`txInfo`|`WitnessInfo`|Bitcoin transaction data.| -|`proof`|`WitnessProof`|Bitcoin proof data.| - -**Returns** - -|Name|Type|Description| -|----|----|-----------| -|`wTxHash`|`bytes32`|Proven 32-byte transaction hash.| - - -## Structs -### WitnessInfo -Represents a Bitcoin transaction with the witness data. - - -```solidity -struct WitnessInfo { - BitcoinTx.Info info; - bytes witnessVector; -} -``` - -### WitnessProof -Represents data needed to perform a Bitcoin SPV proof with witness data. - - -```solidity -struct WitnessProof { - bytes32 witnessNonce; - bytes32 paymentMerkleRoot; - BitcoinTx.Proof coinbaseProof; - BitcoinTx.Proof paymentProof; - BitcoinTx.Info coinbaseTx; -} -``` - diff --git a/docs/docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/contract.AvalonLendingStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/contract.AvalonLendingStrategy.md index 53f35094..eb4df011 100644 --- a/docs/docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/contract.AvalonLendingStrategy.md +++ b/docs/docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/contract.AvalonLendingStrategy.md @@ -2,7 +2,7 @@ [Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/AvalonStrategy.sol) **Inherits:** -[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context +[IStrategyWithSlippageArgs](../../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context ## State Variables diff --git a/docs/docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/contract.AvalonLstStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/contract.AvalonLstStrategy.md index 64e79133..5cc4464a 100644 --- a/docs/docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/contract.AvalonLstStrategy.md +++ b/docs/docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/contract.AvalonLstStrategy.md @@ -2,7 +2,7 @@ [Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/AvalonStrategy.sol) **Inherits:** -[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context +[IStrategyWithSlippageArgs](../../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context ## State Variables diff --git a/docs/docs/contracts/src/src/gateway/strategy/BedrockStrategy.sol/contract.BedrockStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/BedrockStrategy.sol/contract.BedrockStrategy.md index 4b9258fb..e27946e1 100644 --- a/docs/docs/contracts/src/src/gateway/strategy/BedrockStrategy.sol/contract.BedrockStrategy.md +++ b/docs/docs/contracts/src/src/gateway/strategy/BedrockStrategy.sol/contract.BedrockStrategy.md @@ -2,7 +2,7 @@ [Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/BedrockStrategy.sol) **Inherits:** -[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context +[IStrategyWithSlippageArgs](../../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context ## State Variables diff --git a/docs/docs/contracts/src/src/gateway/strategy/IonicStrategy.sol/contract.IonicStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/IonicStrategy.sol/contract.IonicStrategy.md index 1076bf5e..9443ff6a 100644 --- a/docs/docs/contracts/src/src/gateway/strategy/IonicStrategy.sol/contract.IonicStrategy.md +++ b/docs/docs/contracts/src/src/gateway/strategy/IonicStrategy.sol/contract.IonicStrategy.md @@ -2,7 +2,7 @@ [Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/IonicStrategy.sol) **Inherits:** -[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context +[IStrategyWithSlippageArgs](../../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context *Implements IStrategyWithSlippageArgs and allows the contract to handle tokens with slippage arguments.* diff --git a/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellBedrockStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellBedrockStrategy.md index 10d83f42..d26464ec 100644 --- a/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellBedrockStrategy.md +++ b/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellBedrockStrategy.md @@ -2,7 +2,7 @@ [Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/PellStrategy.sol) **Inherits:** -[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context +[IStrategyWithSlippageArgs](../../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context ## State Variables diff --git a/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellSolvLSTStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellSolvLSTStrategy.md index c922bed3..48aaea05 100644 --- a/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellSolvLSTStrategy.md +++ b/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellSolvLSTStrategy.md @@ -2,7 +2,7 @@ [Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/PellStrategy.sol) **Inherits:** -[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context +[IStrategyWithSlippageArgs](../../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context ## State Variables diff --git a/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellStrategy.md index 2941ec65..05c2cb81 100644 --- a/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellStrategy.md +++ b/docs/docs/contracts/src/src/gateway/strategy/PellStrategy.sol/contract.PellStrategy.md @@ -2,7 +2,7 @@ [Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/PellStrategy.sol) **Inherits:** -[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context +[IStrategyWithSlippageArgs](../../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context ## State Variables diff --git a/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentBedrockStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentBedrockStrategy.md index 0d0dd29b..7446cc74 100644 --- a/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentBedrockStrategy.md +++ b/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentBedrockStrategy.md @@ -2,7 +2,7 @@ [Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/SegmentStrategy.sol) **Inherits:** -[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context +[IStrategyWithSlippageArgs](../../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context ## State Variables diff --git a/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentSolvLSTStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentSolvLSTStrategy.md index c66c5c17..93189108 100644 --- a/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentSolvLSTStrategy.md +++ b/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentSolvLSTStrategy.md @@ -2,7 +2,7 @@ [Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/SegmentStrategy.sol) **Inherits:** -[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context +[IStrategyWithSlippageArgs](../../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context ## State Variables diff --git a/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentStrategy.md index 02dc4ce5..c6b1e019 100644 --- a/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentStrategy.md +++ b/docs/docs/contracts/src/src/gateway/strategy/SegmentStrategy.sol/contract.SegmentStrategy.md @@ -2,7 +2,7 @@ [Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/SegmentStrategy.sol) **Inherits:** -[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context +[IStrategyWithSlippageArgs](../../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context ## State Variables diff --git a/docs/docs/contracts/src/src/gateway/strategy/ShoebillStrategy.sol/contract.ShoebillStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/ShoebillStrategy.sol/contract.ShoebillStrategy.md index 55208fd9..fb1962af 100644 --- a/docs/docs/contracts/src/src/gateway/strategy/ShoebillStrategy.sol/contract.ShoebillStrategy.md +++ b/docs/docs/contracts/src/src/gateway/strategy/ShoebillStrategy.sol/contract.ShoebillStrategy.md @@ -2,7 +2,7 @@ [Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/ShoebillStrategy.sol) **Inherits:** -[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context +[IStrategyWithSlippageArgs](../../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context ## State Variables diff --git a/docs/docs/contracts/src/src/gateway/strategy/SolvStrategy.sol/contract.SolvBTCStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/SolvStrategy.sol/contract.SolvBTCStrategy.md index 39745985..a29b5ee1 100644 --- a/docs/docs/contracts/src/src/gateway/strategy/SolvStrategy.sol/contract.SolvBTCStrategy.md +++ b/docs/docs/contracts/src/src/gateway/strategy/SolvStrategy.sol/contract.SolvBTCStrategy.md @@ -2,7 +2,7 @@ [Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/SolvStrategy.sol) **Inherits:** -[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context +[IStrategyWithSlippageArgs](../../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context ## State Variables diff --git a/docs/docs/contracts/src/src/gateway/strategy/SolvStrategy.sol/contract.SolvLSTStrategy.md b/docs/docs/contracts/src/src/gateway/strategy/SolvStrategy.sol/contract.SolvLSTStrategy.md index a5ffd483..612c370c 100644 --- a/docs/docs/contracts/src/src/gateway/strategy/SolvStrategy.sol/contract.SolvLSTStrategy.md +++ b/docs/docs/contracts/src/src/gateway/strategy/SolvStrategy.sol/contract.SolvLSTStrategy.md @@ -2,7 +2,7 @@ [Git Source](https://github.com/bob-collective/bob/blob/master/src/gateway/strategy/SolvStrategy.sol) **Inherits:** -[IStrategyWithSlippageArgs](../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context +[IStrategyWithSlippageArgs](../../../gateway/IStrategy.sol/abstract.IStrategyWithSlippageArgs.md), Context ## State Variables diff --git a/docs/docs/contracts/src/src/swap/Bridge.sol/contract.Bridge.md b/docs/docs/contracts/src/src/swap/Bridge.sol/contract.Bridge.md deleted file mode 100644 index 54408b3e..00000000 --- a/docs/docs/contracts/src/src/swap/Bridge.sol/contract.Bridge.md +++ /dev/null @@ -1,162 +0,0 @@ -# Bridge -[Git Source](https://github.com/bob-collective/bob/blob/master/src/swap/Bridge.sol) - -**Inherits:** -ERC2771Recipient - - -## State Variables -### number - -```solidity -uint256 public number; -``` - - -### collateralThreshold - -```solidity -uint256 public collateralThreshold; -``` - - -### nextOrderId - -```solidity -uint256 nextOrderId; -``` - - -### orders - -```solidity -mapping(uint256 => Order) public orders; -``` - - -### suppliedCollateral - -```solidity -mapping(address => uint256) public suppliedCollateral; -``` - - -### totalCollateral - -```solidity -uint256 totalCollateral; -``` - - -### wrapped - -```solidity -BobWrappedBtc wrapped = new BobWrappedBtc(); -``` - - -## Functions -### constructor - - -```solidity -constructor(uint256 threshold); -``` - -### mint - -lock COL in exchange for zBTC and cCOL - - -```solidity -function mint() public payable; -``` - -### requestSwap - -request zBTC to be redeemed for given amount of BTC. - - -```solidity -function requestSwap(uint256 amountZbtc, uint256 amountBtc, BitcoinAddress calldata bitcoinAddress) public; -``` - -### acceptSwap - - -```solidity -function acceptSwap(uint256 id) public; -``` - -### cancelSwap - - -```solidity -function cancelSwap(uint256 id) public; -``` - -### executeSwap - - -```solidity -function executeSwap(uint256 id, TransactionProof calldata) public; -``` - -### liquidate - - -```solidity -function liquidate(uint256 amountZbtc) public; -``` - -### withdraw - - -```solidity -function withdraw() public; -``` - -### colToBtc - - -```solidity -function colToBtc(uint256 collateral) internal pure returns (uint256); -``` - -### btcToCol - - -```solidity -function btcToCol(uint256 collateral) internal pure returns (uint256); -``` - -## Structs -### Order - -```solidity -struct Order { - bool open; - uint256 amountZbtc; - uint256 amountBtc; - address requesterAddress; - address accepterAddress; - BitcoinAddress bitcoinAddress; -} -``` - -### BitcoinAddress - -```solidity -struct BitcoinAddress { - bytes scriptPubKey; -} -``` - -### TransactionProof - -```solidity -struct TransactionProof { - uint256 dummy; -} -``` - diff --git a/docs/scripts/forge_doc_reformat.py b/docs/scripts/forge_doc_reformat.py index 3c8048c1..e1cd7f7f 100644 --- a/docs/scripts/forge_doc_reformat.py +++ b/docs/scripts/forge_doc_reformat.py @@ -28,14 +28,20 @@ def parse_inherits(md_content): return None # Function to replace paths inside brackets with empty brackets -def replace_paths_with_empty_brackets(line): +def replace_paths_with_empty_brackets(line,file_path): def replace_path(match): default_path = 'docs/docs/src' path = default_path + match.group(0)[1:-1] # Remove parentheses start = "docs/docs/src/src/X/X/" relative_path = os.path.relpath(path, start) + print(f"path: {path}") + print(f"line: {line}") + print(f"file_path: {file_path}") print(f"Original Path: {relative_path}") - return '(' + relative_path + ')' + if '/src/gateway/strategy/' in file_path: + return '(../' + relative_path + ')' + else: + return '(' + relative_path + ')' return re.sub(r'\([^)]+\)', replace_path, line) # Function to process a single Markdown file @@ -45,10 +51,11 @@ def process_md_file(file_path): # Parse Inherits line inherits = parse_inherits(md_content) - + print(f"file_path: ",file_path); # Modify the Inherits line if inherits: - modified_inherits = replace_paths_with_empty_brackets(inherits) + modified_inherits = replace_paths_with_empty_brackets(inherits,file_path) + print(f"modified_inherits: {modified_inherits}") md_content = md_content.replace(inherits, modified_inherits) md_content = replace_git_sources(md_content) @@ -83,4 +90,8 @@ def process_all_md_files(directory): # Process all Markdown files in the specified directory and its subdirectories process_all_md_files(directory_path) + # Specific file path to process + # file_to_process = "/Users/nakul/Desktop/Interlay_Work/bob/docs/scripts/../docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/contract.AvalonLstStrategy.md" + # process_md_file(file_to_process) + print("All Markdown files in the directory processed.") From 6eab03bfd53af9c0bd3fa5f2a3e28541a30a498b Mon Sep 17 00:00:00 2001 From: nakul1010 Date: Sun, 12 Jan 2025 17:02:07 +0530 Subject: [PATCH 4/5] fix: update py script --- docs/scripts/forge_doc_reformat.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/docs/scripts/forge_doc_reformat.py b/docs/scripts/forge_doc_reformat.py index e1cd7f7f..d381b860 100644 --- a/docs/scripts/forge_doc_reformat.py +++ b/docs/scripts/forge_doc_reformat.py @@ -34,10 +34,9 @@ def replace_path(match): path = default_path + match.group(0)[1:-1] # Remove parentheses start = "docs/docs/src/src/X/X/" relative_path = os.path.relpath(path, start) - print(f"path: {path}") - print(f"line: {line}") - print(f"file_path: {file_path}") print(f"Original Path: {relative_path}") + # If the file being processed is under the '/src/gateway/strategy/' directory, + # prepend '../' to the relative path to adjust for the directory level difference if '/src/gateway/strategy/' in file_path: return '(../' + relative_path + ')' else: @@ -51,11 +50,10 @@ def process_md_file(file_path): # Parse Inherits line inherits = parse_inherits(md_content) - print(f"file_path: ",file_path); + # Modify the Inherits line if inherits: modified_inherits = replace_paths_with_empty_brackets(inherits,file_path) - print(f"modified_inherits: {modified_inherits}") md_content = md_content.replace(inherits, modified_inherits) md_content = replace_git_sources(md_content) @@ -90,8 +88,4 @@ def process_all_md_files(directory): # Process all Markdown files in the specified directory and its subdirectories process_all_md_files(directory_path) - # Specific file path to process - # file_to_process = "/Users/nakul/Desktop/Interlay_Work/bob/docs/scripts/../docs/contracts/src/src/gateway/strategy/AvalonStrategy.sol/contract.AvalonLstStrategy.md" - # process_md_file(file_to_process) - print("All Markdown files in the directory processed.") From c669b67c780b12781866c1748ce3dc8e30bf46ca Mon Sep 17 00:00:00 2001 From: nakul1010 Date: Mon, 13 Jan 2025 10:55:03 +0530 Subject: [PATCH 5/5] fix: ionic strategy add back missing import --- src/gateway/strategy/IonicStrategy.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gateway/strategy/IonicStrategy.sol b/src/gateway/strategy/IonicStrategy.sol index 05eee671..88c1b6e2 100644 --- a/src/gateway/strategy/IonicStrategy.sol +++ b/src/gateway/strategy/IonicStrategy.sol @@ -8,6 +8,7 @@ import {SolvLSTStrategy} from "./SolvStrategy.sol"; import {Context} from "@openzeppelin/contracts/utils/Context.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "forge-std/Test.sol"; /** * @dev Interface for the Ionic Finance token, providing minting, redeeming,