Forkchoice Ethereum Mainnet

Address Contract Partially Verified

Address 0x3Ae884D1a67650501278001FDa40DCa975D9194D
Balance 0 ETH
Nonce 1
Code Size 4630 bytes
Indexed Transactions 0 (1 on-chain, 1.5% indexed)
External Etherscan · Sourcify

Contract Bytecode

4630 bytes
Copy Bytecode
0x60806040526004361015610011575f80fd5b5f3560e01c80634ccb7382146100ef578063576aaf88146100ea578063747edcef146100e55780637b103999146100e05780638321928d146100db5780638980f11f146100d65780638da5cb5b146100b35780639265a7d5146100d1578063969d98aa146100cc578063be338bc6146100c7578063cf33d032146100c2578063e4cedf4b146100bd578063ebfa72f8146100b85763f2f4eb26146100b3575f80fd5b610385565b61075f565b61073b565b6106a1565b61062b565b61052c565b6103c9565b6102e2565b6102b4565b610286565b61021d565b610121565b3461011d575f36600319011261011d5760206040517357ab1e0003f623289cd798b1824be09a793e4bec8152f35b5f80fd5b3461011d575f36600319011261011d57602060ff600254166040519015158152f35b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff82111761017957604052565b610143565b67ffffffffffffffff81116101795760051b60200190565b6001600160a01b0381160361011d57565b604435906101b482610196565b565b9080601f8301121561011d5781356101cd8161017e565b926101db6040519485610157565b81845260208085019260051b82010192831161011d57602001905b8282106102035750505090565b60208091833561021281610196565b8152019101906101f6565b3461011d57602036600319011261011d5760043567ffffffffffffffff811161011d57604061025a61025560209336906004016101b6565b6108b9565b815192839181835280519182918282860152018484015e5f828201840152601f01601f19168101030190f35b3461011d575f36600319011261011d5760206040517310101010e0c3171d894b71b3400668af311e7d948152f35b3461011d575f36600319011261011d57602060405173cf5540fffcdc3d510b18bfca6d2b9987b07725598152f35b3461011d57604036600319011261011d5761038361036760043561030581610196565b61037560243561033f337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614610999565b60405163a9059cbb60e01b602082015233602482015260448101919091529283906064820190565b03601f198101845283610157565b6001600160a01b03166111b1565b005b3461011d575f36600319011261011d576040517f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b03168152602090f35b3461011d575f36600319011261011d5761040d337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614610999565b61041f600160ff196002541617600255565b60405163303db68b60e11b81525f816004817310101010e0c3171d894b71b3400668af311e7d945afa9081156104fd575f9161050a575b505f5b81518110156105025780602061049361048761048761047a600496886107eb565b516001600160a01b031690565b6001600160a01b031690565b60405163d8dfeb4560e01b815293849182905afa9182156104fd576001926104c9915f916104cf575b50838060a01b0316610e2e565b01610459565b6104f0915060203d81116104f6575b6104e88183610157565b810190610a5c565b5f6104bc565b503d6104de565b610a51565b610383610f0d565b61052691503d805f833e61051e8183610157565b8101906109cd565b5f610456565b3461011d57608036600319011261011d57610548600435610196565b60443567ffffffffffffffff811161011d576105689036906004016101b6565b610573606435610196565b60025f541461061c575f61058b8192600283556108b9565b6020815191018273cf5540fffcdc3d510b18bfca6d2b9987b07725595af13d15610617573d6105b981610643565b906105c76040519283610157565b81525f60203d92013e5b156105df5761038360015f55565b60405162461bcd60e51b815260206004820152601060248201526f13d91bdcc81cddd85c0819985a5b195960821b6044820152606490fd5b6105d1565b633ee5aeb560e01b5f5260045ffd5b3461011d575f36600319011261011d57610383610a74565b67ffffffffffffffff811161017957601f01601f191660200190565b60206040818301928281528451809452019201905f5b8181106106825750505090565b82516001600160a01b0316845260209384019390920191600101610675565b3461011d57606036600319011261011d5760043567ffffffffffffffff811161011d573660238201121561011d578060040135906106de82610643565b6106eb6040519182610157565b828152366024848401011161011d575f60208461073795602461072b9601838601378301015260243561071d81610196565b6107256101a7565b91610c31565b6040519182918261065f565b0390f35b3461011d575f36600319011261011d576020610755610d8b565b6040519015158152f35b3461011d575f36600319011261011d576020600154604051908152f35b1561078357565b60405162461bcd60e51b815260206004820152600a60248201526908adae0e8f240e0c2e8d60b31b6044820152606490fd5b634e487b7160e01b5f52603260045260245ffd5b8051600110156107d95760400190565b6107b5565b8051156107d95760200190565b80518210156107d95760209160051b010190565b634e487b7160e01b5f52601160045260245ffd5b60011981019190821161082257565b6107ff565b5f1981019190821161082257565b9190820391821161082257565b805191908290602001825e015f815290565b6108619060149392610842565b906bffffffffffffffffffffffff199060601b1681520190565b1561088257565b60405162461bcd60e51b815260206004820152600f60248201526e098cadccee8d040dad2e6dac2e8c6d608b1b6044820152606490fd5b9060606108c88351151561077c565b6108da61048761048761047a866107c9565b926108e58151610813565b60025b81811061095d57506101b49261093e610928879461094c9461090e6109389a6014900690565b918215610954575b6109239161047a916107eb565b610df5565b6040519788936020850190610842565b90610842565b03601f198101865285610157565b83511461087b565b60149250610916565b9260019061099261097161047a87876107eb565b9161098460405193849260208401610854565b03601f198101835282610157565b93016108e8565b156109a057565b60405162461bcd60e51b815260206004820152600560248201526421636f726560d81b6044820152606490fd5b60208183031261011d5780519067ffffffffffffffff821161011d57019080601f8301121561011d578151610a018161017e565b92610a0f6040519485610157565b81845260208085019260051b82010192831161011d57602001905b828210610a375750505090565b602080918351610a4681610196565b815201910190610a2a565b6040513d5f823e3d90fd5b9081602091031261011d5751610a7181610196565b90565b610a83610a7f610d8b565b1590565b6101b45760015460405163303db68b60e11b8152915f836004817310101010e0c3171d894b71b3400668af311e7d945afa9283156104fd575f93610b47575b50905b8251811015610b4057806020610ae661048761048761047a600496896107eb565b60405163d8dfeb4560e01b815293849182905afa9182156104fd57600192610b1c915f91610b22575b50838060a01b0316611017565b01610ac5565b610b3a915060203d81116104f6576104e88183610157565b5f610b0f565b6001559050565b610b5c9193503d805f833e61051e8183610157565b915f610ac2565b906013820180921161082257565b906002820180921161082257565b906001820180921161082257565b906014820180921161082257565b90601f820180921161082257565b9190820180921161082257565b90610bc08261017e565b610bcd6040519182610157565b8281528092610bde601f199161017e565b0190602036910137565b9060148202918083046014149015171561082257565b60408051909190610c0f8382610157565b6014815291601f1901366020840137565b9081518110156107d9570160200190565b92919092805190610c4b610c4483610b63565b6014900490565b91610c81610c68610c63610c5e86610b71565b610b7f565b610bb6565b96610c72886107de565b6001600160a01b039091169052565b610c976001600160a01b038216610c72886107c9565b5f5b838110610cbb57505050506101b490610c72610cb58551610827565b856107eb565b610ce8610cc782610be8565b83610cd182610b8d565b1115610d7957610ce18185610835565b90856110d8565b6014815110610d19575b90610d13610d01600193611163565b610c72610d0d84610b71565b8b6107eb565b01610c99565b93610d2a9796929795919395610bfe565b955f5b8651811015610d675780610d54610d466001938a610c20565b516001600160f81b03191690565b5f1a610d60828b610c20565b5301610d2d565b50969792969195909450909290610cf2565b610ce181610d8681610b8d565b610835565b60ff600254161580610d9a5790565b5060015460405163303db68b60e11b81525f816004817310101010e0c3171d894b71b3400668af311e7d945afa9081156104fd575f91610ddb575b50511190565b610def91503d805f833e61051e8183610157565b5f610dd5565b9190610e19610e0382610643565b91610e116040519384610157565b808352610643565b602082019190601f19013683379260601b9052565b60405163095ea7b360e01b602080830191825273cf5540fffcdc3d510b18bfca6d2b9987b077255960248401525f604484018190529091610e72846064810161093e565b83519082865af15f51903d81610ee1575b501590505b610e90575050565b60405163095ea7b360e01b602082015273cf5540fffcdc3d510b18bfca6d2b9987b077255960248201525f60448201526101b49290610edc90610ed68160648101610984565b826111b1565b6111b1565b15159050610f015750610e886001600160a01b0383163b15155b5f610e83565b6001610e889114610efb565b60405163095ea7b360e01b602080830191825273cf5540fffcdc3d510b18bfca6d2b9987b077255960248401525f604484018190529091610f51846064810161093e565b835190827357ab1e0003f623289cd798b1824be09a793e4bec5af15f51903d81610fe0575b501590505b610f825750565b60405163095ea7b360e01b602082015273cf5540fffcdc3d510b18bfca6d2b9987b077255960248201525f60448201526101b49190610fc690818160648101610984565b7357ab1e0003f623289cd798b1824be09a793e4bec6111b1565b1515905061100b5750610f7b7357ab1e0003f623289cd798b1824be09a793e4bec3b15155b5f610f76565b6001610f7b9114611005565b60405163095ea7b360e01b602080830191825273cf5540fffcdc3d510b18bfca6d2b9987b077255960248401525f196044840152905f90610e72846064810161093e565b1561106257565b60405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606490fd5b1561109f57565b60405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606490fd5b916110ed816110e681610b9b565b101561105b565b61110383516110fc8385610ba9565b1115611098565b8061111b575050506040515f81526020810160405290565b60405192601f821692831560051b80858701019484860193010101905b8084106111505750508252601f01601f191660405290565b9092602080918551815201930190611138565b6014815103611173576014015190565b60405162461bcd60e51b81526020600482015260166024820152754368756e6b206d75737420626520323020627974657360501b6044820152606490fd5b905f602091828151910182855af115610a51575f513d61120057506001600160a01b0381163b155b6111e05750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b600114156111d956fea164736f6c634300081c000a

