Skip to content

Commit c95f85c

Browse files
authored
Create AeolusV2dot2.sol
1 parent b4e7f8a commit c95f85c

File tree

1 file changed

+191
-0
lines changed

1 file changed

+191
-0
lines changed

contracts/AeolusV2dot2.sol

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
pragma solidity <0.6 >=0.4.24;
2+
3+
import "./math/SafeMath.sol";
4+
import "./ownership/Ownable.sol";
5+
import "./token/IERC20.sol";
6+
import "./token/IMintableToken.sol";
7+
import "./token/SafeERC20.sol";
8+
import "./uniswapv1/IExchange.sol";
9+
10+
// Aeolus is the master of Cyclone tokens. He can distribute CYC and he is a fair guy.
11+
//
12+
// Note that it's ownable and the owner wields tremendous power. The ownership
13+
// will be transferred to a governance smart contract once CYC is sufficiently
14+
// distributed and the community can show to govern itself.
15+
//
16+
// Have fun reading it. Hopefully it's bug-free. God bless.
17+
contract AeolusV2dot2 is Ownable {
18+
using SafeMath for uint256;
19+
using SafeERC20 for IERC20;
20+
21+
// Info of each user.
22+
struct UserInfo {
23+
uint256 amount; // How many LP tokens the user has provided.
24+
uint256 rewardDebt; // Reward debt. See explanation below.
25+
//
26+
// We do some fancy math here. Basically, any point in time, the amount of CYCs
27+
// entitled to a user but is pending to be distributed is:
28+
//
29+
// pending reward = (user.amount * accCYCPerShare) - user.rewardDebt
30+
//
31+
// Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:
32+
// 1. Update accCYCPerShare and lastRewardBlock
33+
// 2. User receives the pending reward sent to his/her address.
34+
// 3. User's `amount` gets updated.
35+
// 4. User's `rewardDebt` gets updated.
36+
}
37+
38+
39+
// Address of LP token contract.
40+
IERC20 public lpToken;
41+
// Accumulated CYCs per share, times 1e12. See below.
42+
uint256 public accCYCPerShare;
43+
// Last block reward block height
44+
uint256 public lastRewardBlock;
45+
// Reward per block
46+
uint256 public rewardPerBlock;
47+
// Reward to distribute
48+
uint256 public rewardToDistribute;
49+
// Entrance Fee Rate
50+
uint256 public entranceFeeRate;
51+
52+
IExchange public exchange;
53+
// The Cyclone TOKEN
54+
IMintableToken public cycToken;
55+
56+
// Info of each user that stakes LP tokens.
57+
mapping (address => UserInfo) public userInfo;
58+
59+
event RewardAdded(uint256 amount, bool isBlockReward);
60+
event Deposit(address indexed user, uint256 amount, uint256 fee);
61+
event Withdraw(address indexed user, uint256 amount);
62+
event EmergencyWithdraw(address indexed user, uint256 amount);
63+
64+
constructor(IMintableToken _cycToken, address payable _exchange) public {
65+
cycToken = _cycToken;
66+
lastRewardBlock = block.number;
67+
lpToken = IERC20(_exchange);
68+
exchange = IExchange(_exchange);
69+
}
70+
71+
function() external payable {
72+
}
73+
74+
function setEntranceFeeRate(uint256 _entranceFeeRate) public onlyOwner {
75+
require(_entranceFeeRate < 10000, "invalid entrance fee rate");
76+
entranceFeeRate = _entranceFeeRate;
77+
}
78+
79+
function setRewardPerBlock(uint256 _rewardPerBlock) public onlyOwner {
80+
updateBlockReward();
81+
rewardPerBlock = _rewardPerBlock;
82+
}
83+
84+
function rewardPending() internal view returns (uint256) {
85+
uint256 reward = block.number.sub(lastRewardBlock).mul(rewardPerBlock);
86+
uint256 cycBalance = cycToken.balanceOf(address(this)).sub(rewardToDistribute);
87+
if (cycBalance < reward) {
88+
return cycBalance;
89+
}
90+
return reward;
91+
}
92+
93+
// View function to see pending reward on frontend.
94+
function pendingReward(address _user) external view returns (uint256) {
95+
UserInfo storage user = userInfo[_user];
96+
uint256 acps = accCYCPerShare;
97+
if (rewardPerBlock > 0) {
98+
uint256 lpSupply = lpToken.balanceOf(address(this));
99+
if (block.number > lastRewardBlock && lpSupply > 0) {
100+
acps = acps.add(rewardPending().mul(1e12).div(lpSupply));
101+
}
102+
}
103+
104+
return user.amount.mul(acps).div(1e12).sub(user.rewardDebt);
105+
}
106+
107+
// Update reward variables to be up-to-date.
108+
function updateBlockReward() public {
109+
if (block.number <= lastRewardBlock || rewardPerBlock == 0) {
110+
return;
111+
}
112+
uint256 lpSupply = lpToken.balanceOf(address(this));
113+
uint256 reward = rewardPending();
114+
if (lpSupply == 0 || reward == 0) {
115+
lastRewardBlock = block.number;
116+
return;
117+
}
118+
rewardToDistribute = rewardToDistribute.add(reward);
119+
emit RewardAdded(reward, true);
120+
lastRewardBlock = block.number;
121+
accCYCPerShare = accCYCPerShare.add(reward.mul(1e12).div(lpSupply));
122+
}
123+
124+
// Deposit LP tokens to Aeolus for CYC allocation.
125+
function deposit(uint256 _amount) public {
126+
updateBlockReward();
127+
UserInfo storage user = userInfo[msg.sender];
128+
uint256 originAmount = user.amount;
129+
uint256 acps = accCYCPerShare;
130+
if (originAmount > 0) {
131+
uint256 pending = originAmount.mul(acps).div(1e12).sub(user.rewardDebt);
132+
if (pending > 0) {
133+
safeCYCTransfer(msg.sender, pending);
134+
}
135+
}
136+
uint256 feeInCYC = 0;
137+
if (_amount > 0) {
138+
lpToken.safeTransferFrom(address(msg.sender), address(this), _amount);
139+
uint256 entranceFee = _amount.mul(entranceFeeRate).div(10000);
140+
if (entranceFee > 0) {
141+
(uint256 iotxAmount, uint256 cycAmount) = exchange.removeLiquidity(entranceFee, 1, 1, block.timestamp.mul(2));
142+
feeInCYC = cycAmount.add(exchange.iotxToTokenSwapInput.value(iotxAmount)(1, block.timestamp.mul(2)));
143+
require(cycToken.burn(feeInCYC), "failed to burn cyc token");
144+
_amount = _amount.sub(entranceFee);
145+
}
146+
user.amount = originAmount.add(_amount);
147+
}
148+
user.rewardDebt = user.amount.mul(acps).div(1e12);
149+
emit Deposit(msg.sender, _amount, feeInCYC);
150+
}
151+
152+
// Withdraw LP tokens from Aeolus.
153+
function withdraw(uint256 _amount) public {
154+
UserInfo storage user = userInfo[msg.sender];
155+
uint256 originAmount = user.amount;
156+
require(originAmount >= _amount, "withdraw: not good");
157+
updateBlockReward();
158+
uint256 acps = accCYCPerShare;
159+
uint256 pending = originAmount.mul(acps).div(1e12).sub(user.rewardDebt);
160+
if (pending > 0) {
161+
safeCYCTransfer(msg.sender, pending);
162+
}
163+
if (_amount > 0) {
164+
user.amount = originAmount.sub(_amount);
165+
lpToken.safeTransfer(address(msg.sender), _amount);
166+
}
167+
user.rewardDebt = user.amount.mul(acps).div(1e12);
168+
emit Withdraw(msg.sender, _amount);
169+
}
170+
171+
// Withdraw without caring about rewards. EMERGENCY ONLY.
172+
function emergencyWithdraw() public {
173+
UserInfo storage user = userInfo[msg.sender];
174+
uint256 amount = user.amount;
175+
user.amount = 0;
176+
user.rewardDebt = 0;
177+
lpToken.safeTransfer(address(msg.sender), amount);
178+
emit EmergencyWithdraw(msg.sender, amount);
179+
}
180+
181+
// Safe CYC transfer function, just in case if rounding error causes pool to not have enough CYCs.
182+
function safeCYCTransfer(address _to, uint256 _amount) internal {
183+
IMintableToken token = cycToken;
184+
uint256 cycBalance = token.balanceOf(address(this));
185+
if (_amount > cycBalance) {
186+
_amount = cycBalance;
187+
}
188+
rewardToDistribute = rewardToDistribute.sub(_amount);
189+
require(token.transfer(_to, _amount), "failed to transfer cyc token");
190+
}
191+
}

0 commit comments

Comments
 (0)