-
Notifications
You must be signed in to change notification settings - Fork 99
/
GenesisGroup.sol
164 lines (125 loc) · 4.6 KB
/
GenesisGroup.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
159
160
161
162
163
164
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "./IGenesisGroup.sol";
import "./IDOInterface.sol";
import "../utils/Timed.sol";
import "../refs/CoreRef.sol";
import "../pool/IPool.sol";
import "../oracle/IBondingCurveOracle.sol";
import "../bondingcurve/IBondingCurve.sol";
interface IOrchestrator {
function launchGovernance() external;
function pool() external returns(address);
function bondingCurveOracle() external returns(address);
}
/// @title IGenesisGroup implementation
/// @author Fei Protocol
contract GenesisGroup is IGenesisGroup, CoreRef, ERC20, ERC20Burnable, Timed {
using Decimal for Decimal.D256;
IOrchestrator private orchestrator;
IBondingCurve private bondingcurve;
IBondingCurveOracle private bondingCurveOracle;
IPool private pool;
IDOInterface private ido;
uint private exchangeRateDiscount;
/// @notice a cap on the genesis group purchase price
Decimal.D256 public maxGenesisPrice;
/// @notice GenesisGroup constructor
/// @param _core Fei Core address to reference
/// @param _bondingcurve Bonding curve address for purchase
/// @param _ido IDO contract to deploy
/// @param _oracle Bonding curve oracle
/// @param _pool Staking Pool
/// @param _duration duration of the Genesis Period
/// @param _maxPriceBPs max price of FEI allowed in Genesis Group in dollar terms
/// @param _exchangeRateDiscount a divisor on the FEI/TRIBE ratio at Genesis to deploy to the IDO
constructor(
address _core,
address _bondingcurve,
address _ido,
address _oracle,
address _pool,
uint32 _duration,
uint _maxPriceBPs,
uint _exchangeRateDiscount
) public
CoreRef(_core)
ERC20("Fei Genesis Group", "FGEN")
Timed(_duration)
{
bondingcurve = IBondingCurve(_bondingcurve);
exchangeRateDiscount = _exchangeRateDiscount;
ido = IDOInterface(_ido);
pool = IPool(_pool);
bondingCurveOracle = IBondingCurveOracle(_oracle);
_initTimed();
maxGenesisPrice = Decimal.ratio(_maxPriceBPs, 10000);
}
modifier onlyGenesisPeriod() {
require(!isTimeEnded(), "GenesisGroup: Not in Genesis Period");
_;
}
function purchase(address to, uint value) external override payable onlyGenesisPeriod {
require(msg.value == value, "GenesisGroup: value mismatch");
require(value != 0, "GenesisGroup: no value sent");
_mint(to, value);
emit Purchase(to, value);
}
function redeem(address to) external override postGenesis {
Decimal.D256 memory ratio = _fgenRatio(to);
require(!ratio.equals(Decimal.zero()), "GensisGroup: No balance to redeem");
uint amountIn = balanceOf(to);
burnFrom(to, amountIn);
uint feiAmount = ratio.mul(feiBalance()).asUint256();
fei().transfer(to, feiAmount);
uint tribeAmount = ratio.mul(tribeBalance()).asUint256();
tribe().transfer(to, tribeAmount);
emit Redeem(to, amountIn, feiAmount, tribeAmount);
}
function launch() external override {
require(isTimeEnded() || isAtMaxPrice(), "GenesisGroup: Still in Genesis Period");
core().completeGenesisGroup();
address genesisGroup = address(this);
uint balance = genesisGroup.balance;
bondingCurveOracle.init(bondingcurve.getAveragePrice(balance));
bondingcurve.purchase{value: balance}(genesisGroup, balance);
bondingcurve.allocate();
pool.init();
ido.deploy(_feiTribeExchangeRate());
// solhint-disable-next-line not-rely-on-time
emit Launch(now);
}
function getAmountOut(
uint amountIn,
bool inclusive
) public view override returns (uint feiAmount, uint tribeAmount) {
uint totalIn = totalSupply();
if (!inclusive) {
totalIn += amountIn;
}
require(amountIn <= totalIn, "GenesisGroup: Not enough supply");
uint totalFei = bondingcurve.getAmountOut(totalIn);
uint totalTribe = tribeBalance();
return (totalFei * amountIn / totalIn, totalTribe * amountIn / totalIn);
}
function isAtMaxPrice() public view override returns(bool) {
uint balance = address(this).balance;
require(balance != 0, "GenesisGroup: No balance");
return bondingcurve.getAveragePrice(balance).greaterThanOrEqualTo(maxGenesisPrice);
}
function burnFrom(address account, uint amount) public override {
// Sender doesn't need approval
if (msg.sender == account) {
increaseAllowance(account, amount);
}
super.burnFrom(account, amount);
}
function _fgenRatio(address account) internal view returns (Decimal.D256 memory) {
return Decimal.ratio(balanceOf(account), totalSupply());
}
function _feiTribeExchangeRate() public view returns (Decimal.D256 memory) {
return Decimal.ratio(feiBalance(), tribeBalance()).div(exchangeRateDiscount);
}
}