-
Notifications
You must be signed in to change notification settings - Fork 23
/
TokenPool.sol
155 lines (126 loc) · 5.95 KB
/
TokenPool.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;
import {IPool} from "../interfaces/pools/IPool.sol";
import {OwnerIsCreator} from "../OwnerIsCreator.sol";
import {RateLimiter} from "../libraries/RateLimiter.sol";
import {Pausable} from "../../vendor/openzeppelin-solidity/v4.8.0/security/Pausable.sol";
import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/token/ERC20/IERC20.sol";
import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.0/utils/introspection/IERC165.sol";
import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.8.0/utils/structs/EnumerableSet.sol";
/// @notice Base abstract class with common functions for all token pools.
abstract contract TokenPool is IPool, OwnerIsCreator, Pausable, IERC165 {
using EnumerableSet for EnumerableSet.AddressSet;
using RateLimiter for RateLimiter.TokenBucket;
error PermissionsError();
error NullAddressNotAllowed();
event Locked(address indexed sender, uint256 amount);
event Burned(address indexed sender, uint256 amount);
event Released(address indexed sender, address indexed recipient, uint256 amount);
event Minted(address indexed sender, address indexed recipient, uint256 amount);
event OnRampAllowanceSet(address onRamp, bool allowed);
event OffRampAllowanceSet(address onRamp, bool allowed);
struct RampUpdate {
address ramp;
bool allowed;
}
// The immutable token that belongs to this pool.
IERC20 internal immutable i_token;
// A set of allowed onRamps.
EnumerableSet.AddressSet internal s_onRamps;
// A set of allowed offRamps.
EnumerableSet.AddressSet internal s_offRamps;
// The token bucket object that contains the bucket state.
RateLimiter.TokenBucket private s_rateLimiter;
constructor(IERC20 token, RateLimiter.Config memory rateLimiterConfig) {
if (address(token) == address(0)) revert NullAddressNotAllowed();
s_rateLimiter = RateLimiter.TokenBucket({
rate: rateLimiterConfig.rate,
capacity: rateLimiterConfig.capacity,
tokens: rateLimiterConfig.capacity,
lastUpdated: uint32(block.timestamp),
isEnabled: rateLimiterConfig.isEnabled
});
i_token = token;
}
/// @inheritdoc IPool
function getToken() public view override returns (IERC20 token) {
return i_token;
}
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
return interfaceId == type(IPool).interfaceId || interfaceId == type(IERC165).interfaceId;
}
// ================================================================
// | Ramp permissions |
// ================================================================
/// @notice Checks whether something is a permissioned onRamp on this contract.
/// @return true if the given address is a permissioned onRamp.
function isOnRamp(address onRamp) public view returns (bool) {
return s_onRamps.contains(onRamp);
}
/// @notice Checks whether something is a permissioned offRamp on this contract.
/// @return true is the given address is a permissioned offRamp.
function isOffRamp(address offRamp) public view returns (bool) {
return s_offRamps.contains(offRamp);
}
/// @notice Sets permissions for all on and offRamps.
/// @dev Only callable by the owner
/// @param onRamps A list of onRamps and their new permission status
/// @param offRamps A list of offRamps and their new permission status
function applyRampUpdates(RampUpdate[] memory onRamps, RampUpdate[] memory offRamps) public virtual onlyOwner {
for (uint256 i = 0; i < onRamps.length; ++i) {
RampUpdate memory update = onRamps[i];
if (update.allowed ? s_onRamps.add(update.ramp) : s_onRamps.remove(update.ramp)) {
emit OnRampAllowanceSet(onRamps[i].ramp, onRamps[i].allowed);
}
}
for (uint256 i = 0; i < offRamps.length; ++i) {
RampUpdate memory update = offRamps[i];
if (update.allowed ? s_offRamps.add(update.ramp) : s_offRamps.remove(update.ramp)) {
emit OffRampAllowanceSet(offRamps[i].ramp, offRamps[i].allowed);
}
}
}
// ================================================================
// | Rate limiting |
// ================================================================
/// @notice Consumes rate limiting capacity in this pool
function _consumeRateLimit(uint256 amount) internal {
s_rateLimiter._consume(amount);
}
/// @notice Gets the token bucket with its values for the block it was requested at.
/// @return The token bucket.
function currentRateLimiterState() public 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) public onlyOwner {
s_rateLimiter._setTokenBucketConfig(config);
}
// ================================================================
// | Access |
// ================================================================
/// @notice Checks whether the msg.sender is a permissioned onRamp on this contract
/// @dev Reverts with a PermissionsError if check fails
modifier onlyOnRamp() {
if (!isOnRamp(msg.sender)) revert PermissionsError();
_;
}
/// @notice Checks whether the msg.sender is a permissioned offRamp on this contract
/// @dev Reverts with a PermissionsError if check fails
modifier onlyOffRamp() {
if (!isOffRamp(msg.sender)) revert PermissionsError();
_;
}
/// @notice Pauses the token pool.
function pause() external onlyOwner {
_pause();
}
/// @notice Unpauses the token pool.
function unpause() external onlyOwner {
_unpause();
}
}