1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
// 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);
}
}
|