编译器
0.8.24+commit.e11b9ed9
文件 1 的 15:AbridgeMessageHandler.sol
pragma solidity ^0.8.24;
import { IAbridge, IAbridgeMessageHandler } from "./IAbridge.sol";
abstract contract AbridgeMessageHandler is IAbridgeMessageHandler {
IAbridge private _abridge;
event AbridgeUpdated(address indexed oldBridge, address indexed newBridge);
event RouteUpdated(address indexed sender, bool allowed);
error NotCalledFromAbridge();
modifier onlyAbridge() {
if (msg.sender != address(_abridge)) {
revert NotCalledFromAbridge();
}
_;
}
constructor(address abridge_) {
_abridge = IAbridge(abridge_);
}
function abridge() public view returns (IAbridge) {
return _abridge;
}
function _setAbridge(address bridge) internal {
address oldBridge = address(_abridge);
_abridge = IAbridge(bridge);
emit AbridgeUpdated(oldBridge, address(bridge));
}
function _updateRoute(address sender, bool allowed) internal {
_abridge.updateRoute(sender, allowed);
emit RouteUpdated(sender, allowed);
}
}
文件 2 的 15:Address.sol
pragma solidity ^0.8.20;
library Address {
error AddressInsufficientBalance(address account);
error AddressEmptyCode(address target);
error FailedInnerCall();
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
function _revert(bytes memory returndata) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}
文件 3 的 15:Context.sol
pragma solidity ^0.8.20;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
文件 4 的 15:ERC165.sol
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 5 的 15:IAbridge.sol
pragma solidity ^0.8.24;
interface IAbridgeMessageHandler {
function handleMessage(address _from, bytes calldata _msg, bytes32 guid) external returns (bytes4 response);
}
interface IAbridge {
event MessageSent(address indexed sender, address indexed receiver, bytes32 guid, uint256 fee);
event MessageReceived(address indexed sender, address indexed receiver, bytes32 guid);
event AuthorizedSenderUpdated(address indexed sender, bool authorized);
event RouteUpdated(address indexed receiver, address indexed sender, bool allowed);
error InsufficientFee(uint256 _sent, uint256 _required);
error UnauthorizedSender(address _sender);
error DisallowedRoute(address _sender, address _receiver);
error InvalidReceiverResponse(bytes4 _response);
function updateRoute(address _sender, bool _allowed) external;
function send(
address _receiver,
uint128 _executeGasLimit,
bytes memory _msg
) external payable returns (bytes32 _guid);
function eid() external view returns (uint32);
function authorizedSenders(address sender) external view returns (bool authorized);
function estimateFee(
address _receiver,
uint128 _executeGasLimit,
bytes memory _msg
) external view returns (address _token, uint256 _fee);
}
文件 6 的 15:IERC165.sol
pragma solidity ^0.8.20;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 7 的 15:IERC20.sol
pragma solidity ^0.8.20;
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 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
文件 8 的 15:IERC20Permit.sol
pragma solidity ^0.8.20;
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);
}
文件 9 的 15:IRedemptionAssetVault.sol
pragma solidity ^0.8.24;
interface IRedemptionAssetVault {
struct Redemption {
uint256 amount;
address owner;
uint48 timestamp;
bool isFulfilled;
}
event RedemptionReceived(
uint256 redemptionId,
address lsd,
uint256 amount,
address owner,
uint256 timestamp,
bytes32 guid
);
event RedemptionFulfilled(uint256 redemptionId, address lsd, uint256 amount, address owner, uint256 timestamp);
event NewUnstaker(address unstaker);
event RedemptionOnGravityUpdated(address redemption);
event NewMaxExchangeRateLimit(address token, uint256 maxExchangeRate);
error SendFailed(address to, uint256 amount);
error InvalidBackingAsset();
error InvalidBridgeMessage(uint8 messageType);
error InvalidRedeemAmount(uint256 amount);
error InvalidTimestamp(uint256 timestamp);
error RedemptionAlreadyFulfilled(uint256 redemptionId);
error InvalidLSD();
error InvalidCaller(address caller);
error InvalidBridgeMessageFrom(address from);
error InvalidRedemptionId(uint256 redemptionId);
error ExceedMaxExchangeRate(address lsd, uint256 lsdAmount, uint256 minLSDAmount);
function fulfillRedemption(
uint256 _redemptionId,
address[] calldata _tokens,
uint256[] calldata _amount,
address[] calldata _froms
) external payable;
function nextPendingRedemption() external view returns (Redemption memory);
}
文件 10 的 15:MessageLib.sol
pragma solidity ^0.8.24;
library MessageLib {
struct Message {
uint8 valueType;
uint256 value;
address owner;
uint256 timestamp;
uint256 delta;
}
uint256 internal constant _MAX_VALUE = type(uint136).max;
uint256 internal constant _MAX_TIMESTAMP = type(uint48).max;
uint256 internal constant _MAX_DELTA = type(uint128).max;
uint8 public constant TOTAL_DEPOSITS_TYPE = 1;
uint8 public constant TOTAL_POOL_UNLOCKS_TYPE = 2;
uint8 public constant TOTAL_CLAIMS_TYPE = 3;
uint8 public constant TOTAL_REQUESTS_TYPE = 4;
uint8 public constant TOTAL_REDEEMEDS_TYPE = 5;
error MessageLib_ValueOverflow();
error MessageLib_TimestampOverflow();
error MessageLib_DeltaOverflow();
error MessageLib_InvalidMessageLength(uint256 length);
function unpack(bytes memory b) internal pure returns (Message memory m) {
uint8 valueType;
uint136 value;
address owner;
uint48 _timestamp;
uint128 _delta;
if (b.length != 60) revert MessageLib_InvalidMessageLength(b.length);
assembly {
valueType := mload(add(b, 1))
value := mload(add(b, 18))
owner := mload(add(b, 38))
_timestamp := mload(add(b, 44))
_delta := mload(add(b, 60))
}
return Message(valueType, value, owner, _timestamp, _delta);
}
function pack(Message memory m) internal pure returns (bytes memory) {
if (m.value > _MAX_VALUE) revert MessageLib_ValueOverflow();
if (m.timestamp > _MAX_TIMESTAMP) revert MessageLib_TimestampOverflow();
if (m.delta > _MAX_DELTA) revert MessageLib_DeltaOverflow();
return abi.encodePacked(m.valueType, uint136(m.value), m.owner, uint48(m.timestamp), uint128(m.delta));
}
}
文件 11 的 15:Ownable.sol
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
error OwnableUnauthorizedAccount(address account);
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 12 的 15:Ownable2Step.sol
pragma solidity ^0.8.20;
import {Ownable} from "./Ownable.sol";
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
function acceptOwnership() public virtual {
address sender = _msgSender();
if (pendingOwner() != sender) {
revert OwnableUnauthorizedAccount(sender);
}
_transferOwnership(sender);
}
}
文件 13 的 15:Pausable.sol
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
abstract contract Pausable is Context {
bool private _paused;
event Paused(address account);
event Unpaused(address account);
error EnforcedPause();
error ExpectedPause();
constructor() {
_paused = false;
}
modifier whenNotPaused() {
_requireNotPaused();
_;
}
modifier whenPaused() {
_requirePaused();
_;
}
function paused() public view virtual returns (bool) {
return _paused;
}
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
文件 14 的 15:RedemptionAssetVault.sol
pragma solidity ^0.8.24;
import { MessageLib } from "../message-lib/MessageLib.sol";
import { Pausable } from "@openzeppelin/contracts/utils/Pausable.sol";
import { Ownable2Step, Ownable } from "@openzeppelin/contracts/access/Ownable2Step.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import { IRedemptionAssetVault } from "./IRedemptionAssetVault.sol";
import { IAbridgeMessageHandler } from "../abridge/IAbridge.sol";
import { AbridgeMessageHandler } from "../abridge/AbridgeMessageHandler.sol";
contract RedemptionAssetVault is AbridgeMessageHandler, Ownable2Step, Pausable, ERC165, IRedemptionAssetVault {
using SafeERC20 for IERC20;
address public immutable LSD;
address public unstaker;
mapping(address => uint256) public totalRecevieds;
uint256 public accReceivedRedemptions;
uint256 public accFulfilledRedemptions;
mapping(uint256 => Redemption) public redemptions;
address public redemptionOnGravity;
mapping(address => uint256) public maxExchangeRateLimits;
modifier onlyUnstaker() {
if (msg.sender != unstaker) {
revert InvalidCaller(msg.sender);
}
_;
}
constructor(
address _lsd,
address _owner,
address _abridge
) Ownable(_owner) AbridgeMessageHandler(_abridge) {
if (_lsd == address(0)) {
revert InvalidLSD();
}
LSD = _lsd;
}
receive() external payable {}
function fulfillRedemption(
uint256 _redemptionId,
address[] calldata _tokens,
uint256[] calldata _amounts,
address[] calldata _froms
) external payable whenNotPaused onlyUnstaker {
if ((_tokens.length != _amounts.length) || (_tokens.length != _froms.length)) {
revert InvalidBackingAsset();
}
Redemption storage redemption = redemptions[_redemptionId];
if (redemption.isFulfilled) {
revert RedemptionAlreadyFulfilled(_redemptionId);
}
if (redemption.owner == address(0)) {
revert InvalidRedemptionId(_redemptionId);
}
_mustMeetsMaxExchangeRate(redemption.amount, _tokens, _amounts);
redemption.isFulfilled = true;
accFulfilledRedemptions += redemption.amount;
_transferBackingAsset(_tokens, _amounts, _froms, redemption.owner);
emit RedemptionFulfilled(_redemptionId, LSD, redemption.amount, redemption.owner, redemption.timestamp);
redemption.amount = 0;
}
function pause() external onlyOwner {
_pause();
}
function unpause() external onlyOwner {
_unpause();
}
function setUnstaker(address _unstaker) external onlyOwner {
unstaker = _unstaker;
emit NewUnstaker(_unstaker);
}
function setAbridge(address _abridge) external onlyOwner {
_setAbridge(_abridge);
}
function setRedemptionOnGravity(address _redemption) external onlyOwner {
redemptionOnGravity = _redemption;
emit RedemptionOnGravityUpdated(_redemption);
}
function setMaxExchangeRateLimit(
address[] calldata _tokens,
uint256[] calldata _maxExchangeRates
) external onlyOwner {
for (uint256 i = 0; i < _tokens.length; i++) {
maxExchangeRateLimits[_tokens[i]] = _maxExchangeRates[i];
emit NewMaxExchangeRateLimit(_tokens[i], _maxExchangeRates[i]);
}
}
function handleMessage(
address _from,
bytes calldata _message,
bytes32 _guid
) external override onlyAbridge returns (bytes4 response) {
MessageLib.Message memory m = MessageLib.unpack(_message);
if (m.valueType != MessageLib.TOTAL_REDEEMEDS_TYPE) {
revert InvalidBridgeMessage(m.valueType);
}
if (_from != redemptionOnGravity) {
revert InvalidBridgeMessageFrom(_from);
}
_receiveRedemption(m.owner, m.value, m.timestamp, m.delta, _guid);
return IAbridgeMessageHandler.handleMessage.selector;
}
function updateRoute(address _sender, bool allowed) external onlyOwner {
_updateRoute(_sender, allowed);
}
function rescueWithdraw(address _token, address _to) external onlyOwner {
if (_token == address(0)) {
uint256 amount = address(this).balance;
(bool sent, ) = _to.call{ value: amount }("");
if (!sent) {
revert SendFailed(_to, amount);
}
} else {
uint256 _amount = IERC20(_token).balanceOf(address(this));
IERC20(_token).safeTransfer(_to, _amount);
}
}
function nextPendingRedemption() external view returns (Redemption memory) {
return redemptions[accFulfilledRedemptions];
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IRedemptionAssetVault).interfaceId || super.supportsInterface(interfaceId);
}
function _receiveRedemption(
address _receiver,
uint256 _totalRedeemeds,
uint256 _timestamp,
uint256 _newRedeemed,
bytes32 _guid
) internal {
if (_timestamp == 0) {
revert InvalidTimestamp(_timestamp);
}
if (_totalRedeemeds == 0) {
revert InvalidRedeemAmount(_totalRedeemeds);
}
if (totalRecevieds[_receiver] + _newRedeemed != _totalRedeemeds) {
revert InvalidRedeemAmount(_totalRedeemeds);
}
totalRecevieds[_receiver] = _totalRedeemeds;
uint256 redemptionId = accReceivedRedemptions;
accReceivedRedemptions += _newRedeemed;
redemptions[redemptionId] = Redemption({
amount: _newRedeemed,
owner: _receiver,
timestamp: uint48(_timestamp),
isFulfilled: false
});
emit RedemptionReceived(redemptionId, LSD, _newRedeemed, _receiver, _timestamp, _guid);
}
function _transferBackingAsset(
address[] calldata _tokens,
uint256[] calldata _amounts,
address[] calldata _froms,
address _receiver
) internal {
uint256 nativeTokenAmount = 0;
for (uint256 i = 0; i < _tokens.length; i++) {
if (_tokens[i] == address(0)) {
if (nativeTokenAmount > 0) {
revert InvalidBackingAsset();
}
nativeTokenAmount = _amounts[i];
} else {
IERC20(_tokens[i]).safeTransferFrom(_froms[i], _receiver, _amounts[i]);
}
}
if (nativeTokenAmount > 0) {
if (msg.value != nativeTokenAmount) {
revert InvalidBackingAsset();
}
(bool sent, ) = _receiver.call{ value: nativeTokenAmount }("");
if (!sent) revert SendFailed(_receiver, nativeTokenAmount);
}
}
function _mustMeetsMaxExchangeRate(
uint256 _lsdAmount,
address[] calldata _tokens,
uint256[] calldata _amounts
) internal view {
uint256 minLSDAmount = 0;
for (uint256 i = 0; i < _tokens.length; i++) {
minLSDAmount += (1e18 * _amounts[i]) / maxExchangeRateLimits[_tokens[i]];
}
if (_lsdAmount < minLSDAmount) {
revert ExceedMaxExchangeRate(LSD, _lsdAmount, minLSDAmount);
}
}
}
文件 15 的 15:SafeERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
error SafeERC20FailedOperation(address token);
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}
{
"compilationTarget": {
"contracts/redemption/RedemptionAssetVault.sol": "RedemptionAssetVault"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": [],
"viaIR": true
}
[{"inputs":[{"internalType":"address","name":"_lsd","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_abridge","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[{"internalType":"address","name":"lsd","type":"address"},{"internalType":"uint256","name":"lsdAmount","type":"uint256"},{"internalType":"uint256","name":"minLSDAmount","type":"uint256"}],"name":"ExceedMaxExchangeRate","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidBackingAsset","type":"error"},{"inputs":[{"internalType":"uint8","name":"messageType","type":"uint8"}],"name":"InvalidBridgeMessage","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"}],"name":"InvalidBridgeMessageFrom","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"InvalidCaller","type":"error"},{"inputs":[],"name":"InvalidLSD","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"InvalidRedeemAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"redemptionId","type":"uint256"}],"name":"InvalidRedemptionId","type":"error"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"InvalidTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"MessageLib_InvalidMessageLength","type":"error"},{"inputs":[],"name":"NotCalledFromAbridge","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"uint256","name":"redemptionId","type":"uint256"}],"name":"RedemptionAlreadyFulfilled","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SendFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldBridge","type":"address"},{"indexed":true,"internalType":"address","name":"newBridge","type":"address"}],"name":"AbridgeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"maxExchangeRate","type":"uint256"}],"name":"NewMaxExchangeRateLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"unstaker","type":"address"}],"name":"NewUnstaker","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"redemptionId","type":"uint256"},{"indexed":false,"internalType":"address","name":"lsd","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"RedemptionFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"redemption","type":"address"}],"name":"RedemptionOnGravityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"redemptionId","type":"uint256"},{"indexed":false,"internalType":"address","name":"lsd","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"guid","type":"bytes32"}],"name":"RedemptionReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"RouteUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"LSD","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"abridge","outputs":[{"internalType":"contract IAbridge","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accFulfilledRedemptions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accReceivedRedemptions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_redemptionId","type":"uint256"},{"internalType":"address[]","name":"_tokens","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address[]","name":"_froms","type":"address[]"}],"name":"fulfillRedemption","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"bytes32","name":"_guid","type":"bytes32"}],"name":"handleMessage","outputs":[{"internalType":"bytes4","name":"response","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxExchangeRateLimits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextPendingRedemption","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint48","name":"timestamp","type":"uint48"},{"internalType":"bool","name":"isFulfilled","type":"bool"}],"internalType":"struct IRedemptionAssetVault.Redemption","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"redemptionOnGravity","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"redemptions","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint48","name":"timestamp","type":"uint48"},{"internalType":"bool","name":"isFulfilled","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"}],"name":"rescueWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_abridge","type":"address"}],"name":"setAbridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_tokens","type":"address[]"},{"internalType":"uint256[]","name":"_maxExchangeRates","type":"uint256[]"}],"name":"setMaxExchangeRateLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_redemption","type":"address"}],"name":"setRedemptionOnGravity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_unstaker","type":"address"}],"name":"setUnstaker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalRecevieds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unstaker","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"updateRoute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]