ETH Price: $2,436.10 (-2.11%)

Contract

0xa8687A15D4BE32CC8F0a8a7B9704a4C3993D9613
 
Transaction Hash
Method
Block
From
To
0x60806040159981262022-11-18 16:34:47689 days ago1668789287IN
 Create: OlympusTreasury
0 ETH0.0294533421.61037726

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
OlympusTreasury

Compiler Version
v0.8.15+commit.e14f2714

Optimization Enabled:
Yes with 10 runs

Other Settings:
default evmVersion
File 1 of 6 : OlympusTreasury.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.15;

import {ERC20} from "solmate/tokens/ERC20.sol";
import {ReentrancyGuard} from "solmate/utils/ReentrancyGuard.sol";

import {TransferHelper} from "libraries/TransferHelper.sol";

import {TRSRYv1} from "src/modules/TRSRY/TRSRY.v1.sol";
import "src/Kernel.sol";

/// @notice Treasury holds all other assets under the control of the protocol.
contract OlympusTreasury is TRSRYv1, ReentrancyGuard {
    using TransferHelper for ERC20;

    //============================================================================================//
    //                                      MODULE SETUP                                          //
    //============================================================================================//

    constructor(Kernel kernel_) Module(kernel_) {
        active = true;
    }

    /// @inheritdoc Module
    function KEYCODE() public pure override returns (Keycode) {
        return toKeycode("TRSRY");
    }

    /// @inheritdoc Module
    function VERSION() external pure override returns (uint8 major, uint8 minor) {
        major = 1;
        minor = 0;
    }

    //============================================================================================//
    //                                       CORE FUNCTIONS                                       //
    //============================================================================================//

    /// @inheritdoc TRSRYv1
    function increaseWithdrawApproval(
        address withdrawer_,
        ERC20 token_,
        uint256 amount_
    ) external override permissioned {
        uint256 approval = withdrawApproval[withdrawer_][token_];

        uint256 newAmount = type(uint256).max - approval <= amount_
            ? type(uint256).max
            : approval + amount_;
        withdrawApproval[withdrawer_][token_] = newAmount;

        emit IncreaseWithdrawApproval(withdrawer_, token_, newAmount);
    }

    /// @inheritdoc TRSRYv1
    function decreaseWithdrawApproval(
        address withdrawer_,
        ERC20 token_,
        uint256 amount_
    ) external override permissioned {
        uint256 approval = withdrawApproval[withdrawer_][token_];

        uint256 newAmount = approval <= amount_ ? 0 : approval - amount_;
        withdrawApproval[withdrawer_][token_] = newAmount;

        emit DecreaseWithdrawApproval(withdrawer_, token_, newAmount);
    }

    /// @inheritdoc TRSRYv1
    function withdrawReserves(
        address to_,
        ERC20 token_,
        uint256 amount_
    ) public override permissioned onlyWhileActive {
        withdrawApproval[msg.sender][token_] -= amount_;

        token_.safeTransfer(to_, amount_);

        emit Withdrawal(msg.sender, to_, token_, amount_);
    }

    // =========  DEBT FUNCTIONS ========= //

    /// @inheritdoc TRSRYv1
    function increaseDebtorApproval(
        address debtor_,
        ERC20 token_,
        uint256 amount_
    ) external override permissioned {
        uint256 newAmount = debtApproval[debtor_][token_] + amount_;
        debtApproval[debtor_][token_] = newAmount;
        emit IncreaseDebtorApproval(debtor_, token_, newAmount);
    }

    /// @inheritdoc TRSRYv1
    function decreaseDebtorApproval(
        address debtor_,
        ERC20 token_,
        uint256 amount_
    ) external override permissioned {
        uint256 newAmount = debtApproval[debtor_][token_] - amount_;
        debtApproval[debtor_][token_] = newAmount;
        emit DecreaseDebtorApproval(debtor_, token_, newAmount);
    }

    /// @inheritdoc TRSRYv1
    function incurDebt(ERC20 token_, uint256 amount_)
        external
        override
        permissioned
        onlyWhileActive
    {
        debtApproval[msg.sender][token_] -= amount_;

        // Add debt to caller
        reserveDebt[token_][msg.sender] += amount_;
        totalDebt[token_] += amount_;

        token_.safeTransfer(msg.sender, amount_);

        emit DebtIncurred(token_, msg.sender, amount_);
    }

    /// @inheritdoc TRSRYv1
    function repayDebt(
        address debtor_,
        ERC20 token_,
        uint256 amount_
    ) external override permissioned nonReentrant {
        if (reserveDebt[token_][debtor_] == 0) revert TRSRY_NoDebtOutstanding();

        // Deposit from caller first (to handle nonstandard token transfers)
        uint256 prevBalance = token_.balanceOf(address(this));
        token_.safeTransferFrom(msg.sender, address(this), amount_);

        uint256 received = token_.balanceOf(address(this)) - prevBalance;

        // Choose minimum between passed-in amount and received amount
        if (received > amount_) received = amount_;

        // Subtract debt from debtor
        reserveDebt[token_][debtor_] -= received;
        totalDebt[token_] -= received;

        emit DebtRepaid(token_, debtor_, received);
    }

    /// @inheritdoc TRSRYv1
    function setDebt(
        address debtor_,
        ERC20 token_,
        uint256 amount_
    ) external override permissioned {
        uint256 oldDebt = reserveDebt[token_][debtor_];

        reserveDebt[token_][debtor_] = amount_;

        if (oldDebt < amount_) totalDebt[token_] += amount_ - oldDebt;
        else totalDebt[token_] -= oldDebt - amount_;

        emit DebtSet(token_, debtor_, amount_);
    }

    /// @inheritdoc TRSRYv1
    function deactivate() external override permissioned {
        active = false;
    }

    /// @inheritdoc TRSRYv1
    function activate() external override permissioned {
        active = true;
    }

    //============================================================================================//
    //                                       VIEW FUNCTIONS                                       //
    //============================================================================================//

    /// @inheritdoc TRSRYv1
    function getReserveBalance(ERC20 token_) external view override returns (uint256) {
        return token_.balanceOf(address(this)) + totalDebt[token_];
    }
}

File 2 of 6 : ERC20.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}

File 3 of 6 : ReentrancyGuard.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Gas optimized reentrancy protection for smart contracts.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/ReentrancyGuard.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol)
abstract contract ReentrancyGuard {
    uint256 private locked = 1;

    modifier nonReentrant() virtual {
        require(locked == 1, "REENTRANCY");

        locked = 2;

        _;

        locked = 1;
    }
}

File 4 of 6 : Kernel.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.15;

