-
Notifications
You must be signed in to change notification settings - Fork 7
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
ignore #40
Merged
ignore #40
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
9c9ecaa
WIP
proletesseract c5bef71
Merge branch 'main' into SMR-1677-FlowRate
proletesseract d0326eb
flow rate initial port complete
proletesseract 0061c76
all code ported, some failing tests
proletesseract d2127d3
integration tests passing
proletesseract 3e3d9ff
Merge branch 'main' into SMR-1677-FlowRate
proletesseract a952622
compiling, couple tests to patch
proletesseract 43f8499
tests passing again
proletesseract 1cc475d
Fix linting issue
ermyas d7d7bb3
setup unit tests for flowRate
proletesseract 26e1764
WIP
proletesseract 4b27639
Refactor withdrawal validation
ermyas 51a246f
Replace old references to RootERC20Predicate
ermyas 17f7170
test for getter/setters
proletesseract ef8f6d4
Merge branch 'SMR-1677-FlowRate' of https://github.com/immutable/zkev…
proletesseract a1ea466
test WIP
proletesseract 589fbb7
more tests ported
proletesseract de763bb
Update RootERC20BridgeFlowRate.t.sol
proletesseract f8aac68
patch for native eth withdrawals
proletesseract aacca8b
Merge branch 'main' into SMR-1677-FlowRate
proletesseract f6cfff8
some tests fixed
proletesseract 665998b
Update RootERC20BridgeFlowRate.t.sol
proletesseract a8ab7af
more tests
proletesseract File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,48 @@ | ||
// SPDX-License-Identifier: Apache 2.0 | ||
pragma solidity 0.8.19; | ||
|
||
interface IRootERC20BridgeFlowRate {} | ||
|
||
interface IRootERC20BridgeFlowRateEvents { | ||
/** | ||
* @notice Indicates rate control thresholds have been set for a certain token. | ||
* @param token The token thresholds applied to. | ||
* @param capacity The size of the bucket in tokens. | ||
* @param refillRate How quickly the bucket refills in tokens per second. | ||
* @param largeTransferThreshold Threshold over which a withdrawal is deemed to be large, | ||
* and will be put in the withdrawal queue. | ||
*/ | ||
event RateControlThresholdSet( | ||
address indexed token, uint256 capacity, uint256 refillRate, uint256 largeTransferThreshold | ||
); | ||
|
||
/** | ||
* @notice Indicates a withdrawal was queued. | ||
* @param token Address of token that is being withdrawn. | ||
* @param withdrawer Child chain sender of tokens. | ||
* @param receiver Recipient of tokens. | ||
* @param amount The number of tokens. | ||
* @param delayWithdrawalLargeAmount is true if the reason for queuing was a large transfer. | ||
* @param delayWithdrawalUnknownToken is true if the reason for queuing was that the | ||
* token had not been configured using the setRateControlThreshold function. | ||
* @param withdrawalQueueActivated is true if the withdrawal queue has been activated. | ||
*/ | ||
event QueuedWithdrawal( | ||
address indexed token, | ||
address indexed withdrawer, | ||
address indexed receiver, | ||
uint256 amount, | ||
bool delayWithdrawalLargeAmount, | ||
bool delayWithdrawalUnknownToken, | ||
bool withdrawalQueueActivated | ||
); | ||
} | ||
|
||
interface IRootERC20BridgeFlowRateErrors { | ||
// Error if the RootERC20Bridge initializer is called, and not the one for this contract. | ||
error WrongInitializer(); | ||
// finaliseQueuedWithdrawalsAggregated was called with a zero length indices array. | ||
error ProvideAtLeastOneIndex(); | ||
// The expected and actual token did not match for an aggregated withdrawal. | ||
error MixedTokens(address token, address actualToken); | ||
} |
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,130 @@ | ||
// Copyright Immutable Pty Ltd 2018 - 2023 | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.19; | ||
|
||
/** | ||
* @title Flow Rate Detection | ||
* @author Immutable Pty Ltd (Peter Robinson @drinkcoffee and Zhenyang Shi @wcgcyx) | ||
* @notice Detects large flows of tokens using a bucket system. | ||
* @dev Each token has a bucket. The bucket is filled at a constant rate: a number of | ||
* tokens per second. The bucket empties each time there is a withdrawal. Withdrawal | ||
* requests for tokens that don't have a configured bucket are delayed. | ||
* Note: This code is part of RootERC20BridgeFlowRate. It has been separated out | ||
* to make it easier to understand and test the functionality. | ||
* Note that this contract is upgradeable. | ||
*/ | ||
abstract contract FlowRateDetection { | ||
// Holds flow rate information for a single token. | ||
struct Bucket { | ||
// The number of tokens that can fit in the bucket. | ||
// A capacity of zero indicates that flow rate detection is disabled for the token. | ||
uint256 capacity; | ||
// The number of tokens in the bucket. | ||
uint256 depth; | ||
// The last time the bucket was updated. | ||
uint256 refillTime; | ||
// The number of tokens added per second. | ||
uint256 refillRate; | ||
} | ||
|
||
// Map ERC 20 token address to buckets | ||
mapping(address => Bucket) public flowRateBuckets; | ||
|
||
// True if all tokens should be put in the withdrawal queue. | ||
bool public withdrawalQueueActivated; | ||
|
||
// Emitted when there is a withdrawal request for a token for which there is no bucket. | ||
event WithdrawalForNonFlowRatedToken(address indexed token, uint256 amount); | ||
// Emitted when queue activated or deactivated | ||
event AutoActivatedWithdrawalQueue(); | ||
event ActivatedWithdrawalQueue(address who); | ||
event DeactivatedWithdrawalQueue(address who); | ||
|
||
error InvalidToken(); | ||
error InvalidCapacity(); | ||
error InvalidRefillRate(); | ||
|
||
/** | ||
* @notice Activate the withdrawal queue for all tokens. | ||
*/ | ||
function _activateWithdrawalQueue() internal { | ||
withdrawalQueueActivated = true; | ||
emit ActivatedWithdrawalQueue(msg.sender); | ||
} | ||
|
||
/** | ||
* @notice Deactivate the withdrawal queue for all tokens. | ||
* @dev This does not affect withdrawals already in the queue. | ||
*/ | ||
function _deactivateWithdrawalQueue() internal { | ||
withdrawalQueueActivated = false; | ||
emit DeactivatedWithdrawalQueue(msg.sender); | ||
} | ||
|
||
/** | ||
* @notice Initialise or update a bucket for a token. | ||
* @param token Address of the token to configure the bucket for. | ||
* @param capacity The number of tokens before the bucket overflows. | ||
* @param refillRate The number of tokens added to the bucket each second. | ||
* @dev If this is a new bucket, then the depth is the capacity. If the bucket is existing, then | ||
* the depth is not altered. | ||
*/ | ||
function _setFlowRateThreshold(address token, uint256 capacity, uint256 refillRate) internal { | ||
if (token == address(0)) { | ||
revert InvalidToken(); | ||
} | ||
if (capacity == 0) { | ||
revert InvalidCapacity(); | ||
} | ||
if (refillRate == 0) { | ||
revert InvalidRefillRate(); | ||
} | ||
Bucket storage bucket = flowRateBuckets[token]; | ||
if (bucket.capacity == 0) { | ||
bucket.depth = capacity; | ||
} | ||
bucket.capacity = capacity; | ||
bucket.refillRate = refillRate; | ||
} | ||
|
||
/** | ||
* @notice Update the flow rate measurement for a token. | ||
* @param token Address of token being withdrawn. | ||
* @param amount The number of tokens being withdrawn. | ||
* @return delayWithdrawal Delay this withdrawal because it is for an unconfigured token. | ||
*/ | ||
function _updateFlowRateBucket(address token, uint256 amount) internal returns (bool delayWithdrawal) { | ||
Bucket storage bucket = flowRateBuckets[token]; | ||
|
||
uint256 capacity = bucket.capacity; | ||
if (capacity == 0) { | ||
emit WithdrawalForNonFlowRatedToken(token, amount); | ||
return true; | ||
} | ||
|
||
// Calculate the depth assuming no withdrawal. | ||
// slither-disable-next-line timestamp | ||
uint256 depth = bucket.depth + (block.timestamp - bucket.refillTime) * bucket.refillRate; | ||
// slither-disable-next-line timestamp | ||
bucket.refillTime = block.timestamp; | ||
// slither-disable-next-line timestamp | ||
if (depth > capacity) { | ||
depth = capacity; | ||
} | ||
|
||
// slither-disable-next-line timestamp | ||
if (amount >= depth) { | ||
// The bucket is empty indicating the flow rate is high. Automatically | ||
// enable the withdrawal queue. | ||
emit AutoActivatedWithdrawalQueue(); | ||
withdrawalQueueActivated = true; | ||
bucket.depth = 0; | ||
} else { | ||
bucket.depth = depth - amount; | ||
} | ||
return false; | ||
} | ||
|
||
// slither-disable-next-line unused-state,naming-convention | ||
uint256[50] private __gapFlowRateDetecton; | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Empty interface?