Source Code
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 146671719 | 1 hr ago | 0.000128585314707 ETH | ||||
| 146671719 | 1 hr ago | 0.000128585314707 ETH | ||||
| 146670635 | 1 hr ago | 0.000095038031586 ETH | ||||
| 146670635 | 1 hr ago | 0.000095038031586 ETH | ||||
| 146669445 | 2 hrs ago | 0.000095038031586 ETH | ||||
| 146669445 | 2 hrs ago | 0.000095038031586 ETH | ||||
| 146667988 | 3 hrs ago | 0.000095038031586 ETH | ||||
| 146667988 | 3 hrs ago | 0.000095038031586 ETH | ||||
| 146666230 | 4 hrs ago | 0.000149054843391 ETH | ||||
| 146666230 | 4 hrs ago | 0.000149054843391 ETH | ||||
| 146666230 | 4 hrs ago | 0.000149054843391 ETH | ||||
| 146666230 | 4 hrs ago | 0.000149054843391 ETH | ||||
| 146666230 | 4 hrs ago | 0.000149054843391 ETH | ||||
| 146666230 | 4 hrs ago | 0.000149054843391 ETH | ||||
| 146666230 | 4 hrs ago | 0.000220129595766 ETH | ||||
| 146666230 | 4 hrs ago | 0.000220129595766 ETH | ||||
| 146666230 | 4 hrs ago | 0.000220129595766 ETH | ||||
| 146666230 | 4 hrs ago | 0.000220129595766 ETH | ||||
| 146666230 | 4 hrs ago | 0.000220129595766 ETH | ||||
| 146666230 | 4 hrs ago | 0.000220129595766 ETH | ||||
| 146656876 | 9 hrs ago | 0.000095038031586 ETH | ||||
| 146656876 | 9 hrs ago | 0.000095038031586 ETH | ||||
| 146656876 | 9 hrs ago | 0.000095038031586 ETH | ||||
| 146656876 | 9 hrs ago | 0.000095038031586 ETH | ||||
| 146656854 | 9 hrs ago | 0.000149054843391 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
RootMessageBridge
Compiler Version
v0.8.27+commit.40a35a09
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.19 <0.9.0;
import {EnumerableSet} from "@openzeppelin5/contracts/utils/structs/EnumerableSet.sol";
import {SafeERC20} from "@openzeppelin5/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin5/contracts/token/ERC20/IERC20.sol";
import {IFactoryRegistry} from "../../interfaces/external/IFactoryRegistry.sol";
import {IRootMessageBridge} from "../../interfaces/root/bridge/IRootMessageBridge.sol";
import {IMessageSender} from "../../interfaces/root/bridge/IMessageSender.sol";
import {IVoter} from "../../interfaces/external/IVoter.sol";
import {IWETH} from "../../interfaces/external/IWETH.sol";
import {CrossChainRegistry} from "../../bridge/CrossChainRegistry.sol";
import {Commands} from "../../libraries/Commands.sol";
/*
██╗ ██╗███████╗██╗ ██████╗ ██████╗ ██████╗ ██████╗ ███╗ ███╗███████╗
██║ ██║██╔════╝██║ ██╔═══██╗██╔══██╗██╔══██╗██╔═══██╗████╗ ████║██╔════╝
██║ ██║█████╗ ██║ ██║ ██║██║ ██║██████╔╝██║ ██║██╔████╔██║█████╗
╚██╗ ██╔╝██╔══╝ ██║ ██║ ██║██║ ██║██╔══██╗██║ ██║██║╚██╔╝██║██╔══╝
╚████╔╝ ███████╗███████╗╚██████╔╝██████╔╝██║ ██║╚██████╔╝██║ ╚═╝ ██║███████╗
╚═══╝ ╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝
███████╗██╗ ██╗██████╗ ███████╗██████╗ ██████╗██╗ ██╗ █████╗ ██╗███╗ ██╗
██╔════╝██║ ██║██╔══██╗██╔════╝██╔══██╗██╔════╝██║ ██║██╔══██╗██║████╗ ██║
███████╗██║ ██║██████╔╝█████╗ ██████╔╝██║ ███████║███████║██║██╔██╗ ██║
╚════██║██║ ██║██╔═══╝ ██╔══╝ ██╔══██╗██║ ██╔══██║██╔══██║██║██║╚██╗██║
███████║╚██████╔╝██║ ███████╗██║ ██║╚██████╗██║ ██║██║ ██║██║██║ ╚████║
╚══════╝ ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝
███╗ ███╗███████╗███████╗███████╗ █████╗ ██████╗ ███████╗██████╗ ██████╗ ██╗██████╗ ██████╗ ███████╗
████╗ ████║██╔════╝██╔════╝██╔════╝██╔══██╗██╔════╝ ██╔════╝██╔══██╗██╔══██╗██║██╔══██╗██╔════╝ ██╔════╝
██╔████╔██║█████╗ ███████╗███████╗███████║██║ ███╗█████╗ ██████╔╝██████╔╝██║██║ ██║██║ ███╗█████╗
██║╚██╔╝██║██╔══╝ ╚════██║╚════██║██╔══██║██║ ██║██╔══╝ ██╔══██╗██╔══██╗██║██║ ██║██║ ██║██╔══╝
██║ ╚═╝ ██║███████╗███████║███████║██║ ██║╚██████╔╝███████╗██████╔╝██║ ██║██║██████╔╝╚██████╔╝███████╗
╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═════╝ ╚═╝ ╚═╝╚═╝╚═════╝ ╚═════╝ ╚══════╝
*/
/// @title Velodrome Superchain Root Message Bridge
/// @notice General purpose message bridge contract
/// @dev For notify reward amount, tokens will always be forwarded to the module
/// @dev The module can then use any mechanism available to it to send the tokens cross chain
contract RootMessageBridge is IRootMessageBridge, CrossChainRegistry {
using EnumerableSet for EnumerableSet.UintSet;
using SafeERC20 for IERC20;
using SafeERC20 for IWETH;
using Commands for bytes;
/// @inheritdoc IRootMessageBridge
address public immutable xerc20;
/// @inheritdoc IRootMessageBridge
address public immutable voter;
/// @inheritdoc IRootMessageBridge
address public immutable factoryRegistry;
/// @inheritdoc IRootMessageBridge
address public immutable weth;
constructor(address _owner, address _xerc20, address _voter, address _weth) CrossChainRegistry(_owner) {
xerc20 = _xerc20;
voter = _voter;
factoryRegistry = IVoter(_voter).factoryRegistry();
weth = _weth;
}
receive() external payable {
if (msg.sender != weth) revert NotWETH();
}
/// @inheritdoc IRootMessageBridge
function sendMessage(uint256 _chainid, bytes calldata _message) external {
if (!_chainids.contains({value: _chainid})) revert ChainNotRegistered();
address module = chains[_chainid];
uint256 command = _message.command();
if (command == Commands.DEPOSIT) {
address gauge = _message.toAddress();
if (msg.sender != IVoter(voter).gaugeToFees(gauge)) revert NotAuthorized(Commands.DEPOSIT);
} else if (command == Commands.WITHDRAW) {
address gauge = _message.toAddress();
if (msg.sender != IVoter(voter).gaugeToFees(gauge)) revert NotAuthorized(Commands.WITHDRAW);
} else if (command == Commands.CREATE_GAUGE) {
address factory = _message.toAddress();
(, address gaugeFactory) = IFactoryRegistry(factoryRegistry).factoriesToPoolFactory(factory);
if (msg.sender != gaugeFactory) revert NotAuthorized(Commands.CREATE_GAUGE);
} else if (command == Commands.GET_INCENTIVES) {
address gauge = _message.toAddress();
if (msg.sender != IVoter(voter).gaugeToBribe(gauge)) revert NotAuthorized(Commands.GET_INCENTIVES);
} else if (command == Commands.GET_FEES) {
address gauge = _message.toAddress();
if (msg.sender != IVoter(voter).gaugeToFees(gauge)) revert NotAuthorized(Commands.GET_FEES);
} else if (command == Commands.NOTIFY || command == Commands.NOTIFY_WITHOUT_CLAIM) {
if (!IVoter(voter).isAlive(msg.sender)) revert NotValidGauge();
uint256 amount = _message.amount();
IERC20(xerc20).safeTransferFrom({from: msg.sender, to: module, value: amount});
} else if (command == Commands.KILL_GAUGE) {
if (msg.sender != IVoter(voter).emergencyCouncil()) revert NotAuthorized(Commands.KILL_GAUGE);
} else if (command == Commands.REVIVE_GAUGE) {
if (msg.sender != IVoter(voter).emergencyCouncil()) revert NotAuthorized(Commands.REVIVE_GAUGE);
} else {
revert InvalidCommand();
}
uint256 fee = IMessageSender(module).quote({_destinationDomain: _chainid, _messageBody: _message});
// skip if fee is 0 (some modules may support fee-less messaging)
if (fee > 0) {
IWETH(weth).safeTransferFrom({from: tx.origin, to: address(this), value: fee});
IWETH(weth).withdraw({wad: fee});
}
IMessageSender(module).sendMessage{value: fee}({_chainid: _chainid, _message: _message});
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
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);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
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);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IFactoryRegistry {
error FallbackFactory();
error InvalidFactoriesToPoolFactory();
error PathAlreadyApproved();
error PathNotApproved();
error SameAddress();
error ZeroAddress();
event Approve(address indexed poolFactory, address indexed votingRewardsFactory, address indexed gaugeFactory);
event Unapprove(address indexed poolFactory, address indexed votingRewardsFactory, address indexed gaugeFactory);
event SetManagedRewardsFactory(address indexed _newRewardsFactory);
/// @notice Approve a set of factories used in Velodrome Protocol.
/// Router.sol is able to swap any poolFactories currently approved.
/// Cannot approve address(0) factories.
/// Cannot approve path that is already approved.
/// Each poolFactory has one unique set and maintains state. In the case a poolFactory is unapproved
/// and then re-approved, the same set of factories must be used. In other words, you cannot overwrite
/// the factories tied to a poolFactory address.
/// VotingRewardsFactories and GaugeFactories may use the same address across multiple poolFactories.
/// @dev Callable by onlyOwner
/// @param poolFactory .
/// @param votingRewardsFactory .
/// @param gaugeFactory .
function approve(address poolFactory, address votingRewardsFactory, address gaugeFactory) external;
/// @notice Get the factories correlated to a poolFactory.
/// Once set, this can never be modified.
/// Returns the correlated factories even after an approved poolFactory is unapproved.
function factoriesToPoolFactory(address poolFactory)
external
view
returns (address votingRewardsFactory, address gaugeFactory);
/// @notice Check if a PoolFactory is approved within the factory registry. Router uses this method to
/// ensure a pool swapped from is approved.
/// @param poolFactory .
/// @return True if PoolFactory is approved, else false
function isPoolFactoryApproved(address poolFactory) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IRootMessageBridge {
error InvalidCommand();
error NotAuthorized(uint256 command);
error NotValidGauge();
error NotWETH();
/// @notice Returns the address of the xERC20 token that is bridged by this contract
function xerc20() external view returns (address);
/// @notice Returns the address of the voter contract
/// @dev Used to verify the sender of a message
function voter() external view returns (address);
/// @notice Returns the address of the factory registry contract
function factoryRegistry() external view returns (address);
/// @notice Returns the address of the WETH contract
function weth() external view returns (address);
/// @notice Sends a message to the msg.sender via the module contract
/// @param _message The message
/// @param _chainid The chain id of chain the recipient contract is on
function sendMessage(uint256 _chainid, bytes calldata _message) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IMessageSender {
error NotBridge();
event SentMessage(
uint32 indexed _destination, bytes32 indexed _recipient, uint256 _value, string _message, string _metadata
);
/// @notice Sends a message to the destination module
/// @dev All message modules must implement this function
/// @param _chainid The chain id of the destination chain
/// @param _message The message
function sendMessage(uint256 _chainid, bytes calldata _message) external payable;
/// @notice Quotes the amount of native token required to dispatch a message
/// @param _destinationDomain The chain id of the destination chain
/// @param _messageBody The message body to be dispatched
/// @return The amount of native token required to dispatch the message
function quote(uint256 _destinationDomain, bytes calldata _messageBody) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IFactoryRegistry} from "src/interfaces/external/IFactoryRegistry.sol";
interface IVoter {
error AlreadyVotedOrDeposited();
error DistributeWindow();
error GaugeAlreadyKilled();
error GaugeAlreadyRevived();
error NotEmergencyCouncil();
error ZeroAddress();
event GaugeKilled(address indexed gauge);
event GaugeRevived(address indexed gauge);
/// @dev Gauge => Amount claimable
function claimable(address gauge) external view returns (uint256);
/// @notice Address of Minter.sol
function minter() external view returns (address);
/// @notice Set new emergency council.
/// @dev Throws if not called by emergency council.
/// @param _emergencyCouncil .
function setEmergencyCouncil(address _emergencyCouncil) external;
function vote(uint256 _tokenId, address[] calldata _poolVote, uint256[] calldata _weights) external;
function gauges(address _pool) external view returns (address);
function isGauge(address _gauge) external view returns (bool);
function gaugeToFees(address _gauge) external view returns (address);
function gaugeToBribe(address _gauge) external view returns (address);
/// @dev Nft => Timestamp of last vote (ensures single vote per epoch)
function lastVoted(uint256 tokenId) external view returns (uint256);
function createGauge(address _poolFactory, address _pool) external returns (address);
function factoryRegistry() external view returns (address);
/// @dev Utility to distribute to gauges of pools in array.
/// @param _gauges Array of gauges to distribute to.
function distribute(address[] memory _gauges) external;
function isAlive(address _gauge) external view returns (bool);
function killGauge(address _gauge) external;
/// @notice Revives a killed gauge. Gauge will can receive emissions and deposits again.
/// @dev Throws if not called by emergency council.
/// Throws if gauge is not killed.
/// @param _gauge .
function reviveGauge(address _gauge) external;
function isWhitelistedToken(address _token) external view returns (bool);
function emergencyCouncil() external view returns (address);
function ve() external view returns (address);
/// @notice Claim emissions from gauges.
/// @param _gauges Array of gauges to collect emissions from.
// function claimRewards(address[] memory _gauges) external;
/// @notice Claim fees for a given NFT.
/// @dev Utility to help batch fee claims.
/// @param _fees Array of FeesVotingReward contracts to collect from.
/// @param _tokens Array of tokens that are used as fees.
/// @param _tokenId Id of veNFT that you wish to claim fees for.
function claimFees(address[] memory _fees, address[][] memory _tokens, uint256 _tokenId) external;
/// @notice Called by users to update voting balances in voting rewards contracts.
/// @param _tokenId Id of veNFT whose balance you wish to update.
function poke(uint256 _tokenId) external;
/// @notice Called by users to reset voting state. Required if you wish to make changes to
/// veNFT state (e.g. merge, split, deposit into managed etc).
/// Cannot reset in the same epoch that you voted in.
/// Can vote or deposit into a managed NFT again after reset.
/// @param _tokenId Id of veNFT you are reseting.
function reset(uint256 _tokenId) external;
/// @notice Standard OZ IGovernor using ve for vote weights.
function governor() external view returns (address);
/// @notice Whitelist (or unwhitelist) token for use in incentives.
/// @dev Throws if not called by governor.
/// @param _token .
/// @param _bool .
function whitelistToken(address _token, bool _bool) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC20} from "@openzeppelin5/contracts/token/ERC20/IERC20.sol";
interface IWETH is IERC20 {
function deposit() external payable;
function withdraw(uint256 wad) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.19 <0.9.0;
import {Ownable} from "@openzeppelin5/contracts/access/Ownable.sol";
import {EnumerableSet} from "@openzeppelin5/contracts/utils/structs/EnumerableSet.sol";
import {ICrossChainRegistry} from "../interfaces/bridge/ICrossChainRegistry.sol";
/// @title Cross Chain Registry
/// @notice Contains logic for managing registered chains from which messages can be sent to or received from
abstract contract CrossChainRegistry is ICrossChainRegistry, Ownable {
using EnumerableSet for EnumerableSet.UintSet;
using EnumerableSet for EnumerableSet.AddressSet;
/// @dev Stores list of trusted chains
EnumerableSet.UintSet internal _chainids;
/// @dev Stores list of modules
/// @dev Modules on other chains are not trusted by default and must be checked
EnumerableSet.AddressSet internal _modules;
/// @inheritdoc ICrossChainRegistry
mapping(uint256 => address) public chains;
constructor(address _owner) Ownable(_owner) {}
/// @inheritdoc ICrossChainRegistry
function registerChain(uint256 _chainid, address _module) external onlyOwner {
if (_chainid == 10) revert InvalidChainId();
if (!_modules.contains(_module)) revert ModuleNotAdded();
if (_chainids.contains(_chainid)) revert ChainAlreadyAdded();
chains[_chainid] = _module;
_chainids.add(_chainid);
emit ChainRegistered({_chainid: _chainid, _module: _module});
}
/// @inheritdoc ICrossChainRegistry
function deregisterChain(uint256 _chainid) external onlyOwner {
if (chains[_chainid] == address(0)) revert ChainNotRegistered();
delete chains[_chainid];
_chainids.remove(_chainid);
emit ChainDeregistered({_chainid: _chainid});
}
/// @inheritdoc ICrossChainRegistry
function setModule(uint256 _chainid, address _module) external onlyOwner {
if (!_modules.contains(_module)) revert ModuleNotAdded();
if (!_chainids.contains(_chainid)) revert ChainNotRegistered();
chains[_chainid] = _module;
emit ModuleSet({_chainid: _chainid, _module: _module});
}
/// @inheritdoc ICrossChainRegistry
function addModule(address _module) external onlyOwner {
if (_modules.contains(_module)) revert ModuleAlreadyAdded();
_modules.add(_module);
emit ModuleAdded({_module: _module});
}
/// @inheritdoc ICrossChainRegistry
function chainids() external view returns (uint256[] memory) {
return _chainids.values();
}
/// @inheritdoc ICrossChainRegistry
function containsChain(uint256 _chainid) external view returns (bool) {
return _chainids.contains(_chainid);
}
/// @inheritdoc ICrossChainRegistry
function modules() external view returns (address[] memory) {
return _modules.values();
}
/// @inheritdoc ICrossChainRegistry
function containsModule(address _module) external view returns (bool) {
return _modules.contains(_module);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.19 <0.9.0;
/// @notice Commands for x-chain interactions
/// @dev Existing commands cannot be modified but new commands can be added
library Commands {
uint256 public constant NOTIFY = 0x00;
uint256 public constant NOTIFY_WITHOUT_CLAIM = 0x01;
uint256 public constant GET_INCENTIVES = 0x02;
uint256 public constant GET_FEES = 0x03;
uint256 public constant DEPOSIT = 0x04;
uint256 public constant WITHDRAW = 0x05;
uint256 public constant CREATE_GAUGE = 0x06;
uint256 public constant KILL_GAUGE = 0x07;
uint256 public constant REVIVE_GAUGE = 0x08;
uint256 private constant COMMAND_OFFSET = 0;
uint256 private constant ADDRESS_OFFSET = 1;
/// @dev Second and Third offset are used in messages with multiple consecutive addresses
uint256 private constant SECOND_OFFSET = ADDRESS_OFFSET + 20;
uint256 private constant THIRD_OFFSET = SECOND_OFFSET + 20;
// Offsets for Create Gauge Command
uint256 private constant TOKEN0_OFFSET = THIRD_OFFSET + 20;
uint256 private constant TOKEN1_OFFSET = TOKEN0_OFFSET + 20;
uint256 private constant POOL_PARAM_OFFSET = TOKEN1_OFFSET + 20;
// Offsets for Reward Claims
uint256 private constant LENGTH_OFFSET = THIRD_OFFSET + 32;
uint256 private constant TOKENS_OFFSET = LENGTH_OFFSET + 1;
// Offset for Deposit/Withdraw
uint256 private constant TOKEN_ID_OFFSET = ADDRESS_OFFSET + 20 + 32;
uint256 private constant TIMESTAMP_OFFSET = TOKEN_ID_OFFSET + 32;
// Offset for Send Token amount
uint256 private constant AMOUNT_OFFSET = COMMAND_OFFSET + 20;
/// @notice Returns the command encoded in the message
/// @dev Assumes message is encoded as (command, ...)
/// @param _message The message to be decoded
function command(bytes calldata _message) internal pure returns (uint256) {
return uint256(uint8(bytes1(_message[COMMAND_OFFSET:COMMAND_OFFSET + 1])));
}
/// @notice Returns the address encoded in the message
/// @dev Assumes message is encoded as (command, address, ...)
/// @param _message The message to be decoded
function toAddress(bytes calldata _message) internal pure returns (address) {
return address(bytes20(_message[ADDRESS_OFFSET:ADDRESS_OFFSET + 20]));
}
/// @notice Returns the message without the encoded command
/// @dev Assumes message is encoded as (command, message)
/// @param _message The message to be decoded
function messageWithoutCommand(bytes calldata _message) internal pure returns (bytes calldata) {
return bytes(_message[COMMAND_OFFSET + 1:]);
}
/// @notice Returns the amount encoded in the message
/// @dev Assumes message is encoded as (command, amount, ...)
/// @param _message The message to be decoded
function amount(bytes calldata _message) internal pure returns (uint256) {
return uint256(bytes32(_message[SECOND_OFFSET:SECOND_OFFSET + 32]));
}
/// @notice Returns the amount, tokenId and timestamp encoded in the message
/// @dev Assumes message is encoded as (command, amount, tokenId, timestamp, ...)
/// @param _message The message to be decoded
function voteParams(bytes calldata _message) internal pure returns (uint256, uint256, uint256) {
return (
uint256(bytes32(_message[SECOND_OFFSET:SECOND_OFFSET + 32])),
uint256(bytes32(_message[TOKEN_ID_OFFSET:TIMESTAMP_OFFSET])),
uint256(uint40(bytes5(_message[TIMESTAMP_OFFSET:TIMESTAMP_OFFSET + 5])))
);
}
/// @notice Returns the recipient and amount encoded in the message
/// @dev Assumes no command is encoded and message is encoded as (address, amount)
/// @param _message The message to be decoded
function recipientAndAmount(bytes calldata _message) internal pure returns (address, uint256) {
return (
address(bytes20(_message[COMMAND_OFFSET:COMMAND_OFFSET + 20])),
uint256(bytes32(_message[AMOUNT_OFFSET:AMOUNT_OFFSET + 32]))
);
}
/// @notice Returns the parameters necessary for gauge creation, encoded in the message
/// @dev Assumes message is encoded as (command, address, address, address, address, uint24)
/// @param _message The message to be decoded
function createGaugeParams(bytes calldata _message)
internal
pure
returns (address, address, address, address, address, uint24)
{
return (
address(bytes20(_message[ADDRESS_OFFSET:ADDRESS_OFFSET + 20])),
address(bytes20(_message[SECOND_OFFSET:SECOND_OFFSET + 20])),
address(bytes20(_message[THIRD_OFFSET:THIRD_OFFSET + 20])),
address(bytes20(_message[TOKEN0_OFFSET:TOKEN0_OFFSET + 20])),
address(bytes20(_message[TOKEN1_OFFSET:TOKEN1_OFFSET + 20])),
uint24(bytes3(_message[POOL_PARAM_OFFSET:POOL_PARAM_OFFSET + 3]))
);
}
/// @notice Returns the owner encoded in the message
/// @dev Assumes message is encoded as (command, address, owner, ...)
/// @param _message The message to be decoded
function owner(bytes calldata _message) internal pure returns (address) {
return address(bytes20(_message[SECOND_OFFSET:SECOND_OFFSET + 20]));
}
/// @notice Returns the tokenId encoded in a reward claiming message
/// @dev Assumes message is encoded as (command, address, tokenId, ...)
/// @param _message The message to be decoded
function tokenId(bytes calldata _message) internal pure returns (uint256) {
return uint256(bytes32(_message[THIRD_OFFSET:THIRD_OFFSET + 32]));
}
/// @notice Returns the token addresses encoded in the message
/// @dev Assumes message has length and token addresses encoded
/// @param _message The message to be decoded
function tokens(bytes calldata _message) internal pure returns (address[] memory _tokens) {
uint256 length = uint8(bytes1(_message[LENGTH_OFFSET:LENGTH_OFFSET + 1]));
_tokens = new address[](length);
for (uint256 i = 0; i < length; i++) {
_tokens[i] =
address(uint160(uint256(bytes32(_message[TOKENS_OFFSET + (i * 32):TOKENS_OFFSET + ((i + 1) * 32)]))));
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
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();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
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);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
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);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ICrossChainRegistry {
event ChainRegistered(uint256 indexed _chainid, address indexed _module);
event ChainDeregistered(uint256 indexed _chainid);
event ModuleAdded(address indexed _module);
event ModuleSet(uint256 indexed _chainid, address indexed _module);
error ChainAlreadyAdded();
error ChainNotRegistered();
error InvalidChainId();
error ModuleAlreadyAdded();
error ModuleNotAdded();
/// @notice Add support for a chain with messages forwarded to a given module
/// @dev Check module code if adding a new module for the first time
/// @param _chainid Chain ID to add
/// @param _module Module to forward messages to, must be registered
function registerChain(uint256 _chainid, address _module) external;
/// @notice Remove support for a chain
/// @param _chainid Chain ID to remove
function deregisterChain(uint256 _chainid) external;
/// @notice Add a module to be used for message forwarding
/// @dev Modules are deployed on other chains at the same address
/// @dev Modules are not trusted by default and must be checked prior to usage
/// @param _module Module to register
function addModule(address _module) external;
/// @notice Update a module used by a chain for message forwarding
/// @param _chainid Chain ID to update
/// @param _module Module to forward messages to
function setModule(uint256 _chainid, address _module) external;
/// @notice Get message module for a given chain
/// @param _chainid Chain ID to check
function chains(uint256 _chainid) external view returns (address);
/// @notice Get list of supported chains
function chainids() external view returns (uint256[] memory);
/// @notice Check if a chain is supported
/// @param _chainid Chain ID to check
function containsChain(uint256 _chainid) external view returns (bool);
/// @notice Get list of registered modules
function modules() external view returns (address[] memory);
/// @notice Check if a module is registered
/// @param _module Module to check
function containsModule(address _module) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
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;
}
}{
"remappings": [
"@openzeppelin5/contracts/=lib/openzeppelin-contracts/contracts/",
"ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/src/=lib/forge-std/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"createX/=lib/createX/src/",
"@nomad-xyz/=lib/ExcessivelySafeCall/",
"@hyperlane/=node_modules/@hyperlane-xyz/",
"@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/",
"@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/",
"ExcessivelySafeCall/=lib/ExcessivelySafeCall/src/",
"forge-gas-snapshot/=lib/forge-gas-snapshot/src/",
"openzeppelin/=lib/createX/lib/openzeppelin-contracts/contracts/",
"solady/=lib/createX/lib/solady/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false,
"libraries": {
"src/libraries/rateLimits/RateLimitMidpointCommonLibrary.sol": {
"RateLimitMidpointCommonLibrary": "0x8326B5f31549d12943088CF3F8Dd637dd6465a99"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_xerc20","type":"address"},{"internalType":"address","name":"_voter","type":"address"},{"internalType":"address","name":"_weth","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":"ChainAlreadyAdded","type":"error"},{"inputs":[],"name":"ChainNotRegistered","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidChainId","type":"error"},{"inputs":[],"name":"InvalidCommand","type":"error"},{"inputs":[],"name":"ModuleAlreadyAdded","type":"error"},{"inputs":[],"name":"ModuleNotAdded","type":"error"},{"inputs":[{"internalType":"uint256","name":"command","type":"uint256"}],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"NotValidGauge","type":"error"},{"inputs":[],"name":"NotWETH","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":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_chainid","type":"uint256"}],"name":"ChainDeregistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_chainid","type":"uint256"},{"indexed":true,"internalType":"address","name":"_module","type":"address"}],"name":"ChainRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_module","type":"address"}],"name":"ModuleAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_chainid","type":"uint256"},{"indexed":true,"internalType":"address","name":"_module","type":"address"}],"name":"ModuleSet","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"},{"inputs":[{"internalType":"address","name":"_module","type":"address"}],"name":"addModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"chainids","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"chains","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainid","type":"uint256"}],"name":"containsChain","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_module","type":"address"}],"name":"containsModule","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainid","type":"uint256"}],"name":"deregisterChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factoryRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"modules","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainid","type":"uint256"},{"internalType":"address","name":"_module","type":"address"}],"name":"registerChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainid","type":"uint256"},{"internalType":"bytes","name":"_message","type":"bytes"}],"name":"sendMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainid","type":"uint256"},{"internalType":"address","name":"_module","type":"address"}],"name":"setModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"voter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"xerc20","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
61010060405234801561001157600080fd5b50604051611b1c380380611b1c83398101604081905261003091610166565b83806001600160a01b03811661006057604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b610069816100fa565b50506001600160a01b03808416608052821660a081905260408051633bf0c9fb60e01b81529051633bf0c9fb916004808201926020929091908290030181865afa1580156100bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100df91906101ba565b6001600160a01b0390811660c0521660e052506101dc915050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b038116811461016157600080fd5b919050565b6000806000806080858703121561017c57600080fd5b6101858561014a565b93506101936020860161014a565b92506101a16040860161014a565b91506101af6060860161014a565b905092959194509250565b6000602082840312156101cc57600080fd5b6101d58261014a565b9392505050565b60805160a05160c05160e0516118b361026960003960008181610112015281816101da01528181610ddd0152610e1b015260008181610189015261087201526000818161020e015281816106b7015281816107980152818161094801528181610a1f01528181610ae701528181610bc40152610c870152600081816103df0152610b9201526118b36000f3fe6080604052600436106101025760003560e01c80637eaaac3811610095578063e68e00bf11610064578063e68e00bf14610349578063f2fde38b14610369578063f772795914610389578063f7e80e98146103ab578063ffcbd8d0146103cd57600080fd5b80637eaaac38146102bb5780638da5cb5b146102eb578063e289adcd14610309578063e31b84d81461032957600080fd5b8063550325b5116100d1578063550325b5146102305780635d29163014610266578063715018a6146102865780637e25b5f81461029b57600080fd5b80631ed86f19146101575780633bf0c9fb146101775780633fc8cef3146101c857806346c96aac146101fc57600080fd5b3661015257336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461015057604051635724f38560e01b815260040160405180910390fd5b005b600080fd5b34801561016357600080fd5b50610150610172366004611503565b610401565b34801561018357600080fd5b506101ab7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156101d457600080fd5b506101ab7f000000000000000000000000000000000000000000000000000000000000000081565b34801561020857600080fd5b506101ab7f000000000000000000000000000000000000000000000000000000000000000081565b34801561023c57600080fd5b506101ab61024b366004611520565b6005602052600090815260409020546001600160a01b031681565b34801561027257600080fd5b50610150610281366004611539565b610475565b34801561029257600080fd5b50610150610526565b3480156102a757600080fd5b506101506102b6366004611539565b61053a565b3480156102c757600080fd5b506102db6102d6366004611503565b610621565b60405190151581526020016101bf565b3480156102f757600080fd5b506000546001600160a01b03166101ab565b34801561031557600080fd5b50610150610324366004611569565b610634565b34801561033557600080fd5b506102db610344366004611520565b610eec565b34801561035557600080fd5b50610150610364366004611520565b610ef9565b34801561037557600080fd5b50610150610384366004611503565b610f8c565b34801561039557600080fd5b5061039e610fca565b6040516101bf91906115e7565b3480156103b757600080fd5b506103c0610fdb565b6040516101bf919061162a565b3480156103d957600080fd5b506101ab7f000000000000000000000000000000000000000000000000000000000000000081565b610409610fe7565b610414600382611014565b156104325760405163079f102d60e51b815260040160405180910390fd5b61043d600382611039565b506040516001600160a01b038216907fead6a006345da1073a106d5f32372d2d2204f46cb0b4bca8f5ebafcbbed12b8a90600090a250565b61047d610fe7565b610488600382611014565b6104a55760405163d9b2550b60e01b815260040160405180910390fd5b6104b060018361104e565b6104cd57604051634631318960e11b815260040160405180910390fd5b60008281526005602052604080822080546001600160a01b0319166001600160a01b0385169081179091559051909184917fbf17fdfd9b9ec4dc5b4bfa40af4b752c82856d2fe977cf488315f8e64efc54a99190a35050565b61052e610fe7565b6105386000611066565b565b610542610fe7565b81600a0361056357604051633d23e4d160e11b815260040160405180910390fd5b61056e600382611014565b61058b5760405163d9b2550b60e01b815260040160405180910390fd5b61059660018361104e565b156105b4576040516301419f6d60e21b815260040160405180910390fd5b600082815260056020526040902080546001600160a01b0319166001600160a01b0383161790556105e66001836110b6565b506040516001600160a01b0382169083907f7f74812a5c28f04eea9007878d0e63eb304afe494a442babbe1b2875fbc1cfd690600090a35050565b600061062e600383611014565b92915050565b61063f60018461104e565b61065c57604051634631318960e11b815260040160405180910390fd5b6000838152600560205260408120546001600160a01b03169061067f84846110c2565b90506004810361076257600061069585856110f2565b60405163c4f0816560e01b81526001600160a01b0380831660048301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063c4f0816590602401602060405180830381865afa158015610700573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610724919061166b565b6001600160a01b0316336001600160a01b03161461075c576040516318488cc760e31b81526004818101526024015b60405180910390fd5b50610d54565b6005810361083957600061077685856110f2565b60405163c4f0816560e01b81526001600160a01b0380831660048301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063c4f0816590602401602060405180830381865afa1580156107e1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610805919061166b565b6001600160a01b0316336001600160a01b03161461075c576040516318488cc760e31b815260056004820152602401610753565b6006810361091257600061084d85856110f2565b604051631217afdb60e01b81526001600160a01b0380831660048301529192506000917f00000000000000000000000000000000000000000000000000000000000000001690631217afdb906024016040805180830381865afa1580156108b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108dc9190611688565b915050336001600160a01b0382161461090b576040516318488cc760e31b815260066004820152602401610753565b5050610d54565b600281036109e957600061092685856110f2565b60405163929c8dcd60e01b81526001600160a01b0380831660048301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063929c8dcd90602401602060405180830381865afa158015610991573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b5919061166b565b6001600160a01b0316336001600160a01b03161461075c576040516318488cc760e31b815260026004820152602401610753565b60038103610ac05760006109fd85856110f2565b60405163c4f0816560e01b81526001600160a01b0380831660048301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063c4f0816590602401602060405180830381865afa158015610a68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8c919061166b565b6001600160a01b0316336001600160a01b03161461075c576040516318488cc760e31b815260036004820152602401610753565b801580610acd5750600181145b15610bba57604051631703e5f960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690631703e5f990602401602060405180830381865afa158015610b36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b5a91906116b7565b610b7757604051635d6da4f560e01b815260040160405180910390fd5b6000610b838585611123565b905061075c6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016338584611161565b60078103610c7d577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637778960e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c44919061166b565b6001600160a01b0316336001600160a01b031614610c78576040516318488cc760e31b815260076004820152602401610753565b610d54565b60088103610d3b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637778960e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ce3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d07919061166b565b6001600160a01b0316336001600160a01b031614610c78576040516318488cc760e31b815260086004820152602401610753565b6040516312f269e560e01b815260040160405180910390fd5b6040516377d2b77160e01b81526000906001600160a01b038416906377d2b77190610d87908990899089906004016116d9565b602060405180830381865afa158015610da4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dc8919061170f565b90508015610e8057610e056001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016323084611161565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015610e6757600080fd5b505af1158015610e7b573d6000803e3d6000fd5b505050505b60405163e289adcd60e01b81526001600160a01b0384169063e289adcd908390610eb2908a908a908a906004016116d9565b6000604051808303818588803b158015610ecb57600080fd5b505af1158015610edf573d6000803e3d6000fd5b5050505050505050505050565b600061062e60018361104e565b610f01610fe7565b6000818152600560205260409020546001600160a01b0316610f3657604051634631318960e11b815260040160405180910390fd5b600081815260056020526040902080546001600160a01b0319169055610f5d6001826111c1565b5060405181907f4732a5e8ed8dad61e5185f5b8d342146071e8029d9055b85b5ff24078cee3d8690600090a250565b610f94610fe7565b6001600160a01b038116610fbe57604051631e4fbdf760e01b815260006004820152602401610753565b610fc781611066565b50565b6060610fd660016111cd565b905090565b6060610fd660036111cd565b6000546001600160a01b031633146105385760405163118cdaa760e01b8152336004820152602401610753565b6001600160a01b038116600090815260018301602052604081205415155b9392505050565b6000611032836001600160a01b0384166111da565b60008181526001830160205260408120541515611032565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600061103283836111da565b60008281836110d282600161173e565b926110df93929190611751565b6110e89161177b565b60f81c9392505050565b60008260018361110382601461173e565b9261111093929190611751565b611119916117b1565b60601c9392505050565b600082826111336001601461173e565b906111406001601461173e565b61114b90602061173e565b9261115893929190611751565b611032916117f1565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b1790526111bb908590611229565b50505050565b60006110328383611291565b606060006110328361138b565b60008181526001830160205260408120546112215750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561062e565b50600061062e565b600061123e6001600160a01b038416836113e7565b9050805160001415801561126357508080602001905181019061126191906116b7565b155b1561128c57604051635274afe760e01b81526001600160a01b0384166004820152602401610753565b505050565b6000818152600183016020526040812054801561137a5760006112b560018361180f565b85549091506000906112c99060019061180f565b905080821461132e5760008660000182815481106112e9576112e9611822565b906000526020600020015490508087600001848154811061130c5761130c611822565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061133f5761133f611838565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061062e565b600091505061062e565b5092915050565b6060816000018054806020026020016040519081016040528092919081815260200182805480156113db57602002820191906000526020600020905b8154815260200190600101908083116113c7575b50505050509050919050565b60606110328383600084600080856001600160a01b0316848660405161140d919061184e565b60006040518083038185875af1925050503d806000811461144a576040519150601f19603f3d011682016040523d82523d6000602084013e61144f565b606091505b509150915061145f868383611469565b9695505050505050565b60608261147e57611479826114c5565b611032565b815115801561149557506001600160a01b0384163b155b156114be57604051639996b31560e01b81526001600160a01b0385166004820152602401610753565b5080611032565b8051156114d55780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6001600160a01b0381168114610fc757600080fd5b60006020828403121561151557600080fd5b8135611032816114ee565b60006020828403121561153257600080fd5b5035919050565b6000806040838503121561154c57600080fd5b82359150602083013561155e816114ee565b809150509250929050565b60008060006040848603121561157e57600080fd5b83359250602084013567ffffffffffffffff81111561159c57600080fd5b8401601f810186136115ad57600080fd5b803567ffffffffffffffff8111156115c457600080fd5b8660208284010111156115d657600080fd5b939660209190910195509293505050565b602080825282518282018190526000918401906040840190835b8181101561161f578351835260209384019390920191600101611601565b509095945050505050565b602080825282518282018190526000918401906040840190835b8181101561161f5783516001600160a01b0316835260209384019390920191600101611644565b60006020828403121561167d57600080fd5b8151611032816114ee565b6000806040838503121561169b57600080fd5b82516116a6816114ee565b602084015190925061155e816114ee565b6000602082840312156116c957600080fd5b8151801515811461103257600080fd5b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b60006020828403121561172157600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561062e5761062e611728565b6000808585111561176157600080fd5b8386111561176e57600080fd5b5050820193919092039150565b80356001600160f81b03198116906001841015611384576001600160f81b031960019490940360031b84901b1690921692915050565b80356bffffffffffffffffffffffff198116906014841015611384576bffffffffffffffffffffffff1960149490940360031b84901b1690921692915050565b8035602083101561062e57600019602084900360031b1b1692915050565b8181038181111561062e5761062e611728565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b6000825160005b8181101561186f5760208186018101518583015201611855565b50600092019182525091905056fea26469706673582212209460effbaa7883ed1a5e87cf925ed368b990eade51b3a2f2559081201026cfa964736f6c634300081b0033000000000000000000000000ba4bb89f4d1e66aa86b60696534892ae0ccf91f50000000000000000000000007f9adfbd38b669f03d1d11000bc76b9aaea28a8100000000000000000000000041c914ee0c7e1a5edcd0295623e6dc557b5abf3c0000000000000000000000004200000000000000000000000000000000000006
Deployed Bytecode
0x6080604052600436106101025760003560e01c80637eaaac3811610095578063e68e00bf11610064578063e68e00bf14610349578063f2fde38b14610369578063f772795914610389578063f7e80e98146103ab578063ffcbd8d0146103cd57600080fd5b80637eaaac38146102bb5780638da5cb5b146102eb578063e289adcd14610309578063e31b84d81461032957600080fd5b8063550325b5116100d1578063550325b5146102305780635d29163014610266578063715018a6146102865780637e25b5f81461029b57600080fd5b80631ed86f19146101575780633bf0c9fb146101775780633fc8cef3146101c857806346c96aac146101fc57600080fd5b3661015257336001600160a01b037f0000000000000000000000004200000000000000000000000000000000000006161461015057604051635724f38560e01b815260040160405180910390fd5b005b600080fd5b34801561016357600080fd5b50610150610172366004611503565b610401565b34801561018357600080fd5b506101ab7f000000000000000000000000f4c67cdeaab8360370f41514d06e32ccd8aa1d7b81565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156101d457600080fd5b506101ab7f000000000000000000000000420000000000000000000000000000000000000681565b34801561020857600080fd5b506101ab7f00000000000000000000000041c914ee0c7e1a5edcd0295623e6dc557b5abf3c81565b34801561023c57600080fd5b506101ab61024b366004611520565b6005602052600090815260409020546001600160a01b031681565b34801561027257600080fd5b50610150610281366004611539565b610475565b34801561029257600080fd5b50610150610526565b3480156102a757600080fd5b506101506102b6366004611539565b61053a565b3480156102c757600080fd5b506102db6102d6366004611503565b610621565b60405190151581526020016101bf565b3480156102f757600080fd5b506000546001600160a01b03166101ab565b34801561031557600080fd5b50610150610324366004611569565b610634565b34801561033557600080fd5b506102db610344366004611520565b610eec565b34801561035557600080fd5b50610150610364366004611520565b610ef9565b34801561037557600080fd5b50610150610384366004611503565b610f8c565b34801561039557600080fd5b5061039e610fca565b6040516101bf91906115e7565b3480156103b757600080fd5b506103c0610fdb565b6040516101bf919061162a565b3480156103d957600080fd5b506101ab7f0000000000000000000000007f9adfbd38b669f03d1d11000bc76b9aaea28a8181565b610409610fe7565b610414600382611014565b156104325760405163079f102d60e51b815260040160405180910390fd5b61043d600382611039565b506040516001600160a01b038216907fead6a006345da1073a106d5f32372d2d2204f46cb0b4bca8f5ebafcbbed12b8a90600090a250565b61047d610fe7565b610488600382611014565b6104a55760405163d9b2550b60e01b815260040160405180910390fd5b6104b060018361104e565b6104cd57604051634631318960e11b815260040160405180910390fd5b60008281526005602052604080822080546001600160a01b0319166001600160a01b0385169081179091559051909184917fbf17fdfd9b9ec4dc5b4bfa40af4b752c82856d2fe977cf488315f8e64efc54a99190a35050565b61052e610fe7565b6105386000611066565b565b610542610fe7565b81600a0361056357604051633d23e4d160e11b815260040160405180910390fd5b61056e600382611014565b61058b5760405163d9b2550b60e01b815260040160405180910390fd5b61059660018361104e565b156105b4576040516301419f6d60e21b815260040160405180910390fd5b600082815260056020526040902080546001600160a01b0319166001600160a01b0383161790556105e66001836110b6565b506040516001600160a01b0382169083907f7f74812a5c28f04eea9007878d0e63eb304afe494a442babbe1b2875fbc1cfd690600090a35050565b600061062e600383611014565b92915050565b61063f60018461104e565b61065c57604051634631318960e11b815260040160405180910390fd5b6000838152600560205260408120546001600160a01b03169061067f84846110c2565b90506004810361076257600061069585856110f2565b60405163c4f0816560e01b81526001600160a01b0380831660048301529192507f00000000000000000000000041c914ee0c7e1a5edcd0295623e6dc557b5abf3c9091169063c4f0816590602401602060405180830381865afa158015610700573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610724919061166b565b6001600160a01b0316336001600160a01b03161461075c576040516318488cc760e31b81526004818101526024015b60405180910390fd5b50610d54565b6005810361083957600061077685856110f2565b60405163c4f0816560e01b81526001600160a01b0380831660048301529192507f00000000000000000000000041c914ee0c7e1a5edcd0295623e6dc557b5abf3c9091169063c4f0816590602401602060405180830381865afa1580156107e1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610805919061166b565b6001600160a01b0316336001600160a01b03161461075c576040516318488cc760e31b815260056004820152602401610753565b6006810361091257600061084d85856110f2565b604051631217afdb60e01b81526001600160a01b0380831660048301529192506000917f000000000000000000000000f4c67cdeaab8360370f41514d06e32ccd8aa1d7b1690631217afdb906024016040805180830381865afa1580156108b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108dc9190611688565b915050336001600160a01b0382161461090b576040516318488cc760e31b815260066004820152602401610753565b5050610d54565b600281036109e957600061092685856110f2565b60405163929c8dcd60e01b81526001600160a01b0380831660048301529192507f00000000000000000000000041c914ee0c7e1a5edcd0295623e6dc557b5abf3c9091169063929c8dcd90602401602060405180830381865afa158015610991573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b5919061166b565b6001600160a01b0316336001600160a01b03161461075c576040516318488cc760e31b815260026004820152602401610753565b60038103610ac05760006109fd85856110f2565b60405163c4f0816560e01b81526001600160a01b0380831660048301529192507f00000000000000000000000041c914ee0c7e1a5edcd0295623e6dc557b5abf3c9091169063c4f0816590602401602060405180830381865afa158015610a68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8c919061166b565b6001600160a01b0316336001600160a01b03161461075c576040516318488cc760e31b815260036004820152602401610753565b801580610acd5750600181145b15610bba57604051631703e5f960e01b81523360048201527f00000000000000000000000041c914ee0c7e1a5edcd0295623e6dc557b5abf3c6001600160a01b031690631703e5f990602401602060405180830381865afa158015610b36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b5a91906116b7565b610b7757604051635d6da4f560e01b815260040160405180910390fd5b6000610b838585611123565b905061075c6001600160a01b037f0000000000000000000000007f9adfbd38b669f03d1d11000bc76b9aaea28a8116338584611161565b60078103610c7d577f00000000000000000000000041c914ee0c7e1a5edcd0295623e6dc557b5abf3c6001600160a01b0316637778960e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c44919061166b565b6001600160a01b0316336001600160a01b031614610c78576040516318488cc760e31b815260076004820152602401610753565b610d54565b60088103610d3b577f00000000000000000000000041c914ee0c7e1a5edcd0295623e6dc557b5abf3c6001600160a01b0316637778960e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ce3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d07919061166b565b6001600160a01b0316336001600160a01b031614610c78576040516318488cc760e31b815260086004820152602401610753565b6040516312f269e560e01b815260040160405180910390fd5b6040516377d2b77160e01b81526000906001600160a01b038416906377d2b77190610d87908990899089906004016116d9565b602060405180830381865afa158015610da4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dc8919061170f565b90508015610e8057610e056001600160a01b037f000000000000000000000000420000000000000000000000000000000000000616323084611161565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015610e6757600080fd5b505af1158015610e7b573d6000803e3d6000fd5b505050505b60405163e289adcd60e01b81526001600160a01b0384169063e289adcd908390610eb2908a908a908a906004016116d9565b6000604051808303818588803b158015610ecb57600080fd5b505af1158015610edf573d6000803e3d6000fd5b5050505050505050505050565b600061062e60018361104e565b610f01610fe7565b6000818152600560205260409020546001600160a01b0316610f3657604051634631318960e11b815260040160405180910390fd5b600081815260056020526040902080546001600160a01b0319169055610f5d6001826111c1565b5060405181907f4732a5e8ed8dad61e5185f5b8d342146071e8029d9055b85b5ff24078cee3d8690600090a250565b610f94610fe7565b6001600160a01b038116610fbe57604051631e4fbdf760e01b815260006004820152602401610753565b610fc781611066565b50565b6060610fd660016111cd565b905090565b6060610fd660036111cd565b6000546001600160a01b031633146105385760405163118cdaa760e01b8152336004820152602401610753565b6001600160a01b038116600090815260018301602052604081205415155b9392505050565b6000611032836001600160a01b0384166111da565b60008181526001830160205260408120541515611032565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600061103283836111da565b60008281836110d282600161173e565b926110df93929190611751565b6110e89161177b565b60f81c9392505050565b60008260018361110382601461173e565b9261111093929190611751565b611119916117b1565b60601c9392505050565b600082826111336001601461173e565b906111406001601461173e565b61114b90602061173e565b9261115893929190611751565b611032916117f1565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b1790526111bb908590611229565b50505050565b60006110328383611291565b606060006110328361138b565b60008181526001830160205260408120546112215750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561062e565b50600061062e565b600061123e6001600160a01b038416836113e7565b9050805160001415801561126357508080602001905181019061126191906116b7565b155b1561128c57604051635274afe760e01b81526001600160a01b0384166004820152602401610753565b505050565b6000818152600183016020526040812054801561137a5760006112b560018361180f565b85549091506000906112c99060019061180f565b905080821461132e5760008660000182815481106112e9576112e9611822565b906000526020600020015490508087600001848154811061130c5761130c611822565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061133f5761133f611838565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061062e565b600091505061062e565b5092915050565b6060816000018054806020026020016040519081016040528092919081815260200182805480156113db57602002820191906000526020600020905b8154815260200190600101908083116113c7575b50505050509050919050565b60606110328383600084600080856001600160a01b0316848660405161140d919061184e565b60006040518083038185875af1925050503d806000811461144a576040519150601f19603f3d011682016040523d82523d6000602084013e61144f565b606091505b509150915061145f868383611469565b9695505050505050565b60608261147e57611479826114c5565b611032565b815115801561149557506001600160a01b0384163b155b156114be57604051639996b31560e01b81526001600160a01b0385166004820152602401610753565b5080611032565b8051156114d55780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6001600160a01b0381168114610fc757600080fd5b60006020828403121561151557600080fd5b8135611032816114ee565b60006020828403121561153257600080fd5b5035919050565b6000806040838503121561154c57600080fd5b82359150602083013561155e816114ee565b809150509250929050565b60008060006040848603121561157e57600080fd5b83359250602084013567ffffffffffffffff81111561159c57600080fd5b8401601f810186136115ad57600080fd5b803567ffffffffffffffff8111156115c457600080fd5b8660208284010111156115d657600080fd5b939660209190910195509293505050565b602080825282518282018190526000918401906040840190835b8181101561161f578351835260209384019390920191600101611601565b509095945050505050565b602080825282518282018190526000918401906040840190835b8181101561161f5783516001600160a01b0316835260209384019390920191600101611644565b60006020828403121561167d57600080fd5b8151611032816114ee565b6000806040838503121561169b57600080fd5b82516116a6816114ee565b602084015190925061155e816114ee565b6000602082840312156116c957600080fd5b8151801515811461103257600080fd5b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b60006020828403121561172157600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561062e5761062e611728565b6000808585111561176157600080fd5b8386111561176e57600080fd5b5050820193919092039150565b80356001600160f81b03198116906001841015611384576001600160f81b031960019490940360031b84901b1690921692915050565b80356bffffffffffffffffffffffff198116906014841015611384576bffffffffffffffffffffffff1960149490940360031b84901b1690921692915050565b8035602083101561062e57600019602084900360031b1b1692915050565b8181038181111561062e5761062e611728565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b6000825160005b8181101561186f5760208186018101518583015201611855565b50600092019182525091905056fea26469706673582212209460effbaa7883ed1a5e87cf925ed368b990eade51b3a2f2559081201026cfa964736f6c634300081b0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ba4bb89f4d1e66aa86b60696534892ae0ccf91f50000000000000000000000007f9adfbd38b669f03d1d11000bc76b9aaea28a8100000000000000000000000041c914ee0c7e1a5edcd0295623e6dc557b5abf3c0000000000000000000000004200000000000000000000000000000000000006
-----Decoded View---------------
Arg [0] : _owner (address): 0xBA4BB89f4d1E66AA86B60696534892aE0cCf91F5
Arg [1] : _xerc20 (address): 0x7f9AdFbd38b669F03d1d11000Bc76b9AaEA28A81
Arg [2] : _voter (address): 0x41C914ee0c7E1A5edCD0295623e6dC557B5aBf3C
Arg [3] : _weth (address): 0x4200000000000000000000000000000000000006
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000ba4bb89f4d1e66aa86b60696534892ae0ccf91f5
Arg [1] : 0000000000000000000000007f9adfbd38b669f03d1d11000bc76b9aaea28a81
Arg [2] : 00000000000000000000000041c914ee0c7e1a5edcd0295623e6dc557b5abf3c
Arg [3] : 0000000000000000000000004200000000000000000000000000000000000006
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.