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
- Creator
- 0x4e59b44847…26c0B4956C
- Creation tx
- 0xb019a6a330…ebe5004757
Token
- Name
- flETH
- Symbol
- flETH
- Decimals
- 18
- Holders
- 72
- Market
- View token page →
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