From 9aa991e7fed86a0d878268b770c55af7caa7ccde Mon Sep 17 00:00:00 2001 From: Filip Malachowicz Date: Tue, 9 Dec 2025 11:53:40 +0100 Subject: [PATCH 1/3] feat: add periphery contracts documentation Add documentation for Venus Periphery contracts: - LeverageStrategiesManager: Flash loan-based leverage entry/exit operations - SwapHelper: EIP-712 signed multicall executor for token swaps --- SUMMARY.md | 4 + deployed-contracts/periphery.md | 6 + technical-reference/contracts-overview.md | 13 + .../reference-periphery/README.md | 28 + .../leverage-strategies-manager.md | 510 ++++++++++++++++++ .../reference-periphery/swap-helper.md | 360 +++++++++++++ 6 files changed, 921 insertions(+) create mode 100644 deployed-contracts/periphery.md create mode 100644 technical-reference/reference-periphery/README.md create mode 100644 technical-reference/reference-periphery/leverage-strategies-manager.md create mode 100644 technical-reference/reference-periphery/swap-helper.md diff --git a/SUMMARY.md b/SUMMARY.md index e7d830a5..820918e6 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -187,6 +187,9 @@ * [XVSBridgeAdmin](technical-reference/reference-xvs-bridge/XVSBridgeAdmin.md) * [XVS](technical-reference/reference-xvs-bridge/XVS.md) * [TokenController](technical-reference/reference-xvs-bridge/TokenController.md) +* [Periphery](technical-reference/reference-periphery/README.md) + * [LeverageStrategiesManager](technical-reference/reference-periphery/leverage-strategies-manager.md) + * [SwapHelper](technical-reference/reference-periphery/swap-helper.md) ## Deployed Contracts @@ -197,6 +200,7 @@ * [XVS Omnichain](deployed-contracts/xvs-omnichain.md) * [Token Converters](deployed-contracts/token-converters.md) * [VenusERC4626](deployed-contracts/venus-erc4626.md) +* [Periphery](deployed-contracts/periphery.md) ## Services diff --git a/deployed-contracts/periphery.md b/deployed-contracts/periphery.md new file mode 100644 index 00000000..fa6e6c96 --- /dev/null +++ b/deployed-contracts/periphery.md @@ -0,0 +1,6 @@ +# Periphery - Deployed Contracts + +## BNB Chain Mainnet + +- SwapHelper: [`0xe1a3b4189F56Cf38747BE79348b8664Ef18cCFd1`](https://bscscan.com/address/0xe1a3b4189F56Cf38747BE79348b8664Ef18cCFd1) +- LeverageStrategiesManager: [`0x51438311922e88AEDF0B111944dD601DCB3c4BF9`](https://bscscan.com/address/0x51438311922e88AEDF0B111944dD601DCB3c4BF9) diff --git a/technical-reference/contracts-overview.md b/technical-reference/contracts-overview.md index ed16311e..300313b9 100644 --- a/technical-reference/contracts-overview.md +++ b/technical-reference/contracts-overview.md @@ -7,6 +7,7 @@ Venus Protocol contracts are divided in these repositories: * [venus-protocol](https://github.com/VenusProtocol/venus-protocol): The core protocol is located in this repo. It contains logic central to lending and borrowing of the core pool. * [governance-contracts](https://github.com/VenusProtocol/governance-contracts): The contracts used for proposing, voting and executing changes are kept in the \`governance-contracts repo. * [token-bridge](https://github.com/VenusProtocol/token-bridge): The contracts use to bridge XVS to different networks. +* [venus-periphery](https://github.com/VenusProtocol/venus-periphery): Auxiliary contracts for advanced DeFi operations including leverage strategies and token swaps. ## Isolated Pools Contracts @@ -177,3 +178,15 @@ The core logic for governance proposals is in the [GovernorBraveDelegate](https: To enhance security of the protocol, Venus Protocol uses the [AccessControlManager](https://github.com/VenusProtocol/governance-contracts/blob/main/contracts/Governance/AccessControlManager.sol) to grant accounts access to call specific functions on contracts. This contract is responsible for granting and revoking those permissions. It also provides a getter to check if an address is allowed to call a specific function. **Timelock** Once a proposal has succeeded its execution is managed by the [Timelock](https://github.com/VenusProtocol/governance-contracts/blob/main/contracts/Governance/Timelock.sol) contract. The Timelock can place the proposal in a queue for execution and execute the proposal. It also enables canceling the proposal. + +## Periphery Contracts + +Periphery contracts extend core protocol functionality with auxiliary features for advanced DeFi operations. + +[**LeverageStrategiesManager**](reference-periphery/leverage-strategies-manager.md) + +The [LeverageStrategiesManager](https://github.com/VenusProtocol/venus-periphery/blob/main/contracts/LeverageManager/LeverageStrategiesManager.sol) enables users to enter and exit leveraged positions atomically using flash loans. It consolidates multiple operations (borrow, swap, supply) into single transactions. + +[**SwapHelper**](reference-periphery/swap-helper.md) + +The [SwapHelper](https://github.com/VenusProtocol/venus-periphery/blob/main/contracts/SwapHelper/SwapHelper.sol) provides a secure multicall interface for token swaps with backend signature verification. It enables authorized interactions with external DEX protocols. diff --git a/technical-reference/reference-periphery/README.md b/technical-reference/reference-periphery/README.md new file mode 100644 index 00000000..d97e1185 --- /dev/null +++ b/technical-reference/reference-periphery/README.md @@ -0,0 +1,28 @@ +# Periphery Contracts + +Venus Protocol periphery contracts extend core protocol functionality with auxiliary features for advanced DeFi operations. These contracts integrate with the Venus Comptroller and vToken markets to provide atomic, gas-efficient operations. + +## Overview + +The Venus periphery consists of specialized smart contracts designed to streamline complex DeFi operations: + +- **[LeverageStrategiesManager](leverage-strategies-manager.md)** - Enter and exit leveraged positions atomically using flash loans +- **[SwapHelper](swap-helper.md)** - Execute backend-authorized token swaps with signature verification + +## Key Features + +- Flash loan-based atomic execution +- EIP-712 signature verification for authorized operations +- EIP-1153 transient storage for efficient callback state management +- Comprehensive account safety validation +- Slippage protection on all swap operations + +## Deployment + +Periphery contracts are currently deployed on BNB Chain Mainnet. See [Deployed Contracts](../../deployed-contracts/periphery.md) for addresses and deployment information. + +## Integration + +For users looking to leverage their positions or perform advanced trading strategies, start with the [Leverage Positions Guide](../../guides/leverage-positions.md). + +Developers integrating with periphery contracts should review the detailed API documentation in the individual contract pages. diff --git a/technical-reference/reference-periphery/leverage-strategies-manager.md b/technical-reference/reference-periphery/leverage-strategies-manager.md new file mode 100644 index 00000000..c14a969e --- /dev/null +++ b/technical-reference/reference-periphery/leverage-strategies-manager.md @@ -0,0 +1,510 @@ +# LeverageStrategiesManager + +The LeverageStrategiesManager is a Venus periphery contract that enables users to enter and exit leveraged positions atomically using flash loans. It integrates with the Venus Comptroller's flash loan functionality and the SwapHelper contract to execute complex leverage operations in a single transaction. + +## Overview + +Leverage operations in DeFi typically require multiple transactions: borrowing, swapping, and supplying assets. The LeverageStrategiesManager consolidates these into atomic operations using flash loans, eliminating intermediate exposure and reducing gas costs. + +The contract supports five distinct leverage strategies: + +| Strategy | Description | Swap Required | +| -------------------------- | ----------------------------------------------------------- | ------------- | +| `enterSingleAssetLeverage` | Amplify exposure to a single asset | No | +| `enterLeverage` | Enter leverage with collateral seed, borrow different asset | Yes | +| `enterLeverageFromBorrow` | Enter leverage using borrowed asset as seed | Yes | +| `exitSingleAssetLeverage` | Close single-asset leveraged position | No | +| `exitLeverage` | Close cross-asset leveraged position | Yes | + +## Prerequisites + +Before using the LeverageStrategiesManager, users must delegate borrowing rights to the contract: + +```solidity +// On the Venus Comptroller +comptroller.updateDelegate(leverageStrategiesManagerAddress, true); +``` + +This delegation allows the contract to: + +- Borrow on behalf of the user +- Mint vTokens on behalf of the user +- Redeem vTokens on behalf of the user +- Repay borrows on behalf of the user + +## Inheritance + +- `Ownable2StepUpgradeable` - Two-step ownership transfer pattern +- `ReentrancyGuardUpgradeable` - Reentrancy protection +- `IFlashLoanReceiver` - Flash loan callback interface +- `ILeverageStrategiesManager` - Contract interface + +## Immutable State Variables + +| Variable | Type | Description | +| ------------- | -------------- | ------------------------------------------------------------------ | +| `COMPTROLLER` | `IComptroller` | Venus Comptroller for market interactions and flash loan execution | +| `swapHelper` | `SwapHelper` | Token swap executor for cross-asset operations | +| `vBNB` | `IVToken` | vBNB market address (not supported for leverage operations) | + +## Architecture + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Venus Core Protocol │ +│ ┌───────────┐ ┌──────────┐ ┌────────────────────────────┐│ +│ │Comptroller│ │ vTokens │ │ Flash Loan Module ││ +│ └─────┬─────┘ └────┬─────┘ └─────────────┬──────────────┘│ +└────────┼─────────────┼──────────────────────┼───────────────┘ + │ │ │ + │ │ │ +┌────────┼─────────────┼──────────────────────┼───────────────┐ +│ ▼ ▼ ▼ │ +│ ┌─────────────────────────────────────────────────────────┐│ +│ │ LeverageStrategiesManager ││ +│ │ - Enters/exits leveraged positions ││ +│ │ - Orchestrates flash loans and swaps ││ +│ │ - Validates account safety ││ +│ └──────────────────────────┬──────────────────────────────┘│ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────────────────────────────────────┐│ +│ │ SwapHelper ││ +│ │ - Executes authorized swaps ││ +│ │ - Verifies backend signatures ││ +│ │ - Interacts with DEX protocols ││ +│ └─────────────────────────────────────────────────────────┘│ +│ Venus Periphery │ +└─────────────────────────────────────────────────────────────┘ +``` + +## Transient Storage (EIP-1153) + +The contract uses EIP-1153 transient storage to pass state between entry functions and flash loan callbacks. These values are automatically cleared at transaction end: + +| Variable | Type | Description | +| ----------------------- | --------------- | ------------------------------------------- | +| `operationType` | `OperationType` | Current operation being executed | +| `operationInitiator` | `address` | Original `msg.sender` of the entry function | +| `collateralMarket` | `IVToken` | Target collateral market | +| `collateralAmount` | `uint256` | Collateral seed or redeem amount | +| `borrowedAmountSeed` | `uint256` | User-provided borrowed asset seed | +| `minAmountOutAfterSwap` | `uint256` | Slippage protection threshold | + +# Solidity API + +### enterSingleAssetLeverage + +Enters a leveraged position using the same asset for collateral and borrowing. No swap is required. + +```solidity +function enterSingleAssetLeverage( + IVToken _collateralMarket, + uint256 _collateralAmountSeed, + uint256 _collateralAmountToFlashLoan +) external +``` + +#### Parameters + +| Name | Type | Description | +| ----------------------------- | ------- | ---------------------------------------------------------------- | +| \_collateralMarket | IVToken | The vToken market to use for both collateral and borrowing | +| \_collateralAmountSeed | uint256 | Amount of underlying tokens the user provides as initial capital | +| \_collateralAmountToFlashLoan | uint256 | Amount to flash loan for leverage amplification | + +#### Example + +User has 10 ETH and wants 2x exposure: + +- Provide 10 ETH as seed +- Flash loan 10 ETH +- Supply 20 ETH as collateral +- Final: 20 ETH collateral, 10 ETH debt (plus fees) + +#### Events + +- `SingleAssetLeverageEntered` emitted on success +- `DustTransferred` emitted if residual tokens remain + +#### Access Requirements + +- User must have delegated to this contract via `Comptroller.updateDelegate` + +#### Errors + +- `ZeroFlashLoanAmount` if `_collateralAmountToFlashLoan` is zero +- `MarketNotListed` if market is not listed in Comptroller +- `VBNBNotSupported` if the market is vBNB +- `NotAnApprovedDelegate` if user has not delegated to this contract +- `AccrueInterestFailed` if interest accrual fails on the market +- `EnterMarketFailed` if entering the market fails +- `OperationCausesLiquidation` if pre/post position is unsafe + +--- + +### enterLeverage + +Enters a leveraged position by providing collateral seed and borrowing a different asset. The borrowed asset is swapped to collateral. + +```solidity +function enterLeverage( + IVToken _collateralMarket, + uint256 _collateralAmountSeed, + IVToken _borrowedMarket, + uint256 _borrowedAmountToFlashLoan, + uint256 _minAmountOutAfterSwap, + bytes calldata _swapData +) external +``` + +#### Parameters + +| Name | Type | Description | +| --------------------------- | ------- | ------------------------------------------------------------------ | +| \_collateralMarket | IVToken | The vToken market to supply collateral to | +| \_collateralAmountSeed | uint256 | Amount of collateral underlying the user provides | +| \_borrowedMarket | IVToken | The vToken market to borrow from | +| \_borrowedAmountToFlashLoan | uint256 | Amount of borrowed asset to flash loan | +| \_minAmountOutAfterSwap | uint256 | Minimum collateral tokens expected from swap (slippage protection) | +| \_swapData | bytes | Encoded swap data from Venus Swap API | + +#### Example + +User has 1,000 USDC and wants 3x USDC exposure: + +- Provide 1,000 USDC as collateral seed +- Flash loan 2,000 USDT +- Swap 2,000 USDT → ~2,000 USDC +- Supply 3,000 USDC as collateral +- Final: 3,000 USDC collateral, 2,000 USDT debt (plus fees) + +#### Events + +- `LeverageEntered` emitted on success +- `DustTransferred` emitted for residual collateral and borrowed tokens + +#### Access Requirements + +- User must have delegated to this contract via `Comptroller.updateDelegate` + +#### Errors + +- `ZeroFlashLoanAmount` if `_borrowedAmountToFlashLoan` is zero +- `IdenticalMarkets` if collateral and borrowed markets are the same +- `MarketNotListed` if either market is not listed in Comptroller +- `VBNBNotSupported` if either market is vBNB +- `NotAnApprovedDelegate` if user has not delegated to this contract +- `AccrueInterestFailed` if interest accrual fails on either market +- `EnterMarketFailed` if entering either market fails +- `SlippageExceeded` if swap output is below `_minAmountOutAfterSwap` +- `TokenSwapCallFailed` if swap execution reverts +- `OperationCausesLiquidation` if position becomes unsafe + +--- + +### enterLeverageFromBorrow + +Enters a leveraged position by providing the borrowed asset as seed. Both seed and flash loan are swapped to collateral. + +```solidity +function enterLeverageFromBorrow( + IVToken _collateralMarket, + IVToken _borrowedMarket, + uint256 _borrowedAmountSeed, + uint256 _borrowedAmountToFlashLoan, + uint256 _minAmountOutAfterSwap, + bytes calldata _swapData +) external +``` + +#### Parameters + +| Name | Type | Description | +| --------------------------- | ------- | ------------------------------------------------------------- | +| \_collateralMarket | IVToken | The vToken market to supply collateral to | +| \_borrowedMarket | IVToken | The vToken market providing the seed and flash loan | +| \_borrowedAmountSeed | uint256 | Amount of borrowed asset the user provides as seed | +| \_borrowedAmountToFlashLoan | uint256 | Amount of borrowed asset to flash loan | +| \_minAmountOutAfterSwap | uint256 | Minimum collateral tokens expected from swap | +| \_swapData | bytes | Encoded swap data (must account for seed + flash loan amount) | + +#### Example + +User has 1 ETH and wants leveraged USDC exposure: + +- Provide 1 ETH as seed +- Flash loan 2 ETH +- Swap 3 ETH → ~6,000 USDC +- Supply 6,000 USDC as collateral +- Final: 6,000 USDC collateral, 2 ETH debt (plus fees) + +#### Events + +- `LeverageEnteredFromBorrow` emitted on success +- `DustTransferred` emitted for residual tokens + +#### Access Requirements + +- User must have delegated to this contract + +#### Errors + +- `ZeroFlashLoanAmount` if `_borrowedAmountToFlashLoan` is zero +- `MarketNotListed` if either market is not listed in Comptroller +- `VBNBNotSupported` if either market is vBNB +- `NotAnApprovedDelegate` if user has not delegated to this contract +- `AccrueInterestFailed` if interest accrual fails on either market +- `EnterMarketFailed` if entering either market fails +- `SlippageExceeded` if swap output is below `_minAmountOutAfterSwap` +- `TokenSwapCallFailed` if swap execution reverts +- `OperationCausesLiquidation` if position becomes unsafe + +--- + +### exitSingleAssetLeverage + +Closes or reduces a single-asset leveraged position. Flash loans the asset to repay debt, then redeems collateral to cover the flash loan. + +```solidity +function exitSingleAssetLeverage( + IVToken _collateralMarket, + uint256 _collateralAmountToFlashLoan +) external +``` + +#### Parameters + +| Name | Type | Description | +| ----------------------------- | ------- | ---------------------------------------------- | +| \_collateralMarket | IVToken | The vToken market for both collateral and debt | +| \_collateralAmountToFlashLoan | uint256 | Amount to flash loan for debt repayment | + +#### Example + +User has 20 ETH collateral and 10 ETH debt: + +- Flash loan 10 ETH +- Repay 10 ETH debt +- Redeem ~10 ETH (plus fees) from collateral +- Final: ~10 ETH collateral, 0 debt + +#### Events + +- `SingleAssetLeverageExited` emitted on success +- `DustTransferred` emitted for residual tokens + +#### Access Requirements + +- User must have delegated to this contract + +#### Errors + +- `ZeroFlashLoanAmount` if flash loan amount is zero +- `MarketNotListed` if market is not listed in Comptroller +- `VBNBNotSupported` if the market is vBNB +- `NotAnApprovedDelegate` if user has not delegated to this contract +- `AccrueInterestFailed` if interest accrual fails on the market +- `InsufficientFundsToRepayFlashloan` if redemption insufficient for repayment +- `OperationCausesLiquidation` if final position is unsafe + +--- + +### exitLeverage + +Closes or reduces a cross-asset leveraged position. Flash loans borrowed asset to repay debt, redeems collateral, and swaps to cover the flash loan. + +```solidity +function exitLeverage( + IVToken _collateralMarket, + uint256 _collateralAmountToRedeemForSwap, + IVToken _borrowedMarket, + uint256 _borrowedAmountToFlashLoan, + uint256 _minAmountOutAfterSwap, + bytes calldata _swapData +) external +``` + +#### Parameters + +| Name | Type | Description | +| --------------------------------- | ------- | ------------------------------------------- | +| \_collateralMarket | IVToken | The vToken market holding user's collateral | +| \_collateralAmountToRedeemForSwap | uint256 | Amount of collateral to redeem and swap | +| \_borrowedMarket | IVToken | The vToken market where user has debt | +| \_borrowedAmountToFlashLoan | uint256 | Amount to flash loan for debt repayment | +| \_minAmountOutAfterSwap | uint256 | Minimum borrowed tokens expected from swap | +| \_swapData | bytes | Encoded swap data | + +#### Example + +User has 3,000 USDC collateral and 1 ETH debt: + +- Flash loan 1 ETH +- Repay 1 ETH debt +- Redeem 2,000 USDC from collateral +- Swap 2,000 USDC → ~1 ETH (plus fees) +- Final: ~1,000 USDC collateral, 0 ETH debt + +#### Events + +- `LeverageExited` emitted on success +- `DustTransferred` emitted for residual tokens + +#### Access Requirements + +- User must have delegated to this contract + +#### Errors + +- `ZeroFlashLoanAmount` if flash loan amount is zero +- `IdenticalMarkets` if collateral and borrowed markets are the same +- `MarketNotListed` if either market is not listed in Comptroller +- `VBNBNotSupported` if either market is vBNB +- `NotAnApprovedDelegate` if user has not delegated to this contract +- `AccrueInterestFailed` if interest accrual fails on either market +- `SlippageExceeded` if swap output is below minimum +- `InsufficientFundsToRepayFlashloan` if swap output insufficient for repayment +- `OperationCausesLiquidation` if final position is unsafe + +--- + +### executeOperation + +Flash loan callback invoked by the Comptroller. Routes execution to the appropriate handler based on `operationType`. + +```solidity +function executeOperation( + IVToken[] calldata vTokens, + uint256[] calldata amounts, + uint256[] calldata premiums, + address initiator, + address onBehalf, + bytes calldata param +) external override nonReentrant returns (bool success, uint256[] memory repayAmounts) +``` + +#### Parameters + +| Name | Type | Description | +| --------- | --------- | ------------------------------------------------------------- | +| vTokens | IVToken[] | Array with the borrowed vToken market (single element) | +| amounts | uint256[] | Array with the borrowed underlying amount (single element) | +| premiums | uint256[] | Array with the flash loan fee amount (single element) | +| initiator | address | Address that initiated the flash loan (must be this contract) | +| onBehalf | address | User for whom debt will be opened | +| param | bytes | Encoded auxiliary data for the operation | + +#### Access Requirements + +- Only callable by the Comptroller + +#### Errors + +- `UnauthorizedExecutor` if caller is not Comptroller +- `InitiatorMismatch` if initiator is not this contract +- `OnBehalfMismatch` if onBehalf does not match operationInitiator +- `FlashLoanAssetOrAmountMismatch` if arrays length is not 1 +- `InvalidExecuteOperation` if operation type is unknown + +## Events + +| Event | Parameters | Description | +| ---------------------------- | -------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | +| `SingleAssetLeverageEntered` | user, collateralMarket, collateralAmountSeed, collateralAmountToFlashLoan | Single-asset leverage position opened | +| `LeverageEntered` | user, collateralMarket, collateralAmountSeed, borrowedMarket, borrowedAmountToFlashLoan | Cross-asset leverage position opened with collateral seed | +| `LeverageEnteredFromBorrow` | user, collateralMarket, borrowedMarket, borrowedAmountSeed, borrowedAmountToFlashLoan | Cross-asset leverage position opened with borrowed seed | +| `LeverageExited` | user, collateralMarket, collateralAmountToRedeemForSwap, borrowedMarket, borrowedAmountToFlashLoan | Cross-asset leverage position closed | +| `SingleAssetLeverageExited` | user, collateralMarket, collateralAmountToFlashLoan | Single-asset leverage position closed | +| `DustTransferred` | recipient, token, amount | Residual tokens transferred after operation | + +## Security Considerations + +### Access Control + +- **Delegate Requirement**: All operations verify the user has delegated to this contract via `Comptroller.updateDelegate()` +- **Flash Loan Callback**: `executeOperation` validates `msg.sender` is the Comptroller +- **Initiator Validation**: Callback verifies `initiator == address(this)` to prevent unauthorized triggers +- **OnBehalf Validation**: Callback verifies `onBehalf == operationInitiator` for user consistency + +### Reentrancy Protection + +The `executeOperation` function is protected by OpenZeppelin's `nonReentrant` modifier, preventing reentrant calls during flash loan callback execution. + +### Slippage Protection + +All swap operations accept a `minAmountOutAfterSwap` parameter. The transaction reverts with `SlippageExceeded` if the swap output falls below this threshold. + +### Account Safety + +- Enter operations perform pre-checks to ensure the user is not already at liquidation risk +- All operations perform post-checks to verify the final position is healthy +- Exit operations skip pre-checks since reducing debt can only improve health + +### Dust Handling + +After every operation, any residual token balances are transferred back to the user: + +- Collateral dust → User +- Borrowed dust (all operations) → User + +## Deployment + +See [Deployed Contracts](../deployed-contracts/periphery.md) for current addresses. + +## Integration + +### For Users + +1. **Enable Delegation**: Call `Comptroller.updateDelegate(leverageStrategiesManagerAddress, true)` to authorize the contract +2. **Approve Tokens**: Grant token spending approval to LeverageStrategiesManager for collateral tokens +3. **Execute Operations**: Call the appropriate entry function with parameters + +### For Developers + +LeverageStrategiesManager exposes a clear interface for integration: + +```solidity +interface ILeverageStrategiesManager { + function enterSingleAssetLeverage( + IVToken _collateralMarket, + uint256 _collateralAmountSeed, + uint256 _collateralAmountToFlashLoan + ) external; + + function enterLeverage( + IVToken _collateralMarket, + uint256 _collateralAmountSeed, + IVToken _borrowedMarket, + uint256 _borrowedAmountToFlashLoan, + uint256 _minAmountOutAfterSwap, + bytes calldata _swapData + ) external; + + function exitSingleAssetLeverage( + IVToken _collateralMarket, + uint256 _collateralAmountToFlashLoan + ) external; + + function exitLeverage( + IVToken _collateralMarket, + uint256 _collateralAmountToRedeemForSwap, + IVToken _borrowedMarket, + uint256 _borrowedAmountToFlashLoan, + uint256 _minAmountOutAfterSwap, + bytes calldata _swapData + ) external; +} +``` + +### Swap API Integration + +Cross-asset operations (enterLeverage, enterLeverageFromBorrow, exitLeverage) require signed swap data from the Venus Swap API: + +1. Request a swap quote from the API with source and destination tokens +2. Receive encoded `multicall` parameters with backend signature +3. Pass the signed `_swapData` to the entry function + +## Audits + +LeverageStrategiesManager undergoes security audits before mainnet deployment. Audit reports are available in the [venus-periphery repository](https://github.com/VenusProtocol/venus-periphery/tree/main/audits). diff --git a/technical-reference/reference-periphery/swap-helper.md b/technical-reference/reference-periphery/swap-helper.md new file mode 100644 index 00000000..e4f466f4 --- /dev/null +++ b/technical-reference/reference-periphery/swap-helper.md @@ -0,0 +1,360 @@ +# SwapHelper + +The SwapHelper is a Venus periphery contract that enables secure, backend-authorized token swaps. It provides an atomic multicall interface with EIP-712 signature verification, allowing the Venus backend to authorize specific swap operations while preventing arbitrary execution. + +## Overview + +Token swaps in leverage operations require interaction with external DEX protocols. The SwapHelper provides a controlled execution environment where: + +1. **Backend Authorization**: All swap operations must be signed by the authorized backend signer +2. **Atomic Execution**: Multiple operations execute atomically via multicall +3. **Replay Protection**: Each signed payload is single-use via salt tracking +4. **Time-Bounded**: Signatures include a deadline to prevent stale quote execution + +The contract is designed to be called by the LeverageStrategiesManager during flash loan callbacks, though it can also be used independently for authorized token operations. + +## Architecture + +``` +┌─────────────────────────┐ +│ Venus Swap API │ +│ (Backend Service) │ +└───────────┬─────────────┘ + │ Signs multicall payload + ▼ +┌─────────────────────────┐ +│ Frontend / User │ +│ │ +└───────────┬─────────────┘ + │ Passes signed data to LSM + ▼ +┌─────────────────────────┐ +│ LeverageStrategiesManager│ +│ (Flash Loan Callback) │ +└───────────┬─────────────┘ + │ Calls multicall + ▼ +┌─────────────────────────┐ +│ SwapHelper │ +│ - Verifies signature │ +│ - Executes calls │ +└───────────┬─────────────┘ + │ genericCall + ▼ +┌─────────────────────────┐ +│ DEX Router │ +│ (Uniswap, 1inch, etc.) │ +└─────────────────────────┘ +``` + +## Inheritance + +- `EIP712` - EIP-712 typed data hashing for signature verification +- `Ownable` - Access control for admin functions +- `ReentrancyGuard` - Reentrancy protection + +## State Variables + +| Variable | Type | Description | +| --------------- | -------------------------- | ----------------------------------------------- | +| `backendSigner` | `address` | Address authorized to sign multicall operations | +| `usedSalts` | `mapping(bytes32 => bool)` | Tracks used salts for replay protection | + +## Constants + +```solidity +bytes32 internal constant MULTICALL_TYPEHASH = + keccak256("Multicall(bytes[] calls,uint256 deadline,bytes32 salt)"); +``` + +# Solidity API + +### multicall + +Executes multiple calls atomically with backend signature verification. + +```solidity +function multicall( + bytes[] calldata calls, + uint256 deadline, + bytes32 salt, + bytes calldata signature +) external nonReentrant +``` + +#### Parameters + +| Name | Type | Description | +| --------- | ------- | -------------------------------------------------------------- | +| calls | bytes[] | Array of encoded function calls to execute on this contract | +| deadline | uint256 | Unix timestamp after which the transaction will revert | +| salt | bytes32 | Unique value ensuring this multicall can only be executed once | +| signature | bytes | EIP-712 signature from the backend signer | + +#### Execution Flow + +1. Validate `calls` array is not empty +2. Check `block.timestamp <= deadline` +3. Verify signature is provided +4. Check salt has not been used +5. Mark salt as used +6. Recover signer from EIP-712 digest and verify against `backendSigner` +7. Execute each call atomically +8. Emit `MulticallExecuted` event + +#### Typical Call Structure + +A multicall for a swap operation typically contains: + +```solidity +calls = [ + abi.encodeCall(SwapHelper.approveMax, (tokenIn, dexRouter)), + abi.encodeCall(SwapHelper.genericCall, (dexRouter, swapCalldata)), + abi.encodeCall(SwapHelper.sweep, (tokenOut, recipient)) +] +``` + +#### Events + +- `MulticallExecuted(caller, callsCount, deadline, salt)` on success + +#### Errors + +- `NoCallsProvided` if calls array is empty +- `DeadlineReached` if `block.timestamp > deadline` +- `MissingSignature` if signature length is zero +- `SaltAlreadyUsed` if salt has been used before +- `Unauthorized` if recovered signer does not match `backendSigner` + +--- + +### genericCall + +Executes an arbitrary call to an external contract. Only callable via multicall or by the owner. + +```solidity +function genericCall(address target, bytes calldata data) external onlyOwnerOrSelf +``` + +#### Parameters + +| Name | Type | Description | +| ------ | ------- | ------------------------------- | +| target | address | Address of the contract to call | +| data | bytes | Encoded function call data | + +#### Events + +- `GenericCallExecuted(target, data)` on success + +#### Access Requirements + +- Only callable by owner or contract itself (via multicall) + +#### Errors + +- `CallerNotAuthorized` if caller is not owner or contract itself + +--- + +### sweep + +Transfers the entire balance of an ERC-20 token to a specified recipient. + +```solidity +function sweep(IERC20Upgradeable token, address to) external onlyOwnerOrSelf +``` + +#### Parameters + +| Name | Type | Description | +| ----- | ----------------- | -------------------------------------- | +| token | IERC20Upgradeable | ERC-20 token contract to sweep | +| to | address | Recipient address for the swept tokens | + +#### Events + +- `Swept(token, to, amount)` on execution (emits even if amount is 0) + +#### Access Requirements + +- Only callable by owner or contract itself (via multicall) + +#### Errors + +- `CallerNotAuthorized` if caller is not authorized + +--- + +### approveMax + +Grants maximum approval of an ERC-20 token to a spender. + +```solidity +function approveMax(IERC20Upgradeable token, address spender) external onlyOwnerOrSelf +``` + +#### Parameters + +| Name | Type | Description | +| ------- | ----------------- | -------------------------------- | +| token | IERC20Upgradeable | ERC-20 token contract to approve | +| spender | address | Address to grant approval to | + +#### Events + +- `ApprovedMax(token, spender)` on success + +#### Access Requirements + +- Only callable by owner or contract itself (via multicall) + +#### Errors + +- `CallerNotAuthorized` if caller is not authorized + +--- + +### setBackendSigner + +Updates the authorized backend signer address. + +```solidity +function setBackendSigner(address newSigner) external onlyOwner +``` + +#### Parameters + +| Name | Type | Description | +| --------- | ------- | -------------------------- | +| newSigner | address | New backend signer address | + +#### Events + +- `BackendSignerUpdated(oldSigner, newSigner)` on success + +#### Access Requirements + +- Only callable by contract owner + +#### Errors + +- `ZeroAddress` if newSigner is address(0) + +## Events + +| Event | Parameters | Description | +| ---------------------- | ---------------------------------- | ---------------------------------- | +| `BackendSignerUpdated` | oldSigner, newSigner | Backend signer address changed | +| `MulticallExecuted` | caller, callsCount, deadline, salt | Multicall successfully executed | +| `Swept` | token, to, amount | Tokens transferred out of contract | +| `ApprovedMax` | token, spender | Maximum approval granted | +| `GenericCallExecuted` | target, data | External call executed | + +## Custom Errors + +| Error | Description | +| --------------------- | ---------------------------------------------- | +| `DeadlineReached` | Transaction deadline has passed | +| `Unauthorized` | Signature verification failed | +| `ZeroAddress` | Zero address provided as parameter | +| `SaltAlreadyUsed` | Salt has already been used (replay protection) | +| `CallerNotAuthorized` | Caller is not owner or contract itself | +| `NoCallsProvided` | Empty calls array in multicall | +| `MissingSignature` | Signature is required but empty | + +## Security Considerations + +### Signature Verification + +All multicall operations require a valid EIP-712 signature from the `backendSigner`. The signature covers: + +- The encoded calls array +- The deadline timestamp +- A unique salt + +This prevents: + +- Unauthorized swap execution +- Replay attacks (via salt tracking) +- Stale quote execution (via deadline) + +### Access Control + +Functions that interact with external contracts (`genericCall`, `sweep`, `approveMax`) are protected by `onlyOwnerOrSelf`: + +- Direct calls require owner privileges +- Calls within `multicall` are authorized via backend signature + +### Reentrancy Protection + +The `multicall` function is protected by OpenZeppelin's `nonReentrant` modifier, preventing reentrant calls during execution. + +### EIP-712 Domain + +The contract initializes with: + +- Name: `"VenusSwap"` +- Version: `"1"` + +This domain separation ensures signatures are specific to this contract and version. + +## Deployment + +SwapHelper is currently deployed on BNB Chain Mainnet. See [Deployed Contracts](../deployed-contracts/periphery.md) for current addresses. + +Deployments on additional networks are planned. The contract is designed to be deployed on any EVM-compatible network where Venus Protocol operates. + +## Integration + +### With LeverageStrategiesManager + +The SwapHelper is the designated swap executor for the LeverageStrategiesManager. During leverage operations: + +1. Frontend obtains signed `swapData` from Venus Swap API +2. User calls LeverageStrategiesManager entry function with `swapData` +3. LSM transfers tokens to SwapHelper during flash loan callback +4. LSM calls `swapHelper.call(swapData)` which invokes `multicall` +5. SwapHelper executes the swap and sweeps output tokens back to LSM +6. LSM validates received amount against slippage protection + +### For Developers + +SwapHelper exposes a clear interface for integration: + +```solidity +interface ISwapHelper { + function multicall( + bytes[] calldata calls, + uint256 deadline, + bytes32 salt, + bytes calldata signature + ) external; + + function genericCall(address target, bytes calldata data) external; + + function sweep(IERC20Upgradeable token, address to) external; + + function approveMax(IERC20Upgradeable token, address spender) external; + + function setBackendSigner(address newSigner) external; +} +``` + +### Swap API Request + +When integrating with the Venus Swap API, include: + +| Parameter | Description | +| ----------- | --------------------------------- | +| `tokenIn` | Source token address | +| `tokenOut` | Destination token address | +| `amountIn` | Exact input amount | +| `recipient` | LeverageStrategiesManager address | +| `deadline` | Unix timestamp for expiry | + +The API returns encoded `multicall` parameters with the backend signature. + +## Audits + +SwapHelper undergoes security audits before mainnet deployment. Audit reports are available in the [venus-periphery repository](https://github.com/VenusProtocol/venus-periphery/tree/main/audits). From 4d0f2b8b4f88b29356f450faffc60c9ad1c0a265 Mon Sep 17 00:00:00 2001 From: Filip Malachowicz Date: Thu, 11 Dec 2025 11:24:48 +0100 Subject: [PATCH 2/3] fix: update docs to up to date addreses --- deployed-contracts/periphery.md | 4 +-- .../reference-periphery/swap-helper.md | 25 ++++++++++++++++--- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/deployed-contracts/periphery.md b/deployed-contracts/periphery.md index fa6e6c96..d712992e 100644 --- a/deployed-contracts/periphery.md +++ b/deployed-contracts/periphery.md @@ -2,5 +2,5 @@ ## BNB Chain Mainnet -- SwapHelper: [`0xe1a3b4189F56Cf38747BE79348b8664Ef18cCFd1`](https://bscscan.com/address/0xe1a3b4189F56Cf38747BE79348b8664Ef18cCFd1) -- LeverageStrategiesManager: [`0x51438311922e88AEDF0B111944dD601DCB3c4BF9`](https://bscscan.com/address/0x51438311922e88AEDF0B111944dD601DCB3c4BF9) +- SwapHelper: [`0xD79be25aEe798Aa34A9Ba1230003d7499be29A24`](https://bscscan.com/address/0xD79be25aEe798Aa34A9Ba1230003d7499be29A24) +- LeverageStrategiesManager: [`0x03F079E809185a669Ca188676D0ADb09cbAd6dC1`](https://bscscan.com/address/0x03F079E809185a669Ca188676D0ADb09cbAd6dC1) diff --git a/technical-reference/reference-periphery/swap-helper.md b/technical-reference/reference-periphery/swap-helper.md index e4f466f4..a6491438 100644 --- a/technical-reference/reference-periphery/swap-helper.md +++ b/technical-reference/reference-periphery/swap-helper.md @@ -64,7 +64,7 @@ The contract is designed to be called by the LeverageStrategiesManager during fl ```solidity bytes32 internal constant MULTICALL_TYPEHASH = - keccak256("Multicall(bytes[] calls,uint256 deadline,bytes32 salt)"); + keccak256("Multicall(address caller,bytes[] calls,uint256 deadline,bytes32 salt)"); ``` # Solidity API @@ -98,7 +98,7 @@ function multicall( 3. Verify signature is provided 4. Check salt has not been used 5. Mark salt as used -6. Recover signer from EIP-712 digest and verify against `backendSigner` +6. Recover signer from EIP-712 digest (including caller address) and verify against `backendSigner` 7. Execute each call atomically 8. Emit `MulticallExecuted` event @@ -269,6 +269,7 @@ function setBackendSigner(address newSigner) external onlyOwner All multicall operations require a valid EIP-712 signature from the `backendSigner`. The signature covers: +- The caller address (prevents cross-address replay) - The encoded calls array - The deadline timestamp - A unique salt @@ -276,6 +277,7 @@ All multicall operations require a valid EIP-712 signature from the `backendSign This prevents: - Unauthorized swap execution +- Cross-address signature replay attacks - Replay attacks (via salt tracking) - Stale quote execution (via deadline) @@ -341,6 +343,22 @@ interface ISwapHelper { } ``` +#### Signature Generation + +When generating signatures for the `multicall` function, the backend must include the caller address in the EIP-712 digest: + +```solidity +bytes32 digest = keccak256(abi.encode( + MULTICALL_TYPEHASH, + callerAddress, // Address that will call multicall + keccak256(abi.encodePacked(callHashes)), + deadline, + salt +)); +``` + +This ensures signatures are specific to the address calling `multicall` and cannot be replayed from a different address. + ### Swap API Request When integrating with the Venus Swap API, include: @@ -352,8 +370,9 @@ When integrating with the Venus Swap API, include: | `amountIn` | Exact input amount | | `recipient` | LeverageStrategiesManager address | | `deadline` | Unix timestamp for expiry | +| `caller` | Address that will call multicall | -The API returns encoded `multicall` parameters with the backend signature. +The API returns encoded `multicall` parameters with the backend signature that includes the caller address. ## Audits From ae341531e9de9e5f2105fc5881a38ff2b017ad9f Mon Sep 17 00:00:00 2001 From: Filip Malachowicz Date: Fri, 19 Dec 2025 18:08:21 +0200 Subject: [PATCH 3/3] fix: remove integration section --- technical-reference/reference-periphery/README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/technical-reference/reference-periphery/README.md b/technical-reference/reference-periphery/README.md index d97e1185..0edca5ab 100644 --- a/technical-reference/reference-periphery/README.md +++ b/technical-reference/reference-periphery/README.md @@ -20,9 +20,3 @@ The Venus periphery consists of specialized smart contracts designed to streamli ## Deployment Periphery contracts are currently deployed on BNB Chain Mainnet. See [Deployed Contracts](../../deployed-contracts/periphery.md) for addresses and deployment information. - -## Integration - -For users looking to leverage their positions or perform advanced trading strategies, start with the [Leverage Positions Guide](../../guides/leverage-positions.md). - -Developers integrating with periphery contracts should review the detailed API documentation in the individual contract pages.