Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update eip-5075.md #1

Merged
merged 1 commit into from
May 8, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 77 additions & 66 deletions EIPS/EIPs/eip-5075.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,29 +72,29 @@ This will be non backwards compatible with contracts that are NOT whitelisted wh
## Reference Implementation

```
// SPDX-License-Identifier: CC0
// SPDX-License-Identifier: CC0
pragma solidity ^0.8;

import"./IERC20.sol";
import"@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract rateLimit {
mapping(address => TokenInfo) public infoL;
struct TokenInfo {
uint32 timestamp; //tracks most recent send
uint224 rate; //tracks amount sent for the last timeLimit time
uint224 ratedFlow; //tracks amount sent for the last timeWindow time
}

uint256 public timeLimit = 3600; //how long in seconds to limit within, recommend 1h = 3600
uint16 public rateLimit = 1000; //the basis points (00.0x%) to allow as the max sent within the last timeLimit time
uint256 public timeWindow = 3600; //how long in seconds to limit within, recommend 1h = 3600
uint16 public rateLimit = 1000; //the basis points (00.0x%) to allow as the max sent within the last timeWindow time

mapping(address => uint8) public whitelisted; //stores whitelisted addresses to not be rate limited, useful for yearn style or deposit contracts
address public authAddress; //allows a set address that can whitelist addresses

//updates the time as well as the relative amount in basis points to track and rate limit outflows in which to track
//_rateLimit = 00.x%, _timeLimit = time in seconds
function updateLimits(uint16 _rateLimit, uint256 _timeLimit) internal {
//_rateLimit = 00.x%, _timeWindow = time in seconds
function updateLimits(uint16 _rateLimit, uint256 _timeWindow) internal {
rateLimit = _rateLimit;
timeLimit = _timeLimit;
timeWindow = _timeWindow;
}

//change the auth address that can whitelist addresses
Expand All @@ -116,28 +116,42 @@ contract rateLimit {

//gets the token amount left to be within the allowable limit
function getLimitLeft(address token)
public
view
returns (uint256 rateLeft)
public
view
returns (uint256 rateLeft)
{
TokenInfo storage info = infoL[token];
uint256 rate;
uint256 ratedFlow;
//if outside the time dwindow
if (timeLimit <= block.timestamp - info.timestamp) {
if (timeWindow <= block.timestamp - info.timestamp) {
return (0);
}
//if the last transaction was within the time window, decreases the tracked outflow rate relative to the time elapsed, so that the limit is able to update in realtime rather than in blocks, making flows smooth, and increasing the rate available as time increases without a transaction
else {
rate = info.rate;
uint256 limitUnlocked = uint224(
(address(this).balance * rateLimit) /
(timeLimit / (block.timestamp - info.timestamp)) /
10000
);
if (rate <= limitUnlocked) {
return 0;
} else {
return rate - limitUnlocked;
unchecked {
ratedFlow = info.ratedFlow;

uint256 limitUnlocked;
if (token==address(0)) {
limitUnlocked = uint224(
(address(this).balance * rateLimit) /
(timeWindow / (block.timestamp - info.timestamp)) /
10000
);
}
else {
limitUnlocked = uint224(
IERC20(token).balanceOf(address(this)) * rateLimit /
(timeWindow / (block.timestamp - info.timestamp)) /
10000
);
}

if (ratedFlow <= limitUnlocked) {
return 0;
} else {
return ratedFlow - limitUnlocked;
}
}
}
}
Expand All @@ -162,59 +176,56 @@ contract rateLimit {
//used if the asset is ETH and not an ERC20 token
else {
if (address(token) == address(0)) {
//used to get around solidity 0.8 reverts
unchecked {
//checks to see if the last transaction was outside the time window to track outflow for limiting
if (timeLimit <= block.timestamp - info.timestamp) {
info.rate = 0;
}
//if the last transaction was within the time window, decreases the tracked outflow rate relative to the time elapsed, so that the limit is able to update in realtime rather than in blocks, making flows smooth, and increasing the rate available as time increases without a transaction
else {
info.rate -= uint224(
(address(this).balance * rateLimit) /
(timeLimit /
(block.timestamp - info.timestamp)) /
10000
);
uint256 limitUnlocked = uint224(
(address(this).balance * rateLimit) /
(timeWindow / (block.timestamp - info.timestamp)) /
10000
);
if (info.ratedFlow <= limitUnlocked || timeWindow <= block.timestamp - info.timestamp) {
info.ratedFlow = 0;
} else {
info.ratedFlow -= uint224(limitUnlocked);
}
}
//increases the tracked rate for the current time window by the amount sent out
info.rate += uint224(amount);
//revert if the outflow exceeds rate limit
require(
info.rate <= (rateLimit * address(this).balance) / 10000
);
//sets the current time as the last transfer for the token
info.timestamp = uint32(block.timestamp);
//transfers out
payable(to).transfer(amount);
return(true);

//increases the tracked ratedFlow for the current time window by the amount sent out
info.ratedFlow += uint224(amount);
unchecked {
//revert if the outflow exceeds rate limit
require(
info.ratedFlow <= (rateLimit * address(this).balance) / 10000
);
//sets the current time as the last transfer for the token
info.timestamp = uint32(block.timestamp);
//transfers out
payable(to).transfer(amount);
return(true);
}
//if the token is a ERC20 token
} else {
//used to get around solidity 0.8 reverts
unchecked {
//checks to see if the last transaction was outside the time window to track outflow for limiting
if (timeLimit <= block.timestamp - info.timestamp) {
info.rate = 0;
}
//if the last transaction was within the time window, decreases the tracked outflow rate relative to the time elapsed, so that the limit is able to update in realtime rather than in blocks, making flows smooth, and increasing the rate available as time increases without a transaction
else {
info.rate -= uint224(
(IERC20(token).balanceOf(address(this)) *
rateLimit) /
(timeLimit /
(block.timestamp - info.timestamp)) /
10000
);
uint256 limitUnlocked = uint224(
(IERC20(token).balanceOf(address(this)) * rateLimit) /
(timeWindow / (block.timestamp - info.timestamp)) /
10000
);
if (info.ratedFlow <= limitUnlocked || timeWindow <= block.timestamp - info.timestamp) {
info.ratedFlow = 0;
} else {
info.ratedFlow -= uint224(limitUnlocked);
}
//increases the tracked rate for the current time window by the amount sent out
info.rate += uint224(amount);
}
//increases the tracked ratedFlow for the current time window by the amount sent out
info.ratedFlow += uint224(amount);
unchecked {
//revert if the outflow exceeds rate limit
require(
info.rate <=
(rateLimit *
IERC20(token).balanceOf(address(this))) /
10000
info.ratedFlow <=
(rateLimit *
IERC20(token).balanceOf(address(this))) /
10000
);
//sets the current time as the last transfer for the token
info.timestamp = uint32(block.timestamp);
Expand Down