generated from NomicFoundation/hardhat-boilerplate
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
RocketJoeStakingContract and RocketJoeToken
- Loading branch information
1 parent
b509dbd
commit 06f2397
Showing
29 changed files
with
1,766 additions
and
17,202 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
{ | ||
"manifestVersion": "3.2", | ||
"admin": { | ||
"address": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", | ||
"txHash": "0x3925b8879e79569cf432ca46b1d26510843db17575488fde9738cc1e0652a5ca", | ||
"deployTransaction": { | ||
"hash": "0x3925b8879e79569cf432ca46b1d26510843db17575488fde9738cc1e0652a5ca", | ||
"blockHash": "0xe59a350229ccf67ec990b3fc5f40b19cd6501a51e0a4bffadaba940a9b497d95", | ||
"blockNumber": 8, | ||
"transactionIndex": 0, | ||
"confirmations": 1, | ||
"from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", | ||
"gasPrice": { | ||
"type": "BigNumber", | ||
"hex": "0x511cdedf" | ||
}, | ||
"gasLimit": { | ||
"type": "BigNumber", | ||
"hex": "0x0762b4" | ||
}, | ||
"to": null, | ||
"value": { | ||
"type": "BigNumber", | ||
"hex": "0x00" | ||
}, | ||
"nonce": 7, | ||
"data": "0x608060405234801561001057600080fd5b50600080546001600160a01b031916339081178255604051909182917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350610759806100616000396000f3fe60806040526004361061007b5760003560e01c80639623609d1161004e5780639623609d1461011157806399a88ec414610124578063f2fde38b14610144578063f3b7dead146101645761007b565b8063204e1c7a14610080578063715018a6146100bc5780637eff275e146100d35780638da5cb5b146100f3575b600080fd5b34801561008c57600080fd5b506100a061009b366004610515565b610184565b6040516001600160a01b03909116815260200160405180910390f35b3480156100c857600080fd5b506100d1610215565b005b3480156100df57600080fd5b506100d16100ee366004610554565b610292565b3480156100ff57600080fd5b506000546001600160a01b03166100a0565b6100d161011f36600461058c565b61031c565b34801561013057600080fd5b506100d161013f366004610554565b6103ad565b34801561015057600080fd5b506100d161015f366004610515565b610405565b34801561017057600080fd5b506100a061017f366004610515565b6104ef565b6000806000836001600160a01b03166040516101aa90635c60da1b60e01b815260040190565b600060405180830381855afa9150503d80600081146101e5576040519150601f19603f3d011682016040523d82523d6000602084013e6101ea565b606091505b5091509150816101f957600080fd5b8080602001905181019061020d9190610538565b949350505050565b6000546001600160a01b031633146102485760405162461bcd60e51b815260040161023f906106c0565b60405180910390fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000546001600160a01b031633146102bc5760405162461bcd60e51b815260040161023f906106c0565b6040516308f2839760e41b81526001600160a01b038281166004830152831690638f283970906024015b600060405180830381600087803b15801561030057600080fd5b505af1158015610314573d6000803e3d6000fd5b505050505050565b6000546001600160a01b031633146103465760405162461bcd60e51b815260040161023f906106c0565b60405163278f794360e11b81526001600160a01b03841690634f1ef286903490610376908690869060040161065d565b6000604051808303818588803b15801561038f57600080fd5b505af11580156103a3573d6000803e3d6000fd5b5050505050505050565b6000546001600160a01b031633146103d75760405162461bcd60e51b815260040161023f906106c0565b604051631b2ce7f360e11b81526001600160a01b038281166004830152831690633659cfe6906024016102e6565b6000546001600160a01b0316331461042f5760405162461bcd60e51b815260040161023f906106c0565b6001600160a01b0381166104945760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161023f565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000806000836001600160a01b03166040516101aa906303e1469160e61b815260040190565b600060208284031215610526578081fd5b81356105318161070b565b9392505050565b600060208284031215610549578081fd5b81516105318161070b565b60008060408385031215610566578081fd5b82356105718161070b565b915060208301356105818161070b565b809150509250929050565b6000806000606084860312156105a0578081fd5b83356105ab8161070b565b925060208401356105bb8161070b565b9150604084013567ffffffffffffffff808211156105d7578283fd5b818601915086601f8301126105ea578283fd5b8135818111156105fc576105fc6106f5565b604051601f8201601f19908116603f01168101908382118183101715610624576106246106f5565b8160405282815289602084870101111561063c578586fd5b82602086016020830137856020848301015280955050505050509250925092565b600060018060a01b038416825260206040818401528351806040850152825b818110156106985785810183015185820160600152820161067c565b818111156106a95783606083870101525b50601f01601f191692909201606001949350505050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461072057600080fd5b5056fea2646970667358221220d849f96f3086b9f82cdcf665adb8c697ace05638da1c7c16ab2d26293717af6764736f6c63430008020033", | ||
"r": "0x8dc260c691908e0f595a908cb61020fc5d2d63951f1f25363717b3a22c96f0c5", | ||
"s": "0x76425f8edf2504f163eb90fa987cdd09ca2fbe5a74c5b1402cac364f3abd8a00", | ||
"v": 1, | ||
"creates": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", | ||
"chainId": 31337 | ||
} | ||
}, | ||
"proxies": [ | ||
{ | ||
"address": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82", | ||
"txHash": "0xcca4a6b44dfe11eacb4a5a0cfcbd3f60bdf09e192cd1041f9c95c223c0e0f382", | ||
"kind": "transparent" | ||
}, | ||
{ | ||
"address": "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c", | ||
"txHash": "0xc207da1ba667358fa2e6f0f3a2a1ce11e0b54f9c8ffba0a5231244cd1f8bb1e1", | ||
"kind": "transparent" | ||
}, | ||
{ | ||
"address": "0x4A679253410272dd5232B3Ff7cF5dbB88f295319", | ||
"txHash": "0x859637882dac1c7388ad4df3082ecc5a7e6c8166e1e3d1312d4e00b89193a4a9", | ||
"kind": "transparent" | ||
}, | ||
{ | ||
"address": "0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690", | ||
"txHash": "0x096365e5b2926cbbd9987d6959f86bc375be328df527602772cc42049f60a0b9", | ||
"kind": "transparent" | ||
}, | ||
{ | ||
"address": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", | ||
"txHash": "0x6d44036c30e369c8b1e181c7cba50f8ccdd6d9e345aafe9716ab9f8dd869a3de", | ||
"kind": "transparent" | ||
}, | ||
{ | ||
"address": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6", | ||
"txHash": "0x03b7606dcfef6bc0c9b9ce56e020e20703a46e77c3eda53116fed04eaf02d1b1", | ||
"kind": "transparent" | ||
}, | ||
{ | ||
"address": "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1", | ||
"txHash": "0x320b39bd1d445af2ba123874ed3d9e42b47571f05f8c2e398ec400b79b9c9ed6", | ||
"kind": "transparent" | ||
}, | ||
{ | ||
"address": "0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f", | ||
"txHash": "0x7ef92d6e2ab84a9bf83474e7ad33a71ef67679a06205925540beb2bf3240f258", | ||
"kind": "transparent" | ||
}, | ||
{ | ||
"address": "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB", | ||
"txHash": "0xde7a964526cf7350a7db5161accda12ff476a144c7967e485b123fc9590f6372", | ||
"kind": "transparent" | ||
}, | ||
{ | ||
"address": "0x70e0bA845a1A0F2DA3359C97E0285013525FFC49", | ||
"txHash": "0x497a4bde97ccd2493c352dfb29fdebf160203b26f830c172c751dff0f9235c9e", | ||
"kind": "transparent" | ||
}, | ||
{ | ||
"address": "0x809d550fca64d94Bd9F66E60752A544199cfAC3D", | ||
"txHash": "0x125796c5d629ab3bc171e86c1333e212e7aa17f76acdff1fd09b6378c3ae58d3", | ||
"kind": "transparent" | ||
} | ||
], | ||
"impls": { | ||
"0002ac5494978eaaa1493964bf66ede2d1c7b3ce9a72bb21df782f9879635dfd": { | ||
"address": "0x0165878A594ca255338adfa4d48449f69242Eb8F", | ||
"txHash": "0xd686e808a73b1c19d894db70d18d7814f9f04523a843fc53ab8ea7d47444542c", | ||
"layout": { | ||
"storage": [ | ||
{ | ||
"contract": "Initializable", | ||
"label": "_initialized", | ||
"type": "t_bool", | ||
"src": "@openzeppelin\\contracts-upgradeable\\proxy\\utils\\Initializable.sol:39" | ||
}, | ||
{ | ||
"contract": "Initializable", | ||
"label": "_initializing", | ||
"type": "t_bool", | ||
"src": "@openzeppelin\\contracts-upgradeable\\proxy\\utils\\Initializable.sol:44" | ||
}, | ||
{ | ||
"contract": "ContextUpgradeable", | ||
"label": "__gap", | ||
"type": "t_array(t_uint256)50_storage", | ||
"src": "@openzeppelin\\contracts-upgradeable\\utils\\ContextUpgradeable.sol:31" | ||
}, | ||
{ | ||
"contract": "OwnableUpgradeable", | ||
"label": "_owner", | ||
"type": "t_address", | ||
"src": "@openzeppelin\\contracts-upgradeable\\access\\OwnableUpgradeable.sol:22" | ||
}, | ||
{ | ||
"contract": "OwnableUpgradeable", | ||
"label": "__gap", | ||
"type": "t_array(t_uint256)49_storage", | ||
"src": "@openzeppelin\\contracts-upgradeable\\access\\OwnableUpgradeable.sol:82" | ||
}, | ||
{ | ||
"contract": "RocketJoeStakingContract", | ||
"label": "moJOE", | ||
"type": "t_contract(IERC20Upgradeable)277", | ||
"src": "contracts\\RocketJoeStakingContract.sol:45" | ||
}, | ||
{ | ||
"contract": "RocketJoeStakingContract", | ||
"label": "lastRewardTimestamp", | ||
"type": "t_uint256", | ||
"src": "contracts\\RocketJoeStakingContract.sol:46" | ||
}, | ||
{ | ||
"contract": "RocketJoeStakingContract", | ||
"label": "accRJoePerShare", | ||
"type": "t_uint256", | ||
"src": "contracts\\RocketJoeStakingContract.sol:47" | ||
}, | ||
{ | ||
"contract": "RocketJoeStakingContract", | ||
"label": "rJOE", | ||
"type": "t_contract(RocketJoeToken)2094", | ||
"src": "contracts\\RocketJoeStakingContract.sol:50" | ||
}, | ||
{ | ||
"contract": "RocketJoeStakingContract", | ||
"label": "rJoePerSec", | ||
"type": "t_uint256", | ||
"src": "contracts\\RocketJoeStakingContract.sol:52" | ||
}, | ||
{ | ||
"contract": "RocketJoeStakingContract", | ||
"label": "userInfo", | ||
"type": "t_mapping(t_address,t_struct(UserInfo)1587_storage)", | ||
"src": "contracts\\RocketJoeStakingContract.sol:55" | ||
} | ||
], | ||
"types": { | ||
"t_contract(IERC20Upgradeable)277": { | ||
"label": "contract IERC20Upgradeable" | ||
}, | ||
"t_uint256": { | ||
"label": "uint256" | ||
}, | ||
"t_contract(RocketJoeToken)2094": { | ||
"label": "contract RocketJoeToken" | ||
}, | ||
"t_mapping(t_address,t_struct(UserInfo)1587_storage)": { | ||
"label": "mapping(address => struct RocketJoeStakingContract.UserInfo)" | ||
}, | ||
"t_address": { | ||
"label": "address" | ||
}, | ||
"t_struct(UserInfo)1587_storage": { | ||
"label": "struct RocketJoeStakingContract.UserInfo", | ||
"members": [ | ||
{ | ||
"label": "amount", | ||
"type": "t_uint256" | ||
}, | ||
{ | ||
"label": "rewardDebt", | ||
"type": "t_uint256" | ||
} | ||
] | ||
}, | ||
"t_array(t_uint256)49_storage": { | ||
"label": "uint256[49]" | ||
}, | ||
"t_array(t_uint256)50_storage": { | ||
"label": "uint256[50]" | ||
}, | ||
"t_bool": { | ||
"label": "bool" | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.0; | ||
|
||
import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; | ||
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; | ||
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; | ||
import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; | ||
import "./RocketJoeToken.sol"; | ||
|
||
import "hardhat/console.sol"; | ||
|
||
// MasterChefJoe is a boss. He says "go f your blocks lego boy, I'm gonna use timestamp instead". | ||
// And to top it off, it takes no risks. Because the biggest risk is operator error. | ||
// So we make it virtually impossible for the operator of this contract to cause a bug with people's harvests. | ||
// | ||
// Note that it's ownable and the owner wields tremendous power. The ownership | ||
// will be transferred to a governance smart contract once JOE is sufficiently | ||
// distributed and the community can show to govern itself. | ||
// | ||
// With thanks to the Lydia Finance team. | ||
// | ||
// Godspeed and may the 10x be with you. | ||
contract RocketJoeStakingContract is Initializable, OwnableUpgradeable { | ||
using SafeERC20Upgradeable for IERC20Upgradeable; | ||
|
||
// Info of each user. | ||
struct UserInfo { | ||
uint256 amount; // How many moJOE tokens the user has provided. | ||
uint256 rewardDebt; // Reward debt. See explanation below. | ||
// | ||
// We do some fancy math here. Basically, any point in time, the amount of JOEs | ||
// entitled to a user but is pending to be distributed is: | ||
// | ||
// pending reward = (user.amount * accRJoePerShare) - user.rewardDebt | ||
// | ||
// Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens: | ||
// 1. `accRJoePerShare` (and `lastRewardTimestamp`) gets updated. | ||
// 2. User receives the pending reward sent to his/her address. | ||
// 3. User's `amount` gets updated. | ||
// 4. User's `rewardDebt` gets updated. | ||
} | ||
|
||
// Info. | ||
IERC20Upgradeable moJOE; // Address of moJOE token contract. | ||
uint256 lastRewardTimestamp; // Last timestamp that rJOEs distribution occurs. | ||
uint256 accRJoePerShare; // Accumulated JOEs per share, times 1e12. See below. | ||
|
||
// The rJOE TOKEN! | ||
RocketJoeToken public rJOE; | ||
// rJOE tokens created per second. | ||
uint256 public rJoePerSec; | ||
|
||
// Info of each user that stakes LP tokens. | ||
mapping(address => UserInfo) public userInfo; | ||
|
||
event Deposit(address indexed user, uint256 amount); | ||
event Withdraw(address indexed user, uint256 amount); | ||
event EmergencyWithdraw(address indexed user, uint256 amount); | ||
event UpdateEmissionRate(address indexed user, uint256 _rJoePerSec); | ||
|
||
function initialize(IERC20Upgradeable _moJOE, RocketJoeToken _rJOE, uint256 _rJoePerSec) public initializer { | ||
__Ownable_init(); | ||
|
||
moJOE = _moJOE; | ||
rJOE = _rJOE; | ||
rJoePerSec = _rJoePerSec; | ||
} | ||
|
||
// View function to see pending JOEs on frontend. | ||
function pendingRJoe(address _user) external view returns (uint256) { | ||
UserInfo storage user = userInfo[_user]; | ||
uint256 moJoeSupply = moJOE.balanceOf(address(this)); | ||
uint256 _accRJoePerShare = accRJoePerShare; | ||
|
||
if (block.timestamp > lastRewardTimestamp && moJoeSupply != 0) { | ||
uint256 multiplier = block.timestamp - lastRewardTimestamp; | ||
uint256 rJoeReward = multiplier * rJoePerSec; | ||
_accRJoePerShare = _accRJoePerShare + rJoeReward * 1e12 / moJoeSupply; | ||
} | ||
return user.amount * _accRJoePerShare / 1e12 - user.rewardDebt; | ||
} | ||
|
||
// Update reward variables of the given pool to be up-to-date. | ||
function updatePool() public { | ||
if (block.timestamp <= lastRewardTimestamp) { | ||
return; | ||
} | ||
uint256 moJoeSupply = moJOE.balanceOf(address(this)); | ||
if (moJoeSupply == 0) { | ||
lastRewardTimestamp = block.timestamp; | ||
return; | ||
} | ||
uint256 multiplier = block.timestamp - lastRewardTimestamp; | ||
uint256 rJoeReward = multiplier * rJoePerSec; | ||
accRJoePerShare = accRJoePerShare + rJoeReward * 1e12 / moJoeSupply; | ||
lastRewardTimestamp = block.timestamp; | ||
|
||
rJOE.mint(address(this), rJoeReward); | ||
} | ||
|
||
// Deposit moJOE to RocketJoeStakingContract for rJOE allocation. | ||
function deposit(uint256 _amount) public { | ||
UserInfo storage user = userInfo[msg.sender]; | ||
|
||
updatePool(); | ||
if (user.amount > 0) { | ||
uint256 pending = user.amount * accRJoePerShare / 1e12 - user.rewardDebt; | ||
safeRJoeTransfer(msg.sender, pending); | ||
} | ||
user.amount = user.amount + _amount; | ||
user.rewardDebt = user.amount * accRJoePerShare / 1e12; | ||
|
||
moJOE.safeTransferFrom(address(msg.sender), address(this), _amount); | ||
emit Deposit(msg.sender, _amount); | ||
} | ||
|
||
// Withdraw moJOE from RocketJoeStakingContract. | ||
function withdraw(uint256 _amount) public { | ||
UserInfo storage user = userInfo[msg.sender]; | ||
require(user.amount >= _amount, "withdraw: not good"); | ||
|
||
updatePool(); | ||
uint256 pending = user.amount * accRJoePerShare / 1e12 - user.rewardDebt; | ||
user.amount = user.amount - _amount; | ||
user.rewardDebt = user.amount * accRJoePerShare / 1e12; | ||
|
||
safeRJoeTransfer(msg.sender, pending); | ||
moJOE.safeTransfer(address(msg.sender), _amount); | ||
emit Withdraw(msg.sender, _amount); | ||
} | ||
|
||
// Withdraw without caring about rewards. EMERGENCY ONLY. | ||
function emergencyWithdraw() public { | ||
UserInfo storage user = userInfo[msg.sender]; | ||
|
||
uint256 _amount = user.amount; | ||
user.amount = 0; | ||
user.rewardDebt = 0; | ||
|
||
moJOE.safeTransfer(address(msg.sender), _amount); | ||
emit EmergencyWithdraw(msg.sender, _amount); | ||
} | ||
|
||
// Safe rJoe transfer function, just in case if rounding error causes pool to not have enough JOEs. | ||
function safeRJoeTransfer(address _to, uint256 _amount) internal { | ||
uint256 rJoeBal = rJOE.balanceOf(address(this)); | ||
if (_amount > rJoeBal) { | ||
rJOE.transfer(_to, rJoeBal); | ||
} else { | ||
rJOE.transfer(_to, _amount); | ||
} | ||
} | ||
|
||
// Pancake has to add hidden dummy pools inorder to alter the emission, | ||
// here we make it simple and transparent to all. | ||
function updateEmissionRate(uint256 _rJoePerSec) public onlyOwner { | ||
updatePool(); | ||
rJoePerSec = _rJoePerSec; | ||
emit UpdateEmissionRate(msg.sender, _rJoePerSec); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.0; | ||
|
||
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | ||
import "@openzeppelin/contracts/access/Ownable.sol"; | ||
|
||
// RocketJoeToken, rJoe. | ||
contract RocketJoeToken is ERC20("RocketJoeToken", "rJOE"), Ownable { | ||
/// @notice Infinite supply, but burned to join IDO. | ||
|
||
/// @notice Creates `_amount` token to `_to`. Must only be called by the owner (RocketJoeStakingContract). | ||
function mint(address _to, uint256 _amount) public onlyOwner { | ||
_mint(_to, _amount); | ||
} | ||
} |
Oops, something went wrong.