编译器
0.8.19+commit.7dd6d404
文件 1 的 17:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 2 的 17:ConfirmedOwner.sol
pragma solidity ^0.8.0;
import "./ConfirmedOwnerWithProposal.sol";
contract ConfirmedOwner is ConfirmedOwnerWithProposal {
constructor(address newOwner) ConfirmedOwnerWithProposal(newOwner, address(0)) {}
}
文件 3 的 17:ConfirmedOwnerWithProposal.sol
pragma solidity ^0.8.0;
import "../interfaces/IOwnable.sol";
contract ConfirmedOwnerWithProposal is IOwnable {
address private s_owner;
address private s_pendingOwner;
event OwnershipTransferRequested(address indexed from, address indexed to);
event OwnershipTransferred(address indexed from, address indexed to);
constructor(address newOwner, address pendingOwner) {
require(newOwner != address(0), "Cannot set owner to zero");
s_owner = newOwner;
if (pendingOwner != address(0)) {
_transferOwnership(pendingOwner);
}
}
function transferOwnership(address to) public override onlyOwner {
_transferOwnership(to);
}
function acceptOwnership() external override {
require(msg.sender == s_pendingOwner, "Must be proposed owner");
address oldOwner = s_owner;
s_owner = msg.sender;
s_pendingOwner = address(0);
emit OwnershipTransferred(oldOwner, msg.sender);
}
function owner() public view override returns (address) {
return s_owner;
}
function _transferOwnership(address to) private {
require(to != msg.sender, "Cannot transfer to self");
s_pendingOwner = to;
emit OwnershipTransferRequested(s_owner, to);
}
function _validateOwnership() internal view {
require(msg.sender == s_owner, "Only callable by owner");
}
modifier onlyOwner() {
_validateOwnership();
_;
}
}
文件 4 的 17:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 5 的 17:EnumerableSet.sol
pragma solidity ^0.8.0;
library EnumerableSet {
struct Set {
bytes32[] _values;
mapping(bytes32 => uint256) _indexes;
}
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
function _remove(Set storage set, bytes32 value) private returns (bool) {
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
set._values[toDeleteIndex] = lastValue;
set._indexes[lastValue] = valueIndex;
}
set._values.pop();
delete set._indexes[value];
return true;
} else {
return false;
}
}
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
struct Bytes32Set {
Set _inner;
}
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
assembly {
result := store
}
return result;
}
struct AddressSet {
Set _inner;
}
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly {
result := store
}
return result;
}
struct UintSet {
Set _inner;
}
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly {
result := store
}
return result;
}
}
文件 6 的 17:IARM.sol
pragma solidity ^0.8.0;
interface IARM {
struct TaggedRoot {
address commitStore;
bytes32 root;
}
function isBlessed(TaggedRoot calldata taggedRoot) external view returns (bool);
function isCursed() external view returns (bool);
}
文件 7 的 17:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 8 的 17:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
文件 9 的 17:IOwnable.sol
pragma solidity ^0.8.0;
interface IOwnable {
function owner() external returns (address);
function transferOwnership(address recipient) external;
function acceptOwnership() external;
}
文件 10 的 17:IPool.sol
pragma solidity ^0.8.0;
import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/token/ERC20/IERC20.sol";
interface IPool {
function lockOrBurn(
address originalSender,
bytes calldata receiver,
uint256 amount,
uint64 destChainSelector,
bytes calldata extraArgs
) external returns (bytes memory);
function releaseOrMint(
bytes memory originalSender,
address receiver,
uint256 amount,
uint64 sourceChainSelector,
bytes memory extraData
) external;
function getToken() external view returns (IERC20 token);
}
文件 11 的 17:LockReleaseTokenPool.sol
pragma solidity 0.8.19;
import {TokenPool} from "./TokenPool.sol";
import {RateLimiter} from "../libraries/RateLimiter.sol";
import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/token/ERC20/IERC20.sol";
import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/token/ERC20/utils/SafeERC20.sol";
contract LockReleaseTokenPool is TokenPool {
using SafeERC20 for IERC20;
event LiquidityAdded(address indexed provider, uint256 indexed amount);
event LiquidityRemoved(address indexed provider, uint256 indexed amount);
error InsufficientLiquidity();
error WithdrawalTooHigh();
bytes4 private constant LOCK_RELEASE_INTERFACE_ID = bytes4(keccak256("LockReleaseTokenPool"));
mapping(address provider => uint256 balance) internal s_liquidityProviderBalances;
constructor(IERC20 token, address[] memory allowlist, address armProxy) TokenPool(token, allowlist, armProxy) {}
function lockOrBurn(
address originalSender,
bytes calldata,
uint256 amount,
uint64,
bytes calldata
) external override onlyOnRamp checkAllowList(originalSender) whenHealthy returns (bytes memory) {
_consumeOnRampRateLimit(amount);
emit Locked(msg.sender, amount);
return "";
}
function releaseOrMint(
bytes memory,
address receiver,
uint256 amount,
uint64,
bytes memory
) external override onlyOffRamp whenHealthy {
_consumeOffRampRateLimit(amount);
getToken().safeTransfer(receiver, amount);
emit Released(msg.sender, receiver, amount);
}
function getLockReleaseInterfaceId() public pure returns (bytes4) {
return LOCK_RELEASE_INTERFACE_ID;
}
function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
return interfaceId == LOCK_RELEASE_INTERFACE_ID || super.supportsInterface(interfaceId);
}
function getProvidedLiquidity(address provider) external view returns (uint256) {
return s_liquidityProviderBalances[provider];
}
function addLiquidity(uint256 amount) external {
i_token.safeTransferFrom(msg.sender, address(this), amount);
s_liquidityProviderBalances[msg.sender] += amount;
emit LiquidityAdded(msg.sender, amount);
}
function removeLiquidity(uint256 amount) external {
if (s_liquidityProviderBalances[msg.sender] < amount) revert WithdrawalTooHigh();
if (i_token.balanceOf(address(this)) < amount) revert InsufficientLiquidity();
s_liquidityProviderBalances[msg.sender] -= amount;
i_token.safeTransfer(msg.sender, amount);
emit LiquidityRemoved(msg.sender, amount);
}
}
文件 12 的 17:OwnerIsCreator.sol
pragma solidity ^0.8.0;
import {ConfirmedOwner} from "./ConfirmedOwner.sol";
contract OwnerIsCreator is ConfirmedOwner {
constructor() ConfirmedOwner(msg.sender) {}
}
文件 13 的 17:Pausable.sol
pragma solidity ^0.8.0;
import "./Context.sol";
abstract contract Pausable is Context {
event Paused(address account);
event Unpaused(address account);
bool private _paused;
constructor() {
_paused = false;
}
function paused() public view virtual returns (bool) {
return _paused;
}
modifier whenNotPaused() {
require(!paused(), "Pausable: paused");
_;
}
modifier whenPaused() {
require(paused(), "Pausable: not paused");
_;
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
文件 14 的 17:RateLimiter.sol
pragma solidity ^0.8.0;
library RateLimiter {
error BucketOverfilled();
error OnlyCallableByAdminOrOwner();
error TokenMaxCapacityExceeded(uint256 capacity, uint256 requested, address tokenAddress);
error TokenRateLimitReached(uint256 minWaitInSeconds, uint256 available, address tokenAddress);
error AggregateValueMaxCapacityExceeded(uint256 capacity, uint256 requested);
error AggregateValueRateLimitReached(uint256 minWaitInSeconds, uint256 available);
event TokensConsumed(uint256 tokens);
event ConfigChanged(Config config);
struct TokenBucket {
uint128 tokens;
uint32 lastUpdated;
bool isEnabled;
uint128 capacity;
uint128 rate;
}
struct Config {
bool isEnabled;
uint128 capacity;
uint128 rate;
}
function _consume(TokenBucket storage s_bucket, uint256 requestTokens, address tokenAddress) internal {
if (!s_bucket.isEnabled || requestTokens == 0) {
return;
}
uint256 tokens = s_bucket.tokens;
uint256 capacity = s_bucket.capacity;
uint256 timeDiff = block.timestamp - s_bucket.lastUpdated;
if (timeDiff != 0) {
if (tokens > capacity) revert BucketOverfilled();
tokens = _calculateRefill(capacity, tokens, timeDiff, s_bucket.rate);
s_bucket.lastUpdated = uint32(block.timestamp);
}
if (capacity < requestTokens) {
if (tokenAddress == address(0)) revert AggregateValueMaxCapacityExceeded(capacity, requestTokens);
revert TokenMaxCapacityExceeded(capacity, requestTokens, tokenAddress);
}
if (tokens < requestTokens) {
uint256 rate = s_bucket.rate;
uint256 minWaitInSeconds = ((requestTokens - tokens) + (rate - 1)) / rate;
if (tokenAddress == address(0)) revert AggregateValueRateLimitReached(minWaitInSeconds, tokens);
revert TokenRateLimitReached(minWaitInSeconds, tokens, tokenAddress);
}
tokens -= requestTokens;
s_bucket.tokens = uint128(tokens);
emit TokensConsumed(requestTokens);
}
function _currentTokenBucketState(TokenBucket memory bucket) internal view returns (TokenBucket memory) {
bucket.tokens = uint128(
_calculateRefill(bucket.capacity, bucket.tokens, block.timestamp - bucket.lastUpdated, bucket.rate)
);
bucket.lastUpdated = uint32(block.timestamp);
return bucket;
}
function _setTokenBucketConfig(TokenBucket storage s_bucket, Config memory config) internal {
uint256 timeDiff = block.timestamp - s_bucket.lastUpdated;
if (timeDiff != 0) {
s_bucket.tokens = uint128(_calculateRefill(s_bucket.capacity, s_bucket.tokens, timeDiff, s_bucket.rate));
s_bucket.lastUpdated = uint32(block.timestamp);
}
s_bucket.tokens = uint128(_min(config.capacity, s_bucket.tokens));
s_bucket.isEnabled = config.isEnabled;
s_bucket.capacity = config.capacity;
s_bucket.rate = config.rate;
emit ConfigChanged(config);
}
function _calculateRefill(
uint256 capacity,
uint256 tokens,
uint256 timeDiff,
uint256 rate
) private pure returns (uint256) {
return _min(capacity, tokens + timeDiff * rate);
}
function _min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
}
文件 15 的 17:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 16 的 17:TokenPool.sol
pragma solidity 0.8.19;
import {IPool} from "../interfaces/pools/IPool.sol";
import {IARM} from "../interfaces/IARM.sol";
import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.sol";
import {RateLimiter} from "../libraries/RateLimiter.sol";
import {Pausable} from "../../vendor/Pausable.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";
abstract contract TokenPool is IPool, OwnerIsCreator, IERC165 {
using EnumerableSet for EnumerableSet.AddressSet;
using RateLimiter for RateLimiter.TokenBucket;
error PermissionsError();
error ZeroAddressNotAllowed();
error SenderNotAllowed(address sender);
error AllowListNotEnabled();
error NonExistentRamp(address ramp);
error BadARMSignal();
error RampAlreadyExists(address ramp);
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 OnRampAdded(address onRamp, RateLimiter.Config rateLimiterConfig);
event OnRampConfigured(address onRamp, RateLimiter.Config rateLimiterConfig);
event OnRampRemoved(address onRamp);
event OffRampAdded(address offRamp, RateLimiter.Config rateLimiterConfig);
event OffRampConfigured(address offRamp, RateLimiter.Config rateLimiterConfig);
event OffRampRemoved(address offRamp);
event AllowListAdd(address sender);
event AllowListRemove(address sender);
struct RampUpdate {
address ramp;
bool allowed;
RateLimiter.Config rateLimiterConfig;
}
IERC20 internal immutable i_token;
address internal immutable i_armProxy;
bool internal immutable i_allowlistEnabled;
EnumerableSet.AddressSet internal s_allowList;
EnumerableSet.AddressSet internal s_onRamps;
mapping(address => RateLimiter.TokenBucket) internal s_onRampRateLimits;
EnumerableSet.AddressSet internal s_offRamps;
mapping(address => RateLimiter.TokenBucket) internal s_offRampRateLimits;
constructor(IERC20 token, address[] memory allowlist, address armProxy) {
if (address(token) == address(0)) revert ZeroAddressNotAllowed();
i_token = token;
i_armProxy = armProxy;
i_allowlistEnabled = allowlist.length > 0;
if (i_allowlistEnabled) {
_applyAllowListUpdates(new address[](0), allowlist);
}
}
function getArmProxy() public view returns (address armProxy) {
return i_armProxy;
}
function getToken() public view override returns (IERC20 token) {
return i_token;
}
function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
return interfaceId == type(IPool).interfaceId || interfaceId == type(IERC165).interfaceId;
}
function isOnRamp(address onRamp) public view returns (bool) {
return s_onRamps.contains(onRamp);
}
function isOffRamp(address offRamp) public view returns (bool) {
return s_offRamps.contains(offRamp);
}
function getOnRamps() public view returns (address[] memory) {
return s_onRamps.values();
}
function getOffRamps() public view returns (address[] memory) {
return s_offRamps.values();
}
function applyRampUpdates(RampUpdate[] calldata onRamps, RampUpdate[] calldata offRamps) external virtual onlyOwner {
_applyRampUpdates(onRamps, offRamps);
}
function _applyRampUpdates(RampUpdate[] calldata onRamps, RampUpdate[] calldata offRamps) internal onlyOwner {
for (uint256 i = 0; i < onRamps.length; ++i) {
RampUpdate memory update = onRamps[i];
if (update.allowed) {
if (s_onRamps.add(update.ramp)) {
s_onRampRateLimits[update.ramp] = RateLimiter.TokenBucket({
rate: update.rateLimiterConfig.rate,
capacity: update.rateLimiterConfig.capacity,
tokens: update.rateLimiterConfig.capacity,
lastUpdated: uint32(block.timestamp),
isEnabled: update.rateLimiterConfig.isEnabled
});
emit OnRampAdded(update.ramp, update.rateLimiterConfig);
} else {
revert RampAlreadyExists(update.ramp);
}
} else {
if (s_onRamps.remove(update.ramp)) {
delete s_onRampRateLimits[update.ramp];
emit OnRampRemoved(update.ramp);
} else {
revert NonExistentRamp(update.ramp);
}
}
}
for (uint256 i = 0; i < offRamps.length; ++i) {
RampUpdate memory update = offRamps[i];
if (update.allowed) {
if (s_offRamps.add(update.ramp)) {
s_offRampRateLimits[update.ramp] = RateLimiter.TokenBucket({
rate: update.rateLimiterConfig.rate,
capacity: update.rateLimiterConfig.capacity,
tokens: update.rateLimiterConfig.capacity,
lastUpdated: uint32(block.timestamp),
isEnabled: update.rateLimiterConfig.isEnabled
});
emit OffRampAdded(update.ramp, update.rateLimiterConfig);
} else {
revert RampAlreadyExists(update.ramp);
}
} else {
if (s_offRamps.remove(update.ramp)) {
delete s_offRampRateLimits[update.ramp];
emit OffRampRemoved(update.ramp);
} else {
revert NonExistentRamp(update.ramp);
}
}
}
}
function _consumeOnRampRateLimit(uint256 amount) internal {
s_onRampRateLimits[msg.sender]._consume(amount, address(i_token));
}
function _consumeOffRampRateLimit(uint256 amount) internal {
s_offRampRateLimits[msg.sender]._consume(amount, address(i_token));
}
function currentOnRampRateLimiterState(address onRamp) external view returns (RateLimiter.TokenBucket memory) {
return s_onRampRateLimits[onRamp]._currentTokenBucketState();
}
function currentOffRampRateLimiterState(address offRamp) external view returns (RateLimiter.TokenBucket memory) {
return s_offRampRateLimits[offRamp]._currentTokenBucketState();
}
function setOnRampRateLimiterConfig(address onRamp, RateLimiter.Config memory config) external onlyOwner {
if (!isOnRamp(onRamp)) revert NonExistentRamp(onRamp);
s_onRampRateLimits[onRamp]._setTokenBucketConfig(config);
emit OnRampConfigured(onRamp, config);
}
function setOffRampRateLimiterConfig(address offRamp, RateLimiter.Config memory config) external onlyOwner {
if (!isOffRamp(offRamp)) revert NonExistentRamp(offRamp);
s_offRampRateLimits[offRamp]._setTokenBucketConfig(config);
emit OffRampConfigured(offRamp, config);
}
modifier onlyOnRamp() {
if (!isOnRamp(msg.sender)) revert PermissionsError();
_;
}
modifier onlyOffRamp() {
if (!isOffRamp(msg.sender)) revert PermissionsError();
_;
}
modifier checkAllowList(address sender) {
if (i_allowlistEnabled && !s_allowList.contains(sender)) revert SenderNotAllowed(sender);
_;
}
function getAllowListEnabled() external view returns (bool) {
return i_allowlistEnabled;
}
function getAllowList() external view returns (address[] memory) {
return s_allowList.values();
}
function applyAllowListUpdates(address[] calldata removes, address[] calldata adds) external onlyOwner {
_applyAllowListUpdates(removes, adds);
}
function _applyAllowListUpdates(address[] memory removes, address[] memory adds) internal {
if (!i_allowlistEnabled) revert AllowListNotEnabled();
for (uint256 i = 0; i < removes.length; ++i) {
address toRemove = removes[i];
if (s_allowList.remove(toRemove)) {
emit AllowListRemove(toRemove);
}
}
for (uint256 i = 0; i < adds.length; ++i) {
address toAdd = adds[i];
if (toAdd == address(0)) {
continue;
}
if (s_allowList.add(toAdd)) {
emit AllowListAdd(toAdd);
}
}
}
modifier whenHealthy() {
if (IARM(i_armProxy).isCursed()) revert BadARMSignal();
_;
}
}
文件 17 的 17:draft-IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
{
"compilationTarget": {
"src/v0.8/ccip/pools/LockReleaseTokenPool.sol": "LockReleaseTokenPool"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 26000
},
"remappings": [
":@eth-optimism/=node_modules/@eth-optimism/",
":@openzeppelin/=node_modules/@openzeppelin/",
":ds-test/=foundry-lib/forge-std/lib/ds-test/src/",
":erc4626-tests/=foundry-lib/openzeppelin-contracts/lib/erc4626-tests/",
":forge-std/=foundry-lib/forge-std/src/",
":hardhat/=node_modules/hardhat/",
":openzeppelin-contracts/=foundry-lib/openzeppelin-contracts/contracts/"
]
}
[{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address[]","name":"allowlist","type":"address[]"},{"internalType":"address","name":"armProxy","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"capacity","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"}],"name":"AggregateValueMaxCapacityExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"minWaitInSeconds","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"}],"name":"AggregateValueRateLimitReached","type":"error"},{"inputs":[],"name":"AllowListNotEnabled","type":"error"},{"inputs":[],"name":"BadARMSignal","type":"error"},{"inputs":[],"name":"BucketOverfilled","type":"error"},{"inputs":[],"name":"InsufficientLiquidity","type":"error"},{"inputs":[{"internalType":"address","name":"ramp","type":"address"}],"name":"NonExistentRamp","type":"error"},{"inputs":[],"name":"PermissionsError","type":"error"},{"inputs":[{"internalType":"address","name":"ramp","type":"address"}],"name":"RampAlreadyExists","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"SenderNotAllowed","type":"error"},{"inputs":[{"internalType":"uint256","name":"capacity","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"TokenMaxCapacityExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"minWaitInSeconds","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"TokenRateLimitReached","type":"error"},{"inputs":[],"name":"WithdrawalTooHigh","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"AllowListAdd","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"AllowListRemove","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Burned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LiquidityAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LiquidityRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Locked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Minted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"offRamp","type":"address"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"indexed":false,"internalType":"struct RateLimiter.Config","name":"rateLimiterConfig","type":"tuple"}],"name":"OffRampAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"offRamp","type":"address"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"indexed":false,"internalType":"struct RateLimiter.Config","name":"rateLimiterConfig","type":"tuple"}],"name":"OffRampConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"offRamp","type":"address"}],"name":"OffRampRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"onRamp","type":"address"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"indexed":false,"internalType":"struct RateLimiter.Config","name":"rateLimiterConfig","type":"tuple"}],"name":"OnRampAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"onRamp","type":"address"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"indexed":false,"internalType":"struct RateLimiter.Config","name":"rateLimiterConfig","type":"tuple"}],"name":"OnRampConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"onRamp","type":"address"}],"name":"OnRampRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Released","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"addLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"removes","type":"address[]"},{"internalType":"address[]","name":"adds","type":"address[]"}],"name":"applyAllowListUpdates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"ramp","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"rateLimiterConfig","type":"tuple"}],"internalType":"struct TokenPool.RampUpdate[]","name":"onRamps","type":"tuple[]"},{"components":[{"internalType":"address","name":"ramp","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"rateLimiterConfig","type":"tuple"}],"internalType":"struct TokenPool.RampUpdate[]","name":"offRamps","type":"tuple[]"}],"name":"applyRampUpdates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"offRamp","type":"address"}],"name":"currentOffRampRateLimiterState","outputs":[{"components":[{"internalType":"uint128","name":"tokens","type":"uint128"},{"internalType":"uint32","name":"lastUpdated","type":"uint32"},{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.TokenBucket","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"onRamp","type":"address"}],"name":"currentOnRampRateLimiterState","outputs":[{"components":[{"internalType":"uint128","name":"tokens","type":"uint128"},{"internalType":"uint32","name":"lastUpdated","type":"uint32"},{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.TokenBucket","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllowList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllowListEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getArmProxy","outputs":[{"internalType":"address","name":"armProxy","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockReleaseInterfaceId","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getOffRamps","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOnRamps","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"provider","type":"address"}],"name":"getProvidedLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getToken","outputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"offRamp","type":"address"}],"name":"isOffRamp","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"onRamp","type":"address"}],"name":"isOnRamp","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"originalSender","type":"address"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"lockOrBurn","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"releaseOrMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"removeLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"offRamp","type":"address"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"config","type":"tuple"}],"name":"setOffRampRateLimiterConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"onRamp","type":"address"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"config","type":"tuple"}],"name":"setOnRampRateLimiterConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]