forked from perspectivefi/core-v2-hats
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathYieldToken.sol
158 lines (139 loc) · 4.86 KB
/
YieldToken.sol
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.20;
import "openzeppelin-math/Math.sol";
import "openzeppelin-erc20-extensions/ERC20PermitUpgradeable.sol";
import "openzeppelin-erc20-basic/extensions/IERC20Metadata.sol";
import "../interfaces/IPrincipalToken.sol";
import "../interfaces/IYieldToken.sol";
/**
* @title Yield Token contract
* @author Spectra Finance
* @notice A YieldToken (YT) is a Spectra token that keeps track of users' yield ownership. It is minted at same
* times and amounts as a PT.
*/
contract YieldToken is IYieldToken, ERC20PermitUpgradeable {
using Math for uint256;
/** @notice PT associated with this yt */
address private pt;
/* MODIFIERS
*****************************************************************************************************************/
/** @notice Ensures the associated PT contract is not paused */
modifier whenPTNotPaused() {
if (IPrincipalToken(pt).paused()) {
revert EnforcedPause();
}
_;
}
// constructor
constructor() {
_disableInitializers(); // using this so that the deployed logic contract later cannot be initialized.
}
/**
* @notice Initializer of the contract.
* @param _name The name of the yt token.
* @param _symbol The symbol of the yt token.
* @param _pt The address of the pt associated with this yt token.
*/
function initialize(
string calldata _name,
string calldata _symbol,
address _pt
) external initializer {
__ERC20_init(_name, _symbol);
__ERC20Permit_init(_name);
pt = _pt;
}
/** @dev See {IYieldToken-burnWithoutYieldUpdate} */
function burnWithoutYieldUpdate(
address owner,
address caller,
uint256 amount
) external override {
if (msg.sender != pt) {
revert UnauthorizedCaller();
}
if (owner != caller) {
_spendAllowance(owner, caller, amount);
}
_burn(owner, amount);
}
/** @dev See {IYieldToken-mint} */
function mint(address to, uint256 amount) external override {
if (msg.sender != pt) {
revert UnauthorizedCaller();
}
_mint(to, amount);
}
/** @dev See {IYieldToken-burn} */
function burn(uint256 amount) public override {
if (block.timestamp >= IPrincipalToken(pt).maturity() && amount != 0) {
revert ERC20InsufficientBalance(msg.sender, 0, amount);
}
IPrincipalToken(pt).updateYield(msg.sender);
_burn(msg.sender, amount);
}
/** @dev See {IYieldToken-transfer}. */
function transfer(
address to,
uint256 amount
) public virtual override(IYieldToken, ERC20Upgradeable) returns (bool) {
if (block.timestamp >= IPrincipalToken(pt).maturity() && amount != 0) {
revert ERC20InsufficientBalance(msg.sender, 0, amount);
}
IPrincipalToken(pt).beforeYtTransfer(msg.sender, to);
return super.transfer(to, amount);
}
/** @dev See {IYieldToken-transferFrom}. */
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override(IYieldToken, ERC20Upgradeable) returns (bool) {
if (block.timestamp >= IPrincipalToken(pt).maturity() && amount != 0) {
revert ERC20InsufficientBalance(from, 0, amount);
}
IPrincipalToken(pt).beforeYtTransfer(from, to);
return super.transferFrom(from, to, amount);
}
/** @dev See {IERC20Upgradeable-decimals} */
function decimals()
public
view
virtual
override(IYieldToken, ERC20Upgradeable)
returns (uint8)
{
return IERC20Metadata(pt).decimals();
}
/** @dev See {IYieldToken-getPT} */
function getPT() public view virtual override returns (address) {
return pt;
}
/**
* @dev See {IYieldToken-totalSupply}.
*/
function totalSupply() public view override(IYieldToken, ERC20Upgradeable) returns (uint256) {
return (block.timestamp < IPrincipalToken(pt).maturity()) ? super.totalSupply() : 0;
}
/** @dev See {IYieldToken-balanceOf} */
function balanceOf(
address account
) public view override(IYieldToken, ERC20Upgradeable) returns (uint256) {
return (block.timestamp < IPrincipalToken(pt).maturity()) ? super.balanceOf(account) : 0;
}
/** @dev See {IYieldToken-actualBalanceOf} */
function actualBalanceOf(address account) public view override returns (uint256) {
return super.balanceOf(account);
}
/**
* @dev See {ERC20PermitUpgradeable-_update}.
* @dev the associated PT contract must not be paused.
*/
function _update(
address from,
address to,
uint256 value
) internal virtual override whenPTNotPaused {
super._update(from, to, value);
}
}