Verified Source Code Partial Match

Compiler: v0.8.28+commit.7893614a EVM: cancun Optimization: Yes (200 runs)
SwapperOdos.sol 150 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import { CoreOwnable } from "src/dependencies/CoreOwnable.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import { IResupplyRegistry } from "src/interfaces/IResupplyRegistry.sol";
import { IResupplyPair } from "src/interfaces/IResupplyPair.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { BytesLib } from "solidity-bytes-utils/contracts/BytesLib.sol";

contract SwapperOdos is CoreOwnable, ReentrancyGuard {
    using BytesLib for bytes;
    using SafeERC20 for IERC20;

    address public constant odosRouter = 0xCf5540fFFCdC3d510B18bFcA6d2b9987b0772559;
    address public constant registry = 0x10101010E0C3171D894B71B3400668aF311e7D94;
    address public constant reusd = 0x57aB1E0003F623289CD798B1824Be09a793e4Bec;
    uint256 public nextPairIndex;
    bool public approvalsRevoked;

    constructor(address _core) CoreOwnable(_core) {
        IERC20(reusd).forceApprove(odosRouter, type(uint256).max);
    }

    /**
     * @notice Executes a swap through Odos router using an encoded payload in the path parameter
     * @dev This function accepts bytes data encoded as an address[] for compatibility with the legacy interface in PairCore
     */
    function swap(
        address,
        uint256,
        address[] memory _path,
        address
    ) external nonReentrant {
        bytes memory payload = decode(_path);
        (bool success, bytes memory result) = odosRouter.call{value: 0}(payload);
        require(success, "Odos swap failed");
    }

    /**
     * @notice Permissionless function to update the approvals for the collateral tokens that have not yet been approved
     */
    function updateApprovals() external {
        if (!canUpdateApprovals()) return;
        uint256 _nextIndex = nextPairIndex;
        address[] memory pairs = IResupplyRegistry(registry).getAllPairAddresses();
        for (; _nextIndex < pairs.length; _nextIndex++) {
            address _pair = pairs[_nextIndex];
            address _collateral = IResupplyPair(_pair).collateral();
            IERC20(_collateral).forceApprove(odosRouter, type(uint256).max);
        }
        nextPairIndex = _nextIndex;
    }

    function revokeApprovals() external onlyOwner {
        approvalsRevoked = true;
        address[] memory pairs = IResupplyRegistry(registry).getAllPairAddresses();
        for (uint256 i = 0; i < pairs.length; i++) {
            address _pair = pairs[i];
            address _collateral = IResupplyPair(_pair).collateral();
            IERC20(_collateral).forceApprove(odosRouter, 0);
        }
        IERC20(reusd).forceApprove(odosRouter, 0);
    }

    /**
     * @notice Returns true if there are new pairs to update approvals for
     */
    function canUpdateApprovals() public view returns (bool) {
        return !approvalsRevoked && nextPairIndex < IResupplyRegistry(registry).getAllPairAddresses().length;
    }

    /**
     * @notice Encodes any-length bytes into address[] data type for transport via the interface on Resupply pairs
     * @dev This function is not gas efficient, and should only be used by off-chain calls 
            to prepare a payload for the leveragedPosition or repayWithCollateral functions in a pair.
     * @param payload The bytes payload to encode
     * @return path The encoded address[]
     */
    function encode(bytes memory payload, address _sellToken, address _buyToken) external pure returns (address[] memory path) {
        uint totalLen = payload.length;
        // determine the total number of chunks needed to store the payload
        // each chunk is 20 bytes, so we add 19 to the total length to ensure result is always rounded up
        uint chunkCount = (totalLen + 19) / 20;
        uint dataStartIndex = 2; // index 0 = sell token, index 1 = payload length
        path = new address[](chunkCount + dataStartIndex + 1);
        path[0] = _sellToken;
        path[1] = address(uint160(totalLen)); // packs into the low 20 bytes (safe)
        for (uint i = 0; i < chunkCount; i++) {
            uint offset = i * 20;
            uint end = offset + 20 > totalLen ? totalLen : offset + 20;
            bytes memory chunk = payload.slice(offset, end - offset);
            // Pad to 20 bytes if needed
            if (chunk.length < 20) {
                bytes memory padded = new bytes(20);
                for (uint j = 0; j < chunk.length; j++) {
                    padded[j] = chunk[j];
                }
                chunk = padded;
            }

            path[i + dataStartIndex] = bytesToAddress(chunk);
        }
        path[path.length - 1] = _buyToken; // final item is the buy token
    }

    /**
     * @notice Decodes an address array back into its original bytes payload
     * @dev The first address in the path contains the total length of the original payload as a uint96
     * @dev Each subsequent address contains 20 bytes of the original payload
     * @param path The address array containing the encoded payload
     * @return payload The decoded bytes payload
     */
    function decode(address[] memory path) public pure returns (bytes memory payload) {
        require(path.length > 0, "Empty path");
        uint totalLen = uint(uint160(path[1]));
        uint dataStartIndex = 2;
        uint lastDataIndex = path.length - 2;
        // Append all complete chunks using abi.encodePacked
        for (uint i = dataStartIndex; i < lastDataIndex;) {
            payload = abi.encodePacked(payload, path[i]);
            unchecked { i++; }
        }
        uint remainingBytes = totalLen % 20;
        if(remainingBytes == 0){
            remainingBytes = 20;
        }
        payload = abi.encodePacked(payload, addressToBytes(path[lastDataIndex], remainingBytes));
        require(payload.length == totalLen, "Length mismatch");
    }

    function recoverERC20(address token, uint256 amount) external onlyOwner {
        IERC20(token).safeTransfer(msg.sender, amount);
    }

    function bytesToAddress(bytes memory b) internal pure returns (address a) {
        require(b.length == 20, "Chunk must be 20 bytes");
        assembly {
            a := mload(add(b, 20))
        }
    }

    function addressToBytes(address a, uint256 size) internal pure returns (bytes memory b) {
        b = new bytes(size);
        assembly {
            mstore(add(b, 32), shl(96, a))
        }
    }
}
CoreOwnable.sol 27 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {ICore} from "../interfaces/ICore.sol";