//     ███████    █████       █████ █████ ██████   ██████ ███████████  █████  █████  █████████
//   ███░░░░░███ ░░███       ░░███ ░░███ ░░██████ ██████ ░░███░░░░░███░░███  ░░███  ███░░░░░███
//  ███     ░░███ ░███        ░░███ ███   ░███░█████░███  ░███    ░███ ░███   ░███ ░███    ░░░
// ░███      ░███ ░███         ░░█████    ░███░░███ ░███  ░██████████  ░███   ░███ ░░█████████
// ░███      ░███ ░███          ░░███     ░███ ░░░  ░███  ░███░░░░░░   ░███   ░███  ░░░░░░░░███
// ░░███     ███  ░███      █    ░███     ░███      ░███  ░███         ░███   ░███  ███    ░███
//  ░░░███████░   ███████████    █████    █████     █████ █████        ░░████████  ░░█████████
//    ░░░░░░░    ░░░░░░░░░░░    ░░░░░    ░░░░░     ░░░░░ ░░░░░          ░░░░░░░░    ░░░░░░░░░

//============================================================================================//
//                                        GLOBAL TYPES                                        //
//============================================================================================//

/// @notice Actions to trigger state changes in the kernel. Passed by the executor
enum Actions {
    InstallModule,
    UpgradeModule,
    ActivatePolicy,
    DeactivatePolicy,
    ChangeExecutor,
    MigrateKernel
}

/// @notice Used by executor to select an action and a target contract for a kernel action
struct Instruction {
    Actions action;
    address target;
}

/// @notice Used to define which module functions a policy needs access to
struct Permissions {
    Keycode keycode;
    bytes4 funcSelector;
}

type Keycode is bytes5;

//============================================================================================//
//                                       UTIL FUNCTIONS                                       //
//============================================================================================//

error TargetNotAContract(address target_);
error InvalidKeycode(Keycode keycode_);

// solhint-disable-next-line func-visibility
function toKeycode(bytes5 keycode_) pure returns (Keycode) {
    return Keycode.wrap(keycode_);
}

// solhint-disable-next-line func-visibility
function fromKeycode(Keycode keycode_) pure returns (bytes5) {
    return Keycode.unwrap(keycode_);
}

// solhint-disable-next-line func-visibility
function ensureContract(address target_) view {
    if (target_.code.length == 0) revert TargetNotAContract(target_);
}

// solhint-disable-next-line func-visibility
function ensureValidKeycode(Keycode keycode_) pure {
    bytes5 unwrapped = Keycode.unwrap(keycode_);
    for (uint256 i = 0; i < 5; ) {
        bytes1 char = unwrapped[i];
        if (char < 0x41 || char > 0x5A) revert InvalidKeycode(keycode_); // A-Z only
        unchecked {
            i++;
        }
    }
}

//============================================================================================//
//                                        COMPONENTS                                          //
//============================================================================================//

/// @notice Generic adapter interface for kernel access in modules and policies.
abstract contract KernelAdapter {
    error KernelAdapter_OnlyKernel(address caller_);

    Kernel public kernel;

    constructor(Kernel kernel_) {
        kernel = kernel_;
    }

    /// @notice Modifier to restrict functions to be called only by kernel.
    modifier onlyKernel() {
        if (msg.sender != address(kernel)) revert KernelAdapter_OnlyKernel(msg.sender);
        _;
    }

    /// @notice Function used by kernel when migrating to a new kernel.
    function changeKernel(Kernel newKernel_) external onlyKernel {
        kernel = newKernel_;
    }
}

/// @notice Base level extension of the kernel. Modules act as independent state components to be
///         interacted with and mutated through policies.
/// @dev    Modules are installed and uninstalled via the executor.
abstract contract Module is KernelAdapter {
    error Module_PolicyNotPermitted(address policy_);

    constructor(Kernel kernel_) KernelAdapter(kernel_) {}

    /// @notice Modifier to restrict which policies have access to module functions.
    modifier permissioned() {
        if (!kernel.modulePermissions(KEYCODE(), Policy(msg.sender), msg.sig))
            revert Module_PolicyNotPermitted(msg.sender);
        _;
    }

    /// @notice 5 byte identifier for a module.
    function KEYCODE() public pure virtual returns (Keycode) {}

    /// @notice Returns which semantic version of a module is being implemented.
    /// @return major - Major version upgrade indicates breaking change to the interface.
    /// @return minor - Minor version change retains backward-compatible interface.
    function VERSION() external pure virtual returns (uint8 major, uint8 minor) {}

    /// @notice Initialization function for the module
    /// @dev    This function is called when the module is installed or upgraded by the kernel.
    /// @dev    MUST BE GATED BY onlyKernel. Used to encompass any initialization or upgrade logic.
    function INIT() external virtual onlyKernel {}
}

/// @notice Policies are application logic and external interface for the kernel and installed modules.
/// @dev    Policies are activated and deactivated in the kernel by the executor.
/// @dev    Module dependencies and function permissions must be defined in appropriate functions.
abstract contract Policy is KernelAdapter {
    error Policy_ModuleDoesNotExist(Keycode keycode_);

    constructor(Kernel kernel_) KernelAdapter(kernel_) {}

    /// @notice Easily accessible indicator for if a policy is activated or not.
    function isActive() external view returns (bool) {
        return kernel.isPolicyActive(this);
    }

    /// @notice Function to grab module address from a given keycode.
    function getModuleAddress(Keycode keycode_) internal view returns (address) {
        address moduleForKeycode = address(kernel.getModuleForKeycode(keycode_));
        if (moduleForKeycode == address(0)) revert Policy_ModuleDoesNotExist(keycode_);
        return moduleForKeycode;
    }

    /// @notice Define module dependencies for this policy.
    /// @return dependencies - Keycode array of module dependencies.
    function configureDependencies() external virtual returns (Keycode[] memory dependencies) {}

    /// @notice Function called by kernel to set module function permissions.
    /// @return requests - Array of keycodes and function selectors for requested permissions.
    function requestPermissions() external view virtual returns (Permissions[] memory requests) {}
}

