flETH

0x00000000043c1117dafa3a3d0c7148eb48b30130

Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
6,561 bytes
ABI entries
58
15 read · 17 write
License
none

Contract information

Address
0x00000000043c1117dafa3a3d0c7148eb48b30130
Chain
Robinhood Chain (4663)
Compiler
v0.8.26+commit.8a97fa7a
Optimization
Enabled
Creation tx
0xb019a6a330…ebe5004757

Token

Name
flETH
Symbol
flETH
Decimals
18
Holders
72

Read contract (15)

allowance(address, address)uint256
balanceOf(address)uint256
decimals()uint8
name()string
owner()address
ownershipHandoverExpiresAt(address)uint256
rebalanceThreshold()uint256
strategy()address
symbol()string
totalSupply()uint256
underlyingBalance()uint256
underlyingETHBalance()uint256
weth()address
yieldAccumulated()uint256
yieldReceiver()address

Events (6)

ApprovalOwnershipHandoverCanceledOwnershipHandoverRequestedOwnershipTransferredStrategyFundingSkippedTransfer

ABI

[
  {
    "inputs": [
      {
        "internalType": "contract IWETH",
        "name": "weth_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "yieldReceiver_",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "AlreadyInitialized",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "AmountExceedsETHBalance",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "CurrentStrategyHasBalance",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "allowance",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "needed",
        "type": "uint256"
      }
    ],
    "name": "ERC20InsufficientAllowance",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "balance",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "needed",
        "type": "uint256"
      }
    ],
    "name": "ERC20InsufficientBalance",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "approver",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidApprover",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "receiver",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidReceiver",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidSender",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidSpender",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NewOwnerIsZeroAddress",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NoHandoverRequest",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "OnlySelf",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "RebalanceThresholdExceedsMax",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "Reentrancy",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "name": "SafeERC20FailedOperation",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "UnableToSendETH",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "Unauthorized",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "YieldReceiverIsZero",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "owner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Approval",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "pendingOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipHandoverCanceled",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "pendingOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipHandoverRequested",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "oldOwner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipTransferred",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "bytes",
        "name": "reason",
        "type": "bytes"
      }
    ],
    "name": "StrategyFundingSkipped",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Transfer",
    "type": "event"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      }
    ],
    "name": "allowance",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "approve",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "balanceOf",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "cancelOwnershipHandover",
    "outputs": [],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "contract IFLETHStrategy",
        "name": "strategy_",
        "type": "address"
      }
    ],
    "name": "changeStrategy",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "pendingOwner",
        "type": "address"
      }
    ],
    "name": "completeOwnershipHandover",
    "outputs": [],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "decimals",
    "outputs": [
      {
        "internalType": "uint8",
        "name": "",
        "type": "uint8"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "wethAmount",
        "type": "uint256"
      }
    ],
    "name": "deposit",
    "outputs": [],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "emergencyRescue",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "harvest",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "name",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "pendingOwner",
        "type": "address"
      }
    ],
    "name": "ownershipHandoverExpiresAt",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "result",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "rebalance",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "rebalanceThreshold",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "renounceOwnership",
    "outputs": [],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "requestOwnershipHandover",
    "outputs": [],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "selfRebalance",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "rebalanceThreshold_",
        "type": "uint256"
      }
    ],
    "name": "setRebalanceThreshold",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "yieldReceiver_",
        "type": "address"
      }
    ],
    "name": "setYieldReceiver",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "strategy",
    "outputs": [
      {
        "internalType": "contract IFLStrategy",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "symbol",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalSupply",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "transfer",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "transferFrom",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "underlyingBalance",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "underlyingETHBalance",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "weth",
    "outputs": [
      {
        "internalType": "contract IWETH",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "withdraw",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "yieldAccumulated",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "yieldReceiver",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "stateMutability": "payable",
    "type": "receive"
  }
]

Source code

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {ERC20} from '@openzeppelin/contracts/token/ERC20/ERC20.sol';
import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';

import {FLToken} from '@fleth/base/FLToken.sol';

import {IFLToken} from '@fleth-interfaces/IFLToken.sol';
import {IFLETH} from '@fleth-interfaces/IFLETH.sol';
import {IFLETHStrategy} from '@fleth-interfaces/IFLETHStrategy.sol';
import {IWETH} from '@fleth-interfaces/IWETH.sol';

/**
 * The flETH token. Wraps native ETH 1:1 on top of the shared {FLToken} vault logic.
 *
 *    ______/\\\\\__/\\\\\\_____/\\\\\\\\\\\\\\\__/\\\\\\\\\\\\\\\___/\\\________/\\\__________
 *    _____/\\\///__\////\\\____\/\\\///////////__\///////\\\/////___\/\\\_______\/\\\_________
 *    _____/\\\_________\/\\\____\/\\\___________________\/\\\________\/\\\_______\/\\\________
 *    ___/\\\\\\\\\______\/\\\____\/\\\\\\\\\\\___________\/\\\________\/\\\\\\\\\\\\\\\_______
 *    ___\////\\\//_______\/\\\____\/\\\///////____________\/\\\________\/\\\/////////\\\______
 *    _______\/\\\_________\/\\\____\/\\\___________________\/\\\________\/\\\_______\/\\\_____
 *    ________\/\\\_________\/\\\____\/\\\___________________\/\\\________\/\\\_______\/\\\____
 *    _________\/\\\_______/\\\\\\\\\_\/\\\\\\\\\\\\\\\_______\/\\\________\/\\\_______\/\\\___
 *    __________\///_______\/////////__\///////////////________\///_________\///________\///___
 *
 */
contract flETH is FLToken, IFLETH {
    using SafeERC20 for IWETH;

    /// The WETH token address
    IWETH public immutable override weth;

    /**
     * Set up our contract dependencies and initialise our flETH ERC20.
     *
     * @param weth_ The WETH token address
     * @param yieldReceiver_ The recipient address of yield
     */
    constructor(IWETH weth_, address yieldReceiver_) ERC20('flETH', 'flETH') FLToken(yieldReceiver_) {
        weth = weth_;
    }

    /**
     * Makes a deposit into the contract, taking ETH and/or WETH and returning flETH.
     *
     * @dev This function can receive ETH and will give an amount of flETH equal to ETH + WETH.
     *
     * @param wethAmount The amount of WETH to transfer into the function
     */
    function deposit(uint wethAmount) external payable override nonReentrant {
        uint ethToDeposit = msg.value;

        // If we have WETH specified, then transfer it into the contract and unwrap into ETH
        if (wethAmount != 0) {
            weth.safeTransferFrom(msg.sender, address(this), wethAmount);
            weth.withdraw(wethAmount);
            ethToDeposit += wethAmount;
        }

        _mintAndRebalance(msg.sender, ethToDeposit);
    }

    /**
     * Allows the strategy to be updated. Validates that there is no ETH currently held in the
     * strategy to prevent loss of ETH.
     *
     * @param strategy_ The new {IFLETHStrategy} strategy to be used
     */
    function changeStrategy(IFLETHStrategy strategy_) external override onlyOwner {
        _changeStrategy(strategy_);
    }

    /**
     * ETH-denominated alias of {underlyingBalance}, preserved for backwards compatibility.
     */
    function underlyingETHBalance() external view override returns (uint) {
        return underlyingBalance();
    }

    /**
     * Disambiguates the `owner()` inherited from both {FLToken} and {IFLToken}.
     */
    function owner() public view override (FLToken, IFLToken) returns (address) {
        return FLToken.owner();
    }

    /**
     * The raw ETH balance held directly by the contract.
     */
    function _heldBalance() internal view override returns (uint) {
        return address(this).balance;
    }

    /**
     * Transfers ETH to `to`, ensuring that the call is successful.
     */
    function _transferOut(address to, uint amount) internal override {
        (bool success,) = to.call{value: amount}('');
        if (!success) revert UnableToSendETH();
    }

    /**
     * Funds the strategy by pushing ETH with the call.
     */
    function _fundStrategy(uint amount) internal override {
        IFLETHStrategy(address(strategy)).convertETHToLST{value: amount}();
    }

    function _revertAmountExceedsBalance() internal pure override {
        revert AmountExceedsETHBalance();
    }

    /**
     * Receives ETH from contracts like WETH and the strategy.
     */
    receive() external payable {}
}
Chain explorer4315msChain node81ms