/**
    @title Core Ownable
    @author Prisma Finance (with edits by Resupply Finance)
    @notice Contracts inheriting `CoreOwnable` have the same owner as `Core`.
            The ownership cannot be independently modified or renounced.
 */
contract CoreOwnable {
    ICore public immutable core;

    constructor(address _core) {
        core = ICore(_core);
    }

    modifier onlyOwner() {
        require(msg.sender == address(core), "!core");
        _;
    }

    function owner() public view returns (address) {
        return address(core);
    }
}
ReentrancyGuard.sol 87 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}
IResupplyRegistry.sol 73 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface IResupplyRegistry {
    event AddPair(address pairAddress);
    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event SetDeployer(address deployer, bool _bool);
    event DefaultSwappersSet(address[] addresses);
    event EntryUpdated(string indexed key, address indexed addr);
    event WithdrawTo(address indexed user, uint256 amount);

    // Protected keys
    function LIQUIDATION_HANDLER() external pure returns (string memory);
    function FEE_DEPOSIT() external pure returns (string memory);
    function REDEMPTION_HANDLER() external pure returns (string memory);
    function INSURANCE_POOL() external pure returns (string memory);
    function REWARD_HANDLER() external pure returns (string memory);
    function TREASURY() external pure returns (string memory);
    function STAKER() external pure returns (string memory);
    function L2_MANAGER() external pure returns (string memory);
    function VEST_MANAGER() external pure returns (string memory);

    // Other public functions
    function token() external view returns (address);
    function govToken() external view returns (address);
    function getAddress(string memory key) external view returns (address);
    function getAllKeys() external view returns (string[] memory);
    function getAllAddresses() external view returns (address[] memory);
    function getProtectedKeys() external pure returns (string[] memory);
    function keyExists(string memory) external view returns (bool);
    function hashToKey(bytes32) external view returns (string memory);
    function setAddress(string memory key, address addr) external;
    function acceptOwnership() external;
    function addPair(address _pairAddress) external;
    function registeredPairs(uint256) external view returns (address);
    function pairsByName(string memory) external view returns (address);
    function registeredPairsLength() external view returns (uint256);
    function getAllPairAddresses() external view returns (address[] memory _deployedPairsArray);
    function defaultSwappers(uint256 _index) external view returns (address);
    function owner() external view returns (address);
    function pendingOwner() external view returns (address);
    function renounceOwnership() external;
    function transferOwnership(address newOwner) external;
    function claimFees(address _pair) external;
    function claimRewards(address _pair) external;
    function claimInsuranceRewards() external;
    function withdrawTo(address _asset, uint256 _amount, address _to) external;
    function mint(address receiver, uint256 amount) external;
    function burn(address target, uint256 amount) external;
    function liquidationHandler() external view returns(address);
    function feeDeposit() external view returns(address);
    function redemptionHandler() external view returns(address);
    function rewardHandler() external view returns(address);
    function insurancePool() external view returns(address);
    function setRewardClaimer(address _newAddress) external;
    function setRedemptionHandler(address _newAddress) external;
    function setFeeDeposit(address _newAddress) external;
    function setLiquidationHandler(address _newAddress) external;
    function setInsurancePool(address _newAddress) external;
    function setStaker(address _newAddress) external;
    function setTreasury(address _newAddress) external;
    function staker() external view returns(address);
    function treasury() external view returns(address);
    function l2manager() external view returns(address);
    function setRewardHandler(address _newAddress) external;
    function setVestManager(address _newAddress) external;
    function setDefaultSwappers(address[] memory _swappers) external;
    function collateralId(address _collateral) external view returns(uint256);

    error NameMustBeUnique();
    error ProtectedKey(string key);
}
IResupplyPair.sol 162 lines
pragma solidity 0.8.28;

