-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
# This is a combination of 2 commits.
# This is the 1st commit message: CR changes + test them # This is the commit message #2: use shell array
- Loading branch information
Showing
5 changed files
with
669 additions
and
4 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
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,4 @@ | ||
{ | ||
"filter_paths": "(openzeppelin|mocks/|test/|tests/|testhelpers)", | ||
"detectors_to_exclude": "pragma,solc-version,naming-convention,assembly,reentrancy-events,timestamp,calls-loop,unused-return" | ||
} |
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,4 @@ | ||
{ | ||
"filter_paths": "(openzeppelin|mocks/|test/|tests/|testhelpers)", | ||
"detectors_to_exclude": "pragma" | ||
} |
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,92 @@ | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
pragma solidity 0.8.24; | ||
|
||
import {IPriceRegistry} from "./interfaces/IPriceRegistry.sol"; | ||
|
||
import {OwnerIsCreator} from "./../shared/access/OwnerIsCreator.sol"; | ||
import {Client} from "./libraries/Client.sol"; | ||
import {RateLimiter} from "./libraries/RateLimiter.sol"; | ||
import {USDPriceWith18Decimals} from "./libraries/USDPriceWith18Decimals.sol"; | ||
|
||
/// @notice The aggregate rate limiter is a wrapper of the token bucket rate limiter | ||
/// which permits rate limiting based on the aggregate value of a group of | ||
/// token transfers, using a price registry to convert to a numeraire asset (e.g. USD). | ||
contract AggregateRateLimiter is OwnerIsCreator { | ||
using RateLimiter for RateLimiter.TokenBucket; | ||
using USDPriceWith18Decimals for uint224; | ||
|
||
error PriceNotFoundForToken(address token); | ||
|
||
event AdminSet(address newAdmin); | ||
|
||
// The address of the token limit admin that has the same permissions as the owner. | ||
address internal s_admin; | ||
|
||
// The token bucket object that contains the bucket state. | ||
RateLimiter.TokenBucket private s_rateLimiter; | ||
|
||
/// @param config The RateLimiter.Config | ||
constructor(RateLimiter.Config memory config) { | ||
s_rateLimiter = RateLimiter.TokenBucket({ | ||
rate: config.rate, | ||
capacity: config.capacity, | ||
tokens: config.capacity, | ||
lastUpdated: uint32(block.timestamp), | ||
isEnabled: config.isEnabled | ||
}); | ||
} | ||
|
||
/// @notice Consumes value from the rate limiter bucket based on the token value given. | ||
function _rateLimitValue(uint256 value) internal { | ||
s_rateLimiter._consume(value, address(0)); | ||
} | ||
|
||
function _getTokenValue( | ||
Client.EVMTokenAmount memory tokenAmount, | ||
IPriceRegistry priceRegistry | ||
) internal view returns (uint256) { | ||
// not fetching validated price, as price staleness is not important for value-based rate limiting | ||
// we only need to verify the price is not 0 | ||
uint224 pricePerToken = priceRegistry.getTokenPrice(tokenAmount.token).value; | ||
if (pricePerToken == 0) revert PriceNotFoundForToken(tokenAmount.token); | ||
return pricePerToken._calcUSDValueFromTokenAmount(tokenAmount.amount); | ||
} | ||
|
||
/// @notice Gets the token bucket with its values for the block it was requested at. | ||
/// @return The token bucket. | ||
function currentRateLimiterState() external view returns (RateLimiter.TokenBucket memory) { | ||
return s_rateLimiter._currentTokenBucketState(); | ||
} | ||
|
||
/// @notice Sets the rate limited config. | ||
/// @param config The new rate limiter config. | ||
/// @dev should only be callable by the owner or token limit admin. | ||
function setRateLimiterConfig(RateLimiter.Config memory config) external onlyAdminOrOwner { | ||
s_rateLimiter._setTokenBucketConfig(config); | ||
} | ||
|
||
// ================================================================ | ||
// │ Access │ | ||
// ================================================================ | ||
|
||
/// @notice Gets the token limit admin address. | ||
/// @return the token limit admin address. | ||
function getTokenLimitAdmin() external view returns (address) { | ||
return s_admin; | ||
} | ||
|
||
/// @notice Sets the token limit admin address. | ||
/// @param newAdmin the address of the new admin. | ||
/// @dev setting this to address(0) indicates there is no active admin. | ||
function setAdmin(address newAdmin) external onlyAdminOrOwner { | ||
s_admin = newAdmin; | ||
emit AdminSet(newAdmin); | ||
} | ||
|
||
/// @notice a modifier that allows the owner or the s_tokenLimitAdmin call the functions | ||
/// it is applied to. | ||
modifier onlyAdminOrOwner() { | ||
if (msg.sender != owner() && msg.sender != s_admin) revert RateLimiter.OnlyCallableByAdminOrOwner(); | ||
_; | ||
} | ||
} |
Oops, something went wrong.