/// @notice Main contract that acts as a central component registry for the protocol.
/// @dev    The kernel manages modules and policies. The kernel is mutated via predefined Actions,
/// @dev    which are input from any address assigned as the executor. The executor can be changed as needed.
contract Kernel {
    // =========  EVENTS ========= //

    event PermissionsUpdated(
        Keycode indexed keycode_,
        Policy indexed policy_,
        bytes4 funcSelector_,
        bool granted_
    );
    event ActionExecuted(Actions indexed action_, address indexed target_);

    // =========  ERRORS ========= //

    error Kernel_OnlyExecutor(address caller_);
    error Kernel_ModuleAlreadyInstalled(Keycode module_);
    error Kernel_InvalidModuleUpgrade(Keycode module_);
    error Kernel_PolicyAlreadyActivated(address policy_);
    error Kernel_PolicyNotActivated(address policy_);

    // =========  PRIVILEGED ADDRESSES ========= //

    /// @notice Address that is able to initiate Actions in the kernel. Can be assigned to a multisig or governance contract.
    address public executor;

    // =========  MODULE MANAGEMENT ========= //

    /// @notice Array of all modules currently installed.
    Keycode[] public allKeycodes;

    /// @notice Mapping of module address to keycode.
    mapping(Keycode => Module) public getModuleForKeycode;

    /// @notice Mapping of keycode to module address.
    mapping(Module => Keycode) public getKeycodeForModule;

    /// @notice Mapping of a keycode to all of its policy dependents. Used to efficiently reconfigure policy dependencies.
    mapping(Keycode => Policy[]) public moduleDependents;

    /// @notice Helper for module dependent arrays. Prevents the need to loop through array.
    mapping(Keycode => mapping(Policy => uint256)) public getDependentIndex;

    /// @notice Module <> Policy Permissions.
    /// @dev    Keycode -> Policy -> Function Selector -> bool for permission
    mapping(Keycode => mapping(Policy => mapping(bytes4 => bool))) public modulePermissions;

    // =========  POLICY MANAGEMENT ========= //

    /// @notice List of all active policies
    Policy[] public activePolicies;

    /// @notice Helper to get active policy quickly. Prevents need to loop through array.
    mapping(Policy => uint256) public getPolicyIndex;

    //============================================================================================//
    //                                       CORE FUNCTIONS                                       //
    //============================================================================================//

    constructor() {
        executor = msg.sender;
    }

    /// @notice Modifier to check if caller is the executor.
    modifier onlyExecutor() {
        if (msg.sender != executor) revert Kernel_OnlyExecutor(msg.sender);
        _;
    }

    function isPolicyActive(Policy policy_) public view returns (bool) {
        return activePolicies.length > 0 && activePolicies[getPolicyIndex[policy_]] == policy_;
    }

    /// @notice Main kernel function. Initiates state changes to kernel depending on Action passed in.
    function executeAction(Actions action_, address target_) external onlyExecutor {
        if (action_ == Actions.InstallModule) {
            ensureContract(target_);
            ensureValidKeycode(Module(target_).KEYCODE());
            _installModule(Module(target_));
        } else if (action_ == Actions.UpgradeModule) {
            ensureContract(target_);
            ensureValidKeycode(Module(target_).KEYCODE());
            _upgradeModule(Module(target_));
        } else if (action_ == Actions.ActivatePolicy) {
            ensureContract(target_);
            _activatePolicy(Policy(target_));
        } else if (action_ == Actions.DeactivatePolicy) {
            ensureContract(target_);
            _deactivatePolicy(Policy(target_));
        } else if (action_ == Actions.ChangeExecutor) {
            executor = target_;
        } else if (action_ == Actions.MigrateKernel) {
            ensureContract(target_);
            _migrateKernel(Kernel(target_));
        }

        emit ActionExecuted(action_, target_);
    }

    function _installModule(Module newModule_) internal {
        Keycode keycode = newModule_.KEYCODE();

        if (address(getModuleForKeycode[keycode]) != address(0))
            revert Kernel_ModuleAlreadyInstalled(keycode);

        getModuleForKeycode[keycode] = newModule_;
        getKeycodeForModule[newModule_] = keycode;
        allKeycodes.push(keycode);

        newModule_.INIT();
    }

    function _upgradeModule(Module newModule_) internal {
        Keycode keycode = newModule_.KEYCODE();
        Module oldModule = getModuleForKeycode[keycode];

        if (address(oldModule) == address(0) || oldModule == newModule_)
            revert Kernel_InvalidModuleUpgrade(keycode);

        getKeycodeForModule[oldModule] = Keycode.wrap(bytes5(0));
        getKeycodeForModule[newModule_] = keycode;
        getModuleForKeycode[keycode] = newModule_;

        newModule_.INIT();

        _reconfigurePolicies(keycode);
    }

    function _activatePolicy(Policy policy_) internal {
        if (isPolicyActive(policy_)) revert Kernel_PolicyAlreadyActivated(address(policy_));

        // Add policy to list of active policies
        activePolicies.push(policy_);
        getPolicyIndex[policy_] = activePolicies.length - 1;

        // Record module dependencies
        Keycode[] memory dependencies = policy_.configureDependencies();
        uint256 depLength = dependencies.length;

        for (uint256 i; i < depLength; ) {
            Keycode keycode = dependencies[i];

            moduleDependents[keycode].push(policy_);
            getDependentIndex[keycode][policy_] = moduleDependents[keycode].length - 1;

            unchecked {
                ++i;
            }
        }

        // Grant permissions for policy to access restricted module functions
        Permissions[] memory requests = policy_.requestPermissions();
        _setPolicyPermissions(policy_, requests, true);
    }

    function _deactivatePolicy(Policy policy_) internal {
        if (!isPolicyActive(policy_)) revert Kernel_PolicyNotActivated(address(policy_));

        // Revoke permissions
        Permissions[] memory requests = policy_.requestPermissions();
        _setPolicyPermissions(policy_, requests, false);

        // Remove policy from all policy data structures
        uint256 idx = getPolicyIndex[policy_];
        Policy lastPolicy = activePolicies[activePolicies.length - 1];

        activePolicies[idx] = lastPolicy;
        activePolicies.pop();
        getPolicyIndex[lastPolicy] = idx;
        delete getPolicyIndex[policy_];

        // Remove policy from module dependents
        _pruneFromDependents(policy_);
    }

    /// @notice All functionality will move to the new kernel. WARNING: ACTION WILL BRICK THIS KERNEL.
    /// @dev    New kernel must add in all of the modules and policies via executeAction.
    /// @dev    NOTE: Data does not get cleared from this kernel.
    function _migrateKernel(Kernel newKernel_) internal {
        uint256 keycodeLen = allKeycodes.length;
        for (uint256 i; i < keycodeLen; ) {
            Module module = Module(getModuleForKeycode[allKeycodes[i]]);
            module.changeKernel(newKernel_);
            unchecked {
                ++i;
            }
        }

        uint256 policiesLen = activePolicies.length;
        for (uint256 j; j < policiesLen; ) {
            Policy policy = activePolicies[j];

            // Deactivate before changing kernel
            policy.changeKernel(newKernel_);
            unchecked {
                ++j;
            }
        }
    }

    function _reconfigurePolicies(Keycode keycode_) internal {
        Policy[] memory dependents = moduleDependents[keycode_];
        uint256 depLength = dependents.length;

        for (uint256 i; i < depLength; ) {
            dependents[i].configureDependencies();

            unchecked {
                ++i;
            }
        }
    }

    function _setPolicyPermissions(
        Policy policy_,
        Permissions[] memory requests_,
        bool grant_
    ) internal {
        uint256 reqLength = requests_.length;
        for (uint256 i = 0; i < reqLength; ) {
            Permissions memory request = requests_[i];
            modulePermissions[request.keycode][policy_][request.funcSelector] = grant_;

            emit PermissionsUpdated(request.keycode, policy_, request.funcSelector, grant_);

            unchecked {
                ++i;
            }
        }
    }

    function _pruneFromDependents(Policy policy_) internal {
        Keycode[] memory dependencies = policy_.configureDependencies();
        uint256 depcLength = dependencies.length;

        for (uint256 i; i < depcLength; ) {
            Keycode keycode = dependencies[i];
            Policy[] storage dependents = moduleDependents[keycode];

            uint256 origIndex = getDependentIndex[keycode][policy_];
            Policy lastPolicy = dependents[dependents.length - 1];

            // Swap with last and pop
            dependents[origIndex] = lastPolicy;
            dependents.pop();

            // Record new index and delete deactivated policy index
            getDependentIndex[keycode][lastPolicy] = origIndex;
            delete getDependentIndex[keycode][policy_];

            unchecked {
                ++i;
            }
        }
    }
}

