Skip to content

Commit 748f8fd

Browse files
committed
created _update function by overriding it from the erc20
1 parent ca125fb commit 748f8fd

File tree

2 files changed

+115
-41
lines changed

2 files changed

+115
-41
lines changed

src/RebaseToken.sol

Lines changed: 113 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// SPDX-License-Identifier: MIT
22

3-
43
// Layout of Contract:
54
// version
65
// imports
@@ -28,20 +27,15 @@ pragma solidity ^0.8.0;
2827
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
2928
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
3029

31-
contract RebaseToken is ERC20, Ownable(address(msg.sender)) {
32-
30+
contract RebaseToken is ERC20, Ownable {
3331
//errors
3432

3533
error InterestRatesWillDecreaseWithTime(uint256 InterestRate, uint256 OldInterestRate);
3634

37-
3835
// type declaration
3936

40-
41-
4237
// State variables
4338

44-
4539
// interestRate per year in 1e18 precision
4640
// since this interestis scaled up ( should be 0.05 , but it is 0.05 + 1e18 )
4741
// so whenever we use it , we need to divide the answer by 1e18 , to get the actual answer
@@ -50,38 +44,48 @@ contract RebaseToken is ERC20, Ownable(address(msg.sender)) {
5044
uint256 ratePerSecond = globalInterestRatePerYear / SECONDS_PER_YEAR;
5145

5246
// before updating balance , we will store totol interest gained on previos principle amount
53-
// if amount zero , then first time depositor , so that will be zero , if not then it interest on previous amount will be stored here
54-
mapping (address => uint256) private InterestGained_beforeUpdatingBalance;
47+
// if amount zero , then first time depositor , so that will be zero , if not then it interest on previous amount will be stored here
48+
mapping(address => uint256) private InterestGained_beforeUpdatingBalance;
5549

56-
mapping (address => uint256) internal userToken_LastUpdatedTime;
50+
mapping(address => uint256) internal userToken_LastUpdatedTime;
5751

52+
mapping(address => uint256) internal userToken;
5853

54+
uint256 totalRebaseTokens;
5955

6056
// Events
6157

6258
event globalInterestRateupdated(uint256 _newInterestRate);
6359

60+
// modifiers
61+
62+
modifier notNullAddressCheck(address _user) {
63+
require(_user != address(0), "address cannot be null for this function");
6464

65+
_;
66+
}
6567

68+
constructor(string memory _tokenName, string memory _symbol) ERC20(_tokenName, _symbol) Ownable(address(msg.sender)) {}
6669

67-
constructor(string memory _tokenName, string memory _symbol) ERC20(_tokenName, _symbol) {}
70+
// external
6871

69-
function mint(address _user, uint256 amount) external onlyOwner returns(bool){
72+
/**
73+
* @notice => this will mint new rebase tokens and then update user last updated time to current
74+
*/
75+
function mint(address _user, uint256 amount) external onlyOwner returns (bool) {
76+
InterestGained_beforeUpdatingTokenBalance(msg.sender);
7077
_mint(_user, amount);
78+
userToken[_user] += amount;
7179
userToken_LastUpdatedTime[_user] = block.timestamp;
7280

7381
return true;
74-
75-
7682
}
7783

78-
function burn(uint256 amount, address user) external onlyOwner{
84+
function burn(uint256 amount, address user) external onlyOwner {
7985
_burn(user, amount);
8086
}
8187

82-
83-
84-
/**
88+
/**
8589
* @notice => this function will be called only owner to update the interest of the contract
8690
* @param _newInterestRatePerYear = > this is the new interest rate( in 1e18 precision) that onwer can set and can only be lesser that the previous interest rate
8791
*/
@@ -93,49 +97,118 @@ contract RebaseToken is ERC20, Ownable(address(msg.sender)) {
9397
emit globalInterestRateupdated(_newInterestRatePerYear);
9498
}
9599

100+
/**
101+
* @notice => total interest gained on total principle amount before updating the balance & last update time
102+
* @notice => idea is , if user add more principle/amount , then we will store interest gained for the current amount/before_updating_the_amount and time_deposited
103+
* @notice => since this is updating the user interest gained state , it can be called multiple times and can be hacked , so making it onlyowner and it will called only when the user deposit eth
104+
* @param _user => this is the user who is adding more amount , so we are storing its interest gained till now on current deposited amount , before updaing total amount and last_updated_time
105+
*/
106+
function InterestGained_beforeUpdatingTokenBalance(address _user) internal {
107+
// amount * rate_per_Second * total_time_elapsed_since_last_update
108+
InterestGained_beforeUpdatingBalance[_user] +=
109+
(userToken[_user] * ratePerSecond * (block.timestamp - userToken_LastUpdatedTime[_user])) / 1e18;
110+
}
96111

97-
function balanceOf(address _user) public view override returns(uint256){
98-
99-
return super.balanceOf(_user) + get_InterestGained_beforeUpdatingBalance(_user) + interestGained_on_currentAmount_sinceLastUpdatedTime(_user) ;
112+
// public
100113

114+
/**
115+
* @notice => this will total rebase token holdings + the token earned in interest
116+
*/
117+
function balanceOf(address _user) public view override returns (uint256) {
118+
return userToken[_user] + get_InterestGained_beforeUpdatingBalance(_user)
119+
+ interestGained_on_currentAmount_sinceLastUpdatedTime(_user);
101120
}
102121

122+
/**
123+
* @notice => this function returning total interest earned by the user since last principle and time is updated
124+
* @notice => maybe user has added more amount , so time is update to that time , so total interest on that total amount for (current_time - that_update_time)
125+
* @param _user => the user whos interest is being calculated
126+
*/
127+
function interestGained_on_currentAmount_sinceLastUpdatedTime(address _user) public view returns (uint256) {
128+
// p * rate_per_second * seconds elapsed since last update
129+
return (userToken[_user] * ratePerSecond * (block.timestamp - userToken_LastUpdatedTime[_user])) / 1e18;
130+
}
103131

104132
/**
105-
@notice => this function returning total interest earned by the user since last principle and time is updated
106-
@notice => maybe user has added more amount , so time is update to that time , so total interest on that total amount for (current_time - that_update_time)
107-
@param _user => the user whos interest is being calculated
133+
* @notice => we are overriding this transfer function and this will use our update function and our balanceOf function to transfer token from sender to reciever
134+
* @param => to is the reciever to whom msg.sender is sending tokens
135+
* @param => value is amount of tokens ( should be less that balanceOf of user ( principle + interest gained))
108136
*/
109-
function interestGained_on_currentAmount_sinceLastUpdatedTime(address _user) public view returns(uint256){
137+
function transfer(address to, uint256 value) public override returns (bool) {
138+
require(msg.sender != address(0), "sender cannot be null address");
139+
require(to != address(0), "reciever cannot be null address");
110140

111-
return (super.balanceOf(_user)*ratePerSecond*userToken_LastUpdatedTime[_user])/1e18;
141+
_update(msg.sender, to, value);
112142

143+
return true;
113144
}
114145

115-
/**
116-
@notice => total interest gained on total principle amount before updating the balance & time
117-
@notice => idea is , if user add more principle/amount , then we will store interest gained for the current amount/before_updating_the_amount and time_deposited
118-
@notice => since this is updating the user interest gained state , it can be called multiple times and can be hacked , so making it onlyowner and it will called only when the user deposit eth
119-
@param _user => this is the user who is adding more amount , so we are storing its interest gained till now on current deposited amount , before updaing total amount and last_updated_time
120-
*/
121-
function InterestGained_beforeUpdatingTokenBalance(address _user) external onlyOwner() {
122-
InterestGained_beforeUpdatingBalance[_user] += (super.balanceOf(_user)*ratePerSecond*userToken_LastUpdatedTime[_user])/1e18;
146+
function transferFrom(address from, address to, uint256 value) public override returns (bool) {
147+
require(msg.sender != address(0), "sender cannot be null address");
148+
require(to != address(0), "reciever cannot be null address");
123149

150+
_spendAllowance(msg.sender, to, value);
151+
_update(from, to, value);
152+
return true;
124153
}
125154

155+
// private
156+
157+
function _update(address from, address to, uint256 value) internal override {
158+
uint256 fromBalance = balanceOf(from);
159+
if (from == address(0)) {
160+
// Overflow check required: The rest of the code assumes that totalSupply never overflows
161+
totalRebaseTokens += value;
162+
} else if (fromBalance < value) {
163+
revert ERC20InsufficientBalance(from, fromBalance, value);
164+
} else if (value < userToken[from]) {
165+
// calculating total interest , before changing the user token balance
166+
InterestGained_beforeUpdatingTokenBalance(from);
126167

127-
128-
168+
userToken[from] = userToken[from] - value;
169+
}
170+
// this case where value < (user principle tokens + interest tokens gained)
171+
else if (value <= fromBalance) {
172+
InterestGained_beforeUpdatingTokenBalance(from);
173+
uint256 userInterestAmount = balanceOf(from) - userToken[from];
174+
_mint(from, userInterestAmount);
175+
176+
// new tokens minted , so increasing the user balance and user is transfering , so decreasing value amount of tokend from user balance
177+
userToken[from] = userToken[from] + userInterestAmount - value;
178+
totalRebaseTokens += userInterestAmount;
179+
180+
// minted new interest gained tokens , so total interest gained net is set to zero
181+
InterestGained_beforeUpdatingBalance[from] = 0;
182+
183+
userToken_LastUpdatedTime[from] = block.timestamp;
184+
}
129185

186+
if (to == address(0)) {
187+
unchecked {
188+
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
189+
totalRebaseTokens -= value;
190+
}
191+
} else {
192+
unchecked {
193+
// before updating to user balance , calculate its total interest gained
194+
InterestGained_beforeUpdatingTokenBalance(to);
130195

196+
userToken[to] += value;
197+
198+
userToken_LastUpdatedTime[to] = block.timestamp;
199+
}
200+
}
201+
202+
emit Transfer(from, to, value);
203+
}
131204

132-
// view
205+
// view
133206

134-
function get_InterestGained_beforeUpdatingBalance(address _user) public view returns(uint256){
135-
return InterestGained_beforeUpdatingBalance[_user] ;
207+
function get_InterestGained_beforeUpdatingBalance(address _user) public view returns (uint256) {
208+
return InterestGained_beforeUpdatingBalance[_user];
136209
}
137210

138-
function get_userTokenLastUpdateTime(address _user) view public returns(uint256){
211+
function get_userTokenLastUpdateTime(address _user) public view returns (uint256) {
139212
return userToken_LastUpdatedTime[_user];
140213
}
141214
}

src/RebaseTokenEngine.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ contract RebaseTokenEngine {
7878
*/
7979

8080
// calculating the interest gained on current principle amount + before updating amount and time
81-
rebaseToken.InterestGained_beforeUpdatingTokenBalance(msg.sender);
81+
// this is being called in the mint function
82+
// rebaseToken.InterestGained_beforeUpdatingTokenBalance(msg.sender);
8283
userDeposited_ETH_Balance[msg.sender] += msg.value;
8384
// minting equivalent amount of new rebase token to user
8485
(bool success ) = rebaseToken.mint(msg.sender , msg.value);

0 commit comments

Comments
 (0)