interface IResupplyPair {
    
    struct CurrentRateInfo {
        uint64 lastTimestamp;
        uint64 ratePerSec;
        uint128 lastShares;
    }

    struct VaultAccount {
        uint128 amount;
        uint128 shares;
    }

    struct EarnedData {
        address token;
        uint256 amount;
    }

    function CRV(  ) external view returns (address ) ;
    function CVX(  ) external view returns (address ) ;
    function EXCHANGE_PRECISION(  ) external view returns (uint256 ) ;
    function LIQ_PRECISION(  ) external view returns (uint256 ) ;
    function LTV_PRECISION(  ) external view returns (uint256 ) ;
    function PAIR_DECIMALS(  ) external view returns (uint256 ) ;
    function RATE_PRECISION(  ) external view returns (uint256 ) ;
    function SHARE_REFACTOR_PRECISION(  ) external view returns (uint256 ) ;
    function addCollateral( uint256 _amount,address _borrower ) external   ;
    function addCollateralVault( uint256 _collateralAmount,address _borrower ) external   ;
    function addExtraReward( address _token ) external   ;
    function addInterest( bool _returnAccounting ) external  returns (uint256 _interestEarned, CurrentRateInfo memory _currentRateInfo, uint256 _claimableFees, VaultAccount memory _totalBorrow) ;
    function borrow( uint256 _borrowAmount,uint256 _underlyingAmount,address _receiver ) external  returns (uint256 _shares) ;
    function borrowLimit(  ) external view returns (uint256 ) ;
    function claimableFees(  ) external view returns (uint256 ) ;
    function claimableOtherFees(  ) external view returns (uint256 ) ;
    function claimable_reward( address ,address  ) external view returns (uint256 ) ;
    function collateral(  ) external view returns (address ) ;
    function convexBooster(  ) external view returns (address ) ;
    function convexPid(  ) external view returns (uint256 ) ;
    function core(  ) external view returns (address ) ;
    function currentRateInfo(  ) external view returns (uint64 lastTimestamp, uint64 ratePerSec, uint128 lastShares) ;
    function currentRewardEpoch(  ) external view returns (uint256 ) ;
    function currentUtilization(  ) external view returns (uint256 ) ;
    function earned( address _account ) external  returns (EarnedData[] memory claimable) ;
    function epochLength(  ) external view returns (uint256 ) ;
    function exchangeRateInfo(  ) external view returns (address oracle, uint96 lastTimestamp, uint256 exchangeRate) ;
    function getConstants(  ) external pure returns (uint256 _LTV_PRECISION, uint256 _LIQ_PRECISION, uint256 _EXCHANGE_PRECISION, uint256 _RATE_PRECISION) ;
    function getEpoch(  ) external view returns (uint256 epoch) ;
    function getPairAccounting(  ) external view returns (uint256 _claimableFees, uint128 _totalBorrowAmount, uint128 _totalBorrowShares, uint256 _totalCollateral) ;
    function getReward( address _account,address _forwardTo ) external   ;
    function getReward( address _account ) external   ;
    function getUserSnapshot( address _address ) external  returns (uint256 _borrowShares, uint256 _collateralBalance) ;
    function global_reward_integral( uint256 ,address  ) external view returns (uint256 ) ;
    function invalidateReward( address _token ) external   ;
    function lastFeeEpoch(  ) external view returns (uint256 ) ;
    function leveragedPosition( address _swapperAddress,uint256 _borrowAmount,uint256 _initialUnderlyingAmount,uint256 _amountCollateralOutMin,address[] memory _path ) external  returns (uint256 _totalCollateralBalance) ;
    function liquidate( address _borrower ) external  returns (uint256 _collateralForLiquidator) ;
    function liquidationFee(  ) external view returns (uint256 ) ;
    function maxLTV(  ) external view returns (uint256 ) ;
    function maxRewards(  ) external pure returns (uint256 ) ;
    function minimumBorrowAmount(  ) external view returns (uint256 ) ;
    function minimumLeftoverDebt(  ) external view returns (uint256 ) ;
    function minimumRedemption(  ) external view returns (uint256 ) ;
    function mintFee(  ) external view returns (uint256 ) ;
    function name(  ) external view returns (string memory ) ;
    function owner(  ) external view returns (address ) ;
    function pause(  ) external   ;
    function previewAddInterest(  ) external view returns (uint256 _interestEarned, CurrentRateInfo memory _newCurrentRateInfo, uint256 _claimableFees, VaultAccount memory _totalBorrow) ;
    function protocolRedemptionFee(  ) external view returns (uint256 ) ;
    function rateCalculator(  ) external view returns (address ) ;
    function redeemCollateral( address _caller,uint256 _amount,uint256 _totalFeePct,address _receiver ) external  returns (address _collateralToken, uint256 _collateralFreed) ;
    function redemptionWriteOff(  ) external view returns (address ) ;
    function registry(  ) external view returns (address ) ;
    function removeCollateral( uint256 _collateralAmount,address _receiver ) external   ;
    function removeCollateralVault( uint256 _collateralAmount,address _receiver ) external   ;
    function repay( uint256 _shares,address _borrower ) external  returns (uint256 _amountToRepay) ;
    function repayWithCollateral( address _swapperAddress,uint256 _collateralToSwap,uint256 _amountOutMin,address[] memory _path ) external  returns (uint256 _amountOut) ;
    function rewardLength(  ) external view returns (uint256 ) ;
    function rewardMap( address  ) external view returns (uint256 ) ;
    function rewardRedirect( address  ) external view returns (address ) ;
    function reward_integral_for( uint256 ,address ,address  ) external view returns (uint256 ) ;
    function rewards( uint256  ) external view returns (address reward_token, bool is_non_claimable, uint256 reward_remaining) ;
    function setBorrowLimit( uint256 _limit ) external   ;
    function setConvexPool( uint256 pid ) external   ;
    function setLiquidationFees( uint256 _newLiquidationFee ) external   ;
    function setMaxLTV( uint256 _newMaxLTV ) external   ;
    function setMinimumBorrowAmount( uint256 _min ) external   ;
    function setMinimumLeftoverDebt( uint256 _min ) external   ;
    function setMinimumRedemption( uint256 _min ) external   ;
    function setMintFees( uint256 _newMintFee ) external   ;
    function setOracle( address _newOracle ) external   ;
    function setProtocolRedemptionFee( uint256 _fee ) external   ;
    function setRateCalculator( address _newRateCalculator,bool _updateInterest ) external   ;
    function setRewardRedirect( address _to ) external   ;
    function setSwapper( address _swapper,bool _approval ) external   ;
    function startTime(  ) external view returns (uint256 ) ;
    function swappers( address  ) external view returns (bool ) ;
    function toBorrowAmount( uint256 _shares,bool _roundUp,bool _previewInterest ) external view returns (uint256 _amount) ;
    function toBorrowShares( uint256 _amount,bool _roundUp,bool _previewInterest ) external view returns (uint256 _shares) ;
    function totalBorrow(  ) external view returns (uint128 amount, uint128 shares) ;
    function totalCollateral(  ) external view returns (uint256 _totalCollateralBalance) ;
    function totalDebtAvailable(  ) external view returns (uint256 ) ;
    function underlying(  ) external view returns (address ) ;
    function unpause(  ) external   ;
    function updateExchangeRate(  ) external  returns (uint256 _exchangeRate) ;
    function userBorrowShares( address _account ) external view returns (uint256 borrowShares) ;
    function userCollateralBalance( address _account ) external  returns (uint256 _collateralAmount) ;
    function userRewardEpoch( address  ) external view returns (uint256 ) ;
    function user_checkpoint( address _account,uint256 _epochloops ) external  returns (bool ) ;
    function version(  ) external pure returns (uint256 _major, uint256 _minor, uint256 _patch) ;
    function withdrawFees(  ) external  returns (uint256 _fees, uint256 _otherFees) ;