File 5 of 6 : TransferHelper.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {ERC20} from "solmate/tokens/ERC20.sol";

/// @notice Safe ERC20 and ETH transfer library that safely handles missing return values.
/// @author Modified from Uniswap & old Solmate (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/libraries/TransferHelper.sol)
library TransferHelper {
    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        (bool success, bytes memory data) = address(token).call(
            abi.encodeWithSelector(ERC20.transferFrom.selector, from, to, amount)
        );

        require(success && (data.length == 0 || abi.decode(data, (bool))), "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        (bool success, bytes memory data) = address(token).call(
            abi.encodeWithSelector(ERC20.transfer.selector, to, amount)
        );

        require(success && (data.length == 0 || abi.decode(data, (bool))), "TRANSFER_FAILED");
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        (bool success, bytes memory data) = address(token).call(
            abi.encodeWithSelector(ERC20.approve.selector, to, amount)
        );

        require(success && (data.length == 0 || abi.decode(data, (bool))), "APPROVE_FAILED");
    }
}

File 6 of 6 : TRSRY.v1.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.15;

import {ERC20} from "solmate/tokens/ERC20.sol";
import "src/Kernel.sol";

/// @notice Treasury holds all other assets under the control of the protocol.
abstract contract TRSRYv1 is Module {
    // =========  EVENTS ========= //

    event IncreaseWithdrawApproval(
        address indexed withdrawer_,
        ERC20 indexed token_,
        uint256 newAmount_
    );
    event DecreaseWithdrawApproval(
        address indexed withdrawer_,
        ERC20 indexed token_,
        uint256 newAmount_
    );
    event Withdrawal(
        address indexed policy_,
        address indexed withdrawer_,
        ERC20 indexed token_,
        uint256 amount_
    );
    event IncreaseDebtorApproval(address indexed debtor_, ERC20 indexed token_, uint256 newAmount_);
    event DecreaseDebtorApproval(address indexed debtor_, ERC20 indexed token_, uint256 newAmount_);
    event DebtIncurred(ERC20 indexed token_, address indexed policy_, uint256 amount_);
    event DebtRepaid(ERC20 indexed token_, address indexed policy_, uint256 amount_);
    event DebtSet(ERC20 indexed token_, address indexed policy_, uint256 amount_);

    // =========  ERRORS ========= //

    error TRSRY_NoDebtOutstanding();
    error TRSRY_NotActive();

    // =========  STATE ========= //

    /// @notice Status of the treasury. If false, no withdrawals or debt can be incurred.
    bool public active;

    /// @notice Mapping of who is approved for withdrawal.
    /// @dev    withdrawer -> token -> amount. Infinite approval is max(uint256).
    mapping(address => mapping(ERC20 => uint256)) public withdrawApproval;

    /// @notice Mapping of who is approved to incur debt.
    /// @dev    debtor -> token -> amount. Infinite approval is max(uint256).
    mapping(address => mapping(ERC20 => uint256)) public debtApproval;

    /// @notice Total debt for token across all withdrawals.
    mapping(ERC20 => uint256) public totalDebt;

    /// @notice Debt for particular token and debtor address
    mapping(ERC20 => mapping(address => uint256)) public reserveDebt;

    // =========  FUNCTIONS ========= //

    modifier onlyWhileActive() {
        if (!active) revert TRSRY_NotActive();
        _;
    }

    /// @notice Increase approval for specific withdrawer addresses
    function increaseWithdrawApproval(
        address withdrawer_,
        ERC20 token_,
        uint256 amount_
    ) external virtual;

    /// @notice Decrease approval for specific withdrawer addresses
    function decreaseWithdrawApproval(
        address withdrawer_,
        ERC20 token_,
        uint256 amount_
    ) external virtual;

    /// @notice Allow withdrawal of reserve funds from pre-approved addresses.
    function withdrawReserves(
        address to_,
        ERC20 token_,
        uint256 amount_
    ) external virtual;

    /// @notice Increase approval for someone to accrue debt in order to withdraw reserves.
    /// @dev    Debt will generally be taken by contracts to allocate treasury funds in yield sources.
    function increaseDebtorApproval(
        address debtor_,
        ERC20 token_,
        uint256 amount_
    ) external virtual;

    /// @notice Decrease approval for someone to withdraw reserves as debt.
    function decreaseDebtorApproval(
        address debtor_,
        ERC20 token_,
        uint256 amount_
    ) external virtual;

    /// @notice Pre-approved policies can get a loan to perform operations with treasury assets.
    function incurDebt(ERC20 token_, uint256 amount_) external virtual;

    /// @notice Repay a debtor debt.
    /// @dev    Only confirmed to safely handle standard and non-standard ERC20s.
    /// @dev    Can have unforeseen consequences with ERC777. Be careful with ERC777 as reserve.
    function repayDebt(
        address debtor_,
        ERC20 token_,
        uint256 amount_
    ) external virtual;

    /// @notice An escape hatch for setting debt in special cases, like swapping reserves to another token.
    function setDebt(
        address debtor_,
        ERC20 token_,
        uint256 amount_
    ) external virtual;

    /// @notice Get total balance of assets inside the treasury + any debt taken out against those assets.
    function getReserveBalance(ERC20 token_) external view virtual returns (uint256);

    /// @notice Emergency shutdown of withdrawals.
    function deactivate() external virtual;

    /// @notice Re-activate withdrawals after shutdown.
    function activate() external virtual;
}

