generated from FrankieIsLost/forge-template
-
Notifications
You must be signed in to change notification settings - Fork 7
/
xTRIBE.sol
151 lines (130 loc) · 5.09 KB
/
xTRIBE.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
// SPDX-License-Identifier: MIT
// Voting logic inspired by OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/ERC20Votes.sol)
pragma solidity ^0.8.0;
import {ERC20} from "solmate/tokens/ERC20.sol";
import {Auth, Authority} from "solmate/auth/Auth.sol";
import {Multicall} from "ERC4626/external/Multicall.sol";
import {xERC4626, ERC4626} from "ERC4626/xERC4626.sol";
import {ERC20MultiVotes} from "flywheel/token/ERC20MultiVotes.sol";
import {ERC20Gauges} from "flywheel/token/ERC20Gauges.sol";
interface ITribe {
function getPriorVotes(address account, uint256 blockNumber)
external
view
returns (uint96);
function getCurrentVotes(address account) external view returns (uint96);
}
/**
@title xTribe: Yield bearing, voting, and gauge enabled TRIBE
@notice xTribe is an ERC-4626 compliant TRIBE token which:
* distributes TRIBE rewards to stakers in a manipulation resistant manner.
* allows on-chain voting with both xTRIBE and TRIBE voting power.
* includes gauges for reward direction
The xTRIBE owner/authority ONLY control the maximum number and approved overrides of gauges and delegates, as well as the live gauge list.
*/
contract xTRIBE is ERC20MultiVotes, ERC20Gauges, xERC4626, Multicall {
constructor(
ERC20 _tribe,
address _owner,
Authority _authority,
uint32 _rewardsCycleLength,
uint32 _incrementFreezeWindow
)
Auth(_owner, _authority)
xERC4626(_rewardsCycleLength)
ERC20Gauges(_rewardsCycleLength, _incrementFreezeWindow)
ERC4626(_tribe, "xTribe: Gov + Yield", "xTRIBE")
{}
function tribe() public view returns (ITribe) {
return ITribe(address(asset));
}
/*///////////////////////////////////////////////////////////////
VOTING LOGIC
//////////////////////////////////////////////////////////////*/
/**
@notice calculate voting power of xTRIBE AND underlying TRIBE voting power for user, converted to xTRIBE shares.
@param account the user to calculate voting power of.
@return the voting power of `account`.
*/
function getVotes(address account) public view override returns (uint256) {
return
super.getVotes(account) +
convertToShares(tribe().getCurrentVotes(account));
}
/**
@notice calculate past voting power at a given block of xTRIBE AND underlying TRIBE voting power for user, converted to xTRIBE shares.
@param account the user to calculate voting power of.
@param blockNumber the block in the past to get voting power from.
@return the voting power of `account` at block `blockNumber`.
@dev TRIBE voting power is included converted to xTRIBE shares at the CURRENT conversion rate.
Because xTRIBE shares should monotonically increase in value relative to TRIBE, this makes TRIBE historical voting power decay.
*/
function getPastVotes(address account, uint256 blockNumber)
public
view
override
returns (uint256)
{
return
super.getPastVotes(account, blockNumber) +
convertToShares(tribe().getPriorVotes(account, blockNumber));
}
/**
@notice an event for manually emitting voting balances.
This is important because this contract cannot be synchronously notified of Tribe delegations.
*/
function emitVotingBalances(address[] calldata accounts)
external
requiresAuth
{
uint256 size = accounts.length;
for (uint256 i = 0; i < size; ) {
emit DelegateVotesChanged(accounts[i], 0, getVotes(accounts[i]));
unchecked {
i++;
}
}
}
/*///////////////////////////////////////////////////////////////
xERC4626 LOGIC
//////////////////////////////////////////////////////////////*/
function syncRewards() public override requiresAuth {
super.syncRewards();
}
/*///////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
function _burn(address from, uint256 amount)
internal
virtual
override(ERC20, ERC20Gauges, ERC20MultiVotes)
{
_decrementWeightUntilFree(from, amount);
_decrementVotesUntilFree(from, amount);
ERC20._burn(from, amount);
}
function transfer(address to, uint256 amount)
public
virtual
override(ERC20, ERC20Gauges, ERC20MultiVotes)
returns (bool)
{
_decrementWeightUntilFree(msg.sender, amount);
_decrementVotesUntilFree(msg.sender, amount);
return ERC20.transfer(to, amount);
}
function transferFrom(
address from,
address to,
uint256 amount
)
public
virtual
override(ERC20, ERC20Gauges, ERC20MultiVotes)
returns (bool)
{
_decrementWeightUntilFree(from, amount);
_decrementVotesUntilFree(from, amount);
return ERC20.transferFrom(from, to, amount);
}
}