SwapHelper
SwapHelper
Section titled “SwapHelper”The SwapHelper is a Venus periphery contract for backend-authorized token operations. It provides an atomic multicall interface with EIP-712 signature verification, allowing the configured backend signer to authorize a specific batch of approvals, arbitrary external calls, and token sweeps.
Version scope: This API reference follows the standalone
SwapHelperinvenus-peripheryv1.2.0. It is not a proxy. Its current owner, pending owner, backend signer, EIP-712 domain/address, and consuming manager/router versions are live trust inputs that must be checked before use.
Overview
Section titled “Overview”Token swaps in leverage operations require interaction with external DEX protocols. The SwapHelper provides a controlled execution environment where:
- Backend Authorization: All swap operations must be signed by the authorized backend signer
- Atomic Execution: Multiple operations execute atomically via multicall
- Replay Protection: Each signed payload is single-use via salt tracking
- 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
Section titled “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
Section titled “Inheritance”EIP712- EIP-712 typed data hashing for signature verificationOwnable2Step- Two-step ownership transfer and owner access for admin functionsReentrancyGuard- Reentrancy protection
State Variables
Section titled “State Variables”| Variable | Type | Description |
|---|---|---|
backendSigner | address | Address authorized to sign multicall operations |
usedSalts | mapping(bytes32 => bool) | Tracks used salts for replay protection |
Constants
Section titled “Constants”bytes32 internal constant MULTICALL_TYPEHASH = keccak256("Multicall(address caller,bytes[] calls,uint256 deadline,bytes32 salt)");Solidity API
Section titled “Solidity API”multicall
Section titled “multicall”Executes multiple calls atomically with backend signature verification.
function multicall( bytes[] calldata calls, uint256 deadline, bytes32 salt, bytes calldata signature) external nonReentrantParameters
Section titled “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
Section titled “Execution Flow”- Validate
callsarray is not empty - Check
block.timestamp <= deadline - Verify signature is provided
- Check salt has not been used
- Mark salt as used
- Recover signer from EIP-712 digest (including caller address) and verify against
backendSigner - Execute each call atomically
- Emit
MulticallExecutedevent
Typical Call Structure
Section titled “Typical Call Structure”A multicall for a swap operation typically contains:
calls = [ abi.encodeCall(SwapHelper.approveMax, (tokenIn, dexRouter)), abi.encodeCall(SwapHelper.genericCall, (dexRouter, swapCalldata)), abi.encodeCall(SwapHelper.sweep, (tokenOut, recipient))]Events
Section titled “Events”MulticallExecuted(caller, callsCount, deadline, salt)on success
Errors
Section titled “Errors”NoCallsProvidedif calls array is emptyDeadlineReachedifblock.timestamp > deadlineMissingSignatureif signature length is zeroSaltAlreadyUsedif salt has been used beforeUnauthorizedif recovered signer does not matchbackendSigner
genericCall
Section titled “genericCall”Executes an arbitrary call to an external contract. Only callable via multicall or by the owner.
function genericCall(address target, bytes calldata data) external onlyOwnerOrSelfParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
| target | address | Address of the contract to call |
| data | bytes | Encoded function call data |
Events
Section titled “Events”GenericCallExecuted(target, data)on success
Access Requirements
Section titled “Access Requirements”- Only callable by owner or contract itself (via multicall)
Errors
Section titled “Errors”CallerNotAuthorizedif caller is not owner or contract itself
Transfers the entire balance of an ERC-20 token to a specified recipient.
function sweep(IERC20Upgradeable token, address to) external onlyOwnerOrSelfParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
| token | IERC20Upgradeable | ERC-20 token contract to sweep |
| to | address | Recipient address for the swept tokens |
Events
Section titled “Events”Swept(token, to, amount)on execution (emits even if amount is 0)
Access Requirements
Section titled “Access Requirements”- Only callable by owner or contract itself (via multicall)
Errors
Section titled “Errors”CallerNotAuthorizedif caller is not authorized
approveMax
Section titled “approveMax”Grants maximum approval of an ERC-20 token to a spender.
function approveMax(IERC20Upgradeable token, address spender) external onlyOwnerOrSelfParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
| token | IERC20Upgradeable | ERC-20 token contract to approve |
| spender | address | Address to grant approval to |
Events
Section titled “Events”ApprovedMax(token, spender)on success
Access Requirements
Section titled “Access Requirements”- Only callable by owner or contract itself (via multicall)
Errors
Section titled “Errors”CallerNotAuthorizedif caller is not authorized
setBackendSigner
Section titled “setBackendSigner”Updates the authorized backend signer address.
function setBackendSigner(address newSigner) external onlyOwnerParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
| newSigner | address | New backend signer address |
Events
Section titled “Events”BackendSignerUpdated(oldSigner, newSigner)on success
Access Requirements
Section titled “Access Requirements”- Only callable by contract owner
Errors
Section titled “Errors”ZeroAddressif newSigner is address(0)
Events
Section titled “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
Section titled “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
Section titled “Security Considerations”Signature Verification
Section titled “Signature Verification”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
Assuming the backend signer and owner remain trusted, these checks prevent:
- Unauthorized swap execution
- Cross-address signature replay attacks
- Replay attacks (via salt tracking)
- Stale quote execution (via deadline)
They do not constrain what a valid signed batch may call. The signer can authorize approveMax, genericCall, and sweep, and the owner can call those functions directly. Integrations must validate the complete encoded call list and output conditions, not only the signature and deadline.
Access Control
Section titled “Access Control”Functions that interact with external contracts (genericCall, sweep, approveMax) are protected by onlyOwnerOrSelf:
- Direct calls require owner privileges
- Calls within
multicallare authorized via backend signature
approveMax grants an unlimited allowance and sweep transfers the helper’s full balance of the selected token. End users should not approve SwapHelper or leave tokens in it; callers such as LeverageStrategiesManager should transfer only the amount needed for an atomic operation and validate the returned output.
Reentrancy Protection
Section titled “Reentrancy Protection”The multicall function is protected by OpenZeppelin’s nonReentrant modifier, preventing reentrant calls during execution.
EIP-712 Domain
Section titled “EIP-712 Domain”The contract initializes with:
- Name:
"VenusSwap" - Version:
"1"
This domain separation ensures signatures are specific to this contract and version.
Deployment
Section titled “Deployment”SwapHelper is currently published for BNB Chain Mainnet and testnet. See Deployed Contracts for current addresses. Source portability does not establish a deployment on another network.
Integration
Section titled “Integration”With LeverageStrategiesManager
Section titled “With LeverageStrategiesManager”The SwapHelper is the designated swap executor for the LeverageStrategiesManager. During leverage operations:
- Frontend obtains signed
swapDatafrom Venus Swap API - User calls LeverageStrategiesManager entry function with
swapData - LSM transfers tokens to SwapHelper during flash loan callback
- LSM calls
swapHelper.call(swapData)which invokesmulticall - SwapHelper executes the swap and sweeps output tokens back to LSM
- LSM validates received amount against slippage protection
For Developers
Section titled “For Developers”SwapHelper exposes a clear interface for integration:
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;}Signature Generation
Section titled “Signature Generation”When generating signatures for the multicall function, the backend must include the caller address in the EIP-712 digest:
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
Section titled “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 |
caller | Address that will call multicall |
The API returns encoded multicall parameters with the backend signature that includes the caller address.
Audits
Section titled “Audits”Published SwapHelper audit reports are indexed in the venus-periphery v1.2.0 release. Check each report’s scope and reviewed commit against the deployed standalone bytecode.