Settings
{
  "remappings": [
    "balancer-v2/=lib/balancer-v2/",
    "bonds/=lib/bonds/src/",
    "ds-test/=lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "hardhat/=node_modules/hardhat/",
    "interfaces/=src/interfaces/",
    "libraries/=src/libraries/",
    "modules/=src/modules/",
    "policies/=src/policies/",
    "solmate/=lib/solmate/src/",
    "test/=src/test/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 10
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract Kernel","name":"kernel_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"caller_","type":"address"}],"name":"KernelAdapter_OnlyKernel","type":"error"},{"inputs":[{"internalType":"address","name":"policy_","type":"address"}],"name":"Module_PolicyNotPermitted","type":"error"},{"inputs":[],"name":"TRSRY_NoDebtOutstanding","type":"error"},{"inputs":[],"name":"TRSRY_NotActive","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ERC20","name":"token_","type":"address"},{"indexed":true,"internalType":"address","name":"policy_","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"DebtIncurred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ERC20","name":"token_","type":"address"},{"indexed":true,"internalType":"address","name":"policy_","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"DebtRepaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ERC20","name":"token_","type":"address"},{"indexed":true,"internalType":"address","name":"policy_","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"DebtSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"debtor_","type":"address"},{"indexed":true,"internalType":"contract ERC20","name":"token_","type":"address"},{"indexed":false,"internalType":"uint256","name":"newAmount_","type":"uint256"}],"name":"DecreaseDebtorApproval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"withdrawer_","type":"address"},{"indexed":true,"internalType":"contract ERC20","name":"token_","type":"address"},{"indexed":false,"internalType":"uint256","name":"newAmount_","type":"uint256"}],"name":"DecreaseWithdrawApproval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"debtor_","type":"address"},{"indexed":true,"internalType":"contract ERC20","name":"token_","type":"address"},{"indexed":false,"internalType":"uint256","name":"newAmount_","type":"uint256"}],"name":"IncreaseDebtorApproval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"withdrawer_","type":"address"},{"indexed":true,"internalType":"contract ERC20","name":"token_","type":"address"},{"indexed":false,"internalType":"uint256","name":"newAmount_","type":"uint256"}],"name":"IncreaseWithdrawApproval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"policy_","type":"address"},{"indexed":true,"internalType":"address","name":"withdrawer_","type":"address"},{"indexed":true,"internalType":"contract ERC20","name":"token_","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"Withdrawal","type":"event"},{"inputs":[],"name":"INIT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"KEYCODE","outputs":[{"internalType":"Keycode","name":"","type":"bytes5"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"uint8","name":"major","type":"uint8"},{"internalType":"uint8","name":"minor","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"activate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"active","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Kernel","name":"newKernel_","type":"address"}],"name":"changeKernel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deactivate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"contract ERC20","name":"","type":"address"}],"name":"debtApproval","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"debtor_","type":"address"},{"internalType":"contract ERC20","name":"token_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"decreaseDebtorApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"withdrawer_","type":"address"},{"internalType":"contract ERC20","name":"token_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"decreaseWithdrawApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"token_","type":"address"}],"name":"getReserveBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"debtor_","type":"address"},{"internalType":"contract ERC20","name":"token_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"increaseDebtorApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"withdrawer_","type":"address"},{"internalType":"contract ERC20","name":"token_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"increaseWithdrawApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"token_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"incurDebt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"kernel","outputs":[{"internalType":"contract Kernel","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"debtor_","type":"address"},{"internalType":"contract ERC20","name":"token_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"repayDebt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"reserveDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"debtor_","type":"address"},{"internalType":"contract ERC20","name":"token_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"setDebt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"name":"totalDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"contract ERC20","name":"","type":"address"}],"name":"withdrawApproval","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to_","type":"address"},{"internalType":"contract ERC20","name":"token_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"withdrawReserves","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6080604052600160055534801561001557600080fd5b506040516117753803806117758339810160408190526100349161005e565b600080546001600160a81b0319166001600160a01b0390921691909117600160a01b17905561008e565b60006020828403121561007057600080fd5b81516001600160a01b038116811461008757600080fd5b9392505050565b6116d88061009d6000396000f3fe608060405234801561001057600080fd5b50600436106101075760003560e01c806301a91e5c1461010c57806302fb0c5e146101215780630f15f4c01461014a57806315226b54146101525780631ae7ec2e146101735780631ff517ff1461019457806328a4ace5146101b45780632f42aef5146101df57806332b43ad2146101f25780634657b36c1461021d5780634aae164b1461023057806351b42b00146102435780635f0736a11461024b578063724000c1146102765780638b7f3fb914610289578063d4aae0c41461029c578063e6eb207a146102bc578063ea643914146102cf578063f5b92c73146102d7578063fb393f24146102ea578063ffa1ad74146102fd575b600080fd5b61011f61011a3660046114d4565b610312565b005b60005461013590600160a01b900460ff1681565b60405190151581526020015b60405180910390f35b61011f61045d565b610165610160366004611515565b610517565b604051908152602001610141565b61017b6105a6565b6040516001600160d81b03199091168152602001610141565b6101656101a2366004611515565b60036020526000908152604090205481565b6101656101c2366004611539565b600460209081526000928352604080842090915290825290205481565b61011f6101ed3660046114d4565b6105b2565b610165610200366004611539565b600260209081526000928352604080842090915290825290205481565b61011f61022b366004611515565b61072a565b61011f61023e3660046114d4565b610779565b61011f61090b565b610165610259366004611539565b600160209081526000928352604080842090915290825290205481565b61011f610284366004611572565b6109bf565b61011f6102973660046114d4565b610b84565b6000546102af906001600160a01b031681565b604051610141919061159e565b61011f6102ca3660046114d4565b610cd7565b61011f610e2b565b61011f6102e53660046114d4565b610e5a565b61011f6102f83660046114d4565b61115c565b60408051600181526000602082015201610141565b6000546001600160a01b031663f166d9eb61032b6105a6565b336000356001600160e01b0319166040518463ffffffff1660e01b8152600401610357939291906115b2565b602060405180830381865afa158015610374573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061039891906115e7565b6103c057336040516311bf00c960e01b81526004016103b7919061159e565b60405180910390fd5b6001600160a01b0380841660009081526002602090815260408083209386168352929052908120546103f390839061161f565b6001600160a01b038581166000818152600260209081526040808320948916808452948252918290208590559051848152939450919290917f9afc1acde4b7ec0d84d924e5b530aecfb57d117a7122b80904cb9912badbff5991015b60405180910390a350505050565b6000546001600160a01b031663f166d9eb6104766105a6565b336000356001600160e01b0319166040518463ffffffff1660e01b81526004016104a2939291906115b2565b602060405180830381865afa1580156104bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e391906115e7565b61050257336040516311bf00c960e01b81526004016103b7919061159e565b6000805460ff60a01b1916600160a01b179055565b6001600160a01b0381166000818152600360205260408082205490516370a0823160e01b8152919290916370a082319061055590309060040161159e565b602060405180830381865afa158015610572573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105969190611637565b6105a0919061161f565b92915050565b64545253525960d81b90565b6000546001600160a01b031663f166d9eb6105cb6105a6565b336000356001600160e01b0319166040518463ffffffff1660e01b81526004016105f7939291906115b2565b602060405180830381865afa158015610614573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061063891906115e7565b61065757336040516311bf00c960e01b81526004016103b7919061159e565b600054600160a01b900460ff166106815760405163473b682f60e11b815260040160405180910390fd5b3360009081526001602090815260408083206001600160a01b0386168452909152812080548392906106b4908490611650565b909155506106ce90506001600160a01b0383168483611294565b816001600160a01b0316836001600160a01b0316336001600160a01b03167f342e7ff505a8a0364cd0dc2ff195c315e43bce86b204846ecd36913e117b109e8460405161071d91815260200190565b60405180910390a4505050565b6000546001600160a01b03163314610757573360405163053e900f60e21b81526004016103b7919061159e565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031663f166d9eb6107926105a6565b336000356001600160e01b0319166040518463ffffffff1660e01b81526004016107be939291906115b2565b602060405180830381865afa1580156107db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ff91906115e7565b61081e57336040516311bf00c960e01b81526004016103b7919061159e565b6001600160a01b0382811660009081526004602090815260408083209387168352929052208054908290558181101561088e5761085b8183611650565b6001600160a01b0384166000908152600360205260408120805490919061088390849061161f565b909155506108c69050565b6108988282611650565b6001600160a01b038416600090815260036020526040812080549091906108c0908490611650565b90915550505b836001600160a01b0316836001600160a01b03167f4417d205f6349e66a581332b36195e74d10f878e80db907b4fd3a814aad4049d8460405161044f91815260200190565b6000546001600160a01b031663f166d9eb6109246105a6565b336000356001600160e01b0319166040518463ffffffff1660e01b8152600401610950939291906115b2565b602060405180830381865afa15801561096d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099191906115e7565b6109b057336040516311bf00c960e01b81526004016103b7919061159e565b6000805460ff60a01b19169055565b6000546001600160a01b031663f166d9eb6109d86105a6565b336000356001600160e01b0319166040518463ffffffff1660e01b8152600401610a04939291906115b2565b602060405180830381865afa158015610a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a4591906115e7565b610a6457336040516311bf00c960e01b81526004016103b7919061159e565b600054600160a01b900460ff16610a8e5760405163473b682f60e11b815260040160405180910390fd5b3360009081526002602090815260408083206001600160a01b038616845290915281208054839290610ac1908490611650565b90915550506001600160a01b038216600090815260046020908152604080832033845290915281208054839290610af990849061161f565b90915550506001600160a01b03821660009081526003602052604081208054839290610b2690849061161f565b90915550610b4090506001600160a01b0383163383611294565b60405181815233906001600160a01b038416907f7f04a714958851e1d87b504651ba77ab02f62bae8879f577bf3e07cf8567aba29060200160405180910390a35050565b6000546001600160a01b031663f166d9eb610b9d6105a6565b336000356001600160e01b0319166040518463ffffffff1660e01b8152600401610bc9939291906115b2565b602060405180830381865afa158015610be6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0a91906115e7565b610c2957336040516311bf00c960e01b81526004016103b7919061159e565b6001600160a01b0380841660009081526001602090815260408083209386168352929052908120549082821115610c6957610c648383611650565b610c6c565b60005b6001600160a01b038681166000818152600160209081526040808320948a16808452948252918290208590559051848152939450919290917f40730d80659c76c95521f0340872d27fdc8b3c47befe2ca569d2c2eedc8a049e91015b60405180910390a35050505050565b6000546001600160a01b031663f166d9eb610cf06105a6565b336000356001600160e01b0319166040518463ffffffff1660e01b8152600401610d1c939291906115b2565b602060405180830381865afa158015610d39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5d91906115e7565b610d7c57336040516311bf00c960e01b81526004016103b7919061159e565b6001600160a01b0380841660009081526001602090815260408083209386168352929052908120549082610db283600019611650565b1115610dc757610dc2838361161f565b610dcb565b6000195b6001600160a01b038681166000818152600160209081526040808320948a16808452948252918290208590559051848152939450919290917f8bbc2784c9e4073e20f60d8c7218cbd211c43ca2ee041bc037f977693a0c8c1b9101610cc8565b6000546001600160a01b03163314610e58573360405163053e900f60e21b81526004016103b7919061159e565b565b6000546001600160a01b031663f166d9eb610e736105a6565b336000356001600160e01b0319166040518463ffffffff1660e01b8152600401610e9f939291906115b2565b602060405180830381865afa158015610ebc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee091906115e7565b610eff57336040516311bf00c960e01b81526004016103b7919061159e565b600554600114610f3e5760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064016103b7565b60026005556001600160a01b0380831660009081526004602090815260408083209387168352929052908120549003610f8a5760405163a4255dc560e01b815260040160405180910390fd5b6040516370a0823160e01b81526000906001600160a01b038416906370a0823190610fb990309060040161159e565b602060405180830381865afa158015610fd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ffa9190611637565b90506110116001600160a01b0384163330856113a1565b600081846001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611040919061159e565b602060405180830381865afa15801561105d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110819190611637565b61108b9190611650565b9050828111156110985750815b6001600160a01b038085166000908152600460209081526040808320938916835292905290812080548392906110cf908490611650565b90915550506001600160a01b038416600090815260036020526040812080548392906110fc908490611650565b92505081905550846001600160a01b0316846001600160a01b03167feef1a28252f7c3266ccea3202ee9693f0834485bc3551310a406e04829c7e2cf8360405161114891815260200190565b60405180910390a350506001600555505050565b6000546001600160a01b031663f166d9eb6111756105a6565b336000356001600160e01b0319166040518463ffffffff1660e01b81526004016111a1939291906115b2565b602060405180830381865afa1580156111be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e291906115e7565b61120157336040516311bf00c960e01b81526004016103b7919061159e565b6001600160a01b038084166000908152600260209081526040808320938616835292905290812054611234908390611650565b6001600160a01b038581166000818152600260209081526040808320948916808452948252918290208590559051848152939450919290917fbb8caa1e59333c99899b67ccacb2b942c5a5ebf1a2bff4932b50274da81fe8d5910161044f565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916112f09190611667565b6000604051808303816000865af19150503d806000811461132d576040519150601f19603f3d011682016040523d82523d6000602084013e611332565b606091505b509150915081801561135c57508051158061135c57508080602001905181019061135c91906115e7565b61139a5760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064016103b7565b5050505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916114059190611667565b6000604051808303816000865af19150503d8060008114611442576040519150601f19603f3d011682016040523d82523d6000602084013e611447565b606091505b509150915081801561147157508051158061147157508080602001905181019061147191906115e7565b6114b45760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b60448201526064016103b7565b505050505050565b6001600160a01b03811681146114d157600080fd5b50565b6000806000606084860312156114e957600080fd5b83356114f4816114bc565b92506020840135611504816114bc565b929592945050506040919091013590565b60006020828403121561152757600080fd5b8135611532816114bc565b9392505050565b6000806040838503121561154c57600080fd5b8235611557816114bc565b91506020830135611567816114bc565b809150509250929050565b6000806040838503121561158557600080fd5b8235611590816114bc565b946020939093013593505050565b6001600160a01b0391909116815260200190565b6001600160d81b03199390931683526001600160a01b039190911660208301526001600160e01b031916604082015260600190565b6000602082840312156115f957600080fd5b8151801515811461153257600080fd5b634e487b7160e01b600052601160045260246000fd5b6000821982111561163257611632611609565b500190565b60006020828403121561164957600080fd5b5051919050565b60008282101561166257611662611609565b500390565b6000825160005b81811015611688576020818601810151858301520161166e565b81811115611697576000828501525b50919091019291505056fea26469706673582212201278de3d795ae71bdd12fd402a0a04298e2a537701bf279a3c0fb166fa529f0a64736f6c634300080f00330000000000000000000000002286d7f9639e8158fad1169e76d1fbc38247f54b

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101075760003560e01c806301a91e5c1461010c57806302fb0c5e146101215780630f15f4c01461014a57806315226b54146101525780631ae7ec2e146101735780631ff517ff1461019457806328a4ace5146101b45780632f42aef5146101df57806332b43ad2146101f25780634657b36c1461021d5780634aae164b1461023057806351b42b00146102435780635f0736a11461024b578063724000c1146102765780638b7f3fb914610289578063d4aae0c41461029c578063e6eb207a146102bc578063ea643914146102cf578063f5b92c73146102d7578063fb393f24146102ea578063ffa1ad74146102fd575b600080fd5b61011f61011a3660046114d4565b610312565b005b60005461013590600160a01b900460ff1681565b60405190151581526020015b60405180910390f35b61011f61045d565b610165610160366004611515565b610517565b604051908152602001610141565b61017b6105a6565b6040516001600160d81b03199091168152602001610141565b6101656101a2366004611515565b60036020526000908152604090205481565b6101656101c2366004611539565b600460209081526000928352604080842090915290825290205481565b61011f6101ed3660046114d4565b6105b2565b610165610200366004611539565b600260209081526000928352604080842090915290825290205481565b61011f61022b366004611515565b61072a565b61011f61023e3660046114d4565b610779565b61011f61090b565b610165610259366004611539565b600160209081526000928352604080842090915290825290205481565b61011f610284366004611572565b6109bf565b61011f6102973660046114d4565b610b84565b6000546102af906001600160a01b031681565b604051610141919061159e565b61011f6102ca3660046114d4565b610cd7565b61011f610e2b565b61011f6102e53660046114d4565b610e5a565b61011f6102f83660046114d4565b61115c565b60408051600181526000602082015201610141565b6000546001600160a01b031663f166d9eb61032b6105a6565b336000356001600160e01b0319166040518463ffffffff1660e01b8152600401610357939291906115b2565b602060405180830381865afa158015610374573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061039891906115e7565b6103c057336040516311bf00c960e01b81526004016103b7919061159e565b60405180910390fd5b6001600160a01b0380841660009081526002602090815260408083209386168352929052908120546103f390839061161f565b6001600160a01b038581166000818152600260209081526040808320948916808452948252918290208590559051848152939450919290917f9afc1acde4b7ec0d84d924e5b530aecfb57d117a7122b80904cb9912badbff5991015b60405180910390a350505050565b6000546001600160a01b031663f166d9eb6104766105a6565b336000356001600160e01b0319166040518463ffffffff1660e01b81526004016104a2939291906115b2565b602060405180830381865afa1580156104bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e391906115e7565b61050257336040516311bf00c960e01b81526004016103b7919061159e565b6000805460ff60a01b1916600160a01b179055565b6001600160a01b0381166000818152600360205260408082205490516370a0823160e01b8152919290916370a082319061055590309060040161159e565b602060405180830381865afa158015610572573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105969190611637565b6105a0919061161f565b92915050565b64545253525960d81b90565b6000546001600160a01b031663f166d9eb6105cb6105a6565b336000356001600160e01b0319166040518463ffffffff1660e01b81526004016105f7939291906115b2565b602060405180830381865afa158015610614573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061063891906115e7565b61065757336040516311bf00c960e01b81526004016103b7919061159e565b600054600160a01b900460ff166106815760405163473b682f60e11b815260040160405180910390fd5b3360009081526001602090815260408083206001600160a01b0386168452909152812080548392906106b4908490611650565b909155506106ce90506001600160a01b0383168483611294565b816001600160a01b0316836001600160a01b0316336001600160a01b03167f342e7ff505a8a0364cd0dc2ff195c315e43bce86b204846ecd36913e117b109e8460405161071d91815260200190565b60405180910390a4505050565b6000546001600160a01b03163314610757573360405163053e900f60e21b81526004016103b7919061159e565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031663f166d9eb6107926105a6565b336000356001600160e01b0319166040518463ffffffff1660e01b81526004016107be939291906115b2565b602060405180830381865afa1580156107db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ff91906115e7565b61081e57336040516311bf00c960e01b81526004016103b7919061159e565b6001600160a01b0382811660009081526004602090815260408083209387168352929052208054908290558181101561088e5761085b8183611650565b6001600160a01b0384166000908152600360205260408120805490919061088390849061161f565b909155506108c69050565b6108988282611650565b6001600160a01b038416600090815260036020526040812080549091906108c0908490611650565b90915550505b836001600160a01b0316836001600160a01b03167f4417d205f6349e66a581332b36195e74d10f878e80db907b4fd3a814aad4049d8460405161044f91815260200190565b6000546001600160a01b031663f166d9eb6109246105a6565b336000356001600160e01b0319166040518463ffffffff1660e01b8152600401610950939291906115b2565b602060405180830381865afa15801561096d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099191906115e7565b6109b057336040516311bf00c960e01b81526004016103b7919061159e565b6000805460ff60a01b19169055565b6000546001600160a01b031663f166d9eb6109d86105a6565b336000356001600160e01b0319166040518463ffffffff1660e01b8152600401610a04939291906115b2565b602060405180830381865afa158015610a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a4591906115e7565b610a6457336040516311bf00c960e01b81526004016103b7919061159e565b600054600160a01b900460ff16610a8e5760405163473b682f60e11b815260040160405180910390fd5b3360009081526002602090815260408083206001600160a01b038616845290915281208054839290610ac1908490611650565b90915550506001600160a01b038216600090815260046020908152604080832033845290915281208054839290610af990849061161f565b90915550506001600160a01b03821660009081526003602052604081208054839290610b2690849061161f565b90915550610b4090506001600160a01b0383163383611294565b60405181815233906001600160a01b038416907f7f04a714958851e1d87b504651ba77ab02f62bae8879f577bf3e07cf8567aba29060200160405180910390a35050565b6000546001600160a01b031663f166d9eb610b9d6105a6565b336000356001600160e01b0319166040518463ffffffff1660e01b8152600401610bc9939291906115b2565b602060405180830381865afa158015610be6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0a91906115e7565b610c2957336040516311bf00c960e01b81526004016103b7919061159e565b6001600160a01b0380841660009081526001602090815260408083209386168352929052908120549082821115610c6957610c648383611650565b610c6c565b60005b6001600160a01b038681166000818152600160209081526040808320948a16808452948252918290208590559051848152939450919290917f40730d80659c76c95521f0340872d27fdc8b3c47befe2ca569d2c2eedc8a049e91015b60405180910390a35050505050565b6000546001600160a01b031663f166d9eb610cf06105a6565b336000356001600160e01b0319166040518463ffffffff1660e01b8152600401610d1c939291906115b2565b602060405180830381865afa158015610d39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5d91906115e7565b610d7c57336040516311bf00c960e01b81526004016103b7919061159e565b6001600160a01b0380841660009081526001602090815260408083209386168352929052908120549082610db283600019611650565b1115610dc757610dc2838361161f565b610dcb565b6000195b6001600160a01b038681166000818152600160209081526040808320948a16808452948252918290208590559051848152939450919290917f8bbc2784c9e4073e20f60d8c7218cbd211c43ca2ee041bc037f977693a0c8c1b9101610cc8565b6000546001600160a01b03163314610e58573360405163053e900f60e21b81526004016103b7919061159e565b565b6000546001600160a01b031663f166d9eb610e736105a6565b336000356001600160e01b0319166040518463ffffffff1660e01b8152600401610e9f939291906115b2565b602060405180830381865afa158015610ebc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee091906115e7565b610eff57336040516311bf00c960e01b81526004016103b7919061159e565b600554600114610f3e5760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064016103b7565b60026005556001600160a01b0380831660009081526004602090815260408083209387168352929052908120549003610f8a5760405163a4255dc560e01b815260040160405180910390fd5b6040516370a0823160e01b81526000906001600160a01b038416906370a0823190610fb990309060040161159e565b602060405180830381865afa158015610fd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ffa9190611637565b90506110116001600160a01b0384163330856113a1565b600081846001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611040919061159e565b602060405180830381865afa15801561105d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110819190611637565b61108b9190611650565b9050828111156110985750815b6001600160a01b038085166000908152600460209081526040808320938916835292905290812080548392906110cf908490611650565b90915550506001600160a01b038416600090815260036020526040812080548392906110fc908490611650565b92505081905550846001600160a01b0316846001600160a01b03167feef1a28252f7c3266ccea3202ee9693f0834485bc3551310a406e04829c7e2cf8360405161114891815260200190565b60405180910390a350506001600555505050565b6000546001600160a01b031663f166d9eb6111756105a6565b336000356001600160e01b0319166040518463ffffffff1660e01b81526004016111a1939291906115b2565b602060405180830381865afa1580156111be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e291906115e7565b61120157336040516311bf00c960e01b81526004016103b7919061159e565b6001600160a01b038084166000908152600260209081526040808320938616835292905290812054611234908390611650565b6001600160a01b038581166000818152600260209081526040808320948916808452948252918290208590559051848152939450919290917fbb8caa1e59333c99899b67ccacb2b942c5a5ebf1a2bff4932b50274da81fe8d5910161044f565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916112f09190611667565b6000604051808303816000865af19150503d806000811461132d576040519150601f19603f3d011682016040523d82523d6000602084013e611332565b606091505b509150915081801561135c57508051158061135c57508080602001905181019061135c91906115e7565b61139a5760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064016103b7565b5050505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916114059190611667565b6000604051808303816000865af19150503d8060008114611442576040519150601f19603f3d011682016040523d82523d6000602084013e611447565b606091505b509150915081801561147157508051158061147157508080602001905181019061147191906115e7565b6114b45760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b60448201526064016103b7565b505050505050565b6001600160a01b03811681146114d157600080fd5b50565b6000806000606084860312156114e957600080fd5b83356114f4816114bc565b92506020840135611504816114bc565b929592945050506040919091013590565b60006020828403121561152757600080fd5b8135611532816114bc565b9392505050565b6000806040838503121561154c57600080fd5b8235611557816114bc565b91506020830135611567816114bc565b809150509250929050565b6000806040838503121561158557600080fd5b8235611590816114bc565b946020939093013593505050565b6001600160a01b0391909116815260200190565b6001600160d81b03199390931683526001600160a01b039190911660208301526001600160e01b031916604082015260600190565b6000602082840312156115f957600080fd5b8151801515811461153257600080fd5b634e487b7160e01b600052601160045260246000fd5b6000821982111561163257611632611609565b500190565b60006020828403121561164957600080fd5b5051919050565b60008282101561166257611662611609565b500390565b6000825160005b81811015611688576020818601810151858301520161166e565b81811115611697576000828501525b50919091019291505056fea26469706673582212201278de3d795ae71bdd12fd402a0a04298e2a537701bf279a3c0fb166fa529f0a64736f6c634300080f0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000002286d7f9639e8158fad1169e76d1fbc38247f54b

-----Decoded View---------------
Arg [0] : kernel_ (address): 0x2286d7f9639e8158FaD1169e76d1FbC38247f54b

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000002286d7f9639e8158fad1169e76d1fbc38247f54b


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.