in this contract // SPDX-License-Identifier: SYMM-Core-Business-Source-License-1.1
// This contract is licensed under the SYMM Core Business Source License 1.1
// Copyright © 2023 Symmetry Labs AG
// For more information, see https://docs.symm.io/legal-disclaimer/license
pragma solidity ^0.8.20;

import “@openzeppelin/contracts-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol”;
import “@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol”;
import “@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol”;
import “@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol”;
import “@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol”;
import “./SolverVaultToken.sol”;
import “./interfaces/ISymmio.sol”;

contract SolverVault is
Initializable,
AccessControlEnumerableUpgradeable,
PausableUpgradeable
{
// Use SafeERC20 for safer token transfers
using SafeERC20 for IERC20;

bytes32 public constant DEPOSITOR_ROLE = keccak256(“DEPOSITOR_ROLE”);
bytes32 public constant BALANCER_ROLE = keccak256(“BALANCER_ROLE”);
bytes32 public constant SETTER_ROLE = keccak256(“SETTER_ROLE”);
bytes32 public constant PAUSER_ROLE = keccak256(“PAUSER_ROLE”);
bytes32 public constant UNPAUSER_ROLE = keccak256(“UNPAUSER_ROLE”);

struct WithdrawRequest {
address receiver;
uint256 amount;
RequestStatus status;
uint256 acceptedRatio;
}

enum RequestStatus {
Pending,
Ready,
Done
}

event Deposit(address indexed depositor, uint256 amount);
event DepositToSymmio(
address indexed depositor,
address indexed solver,
uint256 amount
);
event WithdrawRequestEvent(
uint256 indexed requestId,
address indexed receiver,
uint256 amount
);
event WithdrawRequestAcceptedEvent(
uint256 providedAmount,
uint256[] acceptedRequestIds,
uint256 paybackRatio
);
event WithdrawClaimedEvent(
uint256 indexed requestId,
address indexed receiver
);
event SymmioAddressUpdatedEvent(address indexed newSymmioAddress);
event SolverUpdatedEvent(address indexed solver);
event DepositLimitUpdatedEvent(uint256 value);

ISymmio public symmio;
address public collateralTokenAddress;
address public solverVaultTokenAddress;
address public solver;

WithdrawRequest[] public withdrawRequests;
uint256 public lockedBalance;
uint256 public minimumPaybackRatio;
uint256 public depositLimit;
uint256 public currentDeposit;

uint256 public collateralTokenDecimals;
uint256 public solverVaultTokenDecimals;

function initialize(
address _symmioAddress,
address _symmioVaultTokenAddress,
address _solver,
uint256 _minimumPaybackRatio,
uint256 _depositLimit
) public initializer {
__AccessControl_init();
__Pausable_init();

require(_minimumPaybackRatio <= 1e18, “SolverVault: Invalid ratio”);

_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(DEPOSITOR_ROLE, msg.sender);
_grantRole(BALANCER_ROLE, msg.sender);
_grantRole(SETTER_ROLE, msg.sender);
_grantRole(PAUSER_ROLE, msg.sender);
_grantRole(UNPAUSER_ROLE, msg.sender);
setSymmioAddress(_symmioAddress);
setSymmioVaultTokenAddress(_symmioVaultTokenAddress);
setDepositLimit(_depositLimit);
setSolver(_solver);
lockedBalance = 0;
currentDeposit = 0;
minimumPaybackRatio = _minimumPaybackRatio;
}

function setSymmioAddress(
address _symmioAddress
) public onlyRole(SETTER_ROLE) {
require(_symmioAddress != address(0), “SolverVault: Zero address”);
symmio = ISymmio(_symmioAddress);
address beforeCollateral = collateralTokenAddress;
updateCollateral();
require(
beforeCollateral == collateralTokenAddress ||
beforeCollateral == address(0),
“SolverVault: Collateral can not be changed”
);
emit SymmioAddressUpdatedEvent(_symmioAddress);
}

function setSolver(address _solver) public onlyRole(SETTER_ROLE) {
require(_solver != address(0), “SolverVault: Zero address”);
solver = _solver;
emit SolverUpdatedEvent(_solver);
}

function updateCollateral() internal {
collateralTokenAddress = symmio.getCollateral();
collateralTokenDecimals = IERC20Metadata(collateralTokenAddress)
.decimals();
require(
collateralTokenDecimals <= 18,
“SolverVault: Collateral decimals should be lower than 18”
);
}

function setSymmioVaultTokenAddress(
address _symmioVaultTokenAddress
) internal {
require(_symmioVaultTokenAddress != address(0), “SolverVault: Zero address”);
solverVaultTokenAddress = _symmioVaultTokenAddress;
solverVaultTokenDecimals = SolverVaultToken(_symmioVaultTokenAddress)
.decimals();
require(
solverVaultTokenDecimals <= 18,
“SolverVault: SolverVaultToken decimals should be lower than 18”
);
}

function setDepositLimit(
uint256 _depositLimit
) public onlyRole(SETTER_ROLE) {
depositLimit = _depositLimit;
emit DepositLimitUpdatedEvent(_depositLimit);
}

function deposit(uint256 amount) external whenNotPaused {
require(
currentDeposit + amount <= depositLimit,
“SolverVault: Deposit limit reached”
);
IERC20(collateralTokenAddress).safeTransferFrom(
msg.sender,
address(this),
amount
);
uint256 amountInSolverVaultTokenDecimals = solverVaultTokenDecimals >=
collateralTokenDecimals
? amount *
(10 ** (solverVaultTokenDecimals - collateralTokenDecimals))
: amount /
(10 ** (collateralTokenDecimals - solverVaultTokenDecimals));

SolverVaultToken(solverVaultTokenAddress).mint(
msg.sender,
amountInSolverVaultTokenDecimals
);
currentDeposit += amount;
emit Deposit(msg.sender, amount);
}

function depositToSymmio(
uint256 amount
) external onlyRole(DEPOSITOR_ROLE) whenNotPaused {
uint256 contractBalance = IERC20(collateralTokenAddress).balanceOf(
address(this)
);
require(
contractBalance - lockedBalance >= amount,
“SolverVault: Insufficient contract balance”
);
require(
IERC20(collateralTokenAddress).approve(address(symmio), amount),
“SolverVault: Approve failed”
);
symmio.depositFor(solver, amount);
emit DepositToSymmio(msg.sender, solver, amount);
}

function requestWithdraw(
uint256 amount,
address receiver
) external whenNotPaused {
require(
SolverVaultToken(solverVaultTokenAddress).balanceOf(msg.sender) >=
amount,
“SolverVault: Insufficient token balance”
);
SolverVaultToken(solverVaultTokenAddress).burnFrom(msg.sender, amount);

uint256 amountInCollateralDecimals = collateralTokenDecimals >=
solverVaultTokenDecimals
? amount *
(10 ** (collateralTokenDecimals - solverVaultTokenDecimals))
: amount /
(10 ** (solverVaultTokenDecimals - collateralTokenDecimals));

currentDeposit -= amountInCollateralDecimals;

withdrawRequests.push(
WithdrawRequest({
receiver: receiver,
amount: amountInCollateralDecimals,
status: RequestStatus.Pending,
acceptedRatio: 0
})
);
emit WithdrawRequestEvent(
withdrawRequests.length - 1,
receiver,
amountInCollateralDecimals
);
}

function acceptWithdrawRequest(
uint256 providedAmount,
uint256[] memory _acceptedRequestIds,
uint256 _paybackRatio
) external onlyRole(BALANCER_ROLE) whenNotPaused {
IERC20(collateralTokenAddress).safeTransferFrom(
msg.sender,
address(this),
providedAmount
);
require(
_paybackRatio >= minimumPaybackRatio,
“SolverVault: Payback ratio is too low”
);
uint256 totalRequiredBalance = lockedBalance;

for (uint256 i = 0; i < _acceptedRequestIds.length; i++) {
uint256 id = _acceptedRequestIds[i];
require(
id < withdrawRequests.length,
“SolverVault: Invalid request ID”
);
require(
withdrawRequests[id].status == RequestStatus.Pending,
“SolverVault: Invalid accepted request”
);
totalRequiredBalance +=
(withdrawRequests[id].amount * _paybackRatio) /
1e18;
withdrawRequests[id].status = RequestStatus.Ready;
withdrawRequests[id].acceptedRatio = _paybackRatio;
}

require(
IERC20(collateralTokenAddress).balanceOf(address(this)) >=
totalRequiredBalance,
“SolverVault: Insufficient contract balance”
);
lockedBalance = totalRequiredBalance;
emit WithdrawRequestAcceptedEvent(
providedAmount,
_acceptedRequestIds,
_paybackRatio
);
}

function claimForWithdrawRequest(uint256 requestId) external whenNotPaused {
require(
requestId < withdrawRequests.length,
“SolverVault: Invalid request ID”
);
WithdrawRequest storage request = withdrawRequests[requestId];

require(
request.status == RequestStatus.Ready,
“SolverVault: Request not ready for withdrawal”
);

request.status = RequestStatus.Done;
uint256 amount = (request.amount * request.acceptedRatio) / 1e18;
lockedBalance -= amount;
IERC20(collateralTokenAddress).safeTransfer(request.receiver, amount);
emit WithdrawClaimedEvent(requestId, request.receiver);
}

function pause() external onlyRole(PAUSER_ROLE) {
_pause();
}

function unpause() external onlyRole(UNPAUSER_ROLE) {
_unpause();
}
} What would you say are the key components of this system to find vulnerbailites