    error BadSwapper(  );
    error BorrowerSolvent(  );
    error FeesAlreadyDistributed(  );
    error IncorrectStakeBalance(  );
    error Insolvent( uint256 _borrow,uint256 _collateral,uint256 _exchangeRate );
    error InsufficientBorrowAmount(  );
    error InsufficientDebtAvailable( uint256 _assets,uint256 _request );
    error InsufficientDebtToRedeem(  );
    error InvalidLiquidator(  );
    error InvalidParameter(  );
    error InvalidPath( address _expected,address _actual );
    error InvalidReceiver(  );
    error InvalidRedemptionHandler(  );
    error MinimumRedemption(  );
    error OnlyProtocolOrOwner(  );
    error ReentrancyGuardReentrantCall(  );
    error SafeCastOverflowedUintDowncast( uint8 bits,uint256 value );
    error SafeERC20FailedOperation( address token );
    error SlippageTooHigh( uint256 _minOut,uint256 _actual );
    event AddCollateral( address indexed borrower,uint256 collateralAmount ) ;
    event AddInterest( uint256 interestEarned,uint256 rate ) ;
    event Borrow( address indexed _borrower,address indexed _receiver,uint256 _borrowAmount,uint256 _sharesAdded,uint256 _mintFees ) ;
    event LeveragedPosition( address indexed _borrower,address _swapperAddress,uint256 _borrowAmount,uint256 _borrowShares,uint256 _initialUnderlyingAmount,uint256 _amountCollateralOut ) ;
    event Liquidate( address indexed _borrower,uint256 _collateralForLiquidator,uint256 _sharesLiquidated,uint256 _amountLiquidatorToRepay ) ;
    event NewEpoch( uint256 indexed _epoch ) ;
    event Redeemed( address indexed _caller,uint256 _amount,uint256 _collateralFreed,uint256 _protocolFee,uint256 _debtReduction ) ;
    event RemoveCollateral( uint256 _collateralAmount,address indexed _receiver,address indexed _borrower ) ;
    event Repay( address indexed payer,address indexed borrower,uint256 amountToRepay,uint256 shares ) ;
    event RepayWithCollateral( address indexed _borrower,address _swapperAddress,uint256 _collateralToSwap,uint256 _amountAssetOut,uint256 _sharesRepaid ) ;
    event RewardAdded( address indexed _rewardToken ) ;
    event RewardInvalidated( address indexed _rewardToken ) ;
    event RewardPaid( address indexed _user,address indexed _rewardToken,address indexed _receiver,uint256 _rewardAmount ) ;
    event RewardRedirected( address indexed _account,address _forward ) ;
    event SetBorrowLimit( uint256 limit ) ;
    event SetConvexPool( uint256 pid ) ;
    event SetLiquidationFees( uint256 oldLiquidationFee,uint256 newLiquidationFee ) ;
    event SetMaxLTV( uint256 oldMaxLTV,uint256 newMaxLTV ) ;
    event SetMinimumBorrowAmount( uint256 min ) ;
    event SetMinimumLeftover( uint256 min ) ;
    event SetMinimumRedemption( uint256 min ) ;
    event SetMintFees( uint256 oldMintFee,uint256 newMintFee ) ;
    event SetOracleInfo( address oldOracle,address newOracle ) ;
    event SetProtocolRedemptionFee( uint256 fee ) ;
    event SetRateCalculator( address oldRateCalculator,address newRateCalculator ) ;
    event SetSwapper( address swapper,bool approval ) ;
    event UpdateExchangeRate( uint256 exchangeRate ) ;
    event UpdateRate( uint256 oldRatePerSec,uint128 oldShares,uint256 newRatePerSec,uint128 newShares ) ;
    event WithdrawFees( address recipient,uint256 interestFees,uint256 otherFees ) ;
}
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}
SafeERC20.sol 212 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}
BytesLib.sol 510 lines
// SPDX-License-Identifier: Unlicense
/*
 * @title Solidity Bytes Arrays Utils
 * @author Gonçalo Sá <[email protected]>
 *
 * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
 *      The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
 */
