// SPDX-License-Identifier: MIT pragma solidity ^0.8.30; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; /// @title Love /// @notice An ERC-20 pegged to wETH at a fixed rate of 100000 LOVE per wETH. /// Every LOVE in circulation is backed by wETH held by this contract: /// supply only moves through `deposit` and `withdraw`, and both are /// permissionless. contract Love is ERC20 { using SafeERC20 for IERC20; uint256 public constant RATE = 100_000; IERC20 public immutable WETH; error AmountNotDivisibleByRate(uint256 loveAmount, uint256 rate); event Deposit(address indexed account, uint256 wethAmount, uint256 loveAmount); event Withdraw(address indexed account, uint256 loveAmount, uint256 wethAmount); constructor(IERC20 weth_) ERC20("Love", "LOVE") { WETH = weth_; } /// @notice Lock `wethAmount` wETH and mint `wethAmount * RATE` LOVE to the caller. function deposit(uint256 wethAmount) external { uint256 loveAmount = wethAmount * RATE; WETH.safeTransferFrom(msg.sender, address(this), wethAmount); _mint(msg.sender, loveAmount); emit Deposit(msg.sender, wethAmount, loveAmount); } /// @notice Burn `loveAmount` LOVE and release `loveAmount / RATE` wETH to the caller. /// @dev Reverts unless `loveAmount` is a multiple of `RATE`, so the peg never /// rounds against the caller or the remaining holders. function withdraw(uint256 loveAmount) external { if (loveAmount % RATE != 0) revert AmountNotDivisibleByRate(loveAmount, RATE); uint256 wethAmount = loveAmount / RATE; _burn(msg.sender, loveAmount); WETH.safeTransfer(msg.sender, wethAmount); emit Withdraw(msg.sender, loveAmount, wethAmount); } }