├── README.md ├── abi └── maximus.sol /README.md: -------------------------------------------------------------------------------- 1 | # maximus 2 | 3 | ALL RIGHTS RESERVED 4 | 5 | 1. Connect metamask to PulseChain TestNet https://gitlab.com/pulsechaincom/pulsechain-testnet 6 | 2. Get TestNet PLS https://faucet.v2b.testnet.pulsechain.com/ 7 | 3. Swap some tPLS for HEX https://app.v2b.testnet.pulsex.com/ 8 | 4. Go to https://late-lame-bar.anvil.app and follow dapp instructions 9 | 5. sample contract address: 0xD4C58bEd65763E69747Fd9DE4FC8F546Dd926265 10 | 11 | You may clone and run your own copy of the dapp front end via 12 | https://anvil.works/build#clone:2XKDZASWBEKTDLDF=VOCGBJDZ33XOQAOMSTJ6NHE2 13 | 14 | dweb:/ipfs/QmX6VVLVgVEmvW5u5QQnfqfxYLKYPDDxin4FarA4ityeD6 15 | -------------------------------------------------------------------------------- /abi: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "uint256", 6 | "name": "mint_duration", 7 | "type": "uint256" 8 | }, 9 | { 10 | "internalType": "uint256", 11 | "name": "stake_duration", 12 | "type": "uint256" 13 | } 14 | ], 15 | "stateMutability": "nonpayable", 16 | "type": "constructor" 17 | }, 18 | { 19 | "anonymous": false, 20 | "inputs": [ 21 | { 22 | "indexed": true, 23 | "internalType": "address", 24 | "name": "owner", 25 | "type": "address" 26 | }, 27 | { 28 | "indexed": true, 29 | "internalType": "address", 30 | "name": "spender", 31 | "type": "address" 32 | }, 33 | { 34 | "indexed": false, 35 | "internalType": "uint256", 36 | "name": "value", 37 | "type": "uint256" 38 | } 39 | ], 40 | "name": "Approval", 41 | "type": "event" 42 | }, 43 | { 44 | "anonymous": false, 45 | "inputs": [ 46 | { 47 | "indexed": true, 48 | "internalType": "address", 49 | "name": "from", 50 | "type": "address" 51 | }, 52 | { 53 | "indexed": true, 54 | "internalType": "address", 55 | "name": "to", 56 | "type": "address" 57 | }, 58 | { 59 | "indexed": false, 60 | "internalType": "uint256", 61 | "name": "value", 62 | "type": "uint256" 63 | } 64 | ], 65 | "name": "Transfer", 66 | "type": "event" 67 | }, 68 | { 69 | "inputs": [ 70 | { 71 | "internalType": "address", 72 | "name": "owner", 73 | "type": "address" 74 | }, 75 | { 76 | "internalType": "address", 77 | "name": "spender", 78 | "type": "address" 79 | } 80 | ], 81 | "name": "allowance", 82 | "outputs": [ 83 | { 84 | "internalType": "uint256", 85 | "name": "", 86 | "type": "uint256" 87 | } 88 | ], 89 | "stateMutability": "view", 90 | "type": "function" 91 | }, 92 | { 93 | "inputs": [ 94 | { 95 | "internalType": "address", 96 | "name": "spender", 97 | "type": "address" 98 | }, 99 | { 100 | "internalType": "uint256", 101 | "name": "amount", 102 | "type": "uint256" 103 | } 104 | ], 105 | "name": "approve", 106 | "outputs": [ 107 | { 108 | "internalType": "bool", 109 | "name": "", 110 | "type": "bool" 111 | } 112 | ], 113 | "stateMutability": "nonpayable", 114 | "type": "function" 115 | }, 116 | { 117 | "inputs": [ 118 | { 119 | "internalType": "address", 120 | "name": "account", 121 | "type": "address" 122 | } 123 | ], 124 | "name": "balanceOf", 125 | "outputs": [ 126 | { 127 | "internalType": "uint256", 128 | "name": "", 129 | "type": "uint256" 130 | } 131 | ], 132 | "stateMutability": "view", 133 | "type": "function" 134 | }, 135 | { 136 | "inputs": [ 137 | { 138 | "internalType": "uint256", 139 | "name": "amount", 140 | "type": "uint256" 141 | } 142 | ], 143 | "name": "burn", 144 | "outputs": [], 145 | "stateMutability": "nonpayable", 146 | "type": "function" 147 | }, 148 | { 149 | "inputs": [ 150 | { 151 | "internalType": "address", 152 | "name": "account", 153 | "type": "address" 154 | }, 155 | { 156 | "internalType": "uint256", 157 | "name": "amount", 158 | "type": "uint256" 159 | } 160 | ], 161 | "name": "burnFrom", 162 | "outputs": [], 163 | "stateMutability": "nonpayable", 164 | "type": "function" 165 | }, 166 | { 167 | "inputs": [], 168 | "name": "decimals", 169 | "outputs": [ 170 | { 171 | "internalType": "uint8", 172 | "name": "", 173 | "type": "uint8" 174 | } 175 | ], 176 | "stateMutability": "view", 177 | "type": "function" 178 | }, 179 | { 180 | "inputs": [ 181 | { 182 | "internalType": "address", 183 | "name": "spender", 184 | "type": "address" 185 | }, 186 | { 187 | "internalType": "uint256", 188 | "name": "subtractedValue", 189 | "type": "uint256" 190 | } 191 | ], 192 | "name": "decreaseAllowance", 193 | "outputs": [ 194 | { 195 | "internalType": "bool", 196 | "name": "", 197 | "type": "bool" 198 | } 199 | ], 200 | "stateMutability": "nonpayable", 201 | "type": "function" 202 | }, 203 | { 204 | "inputs": [ 205 | { 206 | "internalType": "uint256", 207 | "name": "stakeIndex", 208 | "type": "uint256" 209 | }, 210 | { 211 | "internalType": "uint40", 212 | "name": "stakeIdParam", 213 | "type": "uint40" 214 | } 215 | ], 216 | "name": "endStakeHEX", 217 | "outputs": [], 218 | "stateMutability": "nonpayable", 219 | "type": "function" 220 | }, 221 | { 222 | "inputs": [], 223 | "name": "getEndStaker", 224 | "outputs": [ 225 | { 226 | "internalType": "address", 227 | "name": "end_staker_address", 228 | "type": "address" 229 | } 230 | ], 231 | "stateMutability": "view", 232 | "type": "function" 233 | }, 234 | { 235 | "inputs": [], 236 | "name": "getHEXRedemptionRate", 237 | "outputs": [ 238 | { 239 | "internalType": "uint256", 240 | "name": "", 241 | "type": "uint256" 242 | } 243 | ], 244 | "stateMutability": "view", 245 | "type": "function" 246 | }, 247 | { 248 | "inputs": [], 249 | "name": "getHedronDay", 250 | "outputs": [ 251 | { 252 | "internalType": "uint256", 253 | "name": "day", 254 | "type": "uint256" 255 | } 256 | ], 257 | "stateMutability": "view", 258 | "type": "function" 259 | }, 260 | { 261 | "inputs": [], 262 | "name": "getHedronRedemptionRate", 263 | "outputs": [ 264 | { 265 | "internalType": "uint256", 266 | "name": "", 267 | "type": "uint256" 268 | } 269 | ], 270 | "stateMutability": "view", 271 | "type": "function" 272 | }, 273 | { 274 | "inputs": [], 275 | "name": "getHexDay", 276 | "outputs": [ 277 | { 278 | "internalType": "uint256", 279 | "name": "", 280 | "type": "uint256" 281 | } 282 | ], 283 | "stateMutability": "view", 284 | "type": "function" 285 | }, 286 | { 287 | "inputs": [], 288 | "name": "getMintingPhaseEndDay", 289 | "outputs": [ 290 | { 291 | "internalType": "uint256", 292 | "name": "", 293 | "type": "uint256" 294 | } 295 | ], 296 | "stateMutability": "view", 297 | "type": "function" 298 | }, 299 | { 300 | "inputs": [], 301 | "name": "getMintingPhaseStartDay", 302 | "outputs": [ 303 | { 304 | "internalType": "uint256", 305 | "name": "", 306 | "type": "uint256" 307 | } 308 | ], 309 | "stateMutability": "view", 310 | "type": "function" 311 | }, 312 | { 313 | "inputs": [], 314 | "name": "getStakeEndDay", 315 | "outputs": [ 316 | { 317 | "internalType": "uint256", 318 | "name": "", 319 | "type": "uint256" 320 | } 321 | ], 322 | "stateMutability": "view", 323 | "type": "function" 324 | }, 325 | { 326 | "inputs": [], 327 | "name": "getStakeStartDay", 328 | "outputs": [ 329 | { 330 | "internalType": "uint256", 331 | "name": "", 332 | "type": "uint256" 333 | } 334 | ], 335 | "stateMutability": "view", 336 | "type": "function" 337 | }, 338 | { 339 | "inputs": [ 340 | { 341 | "internalType": "address", 342 | "name": "spender", 343 | "type": "address" 344 | }, 345 | { 346 | "internalType": "uint256", 347 | "name": "addedValue", 348 | "type": "uint256" 349 | } 350 | ], 351 | "name": "increaseAllowance", 352 | "outputs": [ 353 | { 354 | "internalType": "bool", 355 | "name": "", 356 | "type": "bool" 357 | } 358 | ], 359 | "stateMutability": "nonpayable", 360 | "type": "function" 361 | }, 362 | { 363 | "inputs": [ 364 | { 365 | "internalType": "uint256", 366 | "name": "stakeIndex", 367 | "type": "uint256" 368 | }, 369 | { 370 | "internalType": "uint40", 371 | "name": "stakeId", 372 | "type": "uint40" 373 | } 374 | ], 375 | "name": "mintHedron", 376 | "outputs": [], 377 | "stateMutability": "nonpayable", 378 | "type": "function" 379 | }, 380 | { 381 | "inputs": [], 382 | "name": "name", 383 | "outputs": [ 384 | { 385 | "internalType": "string", 386 | "name": "", 387 | "type": "string" 388 | } 389 | ], 390 | "stateMutability": "view", 391 | "type": "function" 392 | }, 393 | { 394 | "inputs": [ 395 | { 396 | "internalType": "uint256", 397 | "name": "amount", 398 | "type": "uint256" 399 | } 400 | ], 401 | "name": "pledgeHEX", 402 | "outputs": [], 403 | "stateMutability": "nonpayable", 404 | "type": "function" 405 | }, 406 | { 407 | "inputs": [ 408 | { 409 | "internalType": "uint256", 410 | "name": "amount_MAXI", 411 | "type": "uint256" 412 | } 413 | ], 414 | "name": "redeemHEX", 415 | "outputs": [], 416 | "stateMutability": "nonpayable", 417 | "type": "function" 418 | }, 419 | { 420 | "inputs": [], 421 | "name": "stakeHEX", 422 | "outputs": [], 423 | "stateMutability": "nonpayable", 424 | "type": "function" 425 | }, 426 | { 427 | "inputs": [], 428 | "name": "symbol", 429 | "outputs": [ 430 | { 431 | "internalType": "string", 432 | "name": "", 433 | "type": "string" 434 | } 435 | ], 436 | "stateMutability": "view", 437 | "type": "function" 438 | }, 439 | { 440 | "inputs": [], 441 | "name": "totalSupply", 442 | "outputs": [ 443 | { 444 | "internalType": "uint256", 445 | "name": "", 446 | "type": "uint256" 447 | } 448 | ], 449 | "stateMutability": "view", 450 | "type": "function" 451 | }, 452 | { 453 | "inputs": [ 454 | { 455 | "internalType": "address", 456 | "name": "to", 457 | "type": "address" 458 | }, 459 | { 460 | "internalType": "uint256", 461 | "name": "amount", 462 | "type": "uint256" 463 | } 464 | ], 465 | "name": "transfer", 466 | "outputs": [ 467 | { 468 | "internalType": "bool", 469 | "name": "", 470 | "type": "bool" 471 | } 472 | ], 473 | "stateMutability": "nonpayable", 474 | "type": "function" 475 | }, 476 | { 477 | "inputs": [ 478 | { 479 | "internalType": "address", 480 | "name": "from", 481 | "type": "address" 482 | }, 483 | { 484 | "internalType": "address", 485 | "name": "to", 486 | "type": "address" 487 | }, 488 | { 489 | "internalType": "uint256", 490 | "name": "amount", 491 | "type": "uint256" 492 | } 493 | ], 494 | "name": "transferFrom", 495 | "outputs": [ 496 | { 497 | "internalType": "bool", 498 | "name": "", 499 | "type": "bool" 500 | } 501 | ], 502 | "stateMutability": "nonpayable", 503 | "type": "function" 504 | } 505 | ] 506 | -------------------------------------------------------------------------------- /maximus.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.2; 3 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 4 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 6 | import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; 7 | import "@openzeppelin/contracts/utils/math/SafeMath.sol"; 8 | import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; 9 | contract HedronToken { 10 | function approve(address spender, uint256 amount) external returns (bool) {} 11 | function transfer(address recipient, uint256 amount) external returns (bool) {} 12 | function mintNative(uint256 stakeIndex, uint40 stakeId) external returns (uint256) {} 13 | function claimNative(uint256 stakeIndex, uint40 stakeId) external returns (uint256) {} 14 | function currentDay() external view returns (uint256) {} 15 | } 16 | 17 | contract HEXToken { 18 | function currentDay() external view returns (uint256){} 19 | function stakeStart(uint256 newStakedHearts, uint256 newStakedDays) external {} 20 | function approve(address spender, uint256 amount) external returns (bool) {} 21 | function transfer(address recipient, uint256 amount) public returns (bool) {} 22 | function stakeEnd(uint256 stakeIndex, uint40 stakeIdParam) public {} 23 | function stakeCount(address stakerAddr) external view returns (uint256) {} 24 | } 25 | /* 26 | ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 27 | ─██████──────────██████────██████████████────████████──████████────██████████────██████──────────██████────██████──██████────██████████████─ 28 | ─██░░██████████████░░██────██░░░░░░░░░░██────██░░░░██──██░░░░██────██░░░░░░██────██░░██████████████░░██────██░░██──██░░██────██░░░░░░░░░░██─ 29 | ─██░░░░░░░░░░░░░░░░░░██────██░░██████░░██────████░░██──██░░████────████░░████────██░░░░░░░░░░░░░░░░░░██────██░░██──██░░██────██░░██████████─ 30 | ─██░░██████░░██████░░██────██░░██──██░░██──────██░░░░██░░░░██────────██░░██──────██░░██████░░██████░░██────██░░██──██░░██────██░░██───────── 31 | ─██░░██──██░░██──██░░██────██░░██████░░██──────████░░░░░░████────────██░░██──────██░░██──██░░██──██░░██────██░░██──██░░██────██░░██████████─ 32 | ─██░░██──██░░██──██░░██────██░░░░░░░░░░██────────██░░░░░░██──────────██░░██──────██░░██──██░░██──██░░██────██░░██──██░░██────██░░░░░░░░░░██─ 33 | ─██░░██──██████──██░░██────██░░██████░░██──────████░░░░░░████────────██░░██──────██░░██──██████──██░░██────██░░██──██░░██────██████████░░██─ 34 | ─██░░██──────────██░░██────██░░██──██░░██──────██░░░░██░░░░██────────██░░██──────██░░██──────────██░░██────██░░██──██░░██────────────██░░██─ 35 | ─██░░██──────────██░░██────██░░██──██░░██────████░░██──██░░████────████░░████────██░░██──────────██░░██────██░░██████░░██────██████████░░██─ 36 | ─██░░██──────────██░░██────██░░██──██░░██────██░░░░██──██░░░░██────██░░░░░░██────██░░██──────────██░░██────██░░░░░░░░░░██────██░░░░░░░░░░██─ 37 | ─██████──────────██████────██████──██████────████████──████████────██████████────██████──────────██████────██████████████────██████████████─ 38 | ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 39 | 40 | █▀ ▀█▀ █▀█ █▀▀ █▄░█ █▀▀ ▀█▀ █░█   ▄▀█ █▄░█ █▀▄   █░█ █▀█ █▄░█ █▀█ █▀█ 41 | ▄█ ░█░ █▀▄ ██▄ █░▀█ █▄█ ░█░ █▀█   █▀█ █░▀█ █▄▀   █▀█ █▄█ █░▀█ █▄█ █▀▄ 42 | 43 | // Maximus is a contract for trustlessly pooling a single max length hex stake. 44 | // Anyone may choose to mint 1 MAXI per HEX deposited into the Maximus Contract Address during the minting phase. 45 | // Anyone may choose to pay for the gas to start and end the stake on behalf of the Maximus Contract. 46 | // Anyone may choose to pay for the gas to mint Hedron the stake earns on behalf of the Maximus Contract. 47 | // MAXI is a standard ERC20 token, only minted upon HEX deposit and burnt upon HEX redemption with no pre-mine or contract fee. 48 | // MAXI holders may choose to burn MAXI to redeem HEX principal and yield (Including HEDRON) pro-rata from the Maximus Contract Address during the redemption phase. 49 | // 50 | // |--- Minting Phase---|---------- 5555 Day Stake Phase ------------...-----|------ Redemption Phase ----------> 51 | 52 | 53 | THE MAXIMUS CONTRACT, SUPPORTING WEBSITES, AND ALL OTHER INTERFACES (THE SOFTWARE) IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 54 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 55 | 56 | BY INTERACTING WITH THE SOFTWARE YOU ARE ASSERTING THAT YOU BEAR ALL THE RISKS ASSOCIATED WITH DOING SO. AN INFINITE NUMBER OF UNPREDICTABLE THINGS MAY GO WRONG WHICH COULD POTENTIALLY RESULT IN CRITICAL FAILURE AND FINANCIAL LOSS. BY INTERACTING WITH THE SOFTWARE YOU ARE ASSERTING THAT YOU AGREE THERE IS NO RECOURSE AVAILABLE AND YOU WILL NOT SEEK IT. 57 | 58 | INTERACTING WITH THE SOFTWARE SHALL NOT BE CONSIDERED AN INVESTMENT OR A COMMON ENTERPRISE. INSTEAD, INTERACTING WITH THE SOFTWARE IS EQUIVALENT TO CARPOOLING WITH FRIENDS TO SAVE ON GAS AND EXPERIENCE THE BENEFITS OF THE H.O.V. LANE. 59 | 60 | YOU SHALL HAVE NO EXPECTATION OF PROFIT OR ANY TYPE OF GAIN FROM THE WORK OF OTHER PEOPLE. 61 | 62 | */ 63 | 64 | 65 | contract Maximus is ERC20, ERC20Burnable, ReentrancyGuard { 66 | // all days are measured in terms of the HEX contract day number 67 | uint256 MINTING_PHASE_START; 68 | uint256 MINTING_PHASE_END; 69 | uint256 STAKE_START_DAY; 70 | uint256 STAKE_END_DAY; 71 | uint256 STAKE_LENGTH; 72 | uint256 HEX_REDEMPTION_RATE; // Number of HEX units redeemable per MAXI 73 | uint256 HEDRON_REDEMPTION_RATE; // Number of HEDRON units redeemable per MAXI 74 | bool HAS_STAKE_STARTED; 75 | bool HAS_STAKE_ENDED; 76 | bool HAS_HEDRON_MINTED; 77 | address END_STAKER; 78 | 79 | constructor(uint256 mint_duration, uint256 stake_duration) ERC20("Maximus", "MAXI") ReentrancyGuard() { 80 | uint256 start_day=hex_token.currentDay(); 81 | MINTING_PHASE_START = start_day; 82 | MINTING_PHASE_END = start_day+mint_duration; 83 | STAKE_LENGTH=stake_duration; 84 | HAS_STAKE_STARTED=false; 85 | HAS_STAKE_ENDED = false; 86 | HAS_HEDRON_MINTED=false; 87 | HEX_REDEMPTION_RATE=100000000; // HEX and MAXI are 1:1 convertible up until the stake is initiated 88 | HEDRON_REDEMPTION_RATE=0; //no hedron is redeemable until minting has occurred 89 | 90 | 91 | } 92 | 93 | /** 94 | * @dev View number of decimal places the MAXI token is divisible to. Manually overwritten from default 18 to 8 to match that of HEX. 1 MAXI = 10^8 mini 95 | */ 96 | 97 | function decimals() public view virtual override returns (uint8) { 98 | return 8; 99 | } 100 | address MAXI_ADDRESS =address(this); 101 | address constant HEX_ADDRESS = 0x2b591e99afE9f32eAA6214f7B7629768c40Eeb39; // "2b, 5 9 1e? that is the question..." 102 | address constant HEDRON_ADDRESS=0x3819f64f282bf135d62168C1e513280dAF905e06; 103 | 104 | IERC20 hex_contract = IERC20(HEX_ADDRESS); 105 | IERC20 hedron_contract=IERC20(HEDRON_ADDRESS); 106 | HEXToken hex_token = HEXToken(HEX_ADDRESS); 107 | HedronToken hedron_token = HedronToken(HEDRON_ADDRESS); 108 | // public function 109 | /** 110 | * @dev Returns the HEX Day that the Minting Phase started. 111 | * @return HEX Day that the Minting Phase started. 112 | */ 113 | function getMintingPhaseStartDay() external view returns (uint256) {return MINTING_PHASE_START;} 114 | /** 115 | * @dev Returns the HEX Day that the Minting Phase ends. 116 | * @return HEX Day that the Minting Phase ends. 117 | */ 118 | function getMintingPhaseEndDay() external view returns (uint256) {return MINTING_PHASE_END;} 119 | /** 120 | * @dev Returns the HEX Day that the Maximus HEX Stake started. 121 | * @return HEX Day that the Maximus HEX Stake started. 122 | */ 123 | function getStakeStartDay() external view returns (uint256) {return STAKE_START_DAY;} 124 | /** 125 | * @dev Returns the HEX Day that the Maximus HEX Stake ends. 126 | * @return HEX Day that the Maximus HEX Stake ends. 127 | */ 128 | function getStakeEndDay() external view returns (uint256) {return STAKE_END_DAY;} 129 | /** 130 | * @dev Returns the rate at which MAXI may be redeemed for HEX. "Number of HEX hearts per 1 MAXI redeemed." 131 | * @return Rate at which MAXI may be redeemed for HEX. "Number of HEX hearts per 1 MAXI redeemed." 132 | */ 133 | function getHEXRedemptionRate() external view returns (uint256) {return HEX_REDEMPTION_RATE;} 134 | /** 135 | * @dev Returns the rate at which MAXI may be redeemed for HEDRON. 136 | * @return Rate at which MAXI may be redeemed for HDRN. 137 | */ 138 | function getHedronRedemptionRate() external view returns (uint256) {return HEDRON_REDEMPTION_RATE;} 139 | 140 | /** 141 | * @dev Returns the current HEX day." 142 | * @return Current HEX Day 143 | */ 144 | function getHexDay() external view returns (uint256){ 145 | uint256 day = hex_token.currentDay(); 146 | return day; 147 | } 148 | /** 149 | * @dev Returns the current HEDRON day." 150 | * @return day Current HEDRON Day 151 | */ 152 | function getHedronDay() external view returns (uint day) {return hedron_token.currentDay();} 153 | 154 | /** 155 | * @dev Returns the address of the person who ends stake. May be used by external gas pooling contracts. If stake has not been ended yet will return 0x000...000" 156 | * @return end_staker_address This person should be honored and celebrated as a hero. 157 | */ 158 | function getEndStaker() external view returns (address end_staker_address) {return END_STAKER;} 159 | 160 | // MAXI Issuance and Redemption Functions 161 | /** 162 | * @dev Mints MAXI. 163 | * @param amount of MAXI to mint, measured in minis 164 | */ 165 | function mint(uint256 amount) private { 166 | _mint(msg.sender, amount); 167 | } 168 | /** 169 | * @dev Ensures that MAXI Minting Phase is ongoing and that the user has allowed the Maximus Contract address to spend the amount of HEX the user intends to pledge to Maximus. Then sends the designated HEX from the user to the Maximus Contract address and mints 1 MAXI per HEX pledged. 170 | * @param amount of HEX user chose to pledge, measured in hearts 171 | */ 172 | function pledgeHEX(uint256 amount) nonReentrant external { 173 | require(hex_token.currentDay()<=MINTING_PHASE_END, "Minting Phase is Done"); 174 | require(hex_contract.allowance(msg.sender, MAXI_ADDRESS)>=amount, "Please approve contract address as allowed spender in the hex contract."); 175 | address from = msg.sender; 176 | hex_contract.transferFrom(from, MAXI_ADDRESS, amount); 177 | mint(amount); 178 | } 179 | /** 180 | * @dev Ensures that it is currently a redemption period (before stake starts or after stake ends) and that the user has at least the number of maxi they entered. Then it calculates how much hex may be redeemed, burns the MAXI, and transfers them the hex. 181 | * @param amount_MAXI number of MAXI that the user is redeeming, measured in mini 182 | */ 183 | function redeemHEX(uint256 amount_MAXI) nonReentrant external { 184 | require(HAS_STAKE_STARTED==false || HAS_STAKE_ENDED==true , "Redemption can only happen before stake starts or after stake ends."); 185 | uint256 yourMAXI = balanceOf(msg.sender); 186 | require(yourMAXI>=amount_MAXI, "You do not have that much MAXI."); 187 | uint256 raw_redeemable_amount = amount_MAXI*HEX_REDEMPTION_RATE; 188 | uint256 redeemable_amount = raw_redeemable_amount/100000000; //scaled back down to handle integer rounding 189 | burn(amount_MAXI); 190 | hex_token.transfer(msg.sender, redeemable_amount); 191 | if (HAS_HEDRON_MINTED==true) { 192 | uint256 raw_redeemable_hedron = amount_MAXI*HEDRON_REDEMPTION_RATE; 193 | uint256 redeemable_hedron = raw_redeemable_hedron/100000000; //scaled back down to handle integer rounding 194 | hedron_token.transfer(msg.sender, redeemable_hedron); 195 | } 196 | } 197 | //Staking Functions 198 | // Anyone may run these functions during the allowed time, so long as they pay the gas. 199 | // While nothing is forcing you to, gracious Maximus members will tip the sender some ETH for paying gas to end your stake. 200 | 201 | /** 202 | * @dev Ensures that the stake has not started yet and that the minting phase is over. Then it stakes all the hex in the contract and schedules the STAKE_END_DAY. 203 | * @notice This will trigger the start of the HEX stake. If you run this, you will pay the gas on behalf of the contract and you should not expect reimbursement. 204 | 205 | */ 206 | function stakeHEX() nonReentrant external { 207 | require(HAS_STAKE_STARTED==false, "Stake has already been started."); 208 | uint256 current_day = hex_token.currentDay(); 209 | require(current_day>MINTING_PHASE_END, "Minting Phase is still ongoing - see MINTING_PHASE_END day."); 210 | uint256 amount = hex_contract.balanceOf(address(this)); 211 | _stakeHEX(amount); 212 | HAS_STAKE_STARTED=true; 213 | STAKE_START_DAY=current_day; 214 | STAKE_END_DAY=current_day+STAKE_LENGTH; 215 | } 216 | function _stakeHEX(uint256 amount) private { 217 | hex_token.stakeStart(amount,STAKE_LENGTH); 218 | } 219 | 220 | function _endStakeHEX(uint256 stakeIndex,uint40 stakeIdParam ) private { 221 | hex_token.stakeEnd(stakeIndex, stakeIdParam); 222 | } 223 | /** 224 | * @dev Ensures that the stake is fully complete and that it has not already been ended. Then it ends the hex stake and updates the redemption rate. 225 | * @notice This will trigger the ending of the HEX stake and calculate the new redemption rate. This may be very expensive. If you run this, you will pay the gas on behalf of the contract and you should not expect reimbursement. 226 | * @param stakeIndex index of stake found in stakeLists[contract_address] in hex contract. 227 | * @param stakeIdParam stake identifier found in stakeLists[contract_address] in hex contract. 228 | */ 229 | function endStakeHEX(uint256 stakeIndex,uint40 stakeIdParam ) nonReentrant external { 230 | require(hex_token.currentDay()>STAKE_END_DAY, "Stake is not complete yet."); 231 | require(HAS_STAKE_STARTED==true && HAS_STAKE_ENDED==false, "Stake has already been started."); 232 | _endStakeHEX(stakeIndex, stakeIdParam); 233 | HAS_STAKE_ENDED=true; 234 | uint256 hex_balance = hex_contract.balanceOf(address(this)); 235 | uint256 total_maxi_supply = IERC20(address(this)).totalSupply(); 236 | HEX_REDEMPTION_RATE = calculate_redemption_rate(hex_balance, total_maxi_supply); 237 | END_STAKER=msg.sender; 238 | } 239 | /** 240 | * @dev Calculates the pro-rata redemption rate of any coin per maxi. Scales value by 10^8 to handle integer rounding. 241 | * @param treasury_balance The balance of coins in the maximus contract address (either HEX or HEDRON) 242 | * @param maxi_supply total maxi supply 243 | * @return redemption_rate Number of units redeemable per 10^8 decimal units of MAXI. Is scaled back down by 10^8 on redemption transaction. 244 | */ 245 | function calculate_redemption_rate(uint treasury_balance, uint maxi_supply) private view returns (uint redemption_rate) { 246 | uint256 scalar = 10**8; 247 | uint256 scaled = (treasury_balance * scalar) / maxi_supply; // scale value to calculate redemption amount per maxi and then divide by same scalar after multiplication 248 | return scaled; 249 | } 250 | 251 | /** 252 | * @dev Public function which calls the private function which is used for minting available HDRN accumulated by the contract stake. 253 | * @notice This will trigger the minting of the mintable Hedron earned by the stake. If you run this, you will pay the gas on behalf of the contract and you should not expect reimbursement. If check to make sure this has not been run yet already or the transaction will fail. 254 | * @param stakeIndex index of stake found in stakeLists[contract_address] in hex contract. 255 | * @param stakeId stake identifier found in stakeLists[contract_address] in hex contract. 256 | */ 257 | function mintHedron(uint256 stakeIndex,uint40 stakeId ) external { 258 | _mintHedron(stakeIndex, stakeId); 259 | } 260 | /** 261 | * @dev Private function used for minting available HDRN accumulated by the contract stake and updating the HDRON redemption rate. 262 | * @param stakeIndex index of stake found in stakeLists[contract_address] in hex contract. 263 | * @param stakeId stake identifier found in stakeLists[contract_address] in hex contract. 264 | */ 265 | function _mintHedron(uint256 stakeIndex,uint40 stakeId ) private { 266 | hedron_token.mintNative(stakeIndex, stakeId); 267 | uint256 total_hedron= hedron_contract.balanceOf(address(this)); 268 | uint256 total_maxi = IERC20(address(this)).totalSupply(); 269 | 270 | HEDRON_REDEMPTION_RATE = calculate_redemption_rate(total_hedron, total_maxi); 271 | HAS_HEDRON_MINTED = true; 272 | } 273 | 274 | } 275 | --------------------------------------------------------------------------------