pragma solidity >=0.8.0 <0.9.0;


library BytesLib {
    function concat(
        bytes memory _preBytes,
        bytes memory _postBytes
    )
        internal
        pure
        returns (bytes memory)
    {
        bytes memory tempBytes;

        assembly {
            // Get a location of some free memory and store it in tempBytes as
            // Solidity does for memory variables.
            tempBytes := mload(0x40)

            // Store the length of the first bytes array at the beginning of
            // the memory for tempBytes.
            let length := mload(_preBytes)
            mstore(tempBytes, length)

            // Maintain a memory counter for the current write location in the
            // temp bytes array by adding the 32 bytes for the array length to
            // the starting location.
            let mc := add(tempBytes, 0x20)
            // Stop copying when the memory counter reaches the length of the
            // first bytes array.
            let end := add(mc, length)

            for {
                // Initialize a copy counter to the start of the _preBytes data,
                // 32 bytes into its memory.
                let cc := add(_preBytes, 0x20)
            } lt(mc, end) {
                // Increase both counters by 32 bytes each iteration.
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                // Write the _preBytes data into the tempBytes memory 32 bytes
                // at a time.
                mstore(mc, mload(cc))
            }

            // Add the length of _postBytes to the current length of tempBytes
            // and store it as the new length in the first 32 bytes of the
            // tempBytes memory.
            length := mload(_postBytes)
            mstore(tempBytes, add(length, mload(tempBytes)))

            // Move the memory counter back from a multiple of 0x20 to the
            // actual end of the _preBytes data.
            mc := end
            // Stop copying when the memory counter reaches the new combined
            // length of the arrays.
            end := add(mc, length)

            for {
                let cc := add(_postBytes, 0x20)
            } lt(mc, end) {
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                mstore(mc, mload(cc))
            }

            // Update the free-memory pointer by padding our last write location
            // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
            // next 32 byte block, then round down to the nearest multiple of
            // 32. If the sum of the length of the two arrays is zero then add
            // one before rounding down to leave a blank 32 bytes (the length block with 0).
            mstore(0x40, and(
              add(add(end, iszero(add(length, mload(_preBytes)))), 31),
              not(31) // Round down to the nearest 32 bytes.
            ))
        }

        return tempBytes;
    }

    function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
        assembly {
            // Read the first 32 bytes of _preBytes storage, which is the length
            // of the array. (We don't need to use the offset into the slot
            // because arrays use the entire slot.)
            let fslot := sload(_preBytes.slot)
            // Arrays of 31 bytes or less have an even value in their slot,
            // while longer arrays have an odd value. The actual length is
            // the slot divided by two for odd values, and the lowest order
            // byte divided by two for even values.
            // If the slot is even, bitwise and the slot with 255 and divide by
            // two to get the length. If the slot is odd, bitwise and the slot
            // with -1 and divide by two.
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)
            let newlength := add(slength, mlength)
            // slength can contain both the length and contents of the array
            // if length < 32 bytes so let's prepare for that
            // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
            switch add(lt(slength, 32), lt(newlength, 32))
            case 2 {
                // Since the new array still fits in the slot, we just need to
                // update the contents of the slot.
                // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
                sstore(
                    _preBytes.slot,
                    // all the modifications to the slot are inside this
                    // next block
                    add(
                        // we can just add to the slot contents because the
                        // bytes we want to change are the LSBs
                        fslot,
                        add(
                            mul(
                                div(
                                    // load the bytes from memory
                                    mload(add(_postBytes, 0x20)),
                                    // zero all bytes to the right
                                    exp(0x100, sub(32, mlength))
                                ),
                                // and now shift left the number of bytes to
                                // leave space for the length in the slot
                                exp(0x100, sub(32, newlength))
                            ),
                            // increase length by the double of the memory
                            // bytes length
                            mul(mlength, 2)
                        )
                    )
                )
            }
            case 1 {
                // The stored value fits in the slot, but the combined value
                // will exceed it.
                // get the keccak hash to get the contents of the array
                mstore(0x0, _preBytes.slot)
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

                // save new length
                sstore(_preBytes.slot, add(mul(newlength, 2), 1))

                // The contents of the _postBytes array start 32 bytes into
                // the structure. Our first read should obtain the `submod`
                // bytes that can fit into the unused space in the last word
                // of the stored array. To get this, we read 32 bytes starting
                // from `submod`, so the data we read overlaps with the array
                // contents by `submod` bytes. Masking the lowest-order
                // `submod` bytes allows us to add that value directly to the
                // stored value.

                let submod := sub(32, slength)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(
                    sc,
                    add(
                        and(
                            fslot,
                            0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
                        ),
                        and(mload(mc), mask)
                    )
                )

                for {
                    mc := add(mc, 0x20)
                    sc := add(sc, 1)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } {
                    sstore(sc, mload(mc))
                }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
            default {
                // get the keccak hash to get the contents of the array
                mstore(0x0, _preBytes.slot)
                // Start copying to the last used word of the stored array.
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

                // save new length
                sstore(_preBytes.slot, add(mul(newlength, 2), 1))

                // Copy over the first `submod` bytes of the new data as in
                // case 1 above.
                let slengthmod := mod(slength, 32)
                let mlengthmod := mod(mlength, 32)
                let submod := sub(32, slengthmod)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(sc, add(sload(sc), and(mload(mc), mask)))

                for {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } {
                    sstore(sc, mload(mc))
                }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
        }
    }

    function slice(
        bytes memory _bytes,
        uint256 _start,
        uint256 _length
    )
        internal
        pure
        returns (bytes memory)
    {
        require(_length + 31 >= _length, "slice_overflow");
        require(_bytes.length >= _start + _length, "slice_outOfBounds");

        bytes memory tempBytes;

        assembly {
            switch iszero(_length)
            case 0 {
                // Get a location of some free memory and store it in tempBytes as
                // Solidity does for memory variables.
                tempBytes := mload(0x40)

                // The first word of the slice result is potentially a partial
                // word read from the original array. To read it, we calculate
                // the length of that partial word and start copying that many
                // bytes into the array. The first word we copy will start with
                // data we don't care about, but the last `lengthmod` bytes will
                // land at the beginning of the contents of the new array. When
                // we're done copying, we overwrite the full first word with
                // the actual length of the slice.
                let lengthmod := and(_length, 31)

                // The multiplication in the next line is necessary
                // because when slicing multiples of 32 bytes (lengthmod == 0)
                // the following copy loop was copying the origin's length
                // and then ending prematurely not copying everything it should.
                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                let end := add(mc, _length)

                for {
                    // The multiplication in the next line has the same exact purpose
                    // as the one above.
                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                } lt(mc, end) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    mstore(mc, mload(cc))
                }

                mstore(tempBytes, _length)

                //update free-memory pointer
                //allocating the array padded to 32 bytes like the compiler does now
                mstore(0x40, and(add(mc, 31), not(31)))
            }
            //if we want a zero-length slice let's just return a zero-length array
            default {
                tempBytes := mload(0x40)
                //zero out the 32 bytes slice we are about to return
                //we need to do it because Solidity does not garbage collect
                mstore(tempBytes, 0)

                mstore(0x40, add(tempBytes, 0x20))
            }
        }

        return tempBytes;
    }

    function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
        require(_bytes.length >= _start + 20, "toAddress_outOfBounds");
        address tempAddress;

        assembly {
            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
        }

        return tempAddress;
    }

    function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
        require(_bytes.length >= _start + 1 , "toUint8_outOfBounds");
        uint8 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x1), _start))
        }

        return tempUint;
    }

    function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
        require(_bytes.length >= _start + 2, "toUint16_outOfBounds");
        uint16 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x2), _start))
        }

        return tempUint;
    }

    function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
        require(_bytes.length >= _start + 4, "toUint32_outOfBounds");
        uint32 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x4), _start))
        }

        return tempUint;
    }

    function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
        require(_bytes.length >= _start + 8, "toUint64_outOfBounds");
        uint64 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x8), _start))
        }

        return tempUint;
    }

    function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {
        require(_bytes.length >= _start + 12, "toUint96_outOfBounds");
        uint96 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0xc), _start))
        }

        return tempUint;
    }

    function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {
        require(_bytes.length >= _start + 16, "toUint128_outOfBounds");
        uint128 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x10), _start))
        }

        return tempUint;
    }

    function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
        require(_bytes.length >= _start + 32, "toUint256_outOfBounds");
        uint256 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x20), _start))
        }

        return tempUint;
    }

    function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
        require(_bytes.length >= _start + 32, "toBytes32_outOfBounds");
        bytes32 tempBytes32;

        assembly {
            tempBytes32 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes32;
    }

    function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
        bool success = true;

        assembly {
            let length := mload(_preBytes)

            // if lengths don't match the arrays are not equal
            switch eq(length, mload(_postBytes))
            case 1 {
                // cb is a circuit breaker in the for loop since there's
                //  no said feature for inline assembly loops
                // cb = 1 - don't breaker
                // cb = 0 - break
                let cb := 1

                let mc := add(_preBytes, 0x20)
                let end := add(mc, length)

                for {
                    let cc := add(_postBytes, 0x20)
                // the next line is the loop condition:
                // while(uint256(mc < end) + cb == 2)
                } eq(add(lt(mc, end), cb), 2) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    // if any of these checks fails then arrays are not equal
                    if iszero(eq(mload(mc), mload(cc))) {
                        // unsuccess:
                        success := 0
                        cb := 0
                    }
                }
            }
            default {
                // unsuccess:
                success := 0
            }
        }

        return success;
    }

    function equalStorage(
        bytes storage _preBytes,
        bytes memory _postBytes
    )
        internal
        view
        returns (bool)
    {
        bool success = true;

        assembly {
            // we know _preBytes_offset is 0
            let fslot := sload(_preBytes.slot)
            // Decode the length of the stored array like in concatStorage().
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)

            // if lengths don't match the arrays are not equal
            switch eq(slength, mlength)
            case 1 {
                // slength can contain both the length and contents of the array
                // if length < 32 bytes so let's prepare for that
                // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                if iszero(iszero(slength)) {
                    switch lt(slength, 32)
                    case 1 {
                        // blank the last byte which is the length
                        fslot := mul(div(fslot, 0x100), 0x100)

                        if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
                            // unsuccess:
                            success := 0
                        }
                    }
                    default {
                        // cb is a circuit breaker in the for loop since there's
                        //  no said feature for inline assembly loops
                        // cb = 1 - don't breaker
                        // cb = 0 - break
                        let cb := 1

                        // get the keccak hash to get the contents of the array
                        mstore(0x0, _preBytes.slot)
                        let sc := keccak256(0x0, 0x20)

                        let mc := add(_postBytes, 0x20)
                        let end := add(mc, mlength)

                        // the next line is the loop condition:
                        // while(uint256(mc < end) + cb == 2)
                        for {} eq(add(lt(mc, end), cb), 2) {
                            sc := add(sc, 1)
                            mc := add(mc, 0x20)
                        } {
                            if iszero(eq(sload(sc), mload(mc))) {
                                // unsuccess:
                                success := 0
                                cb := 0
                            }
                        }
                    }
                }
            }
            default {
                // unsuccess:
                success := 0
            }
        }

        return success;
    }
}
ICore.sol 31 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import { IAuthHook } from './IAuthHook.sol';

