all files / contracts/ Bridge.sol

100% Statements 21/21
80% Branches 24/30
100% Functions 8/8
100% Lines 44/44
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130                                                                                                                                                                           
// SPDX-License-Identifier: MIT
pragma solidity =0.8.20;
 
import "@openzeppelin/contracts/access/Ownable.sol";
import "./AbstractDAO.sol";
 
contract Bridge is AbstractDAO {
    event Unwrapped(
        address indexed receiver,
        uint256 indexed value,
        uint256 indexed nonce
    );
    event FundsReceived(
        address indexed recipient,
        uint256 indexed value,
        uint256 indexed nonce
    );
 
    address public _feeRecipient;
    mapping(uint256 => bool) private _withdrawalNonces;
 
    uint256 private _feeIn;
    uint256 private _feeOut;
    uint256 private _nonce;
 
    bool internal locked;
 
    constructor(
        uint256 feeIn,
        uint256 feeOut,
        uint256 thresholdLevel
    ) Ownable(msg.sender) {
        _feeIn = feeIn;
        _feeOut = feeOut;
        _thresholdLevel = thresholdLevel;
        _threshold = thresholdLevel;
        _nonce = 0;
        _queueOrder = 1;
        _votesSent = 0;
        _votingInProgress = 0;
        _bps = 6666;
        _requiredVoteThreshold = 2 * _bps;
        _authorizedAddressesCount = 2;
        _feeRecipient = owner();
        _operator = owner();
    }
 
    modifier nonReentrant() {
        Erequire(!locked, "cannot reenter");
        locked = true;
        _;
        locked = false;
    }
 
    receive() external payable {
        deposit(msg.sender);
    }
 
    function feeUnwrap() external view returns (uint256) {
        return _feeOut;
    }
 
    function feeWrap() external view returns (uint256) {
        return _feeIn;
    }
 
    function deposit(address onBehalf) public payable EnonReentrant {
        require(
            msg.value > _feeIn,
            "Cannot process value lower or equal to fee"
        );
        address feeRecipient = payable(_feeRecipient);
 
        (bool sent,) = feeRecipient.call{value: _feeIn}("");
        Erequire(sent, "Failed to process fee");
 
        emit FundsReceived(onBehalf, msg.value - _feeIn, _nonce++);
    }
 
    function setFees(uint256 authorizedIndex, uint256 newFeeIn, uint256 newFeeOut) external {
        require(
            msg.sender == _authorizedAddresses[authorizedIndex],
            "Must be sent from authorized sender"
        );
        _feeIn = newFeeIn;
        _feeOut = newFeeOut;
    }
 
    function setFeeRecipient(uint256 authorizedIndex, address __feeRecipient) external {
        require(
            __feeRecipient != address(0),
            "Must not be null address"
        );
        require(
            msg.sender == _authorizedAddresses[authorizedIndex],
            "Must be sent from authorized sender"
        );
        require(
            _feeRecipient != __feeRecipient,
            "This withdrawer is already set"
        );
        _feeRecipient = __feeRecipient;
    }
 
    function withdraw(
        address recipient,
        uint256 value,
        uint256 burnNonce
    ) external EnonReentrant {
        require(!_withdrawalNonces[burnNonce], "Nonce already used");
        require(
            msg.sender == _operator,
            "Must be sent from operator address"
        );
        require(value > _feeOut, "Cannot process value lower or equal to fee");
        require(_threshold >= value, "Value exceeds the threshold");
        _withdrawalNonces[burnNonce] = true;
        address feeRecipient = payable(_feeRecipient);
        _threshold -= value;
 
        (bool sent,) = feeRecipient.call{value: _feeOut}("");
        Erequire(sent, "Failed to process fee");
 
        (sent,) = recipient.call{value: value - _feeOut}("");
        Erequire(sent, "Failed to process withdrawal");
 
        emit Unwrapped(recipient, value, burnNonce);
    }
}