-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsprotocolOracle.sol
249 lines (203 loc) · 8.01 KB
/
sprotocolOracle.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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
pragma solidity ^0.8.4;
/******************************************/
/* ChainLink starts here */
/******************************************/
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
// getRoundData and latestRoundData should both raise "No data present"
// if they do not have data to report, instead of returning unset values
// which could be misinterpreted as actual reported values.
function getRoundData(uint80 _roundId)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}
/******************************************/
/* Sprotocol starts here */
/******************************************/
abstract contract Sprotocol
{
function rebase(uint256 supplyDelta, bool increaseSupply) external virtual returns (uint256);
function transfer(address to, uint256 value) external virtual returns (bool);
function balanceOf(address who) external virtual view returns (uint256);
function totalSupply() external virtual view returns (uint256);
}
/******************************************/
/* SprotocolSync starts here */
/******************************************/
abstract contract SprotocolSync
{
function syncPools() external virtual;
}
/******************************************/
/* SprotocolOracle starts here */
/******************************************/
contract SprotocolOracle {
AggregatorV3Interface internal priceFeed;
int256 public lastOracleWti;
address owner1;
address owner2;
address public standard;
uint256 public standardRewards;
Sprotocol public bm;
SprotocolSync public sync;
Transaction public pendingRebasement;
uint256 internal lastRebasementTime;
struct Transaction {
address initiator;
int256 rebaseOne;
int256 rebaseTwo;
bool executed;
}
modifier isOwner()
{
require (msg.sender == owner1 || msg.sender == owner2);
_;
}
constructor(address _sprotocol, address _standard, address _sync)
{
/**
* Network: Binance Smart Chain
* Aggregator: WTI - https://market.link/feeds/3bc2cf75-9ffb-4d4e-b0be-374ebe528404
* Address: 0xb1BED6C1fC1adE2A975F54F24851c7F410e27718
*/
priceFeed = AggregatorV3Interface(0xb1BED6C1fC1adE2A975F54F24851c7F410e27718);
lastOracleWti = getOracleWti();
owner1 = 0x6b80FD0457273494007813d1Dca3Fa4aB11F272e;
owner2 = 0x7600277697748a01446B4888b65B337b7a855E6d;
standard = _standard;
bm = Sprotocol(_sprotocol);
sync = SprotocolSync(_sync);
pendingRebasement.executed = true;
}
/**
* Returns the latest price
*/
function getOracleWti() public view returns (int) {
(
uint80 roundID,
int price,
uint startedAt,
uint timeStamp,
uint80 answeredInRound
) = priceFeed.latestRoundData();
return price;
}
/**
* Returns absolute value.
*/
function abs(int x) private pure returns (int) {
return x >= 0 ? x : -x;
}
/**
* @dev Initiates a rebasement proposal that has to be confirmed by another owner of the contract to be executed. Can't be called while another proposal is pending.
* @param _rebaseOne Divergence from the target price.
* @param _rebaseTwo WTI difference.
*/
function initiateRebasement(int256 _rebaseOne, int256 _rebaseTwo) public isOwner
{
require (pendingRebasement.executed == true, "Pending rebasement.");
require (lastRebasementTime < (block.timestamp - 54000), "Rebasement has already occured within the past 15 hours.");
Transaction storage txn = pendingRebasement;
txn.initiator = msg.sender;
txn.rebaseOne = _rebaseOne;
txn.rebaseTwo = _rebaseTwo;
txn.executed = false;
}
/**
* @dev Confirms and executes a pending rebasement proposal. Prohibits further proposals for 15 hours. Distribute Standard rewards and sync liquidity pools.
* @param _overrule True if Chainlink Oracle should be ignored.
* @param _currentWti Manually provide current WTI value if Chainlink Oracle is ignored.
*/
function confirmRebasement(bool _overrule, int256 _currentWti) public isOwner
{
require (pendingRebasement.initiator != msg.sender, "Initiator can't confirm rebasement.");
require (pendingRebasement.executed == false, "Rebasement already executed.");
int256 oracleRebaseTwo;
if (_overrule == false) {
oracleRebaseTwo = ((getOracleWti() - lastOracleWti) * 1e10) / lastOracleWti;
oracleRebaseTwo = oracleRebaseTwo < 0 ? int(0) : oracleRebaseTwo;
require (oracleRebaseTwo == pendingRebasement.rebaseTwo, "WTI rebases don't match!");
lastOracleWti = getOracleWti();
} else {
oracleRebaseTwo = pendingRebasement.rebaseTwo;
require(_currentWti != 0, "Current WTI not provided.");
lastOracleWti = _currentWti;
}
pendingRebasement.executed = true;
lastRebasementTime = block.timestamp;
int256 rebasePercentage = pendingRebasement.rebaseOne + oracleRebaseTwo;
bool increaseSupply = rebasePercentage >= 0 ? true : false;
uint256 absolutePercentage = uint256(abs(rebasePercentage));
uint256 supplyDelta = bm.totalSupply() * absolutePercentage / 1e10;
bm.rebase(supplyDelta, increaseSupply);
bm.transfer(standard, standardRewards);
sync.syncPools();
}
/**
* @dev View Supply delta and sign for rebasement verification.
* @param _overrule True if Chainlink Oracle should be ignored.
*/
function verifyRebasement(bool _overrule) public view returns (uint256, bool)
{
int256 oracleRebaseTwo;
if (_overrule == false) {
oracleRebaseTwo = ((getOracleWti() - lastOracleWti) * 1e10) / lastOracleWti;
oracleRebaseTwo = oracleRebaseTwo < 0 ? int(0) : oracleRebaseTwo;
require (oracleRebaseTwo == pendingRebasement.rebaseTwo, "WTI rebases don't match!");
} else {
oracleRebaseTwo = pendingRebasement.rebaseTwo;
}
int256 rebasePercentage = pendingRebasement.rebaseOne + oracleRebaseTwo;
bool increaseSupply = rebasePercentage >= 0 ? true : false;
uint256 absolutePercentage = uint256(abs(rebasePercentage));
uint256 supplyDelta = bm.totalSupply() * absolutePercentage / 1e10;
return(supplyDelta, increaseSupply);
}
/**
* @dev Denies a pending rebasement proposal and allows the creation of a new proposal.
*/
function denyRebasement() public isOwner
{
require (pendingRebasement.executed == false, "Rebasement already executed.");
pendingRebasement.executed = true;
}
/**
* @dev Change Standard staking rewards.
* @param _standardRewards New amount.
*/
function setStandardRewards(uint256 _standardRewards) public isOwner {
standardRewards = _standardRewards;
}
/**
* @dev Remove all WTISDR deposited on this contract.
*/
function withdrawWtisdr() public {
require (msg.sender == 0x6b80FD0457273494007813d1Dca3Fa4aB11F272e || msg.sender == 0x7600277697748a01446B4888b65B337b7a855E6d, "Only Masterchief can withdraw.");
bm.transfer(msg.sender, bm.balanceOf(address(this)));
}
/**
* @dev Change the contract for pool synchronization.
*/
function setSyncContract(address _sync) public isOwner {
sync = SprotocolSync(_sync);
}
}