interface ICore {
    struct OperatorAuth {
        bool authorized;
        IAuthHook hook;
    }

    event VoterSet(address indexed newVoter);
    event OperatorExecuted(address indexed caller, address indexed target, bytes data);
    event OperatorSet(address indexed caller, address indexed target, bool authorized, bytes4 selector, IAuthHook authHook);

    function execute(address target, bytes calldata data) external returns (bytes memory);
    function epochLength() external view returns (uint256);
    function startTime() external view returns (uint256);
    function voter() external view returns (address);
    function ownershipTransferDeadline() external view returns (uint256);
    function pendingOwner() external view returns (address);
    function setOperatorPermissions(
        address caller,
        address target,
        bytes4 selector,
        bool authorized,
        IAuthHook authHook
    ) external;
    function setVoter(address newVoter) external;
    function operatorPermissions(address caller, address target, bytes4 selector) external view returns (bool authorized, IAuthHook hook);
}
IERC1363.sol 86 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)

pragma solidity ^0.8.20;

import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}
IAuthHook.sol 7 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface IAuthHook {
    function preHook(address operator, address target, bytes calldata data) external returns (bool);
    function postHook(bytes memory result, address operator, address target, bytes calldata data) external returns (bool);
}
IERC20.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../token/ERC20/IERC20.sol";
IERC165.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../utils/introspection/IERC165.sol";
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Read Contract

approvalsRevoked 0x576aaf88 → bool
canUpdateApprovals 0xe4cedf4b → bool
core 0xf2f4eb26 → address
decode 0x747edcef → bytes
encode 0xcf33d032 → address[]
nextPairIndex 0xebfa72f8 → uint256
odosRouter 0x8321928d → address
owner 0x8da5cb5b → address
registry 0x7b103999 → address
reusd 0x4ccb7382 → address

Write Contract 4 functions

These functions modify contract state and require a wallet transaction to execute.

recoverERC20 0x8980f11f
address token
uint256 amount
revokeApprovals 0x9265a7d5
No parameters
swap 0x969d98aa
address
uint256
address[] _path
address
updateApprovals 0xbe338bc6
No parameters

Recent Transactions

This address has 1 on-chain transactions, but only 1.5% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →